aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/bindings/str.rs2
-rw-r--r--components/script/dom/mod.rs3
-rw-r--r--components/script/dom/performance.rs197
-rw-r--r--components/script/dom/performanceentry.rs76
-rw-r--r--components/script/dom/performanceobserver.rs117
-rw-r--r--components/script/dom/performanceobserverentrylist.rs54
-rw-r--r--components/script/dom/webidls/Performance.webidl9
-rw-r--r--components/script/dom/webidls/PerformanceEntry.webidl17
-rw-r--r--components/script/dom/webidls/PerformanceObserver.webidl21
-rw-r--r--components/script/dom/webidls/PerformanceObserverEntryList.webidl15
-rw-r--r--components/script/dom/window.rs9
-rw-r--r--components/script/script_thread.rs16
-rw-r--r--components/script/task_source/mod.rs1
-rw-r--r--components/script/task_source/performance_timeline.rs58
-rw-r--r--tests/wpt/metadata/navigation-timing/nav2_test_document_replaced.html.ini1
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json4
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.html3
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.worker.js3
18 files changed, 599 insertions, 7 deletions
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index 761acab3068..36b104eb262 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -122,7 +122,7 @@ pub fn is_token(s: &[u8]) -> bool {
///
/// [idl]: https://heycam.github.io/webidl/#idl-DOMString
///
-/// Cenceptually, a DOMString has the same value space as a JavaScript String,
+/// Conceptually, a DOMString has the same value space as a JavaScript String,
/// i.e., an array of 16-bit *code units* representing UTF-16, potentially with
/// unpaired surrogates present (also sometimes called WTF-16).
///
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index fe17bb712d7..a3b280668e3 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -397,6 +397,9 @@ pub mod paintrenderingcontext2d;
pub mod paintsize;
pub mod paintworkletglobalscope;
pub mod performance;
+pub mod performanceentry;
+pub mod performanceobserver;
+pub mod performanceobserverentrylist;
pub mod performancetiming;
pub mod permissions;
pub mod permissionstatus;
diff --git a/components/script/dom/performance.rs b/components/script/dom/performance.rs
index 7ce0cd7d1eb..bb2c5885bcb 100644
--- a/components/script/dom/performance.rs
+++ b/components/script/dom/performance.rs
@@ -2,22 +2,79 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PerformanceBinding;
-use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
+use dom::bindings::codegen::Bindings::PerformanceBinding::{DOMHighResTimeStamp, PerformanceMethods};
+use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceEntryList as DOMPerformanceEntryList;
use dom::bindings::js::{JS, Root};
use dom::bindings::num::Finite;
-use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::refcounted::Trusted;
+use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::performanceentry::PerformanceEntry;
+use dom::performanceobserver::PerformanceObserver as DOMPerformanceObserver;
use dom::performancetiming::PerformanceTiming;
use dom::window::Window;
use dom_struct::dom_struct;
+use script_thread::{Runnable, ScriptThread};
+use std::cell::Cell;
use time;
-pub type DOMHighResTimeStamp = Finite<f64>;
+/// Implementation of a list of PerformanceEntry items shared by the
+/// Performance and PerformanceObserverEntryList interfaces implementations.
+#[derive(HeapSizeOf, JSTraceable)]
+pub struct PerformanceEntryList {
+ entries: DOMPerformanceEntryList,
+}
+
+impl PerformanceEntryList {
+ pub fn new(entries: DOMPerformanceEntryList) -> Self {
+ PerformanceEntryList {
+ entries,
+ }
+ }
+
+ pub fn get_entries(&self) -> Vec<Root<PerformanceEntry>> {
+ self.entries.clone()
+ }
+
+ pub fn get_entries_by_type(&self, entry_type: DOMString) -> Vec<Root<PerformanceEntry>> {
+ self.entries.iter().filter(|e| *e.entry_type() == entry_type)
+ .map(|e| e.clone())
+ .collect()
+ }
+
+ pub fn get_entries_by_name(&self, name: DOMString, entry_type: Option<DOMString>)
+ -> Vec<Root<PerformanceEntry>> {
+ self.entries.iter().filter(|e|
+ *e.name() == name &&
+ entry_type.as_ref().map_or(true, |type_| *e.entry_type() == *type_)
+ ).map(|e| e.clone()).collect()
+ }
+}
+
+impl IntoIterator for PerformanceEntryList {
+ type Item = Root<PerformanceEntry>;
+ type IntoIter = ::std::vec::IntoIter<Root<PerformanceEntry>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.entries.into_iter()
+ }
+}
+
+#[derive(HeapSizeOf, JSTraceable)]
+struct PerformanceObserver {
+ observer: Root<DOMPerformanceObserver>,
+ entry_types: Vec<DOMString>,
+}
#[dom_struct]
pub struct Performance {
reflector_: Reflector,
timing: JS<PerformanceTiming>,
+ entries: DOMRefCell<PerformanceEntryList>,
+ observers: DOMRefCell<Vec<PerformanceObserver>>,
+ pending_notification_observers_task: Cell<bool>,
}
impl Performance {
@@ -29,6 +86,9 @@ impl Performance {
timing: JS::from_ref(&*PerformanceTiming::new(window,
navigation_start,
navigation_start_precise)),
+ entries: DOMRefCell::new(PerformanceEntryList::new(Vec::new())),
+ observers: DOMRefCell::new(Vec::new()),
+ pending_notification_observers_task: Cell::new(false),
}
}
@@ -41,6 +101,121 @@ impl Performance {
window,
PerformanceBinding::Wrap)
}
+
+ /// Add a PerformanceObserver to the list of observers with a set of
+ /// observed entry types.
+ pub fn add_observer(&self,
+ observer: &DOMPerformanceObserver,
+ entry_types: Vec<DOMString>) {
+ 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
+ // entry types.
+ Some(p) => observers[p].entry_types = entry_types,
+ // Otherwise, we create and insert the new PerformanceObserver.
+ None => observers.push(PerformanceObserver {
+ observer: Root::from_ref(observer),
+ entry_types
+ })
+ };
+ }
+
+ /// Remove a PerformanceObserver from the list of observers.
+ pub fn remove_observer(&self, observer: &DOMPerformanceObserver) {
+ let mut observers = self.observers.borrow_mut();
+ let index = match observers.iter().position(|o| &(*o.observer) == observer) {
+ Some(p) => p,
+ None => return,
+ };
+ observers.remove(index);
+ }
+
+ /// Queue a notification for each performance observer interested in
+ /// this type of performance entry and queue a low priority task to
+ /// notify the observers if no other notification task is already queued.
+ ///
+ /// Algorithm spec:
+ /// https://w3c.github.io/performance-timeline/#queue-a-performanceentry
+ ///
+ /// XXX This should be called at some point by the User Timing, Resource
+ /// Timing, Server Timing and Paint Timing APIs.
+ pub fn queue_entry(&self, entry: &PerformanceEntry,
+ add_to_performance_entries_buffer: bool) {
+ // Steps 1-3.
+ // Add the performance entry to the list of performance entries that have not
+ // been notified to each performance observer owner, filtering the ones it's
+ // interested in.
+ for o in self.observers.borrow().iter().filter(|o| o.entry_types.contains(entry.entry_type())) {
+ o.observer.queue_entry(entry);
+ }
+
+ // Step 4.
+ // If the "add to performance entry buffer flag" is set, add the
+ // new entry to the buffer.
+ if add_to_performance_entries_buffer {
+ self.entries.borrow_mut().entries.push(Root::from_ref(entry));
+ }
+
+ // Step 5.
+ // If there is already a queued notification task, we just bail out.
+ if self.pending_notification_observers_task.get() {
+ return;
+ }
+
+ // Step 6.
+ // Queue a new notification task.
+ self.pending_notification_observers_task.set(true);
+ let global = self.global();
+ let window = global.as_window();
+ let task_source = window.performance_timeline_task_source();
+ task_source.queue_notification(self, window);
+ }
+
+ /// Observers notifications task.
+ ///
+ /// Algorithm spec (step 7):
+ /// https://w3c.github.io/performance-timeline/#queue-a-performanceentry
+ fn notify_observers(&self) {
+ // Step 7.1.
+ self.pending_notification_observers_task.set(false);
+
+ // Step 7.2.
+ // We have to operate over a copy of the performance observers to avoid
+ // the risk of an observer's callback modifying the list of registered
+ // observers.
+ let observers: Vec<Root<DOMPerformanceObserver>> =
+ self.observers.borrow().iter()
+ .map(|o| DOMPerformanceObserver::new(&self.global(),
+ o.observer.callback(),
+ o.observer.entries()))
+ .collect();
+
+ // Step 7.3.
+ for o in observers.iter() {
+ o.notify();
+ }
+ }
+}
+
+pub struct NotifyPerformanceObserverRunnable {
+ owner: Trusted<Performance>,
+}
+
+impl NotifyPerformanceObserverRunnable {
+ pub fn new(owner: Trusted<Performance>) -> Self {
+ NotifyPerformanceObserverRunnable {
+ owner,
+ }
+ }
+}
+
+impl Runnable for NotifyPerformanceObserverRunnable {
+ fn name(&self) -> &'static str { "NotifyPerformanceObserverRunnable" }
+
+ fn main_thread_handler(self: Box<NotifyPerformanceObserverRunnable>,
+ _: &ScriptThread) {
+ self.owner.root().notify_observers();
+ }
}
impl PerformanceMethods for Performance {
@@ -55,4 +230,20 @@ impl PerformanceMethods for Performance {
let now = (time::precise_time_ns() as f64 - nav_start) / 1000000 as f64;
Finite::wrap(now)
}
+
+ // https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
+ fn GetEntries(&self) -> Vec<Root<PerformanceEntry>> {
+ self.entries.borrow().get_entries()
+ }
+
+ // https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentriesbytype
+ fn GetEntriesByType(&self, entry_type: DOMString) -> Vec<Root<PerformanceEntry>> {
+ self.entries.borrow().get_entries_by_type(entry_type)
+ }
+
+ // https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentriesbyname
+ fn GetEntriesByName(&self, name: DOMString, entry_type: Option<DOMString>)
+ -> Vec<Root<PerformanceEntry>> {
+ self.entries.borrow().get_entries_by_name(name, entry_type)
+ }
}
diff --git a/components/script/dom/performanceentry.rs b/components/script/dom/performanceentry.rs
new file mode 100644
index 00000000000..7de1116c320
--- /dev/null
+++ b/components/script/dom/performanceentry.rs
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::PerformanceEntryBinding;
+use dom::bindings::codegen::Bindings::PerformanceEntryBinding::PerformanceEntryMethods;
+use dom::bindings::js::Root;
+use dom::bindings::num::Finite;
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct PerformanceEntry {
+ reflector_: Reflector,
+ name: DOMString,
+ entry_type: DOMString,
+ start_time: f64,
+ duration: f64,
+}
+
+impl PerformanceEntry {
+ fn new_inherited(name: DOMString,
+ entry_type: DOMString,
+ start_time: f64,
+ duration: f64) -> PerformanceEntry {
+ PerformanceEntry {
+ reflector_: Reflector::new(),
+ name,
+ entry_type,
+ start_time,
+ duration,
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(global: &GlobalScope,
+ name: DOMString,
+ entry_type: DOMString,
+ start_time: f64,
+ duration: f64) -> Root<PerformanceEntry> {
+ let entry = PerformanceEntry::new_inherited(name, entry_type, start_time, duration);
+ reflect_dom_object(box entry, global, PerformanceEntryBinding::Wrap)
+ }
+
+ pub fn entry_type(&self) -> &DOMString {
+ &self.entry_type
+ }
+
+ pub fn name(&self) -> &DOMString {
+ &self.name
+ }
+}
+
+impl PerformanceEntryMethods for PerformanceEntry {
+ // https://w3c.github.io/performance-timeline/#dom-performanceentry-name
+ fn Name(&self) -> DOMString {
+ DOMString::from(self.name.clone())
+ }
+
+ // https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype
+ fn EntryType(&self) -> DOMString {
+ DOMString::from(self.entry_type.clone())
+ }
+
+ // https://w3c.github.io/performance-timeline/#dom-performanceentry-starttime
+ fn StartTime(&self) -> Finite<f64> {
+ Finite::wrap(self.start_time)
+ }
+
+ // https://w3c.github.io/performance-timeline/#dom-performanceentry-duration
+ fn Duration(&self) -> Finite<f64> {
+ Finite::wrap(self.duration)
+ }
+}
diff --git a/components/script/dom/performanceobserver.rs b/components/script/dom/performanceobserver.rs
new file mode 100644
index 00000000000..e0d2e49a57b
--- /dev/null
+++ b/components/script/dom/performanceobserver.rs
@@ -0,0 +1,117 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::callback::ExceptionHandling;
+use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceEntryList as DOMPerformanceEntryList;
+use dom::bindings::codegen::Bindings::PerformanceObserverBinding;
+use dom::bindings::codegen::Bindings::PerformanceObserverBinding::PerformanceObserverCallback;
+use dom::bindings::codegen::Bindings::PerformanceObserverBinding::PerformanceObserverInit;
+use dom::bindings::codegen::Bindings::PerformanceObserverBinding::PerformanceObserverMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
+use dom::bindings::error::{Error, Fallible};
+use dom::bindings::js::Root;
+use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::globalscope::GlobalScope;
+use dom::performance::PerformanceEntryList;
+use dom::performanceentry::PerformanceEntry;
+use dom::performanceobserverentrylist::PerformanceObserverEntryList;
+use dom_struct::dom_struct;
+use std::rc::Rc;
+
+/// List of allowed performance entry types.
+const VALID_ENTRY_TYPES: &'static [&'static str] = &[
+ // "mark", XXX User Timing API
+ // "measure", XXX User Timing API
+ // "resource", XXX Resource Timing API
+ // "server", XXX Server Timing API
+ // "paint", XXX Paint Timing API
+];
+
+#[dom_struct]
+pub struct PerformanceObserver {
+ reflector_: Reflector,
+ #[ignore_heap_size_of = "can't measure Rc values"]
+ callback: Rc<PerformanceObserverCallback>,
+ entries: DOMRefCell<DOMPerformanceEntryList>,
+}
+
+impl PerformanceObserver {
+ fn new_inherited(callback: Rc<PerformanceObserverCallback>,
+ entries: DOMRefCell<DOMPerformanceEntryList>)
+ -> PerformanceObserver {
+ PerformanceObserver {
+ reflector_: Reflector::new(),
+ callback,
+ entries,
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(global: &GlobalScope,
+ callback: Rc<PerformanceObserverCallback>,
+ entries: DOMPerformanceEntryList)
+ -> Root<PerformanceObserver> {
+ let observer = PerformanceObserver::new_inherited(callback, DOMRefCell::new(entries));
+ reflect_dom_object(box observer, global, PerformanceObserverBinding::Wrap)
+ }
+
+ pub fn Constructor(global: &GlobalScope, callback: Rc<PerformanceObserverCallback>)
+ -> Fallible<Root<PerformanceObserver>> {
+ Ok(PerformanceObserver::new(global, callback, Vec::new()))
+ }
+
+ /// Buffer a new performance entry.
+ pub fn queue_entry(&self, entry: &PerformanceEntry) {
+ self.entries.borrow_mut().push(Root::from_ref(entry));
+ }
+
+ /// 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() {
+ 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 _ = self.callback.Call__(&observer_entry_list, self, ExceptionHandling::Report);
+ }
+
+ pub fn callback(&self) -> Rc<PerformanceObserverCallback> {
+ self.callback.clone()
+ }
+
+ pub fn entries(&self) -> DOMPerformanceEntryList {
+ self.entries.borrow().clone()
+ }
+}
+
+impl PerformanceObserverMethods for PerformanceObserver {
+ // https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe()
+ fn Observe(&self, options: &PerformanceObserverInit) -> Fallible<()> {
+ // 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>>();
+ // 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);
+ Ok(())
+ }
+
+ // https://w3c.github.io/performance-timeline/#dom-performanceobserver-disconnect()
+ fn Disconnect(&self) {
+ self.global().as_window().Performance().remove_observer(self);
+ self.entries.borrow_mut().clear();
+ }
+}
diff --git a/components/script/dom/performanceobserverentrylist.rs b/components/script/dom/performanceobserverentrylist.rs
new file mode 100644
index 00000000000..9c6a039cd4c
--- /dev/null
+++ b/components/script/dom/performanceobserverentrylist.rs
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::PerformanceObserverEntryListBinding;
+use dom::bindings::codegen::Bindings::PerformanceObserverEntryListBinding::PerformanceObserverEntryListMethods;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::DOMString;
+use dom::globalscope::GlobalScope;
+use dom::performance::PerformanceEntryList;
+use dom::performanceentry::PerformanceEntry;
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct PerformanceObserverEntryList {
+ reflector_: Reflector,
+ entries: DOMRefCell<PerformanceEntryList>,
+}
+
+impl PerformanceObserverEntryList {
+ fn new_inherited(entries: PerformanceEntryList) -> PerformanceObserverEntryList {
+ PerformanceObserverEntryList {
+ reflector_: Reflector::new(),
+ entries: DOMRefCell::new(entries),
+ }
+ }
+
+ #[allow(unrooted_must_root)]
+ pub fn new(global: &GlobalScope, entries: PerformanceEntryList)
+ -> Root<PerformanceObserverEntryList> {
+ let observer_entry_list = PerformanceObserverEntryList::new_inherited(entries);
+ reflect_dom_object(box observer_entry_list, global, PerformanceObserverEntryListBinding::Wrap)
+ }
+}
+
+impl PerformanceObserverEntryListMethods for PerformanceObserverEntryList {
+ // https://w3c.github.io/performance-timeline/#dom-performanceobserver
+ fn GetEntries(&self) -> Vec<Root<PerformanceEntry>> {
+ self.entries.borrow().get_entries()
+ }
+
+ // https://w3c.github.io/performance-timeline/#dom-performanceobserver
+ fn GetEntriesByType(&self, entry_type: DOMString) -> Vec<Root<PerformanceEntry>> {
+ self.entries.borrow().get_entries_by_type(entry_type)
+ }
+
+ // https://w3c.github.io/performance-timeline/#dom-performanceobserver
+ fn GetEntriesByName(&self, name: DOMString, entry_type: Option<DOMString>)
+ -> Vec<Root<PerformanceEntry>> {
+ self.entries.borrow().get_entries_by_name(name, entry_type)
+ }
+}
diff --git a/components/script/dom/webidls/Performance.webidl b/components/script/dom/webidls/Performance.webidl
index 6aeaa6d11aa..30f2c41e2bc 100644
--- a/components/script/dom/webidls/Performance.webidl
+++ b/components/script/dom/webidls/Performance.webidl
@@ -7,6 +7,7 @@
*/
typedef double DOMHighResTimeStamp;
+typedef sequence<PerformanceEntry> PerformanceEntryList;
[Exposed=(Window,Worker)]
interface Performance {
@@ -17,3 +18,11 @@ interface Performance {
partial interface Performance {
DOMHighResTimeStamp now();
};
+
+// https://w3c.github.io/performance-timeline/#extensions-to-the-performance-interface
+partial interface Performance {
+ PerformanceEntryList getEntries();
+ PerformanceEntryList getEntriesByType(DOMString type);
+ PerformanceEntryList getEntriesByName(DOMString name,
+ optional DOMString type);
+};
diff --git a/components/script/dom/webidls/PerformanceEntry.webidl b/components/script/dom/webidls/PerformanceEntry.webidl
new file mode 100644
index 00000000000..8980f769888
--- /dev/null
+++ b/components/script/dom/webidls/PerformanceEntry.webidl
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://w3c.github.io/performance-timeline/#the-performanceentry-interface
+ */
+
+[Exposed=(Window,Worker)]
+interface PerformanceEntry {
+ readonly attribute DOMString name;
+ readonly attribute DOMString entryType;
+ readonly attribute DOMHighResTimeStamp startTime;
+ readonly attribute DOMHighResTimeStamp duration;
+
+ // [Default] object toJSON();
+};
diff --git a/components/script/dom/webidls/PerformanceObserver.webidl b/components/script/dom/webidls/PerformanceObserver.webidl
new file mode 100644
index 00000000000..a67c52e2730
--- /dev/null
+++ b/components/script/dom/webidls/PerformanceObserver.webidl
@@ -0,0 +1,21 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://w3c.github.io/performance-timeline/#the-performanceobserver-interface
+ */
+
+dictionary PerformanceObserverInit {
+ required sequence<DOMString> entryTypes;
+};
+
+callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
+
+[Constructor(PerformanceObserverCallback callback),
+ Exposed=(Window,Worker)]
+interface PerformanceObserver {
+ [Throws]
+ void observe(PerformanceObserverInit options);
+ void disconnect();
+};
diff --git a/components/script/dom/webidls/PerformanceObserverEntryList.webidl b/components/script/dom/webidls/PerformanceObserverEntryList.webidl
new file mode 100644
index 00000000000..a65316cdacc
--- /dev/null
+++ b/components/script/dom/webidls/PerformanceObserverEntryList.webidl
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://w3c.github.io/performance-timeline/#performanceobserverentrylist-interface
+ */
+
+[Exposed=(Window,Worker)]
+interface PerformanceObserverEntryList {
+ PerformanceEntryList getEntries();
+ PerformanceEntryList getEntriesByType(DOMString entryType);
+ PerformanceEntryList getEntriesByName(DOMString name,
+ optional DOMString entryType);
+};
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 2da650ee1ee..48677a64d38 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -118,6 +118,7 @@ use task_source::dom_manipulation::DOMManipulationTaskSource;
use task_source::file_reading::FileReadingTaskSource;
use task_source::history_traversal::HistoryTraversalTaskSource;
use task_source::networking::NetworkingTaskSource;
+use task_source::performance_timeline::PerformanceTimelineTaskSource;
use task_source::user_interaction::UserInteractionTaskSource;
use time;
use timers::{IsInterval, TimerCallback};
@@ -175,6 +176,8 @@ pub struct Window {
history_traversal_task_source: HistoryTraversalTaskSource,
#[ignore_heap_size_of = "task sources are hard"]
file_reading_task_source: FileReadingTaskSource,
+ #[ignore_heap_size_of = "task sources are hard"]
+ performance_timeline_task_source: PerformanceTimelineTaskSource,
navigator: MutNullableJS<Navigator>,
#[ignore_heap_size_of = "Arc"]
image_cache: Arc<ImageCache>,
@@ -329,6 +332,10 @@ impl Window {
self.file_reading_task_source.clone()
}
+ pub fn performance_timeline_task_source(&self) -> PerformanceTimelineTaskSource {
+ self.performance_timeline_task_source.clone()
+ }
+
pub fn main_thread_script_chan(&self) -> &Sender<MainThreadScriptMsg> {
&self.script_chan.0
}
@@ -1791,6 +1798,7 @@ impl Window {
network_task_source: NetworkingTaskSource,
history_task_source: HistoryTraversalTaskSource,
file_task_source: FileReadingTaskSource,
+ performance_timeline_task_source: PerformanceTimelineTaskSource,
image_cache_chan: Sender<ImageCacheMsg>,
image_cache: Arc<ImageCache>,
resource_threads: ResourceThreads,
@@ -1839,6 +1847,7 @@ impl Window {
networking_task_source: network_task_source,
history_traversal_task_source: history_task_source,
file_reading_task_source: file_task_source,
+ performance_timeline_task_source,
image_cache_chan: image_cache_chan,
image_cache: image_cache.clone(),
navigator: Default::default(),
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 4a05002637a..85874ece2ca 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -115,6 +115,7 @@ use task_source::dom_manipulation::{DOMManipulationTask, DOMManipulationTaskSour
use task_source::file_reading::FileReadingTaskSource;
use task_source::history_traversal::HistoryTraversalTaskSource;
use task_source::networking::NetworkingTaskSource;
+use task_source::performance_timeline::{PerformanceTimelineTask, PerformanceTimelineTaskSource};
use task_source::user_interaction::{UserInteractionTask, UserInteractionTaskSource};
use time::{get_time, precise_time_ns, Tm};
use url::Position;
@@ -270,6 +271,8 @@ pub enum MainThreadScriptMsg {
/// Notifies the script thread that a new worklet has been loaded, and thus the page should be
/// reflowed.
WorkletLoaded(PipelineId),
+ /// Tasks that originate from the performance timeline task source.
+ PerformanceTimeline(PerformanceTimelineTask),
}
impl OpaqueSender<CommonScriptMsg> for Box<ScriptChan + Send> {
@@ -455,6 +458,8 @@ pub struct ScriptThread {
file_reading_task_source: FileReadingTaskSource,
+ performance_timeline_task_source: PerformanceTimelineTaskSource,
+
/// A channel to hand out to threads that need to respond to a message from the script thread.
control_chan: IpcSender<ConstellationControlMsg>,
@@ -854,8 +859,9 @@ impl ScriptThread {
dom_manipulation_task_source: DOMManipulationTaskSource(chan.clone()),
user_interaction_task_source: UserInteractionTaskSource(chan.clone()),
networking_task_source: NetworkingTaskSource(boxed_script_sender.clone()),
- history_traversal_task_source: HistoryTraversalTaskSource(chan),
+ history_traversal_task_source: HistoryTraversalTaskSource(chan.clone()),
file_reading_task_source: FileReadingTaskSource(boxed_script_sender),
+ performance_timeline_task_source: PerformanceTimelineTaskSource(chan),
control_chan: state.control_chan,
control_port: control_port,
@@ -1286,6 +1292,8 @@ impl ScriptThread {
self.handle_worklet_loaded(pipeline_id),
MainThreadScriptMsg::DOMManipulation(task) =>
task.handle_task(self),
+ MainThreadScriptMsg::PerformanceTimeline(task) =>
+ task.handle_task(self),
MainThreadScriptMsg::UserInteraction(task) =>
task.handle_task(self),
}
@@ -1717,6 +1725,10 @@ impl ScriptThread {
&self.dom_manipulation_task_source
}
+ pub fn performance_timeline_task_source(&self) -> &PerformanceTimelineTaskSource {
+ &self.performance_timeline_task_source
+ }
+
/// Handles a request for the window title.
fn handle_get_title_msg(&self, pipeline_id: PipelineId) {
let document = match { self.documents.borrow().find_document(pipeline_id) } {
@@ -1991,6 +2003,7 @@ impl ScriptThread {
let DOMManipulationTaskSource(ref dom_sender) = self.dom_manipulation_task_source;
let UserInteractionTaskSource(ref user_sender) = self.user_interaction_task_source;
let HistoryTraversalTaskSource(ref history_sender) = self.history_traversal_task_source;
+ let PerformanceTimelineTaskSource(ref performance_sender) = self.performance_timeline_task_source;
let (ipc_timer_event_chan, ipc_timer_event_port) = ipc::channel().unwrap();
ROUTER.route_ipc_receiver_to_mpsc_sender(ipc_timer_event_port,
@@ -2015,6 +2028,7 @@ impl ScriptThread {
self.networking_task_source.clone(),
HistoryTraversalTaskSource(history_sender.clone()),
self.file_reading_task_source.clone(),
+ PerformanceTimelineTaskSource(performance_sender.clone()),
self.image_cache_channel.clone(),
self.image_cache.clone(),
self.resource_threads.clone(),
diff --git a/components/script/task_source/mod.rs b/components/script/task_source/mod.rs
index 6e2a9985fa0..ff41a63f118 100644
--- a/components/script/task_source/mod.rs
+++ b/components/script/task_source/mod.rs
@@ -6,6 +6,7 @@ pub mod dom_manipulation;
pub mod file_reading;
pub mod history_traversal;
pub mod networking;
+pub mod performance_timeline;
pub mod user_interaction;
use dom::globalscope::GlobalScope;
diff --git a/components/script/task_source/performance_timeline.rs b/components/script/task_source/performance_timeline.rs
new file mode 100644
index 00000000000..272d971737d
--- /dev/null
+++ b/components/script/task_source/performance_timeline.rs
@@ -0,0 +1,58 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// XXX The spec says that the performance timeline task source should be
+// a low priority task and it should be processed during idle periods.
+// We are currently treating this task queue as a normal priority queue.
+
+use dom::bindings::inheritance::Castable;
+use dom::bindings::refcounted::Trusted;
+use dom::performance::{NotifyPerformanceObserverRunnable, Performance};
+use dom::window::Window;
+use script_thread::{MainThreadScriptMsg, Runnable, RunnableWrapper, ScriptThread};
+use std::fmt;
+use std::result::Result;
+use std::sync::mpsc::Sender;
+use task_source::TaskSource;
+
+#[derive(JSTraceable, Clone)]
+pub struct PerformanceTimelineTaskSource(pub Sender<MainThreadScriptMsg>);
+
+impl fmt::Debug for PerformanceTimelineTaskSource {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "PerformanceTimelineTaskSource(...)")
+ }
+}
+
+impl TaskSource for PerformanceTimelineTaskSource {
+ fn queue_with_wrapper<T>(&self,
+ msg: Box<T>,
+ wrapper: &RunnableWrapper) -> Result<(), ()>
+ where T: Runnable + Send + 'static {
+ let msg = PerformanceTimelineTask(wrapper.wrap_runnable(msg));
+ self.0.send(MainThreadScriptMsg::PerformanceTimeline(msg)).map_err(|_| ())
+ }
+}
+
+impl PerformanceTimelineTaskSource {
+ pub fn queue_notification(&self, owner: &Performance, window: &Window) {
+ let owner = Trusted::new(owner);
+ let runnable = box NotifyPerformanceObserverRunnable::new(owner);
+ let _ = self.queue(runnable, window.upcast());
+ }
+}
+
+pub struct PerformanceTimelineTask(pub Box<Runnable + Send>);
+
+impl fmt::Debug for PerformanceTimelineTask {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "PerformanceTimelineTask(...)")
+ }
+}
+
+impl PerformanceTimelineTask {
+ pub fn handle_task(self, script_thread: &ScriptThread) {
+ self.0.main_thread_handler(script_thread);
+ }
+}
diff --git a/tests/wpt/metadata/navigation-timing/nav2_test_document_replaced.html.ini b/tests/wpt/metadata/navigation-timing/nav2_test_document_replaced.html.ini
index 123c842b619..ed236342863 100644
--- a/tests/wpt/metadata/navigation-timing/nav2_test_document_replaced.html.ini
+++ b/tests/wpt/metadata/navigation-timing/nav2_test_document_replaced.html.ini
@@ -1,5 +1,6 @@
[nav2_test_document_replaced.html]
type: testharness
+ expected: TIMEOUT
[Navigation Timing 2 WPT]
expected: FAIL
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index a17f094b697..81e261a2eff 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -27276,7 +27276,7 @@
"testharness"
],
"mozilla/interfaces.html": [
- "c884fee8603f93099ffd0acc30f0ab0cbee5b5f8",
+ "7ac46204fb780c96344f166d34d0fb888c9e25c4",
"testharness"
],
"mozilla/interfaces.js": [
@@ -27284,7 +27284,7 @@
"support"
],
"mozilla/interfaces.worker.js": [
- "9b3a3c96ec539bb323a0def92c747996deaa7331",
+ "1474c6500ce1c4aef99d200dae5407324ddbdd4a",
"testharness"
],
"mozilla/iterable.html": [
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html
index 33aa76d0481..90c4531467b 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html
@@ -159,6 +159,9 @@ test_interfaces([
"NodeList",
"PageTransitionEvent",
"Performance",
+ "PerformanceEntry",
+ "PerformanceObserver",
+ "PerformanceObserverEntryList",
"PerformanceTiming",
"Plugin",
"PluginArray",
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js
index 780200349de..e410bb863b0 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.worker.js
@@ -34,6 +34,9 @@ test_interfaces([
"MessageEvent",
"Performance",
"PerformanceTiming",
+ "PerformanceEntry",
+ "PerformanceObserver",
+ "PerformanceObserverEntryList",
"ProgressEvent",
"Request",
"Response",