mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Performance Timeline API
This commit is contained in:
parent
24270f9357
commit
52348f1fcc
18 changed files with 599 additions and 7 deletions
|
@ -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).
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
76
components/script/dom/performanceentry.rs
Normal file
76
components/script/dom/performanceentry.rs
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
117
components/script/dom/performanceobserver.rs
Normal file
117
components/script/dom/performanceobserver.rs
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
54
components/script/dom/performanceobserverentrylist.rs
Normal file
54
components/script/dom/performanceobserverentrylist.rs
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
|
17
components/script/dom/webidls/PerformanceEntry.webidl
Normal file
17
components/script/dom/webidls/PerformanceEntry.webidl
Normal file
|
@ -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();
|
||||
};
|
21
components/script/dom/webidls/PerformanceObserver.webidl
Normal file
21
components/script/dom/webidls/PerformanceObserver.webidl
Normal file
|
@ -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();
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
|
58
components/script/task_source/performance_timeline.rs
Normal file
58
components/script/task_source/performance_timeline.rs
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
[nav2_test_document_replaced.html]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
||||
[Navigation Timing 2 WPT]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -159,6 +159,9 @@ test_interfaces([
|
|||
"NodeList",
|
||||
"PageTransitionEvent",
|
||||
"Performance",
|
||||
"PerformanceEntry",
|
||||
"PerformanceObserver",
|
||||
"PerformanceObserverEntryList",
|
||||
"PerformanceTiming",
|
||||
"Plugin",
|
||||
"PluginArray",
|
||||
|
|
|
@ -34,6 +34,9 @@ test_interfaces([
|
|||
"MessageEvent",
|
||||
"Performance",
|
||||
"PerformanceTiming",
|
||||
"PerformanceEntry",
|
||||
"PerformanceObserver",
|
||||
"PerformanceObserverEntryList",
|
||||
"ProgressEvent",
|
||||
"Request",
|
||||
"Response",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue