зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #18028 - Performance Timeline API (from ferjm:performance.timeline); r=jdm
[Performance Timeline API](https://www.w3.org/TR/performance-timeline-2/) implementation. This API is required to allow DOM access to the [Paint Timing API](https://wicg.github.io/paint-timing/#example) metrics implemented in #17256. Unfortunately, I couldn't test it properly, as its usage depends on other APIs like the Paint Timing, User Timing, Resource Timing or Server Timing APIs. I'll work in the integration with the Paint Timing API next. - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] There are [WPTs](https://github.com/servo/servo/tree/master/tests/wpt/web-platform-tests/performance-timeline) for this API, however they depend on the implementation of the User Timing and the Resource Timing APIs, which I'll hopefully be implementing soon. Source-Repo: https://github.com/servo/servo Source-Revision: 6988c7424ddfdd9a98e6a458ff2ad307a74237aa --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 004a98426527db5a2d4a91143becb5b71b31daae
This commit is contained in:
Родитель
9fc59f579b
Коммит
9b268f64a9
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче