Performance Timeline API

This commit is contained in:
Fernando Jiménez Moreno 2017-08-01 14:57:55 +02:00
parent 24270f9357
commit 52348f1fcc
18 changed files with 599 additions and 7 deletions

View file

@ -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).
///

View file

@ -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;

View file

@ -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)
}
}

View 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)
}
}

View 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();
}
}

View 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)
}
}

View file

@ -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);
};

View 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();
};

View 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();
};

View file

@ -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);
};

View file

@ -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(),

View file

@ -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(),

View file

@ -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;

View 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);
}
}

View file

@ -1,5 +1,6 @@
[nav2_test_document_replaced.html]
type: testharness
expected: TIMEOUT
[Navigation Timing 2 WPT]
expected: FAIL

View file

@ -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": [

View file

@ -159,6 +159,9 @@ test_interfaces([
"NodeList",
"PageTransitionEvent",
"Performance",
"PerformanceEntry",
"PerformanceObserver",
"PerformanceObserverEntryList",
"PerformanceTiming",
"Plugin",
"PluginArray",

View file

@ -34,6 +34,9 @@ test_interfaces([
"MessageEvent",
"Performance",
"PerformanceTiming",
"PerformanceEntry",
"PerformanceObserver",
"PerformanceObserverEntryList",
"ProgressEvent",
"Request",
"Response",