servo: Merge #18283 - User Timing API (from ferjm:user.timing.api); r=jdm

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #18109
- [X] There are tests for these changes. I enabled the peformance-timeline API WPTs but some of them are still failing because of implementation bugs or missing APIs (Resource Timing, for instance) the tests are dependent of. I'll file issues to fix them.

Source-Repo: https://github.com/servo/servo
Source-Revision: 1e93749941d2e3569c7c907832658c57ffb18c72

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 4344c6a1c60484c840cbd3be4112d0c3a710b523
This commit is contained in:
Fernando Jiménez Moreno 2017-09-07 12:45:46 -05:00
parent 9c94a5b109
commit 383681557d
9 changed files with 213 additions and 11 deletions

View File

@ -595,3 +595,42 @@ macro_rules! rooted_vec {
let mut $name = $crate::dom::bindings::trace::RootedVec::from_iter(&mut root, $iter);
}
}
/// DOM struct implementation for simple interfaces inheriting from PerformanceEntry.
macro_rules! impl_performance_entry_struct(
($binding:ident, $struct:ident, $type:expr) => (
use dom::bindings::codegen::Bindings::$binding;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::str::DOMString;
use dom::globalscope::GlobalScope;
use dom::performanceentry::PerformanceEntry;
use dom_struct::dom_struct;
#[dom_struct]
pub struct $struct {
entry: PerformanceEntry,
}
impl $struct {
fn new_inherited(name: DOMString, start_time: f64, duration: f64)
-> $struct {
$struct {
entry: PerformanceEntry::new_inherited(name,
DOMString::from($type),
start_time,
duration)
}
}
#[allow(unrooted_must_root)]
pub fn new(global: &GlobalScope,
name: DOMString,
start_time: f64,
duration: f64) -> Root<$struct> {
let entry = $struct::new_inherited(name, start_time, duration);
reflect_dom_object(box entry, global, $binding::Wrap)
}
}
);
);

View File

@ -399,6 +399,8 @@ pub mod paintsize;
pub mod paintworkletglobalscope;
pub mod performance;
pub mod performanceentry;
pub mod performancemark;
pub mod performancemeasure;
pub mod performanceobserver;
pub mod performanceobserverentrylist;
pub mod performancepainttiming;

View File

@ -6,6 +6,7 @@ use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::PerformanceBinding;
use dom::bindings::codegen::Bindings::PerformanceBinding::{DOMHighResTimeStamp, PerformanceMethods};
use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceEntryList as DOMPerformanceEntryList;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root};
use dom::bindings::num::Finite;
@ -13,6 +14,8 @@ use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::globalscope::GlobalScope;
use dom::performanceentry::PerformanceEntry;
use dom::performancemark::PerformanceMark;
use dom::performancemeasure::PerformanceMeasure;
use dom::performanceobserver::PerformanceObserver as DOMPerformanceObserver;
use dom::performancetiming::PerformanceTiming;
use dom::window::Window;
@ -21,6 +24,30 @@ use std::cell::Cell;
use std::cmp::Ordering;
use time;
const INVALID_ENTRY_NAMES: &'static [&'static str] = &[
"navigationStart",
"unloadEventStart",
"unloadEventEnd",
"redirectStart",
"redirectEnd",
"fetchStart",
"domainLookupStart",
"domainLookupEnd",
"connectStart",
"connectEnd",
"secureConnectionStart",
"requestStart",
"responseStart",
"responseEnd",
"domLoading",
"domInteractive",
"domContentLoadedEventStart",
"domContentLoadedEventEnd",
"domComplete",
"loadEventStart",
"loadEventEnd",
];
/// Implementation of a list of PerformanceEntry items shared by the
/// Performance and PerformanceObserverEntryList interfaces implementations.
#[derive(HeapSizeOf, JSTraceable)]
@ -44,6 +71,25 @@ impl PerformanceEntryList {
res.sort_by(|a, b| a.start_time().partial_cmp(&b.start_time()).unwrap_or(Ordering::Equal));
res
}
pub fn clear_entries_by_name_and_type(&mut self, name: Option<DOMString>,
entry_type: Option<DOMString>) {
self.entries.retain(|e|
name.as_ref().map_or(true, |name_| *e.name() == *name_) &&
entry_type.as_ref().map_or(true, |type_| *e.entry_type() == *type_)
);
}
fn get_last_entry_start_time_with_name_and_type(&self, name: DOMString,
entry_type: DOMString) -> f64 {
match self.entries.iter()
.rev()
.find(|e| *e.entry_type() == *entry_type &&
*e.name() == *name) {
Some(entry) => entry.start_time(),
None => 0.,
}
}
}
impl IntoIterator for PerformanceEntryList {
@ -145,9 +191,6 @@ impl Performance {
///
/// 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.
@ -202,6 +245,14 @@ impl Performance {
o.notify();
}
}
fn now(&self) -> f64 {
let nav_start = match self.timing {
Some(ref timing) => timing.navigation_start_precise(),
None => self.navigation_start_precise,
};
(time::precise_time_ns() as f64 - nav_start) / 1000000 as f64
}
}
impl PerformanceMethods for Performance {
@ -215,12 +266,7 @@ impl PerformanceMethods for Performance {
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now
fn Now(&self) -> DOMHighResTimeStamp {
let nav_start = match self.timing {
Some(ref timing) => timing.navigation_start_precise(),
None => self.navigation_start_precise,
};
let now = (time::precise_time_ns() as f64 - nav_start) / 1000000 as f64;
Finite::wrap(now)
Finite::wrap(self.now())
}
// https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
@ -238,4 +284,72 @@ impl PerformanceMethods for Performance {
-> Vec<Root<PerformanceEntry>> {
self.entries.borrow().get_entries_by_name_and_type(Some(name), entry_type)
}
// https://w3c.github.io/user-timing/#dom-performance-mark
fn Mark(&self, mark_name: DOMString) -> Fallible<()> {
let global = self.global();
// Step 1.
if global.is::<Window>() && INVALID_ENTRY_NAMES.contains(&mark_name.as_ref()) {
return Err(Error::Syntax);
}
// Steps 2 to 6.
let entry = PerformanceMark::new(&global,
mark_name,
self.now(),
0.);
// Steps 7 and 8.
self.queue_entry(&entry.upcast::<PerformanceEntry>(),
true /* buffer performance entry */);
// Step 9.
Ok(())
}
// https://w3c.github.io/user-timing/#dom-performance-clearmarks
fn ClearMarks(&self, mark_name: Option<DOMString>) {
self.entries.borrow_mut().clear_entries_by_name_and_type(mark_name,
Some(DOMString::from("mark")));
}
// https://w3c.github.io/user-timing/#dom-performance-measure
fn Measure(&self,
measure_name: DOMString,
start_mark: Option<DOMString>,
end_mark: Option<DOMString>) -> Fallible<()> {
// Steps 1 and 2.
let end_time = match end_mark {
Some(name) =>
self.entries.borrow().get_last_entry_start_time_with_name_and_type(
DOMString::from("mark"), name),
None => self.now(),
};
// Step 3.
let start_time = match start_mark {
Some(name) =>
self.entries.borrow().get_last_entry_start_time_with_name_and_type(
DOMString::from("mark"), name),
None => 0.,
};
// Steps 4 to 8.
let entry = PerformanceMeasure::new(&self.global(),
measure_name,
start_time,
end_time - start_time);
// Step 9 and 10.
self.queue_entry(&entry.upcast::<PerformanceEntry>(),
true /* buffer performance entry */);
// Step 11.
Ok(())
}
// https://w3c.github.io/user-timing/#dom-performance-clearmeasures
fn ClearMeasures(&self, measure_name: Option<DOMString>) {
self.entries.borrow_mut().clear_entries_by_name_and_type(measure_name,
Some(DOMString::from("measure")));
}
}

View File

@ -0,0 +1,7 @@
/* 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/. */
impl_performance_entry_struct!(PerformanceMarkBinding,
PerformanceMark,
"mark");

View File

@ -0,0 +1,7 @@
/* 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/. */
impl_performance_entry_struct!(PerformanceMeasureBinding,
PerformanceMeasure,
"measure");

View File

@ -22,8 +22,8 @@ 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
"mark", // User Timing API
"measure", // User Timing API
// "resource", XXX Resource Timing API
// "server", XXX Server Timing API
"paint", // Paint Timing API

View File

@ -28,3 +28,14 @@ partial interface Performance {
PerformanceEntryList getEntriesByName(DOMString name,
optional DOMString type);
};
// https://w3c.github.io/user-timing/#extensions-performance-interface
[Exposed=(Window,Worker)]
partial interface Performance {
[Throws]
void mark(DOMString markName);
void clearMarks(optional DOMString markName);
[Throws]
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
void clearMeasures(optional DOMString measureName);
};

View File

@ -0,0 +1,11 @@
/* 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/user-timing/#performancemark
*/
[Exposed=(Window,Worker)]
interface PerformanceMark : PerformanceEntry {
};

View File

@ -0,0 +1,11 @@
/* 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/user-timing/#performancemeasure
*/
[Exposed=(Window,Worker)]
interface PerformanceMeasure : PerformanceEntry {
};