diff options
author | Patrick Shaughnessy <pshaughn@comcast.net> | 2020-01-23 12:48:58 -0500 |
---|---|---|
committer | Patrick Shaughnessy <pshaughn@comcast.net> | 2020-01-27 15:35:39 -0500 |
commit | 6d15c0682d3c800886b6a92f8200d7f907a3116f (patch) | |
tree | 13068e6b3d4b14fa82545ff08ed8131cff499dfe /components/script/dom/performanceobserver.rs | |
parent | d0f64d9d56979f66a0de2f239c3fc691b45535d6 (diff) | |
download | servo-6d15c0682d3c800886b6a92f8200d7f907a3116f.tar.gz servo-6d15c0682d3c800886b6a92f8200d7f907a3116f.zip |
Performance observers better, not perfect
Diffstat (limited to 'components/script/dom/performanceobserver.rs')
-rw-r--r-- | components/script/dom/performanceobserver.rs | 140 |
1 files changed, 115 insertions, 25 deletions
diff --git a/components/script/dom/performanceobserver.rs b/components/script/dom/performanceobserver.rs index 0683a3cb46e..e107c4a08d9 100644 --- a/components/script/dom/performanceobserver.rs +++ b/components/script/dom/performanceobserver.rs @@ -13,11 +13,13 @@ use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; +use crate::dom::console::Console; use crate::dom::globalscope::GlobalScope; use crate::dom::performance::PerformanceEntryList; use crate::dom::performanceentry::PerformanceEntry; use crate::dom::performanceobserverentrylist::PerformanceObserverEntryList; use dom_struct::dom_struct; +use std::cell::Cell; use std::rc::Rc; /// List of allowed performance entry types. @@ -31,12 +33,20 @@ const VALID_ENTRY_TYPES: &'static [&'static str] = &[ "paint", // Paint Timing API ]; +#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)] +enum ObserverType { + Undefined, + Single, + Multiple, +} + #[dom_struct] pub struct PerformanceObserver { reflector_: Reflector, #[ignore_malloc_size_of = "can't measure Rc values"] callback: Rc<PerformanceObserverCallback>, entries: DomRefCell<DOMPerformanceEntryList>, + observer_type: Cell<ObserverType>, } impl PerformanceObserver { @@ -48,6 +58,7 @@ impl PerformanceObserver { reflector_: Reflector::new(), callback, entries, + observer_type: Cell::new(ObserverType::Undefined), } } @@ -77,17 +88,15 @@ impl PerformanceObserver { /// Trigger performance observer callback with the list of performance entries /// buffered since the last callback call. pub fn notify(&self) { - let entries = self.entries.borrow(); - if entries.is_empty() { + if self.entries.borrow().is_empty() { return; } - let mut entries = entries.clone(); - let global = self.global(); - let entry_list = PerformanceEntryList::new(entries.drain(..).collect()); - let observer_entry_list = PerformanceObserverEntryList::new(&global, entry_list); + let entry_list = PerformanceEntryList::new(self.entries.borrow_mut().drain(..).collect()); + let observer_entry_list = PerformanceObserverEntryList::new(&self.global(), entry_list); + // using self both as thisArg and as the second formal argument let _ = self .callback - .Call__(&observer_entry_list, self, ExceptionHandling::Report); + .Call_(self, &observer_entry_list, self, ExceptionHandling::Report); } pub fn callback(&self) -> Rc<PerformanceObserverCallback> { @@ -106,31 +115,112 @@ impl PerformanceObserver { impl PerformanceObserverMethods for PerformanceObserver { // https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe() fn Observe(&self, options: &PerformanceObserverInit) -> Fallible<()> { - // step 1 - // Make sure the client is asking to observe events from allowed entry types. - let entry_types = options - .entryTypes - .iter() - .filter(|e| VALID_ENTRY_TYPES.contains(&e.as_ref())) - .map(|e| e.clone()) - .collect::<Vec<DOMString>>(); - // step 2 - // There must be at least one valid entry type. - if entry_types.is_empty() { - return Err(Error::Type("entryTypes cannot be empty".to_string())); + // Step 1 is self + + // Step 2 is self.global() + + // Step 3 + if options.entryTypes.is_none() && options.type_.is_none() { + return Err(Error::Syntax); + } + + // Step 4 + if options.entryTypes.is_some() && (options.buffered.is_some() || options.type_.is_some()) { + return Err(Error::Syntax); + } + + // If this point is reached, then one of options.entryTypes or options.type_ + // is_some, but not both. + + // Step 5 + match self.observer_type.get() { + ObserverType::Undefined => { + if options.entryTypes.is_some() { + self.observer_type.set(ObserverType::Multiple); + } else { + self.observer_type.set(ObserverType::Single); + } + }, + ObserverType::Single => { + if options.entryTypes.is_some() { + return Err(Error::InvalidModification); + } + }, + ObserverType::Multiple => { + if options.type_.is_some() { + return Err(Error::InvalidModification); + } + }, } - // step 3-4-5 - self.global() - .performance() - .add_observer(self, entry_types, options.buffered); + // The entryTypes and type paths diverge here + if let Some(entry_types) = &options.entryTypes { + // Steps 6.1 - 6.2 + let entry_types = entry_types + .iter() + .filter(|e| VALID_ENTRY_TYPES.contains(&e.as_ref())) + .map(|e| e.clone()) + .collect::<Vec<DOMString>>(); + + // Step 6.3 + if entry_types.is_empty() { + Console::Warn( + &*self.global(), + vec![DOMString::from( + "No valid entry type provided to observe().", + )], + ); + return Ok(()); + } + + // Steps 6.4-6.5 + // This never pre-fills buffered entries, and + // any existing types are replaced. + self.global() + .performance() + .add_multiple_type_observer(self, entry_types); + Ok(()) + } else if let Some(entry_type) = &options.type_ { + // Step 7.2 + if !VALID_ENTRY_TYPES.contains(&entry_type.as_ref()) { + Console::Warn( + &*self.global(), + vec![DOMString::from( + "No valid entry type provided to observe().", + )], + ); + return Ok(()); + } - Ok(()) + // Steps 7.3-7.5 + // This may pre-fill buffered entries, and + // existing types are appended to. + self.global().performance().add_single_type_observer( + self, + entry_type, + options.buffered.unwrap_or(false), + ); + Ok(()) + } else { + // Step 7.1 + unreachable!() + } } - // https://w3c.github.io/performance-timeline/#dom-performanceobserver-disconnect() + // https://w3c.github.io/performance-timeline/#dom-performanceobserver-disconnect fn Disconnect(&self) { self.global().performance().remove_observer(self); self.entries.borrow_mut().clear(); } + + // https://w3c.github.io/performance-timeline/#takerecords-method + fn TakeRecords(&self) -> Vec<DomRoot<PerformanceEntry>> { + let mut entries = self.entries.borrow_mut(); + let taken = entries + .iter() + .map(|entry| DomRoot::from_ref(&**entry)) + .collect(); + entries.clear(); + return taken; + } } |