diff --git a/components/script/dom/performance.rs b/components/script/dom/performance.rs index bb2c5885bcb..fdcbfd4a813 100644 --- a/components/script/dom/performance.rs +++ b/components/script/dom/performance.rs @@ -18,6 +18,7 @@ use dom::window::Window; use dom_struct::dom_struct; use script_thread::{Runnable, ScriptThread}; use std::cell::Cell; +use std::cmp::Ordering; use time; /// Implementation of a list of PerformanceEntry items shared by the @@ -51,6 +52,16 @@ impl PerformanceEntryList { entry_type.as_ref().map_or(true, |type_| *e.entry_type() == *type_) ).map(|e| e.clone()).collect() } + + pub fn get_entries_by_name_and_type(&self, name: Option, entry_type: Option) + -> Vec> { + let mut res = self.entries.iter().filter(|e| + name.as_ref().map_or(true, |name_| *e.name() == *name_) && + entry_type.as_ref().map_or(true, |type_| *e.entry_type() == *type_) + ).map(|e| e.clone()).collect::>>(); + res.sort_by(|a, b| a.start_time().partial_cmp(&b.start_time()).unwrap_or(Ordering::Equal)); + res + } } impl IntoIterator for PerformanceEntryList { @@ -106,7 +117,17 @@ impl Performance { /// observed entry types. pub fn add_observer(&self, observer: &DOMPerformanceObserver, - entry_types: Vec) { + entry_types: Vec, + buffered: bool) { + if buffered { + let entries = self.entries.borrow(); + let mut new_entries = entry_types.iter() + .flat_map(|e| entries.get_entries_by_name_and_type(None, Some(e.clone()))) + .collect::(); + let mut obs_entries = observer.entries(); + obs_entries.append(&mut new_entries); + observer.set_entries(obs_entries); + } let mut observers = self.observers.borrow_mut(); match observers.iter().position(|o| &(*o.observer) == observer) { // If the observer is already in the list, we only update the observed diff --git a/components/script/dom/performanceentry.rs b/components/script/dom/performanceentry.rs index 2c6fef87db0..3242d5d5abd 100644 --- a/components/script/dom/performanceentry.rs +++ b/components/script/dom/performanceentry.rs @@ -51,6 +51,10 @@ impl PerformanceEntry { pub fn name(&self) -> &DOMString { &self.name } + + pub fn start_time(&self) -> f64 { + self.start_time + } } impl PerformanceEntryMethods for PerformanceEntry { diff --git a/components/script/dom/performanceobserver.rs b/components/script/dom/performanceobserver.rs index 087cb44cd09..56727177a32 100644 --- a/components/script/dom/performanceobserver.rs +++ b/components/script/dom/performanceobserver.rs @@ -89,23 +89,30 @@ impl PerformanceObserver { pub fn entries(&self) -> DOMPerformanceEntryList { self.entries.borrow().clone() } + + pub fn set_entries(&self, entries: DOMPerformanceEntryList) { + *self.entries.borrow_mut() = entries; + } } 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::>(); + // 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()))); } let performance = self.global().as_window().Performance(); - performance.add_observer(self, entry_types); + // step 3-4-5 + performance.add_observer(self, entry_types, options.buffered); Ok(()) } diff --git a/components/script/dom/webidls/PerformanceObserver.webidl b/components/script/dom/webidls/PerformanceObserver.webidl index a67c52e2730..4468352e4a9 100644 --- a/components/script/dom/webidls/PerformanceObserver.webidl +++ b/components/script/dom/webidls/PerformanceObserver.webidl @@ -8,6 +8,7 @@ dictionary PerformanceObserverInit { required sequence entryTypes; + boolean buffered = false; }; callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);