aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/performanceobserver.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/performanceobserver.rs')
-rw-r--r--components/script/dom/performanceobserver.rs140
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;
+ }
}