mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
refactored performance timing to align with updated spec
refactoring with ResourceFetchMetadata implemented deprecated window.timing functionality created ResourceTimingListener trait fixed w3c links in navigation timing updated include.ini to run resource timing tests on ci
This commit is contained in:
parent
3fe83f1d06
commit
26007fddd3
103 changed files with 1881 additions and 322 deletions
|
@ -80,7 +80,7 @@ use net_traits::request::{Request, RequestInit};
|
|||
use net_traits::response::HttpsState;
|
||||
use net_traits::response::{Response, ResponseBody};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming, ResourceThreads};
|
||||
use offscreen_gl_context::GLLimits;
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||
|
@ -466,6 +466,7 @@ unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamTy
|
|||
unsafe_no_jsmanaged_fields!(dyn Player<Error = ServoMediaError>);
|
||||
unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>);
|
||||
unsafe_no_jsmanaged_fields!(RenderApiSender);
|
||||
unsafe_no_jsmanaged_fields!(ResourceFetchTiming);
|
||||
|
||||
unsafe impl<'a> JSTraceable for &'a str {
|
||||
#[inline]
|
||||
|
|
|
@ -356,6 +356,8 @@ pub struct Document {
|
|||
top_level_dom_complete: Cell<u64>,
|
||||
load_event_start: Cell<u64>,
|
||||
load_event_end: Cell<u64>,
|
||||
unload_event_start: Cell<u64>,
|
||||
unload_event_end: Cell<u64>,
|
||||
/// <https://html.spec.whatwg.org/multipage/#concept-document-https-state>
|
||||
https_state: Cell<HttpsState>,
|
||||
/// The document's origin.
|
||||
|
@ -406,6 +408,8 @@ pub struct Document {
|
|||
fired_unload: Cell<bool>,
|
||||
/// List of responsive images
|
||||
responsive_images: DomRefCell<Vec<Dom<HTMLImageElement>>>,
|
||||
/// Number of redirects for the document load
|
||||
redirect_count: Cell<u16>,
|
||||
}
|
||||
|
||||
#[derive(JSTraceable, MallocSizeOf)]
|
||||
|
@ -2290,6 +2294,14 @@ impl Document {
|
|||
self.load_event_end.get()
|
||||
}
|
||||
|
||||
pub fn get_unload_event_start(&self) -> u64 {
|
||||
self.unload_event_start.get()
|
||||
}
|
||||
|
||||
pub fn get_unload_event_end(&self) -> u64 {
|
||||
self.unload_event_end.get()
|
||||
}
|
||||
|
||||
pub fn start_tti(&self) {
|
||||
if self.get_interactive_metrics().needs_tti() {
|
||||
self.tti_window.borrow_mut().start_window();
|
||||
|
@ -2654,6 +2666,8 @@ impl Document {
|
|||
top_level_dom_complete: Cell::new(Default::default()),
|
||||
load_event_start: Cell::new(Default::default()),
|
||||
load_event_end: Cell::new(Default::default()),
|
||||
unload_event_start: Cell::new(Default::default()),
|
||||
unload_event_end: Cell::new(Default::default()),
|
||||
https_state: Cell::new(HttpsState::None),
|
||||
origin: origin,
|
||||
referrer: referrer,
|
||||
|
@ -2674,6 +2688,7 @@ impl Document {
|
|||
salvageable: Cell::new(true),
|
||||
fired_unload: Cell::new(false),
|
||||
responsive_images: Default::default(),
|
||||
redirect_count: Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2739,6 +2754,14 @@ impl Document {
|
|||
document
|
||||
}
|
||||
|
||||
pub fn get_redirect_count(&self) -> u16 {
|
||||
self.redirect_count.get()
|
||||
}
|
||||
|
||||
pub fn set_redirect_count(&self, count: u16) {
|
||||
self.redirect_count.set(count)
|
||||
}
|
||||
|
||||
fn create_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> DomRoot<NodeList> {
|
||||
let doc = self.GetDocumentElement();
|
||||
let maybe_node = doc.r().map(Castable::upcast::<Node>);
|
||||
|
@ -4268,6 +4291,9 @@ impl DocumentMethods for Document {
|
|||
return Ok(DomRoot::from_ref(self));
|
||||
}
|
||||
|
||||
// TODO: prompt to unload.
|
||||
// TODO: set unload_event_start and unload_event_end
|
||||
|
||||
window_from_node(self).set_navigation_start();
|
||||
|
||||
// Step 7
|
||||
|
|
|
@ -16,8 +16,9 @@ use crate::dom::event::Event;
|
|||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::messageevent::MessageEvent;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::task_source::{TaskSource, TaskSourceName};
|
||||
use crate::timers::OneshotTimerCallback;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -34,6 +35,7 @@ use net_traits::request::{CacheMode, CorsSettings, CredentialsMode};
|
|||
use net_traits::request::{RequestInit, RequestMode};
|
||||
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata};
|
||||
use net_traits::{FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_atoms::Atom;
|
||||
use servo_url::ServoUrl;
|
||||
use std::cell::Cell;
|
||||
|
@ -91,6 +93,8 @@ struct EventSourceContext {
|
|||
event_type: String,
|
||||
data: String,
|
||||
last_event_id: String,
|
||||
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl EventSourceContext {
|
||||
|
@ -398,12 +402,34 @@ impl FetchResponseListener for EventSourceContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, _response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
if let Some(_) = self.incomplete_utf8.take() {
|
||||
self.parse("\u{FFFD}".chars());
|
||||
}
|
||||
self.reestablish_the_connection();
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for EventSourceContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(InitiatorType::Other, self.event_source.root().url().clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.event_source.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for EventSourceContext {
|
||||
|
@ -463,6 +489,10 @@ impl EventSource {
|
|||
self.request.borrow().clone().unwrap()
|
||||
}
|
||||
|
||||
pub fn url(&self) -> &ServoUrl {
|
||||
&self.url
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-eventsource
|
||||
pub fn Constructor(
|
||||
global: &GlobalScope,
|
||||
|
@ -533,6 +563,7 @@ impl EventSource {
|
|||
event_type: String::new(),
|
||||
data: String::new(),
|
||||
last_event_id: String::new(),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
};
|
||||
let listener = NetworkListener {
|
||||
context: Arc::new(Mutex::new(context)),
|
||||
|
|
|
@ -25,6 +25,7 @@ use crate::dom::element::{reflect_cross_origin_attribute, set_cross_origin_attri
|
|||
use crate::dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
|
||||
use crate::dom::event::{Event, EventBubbles, EventCancelable};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlareaelement::HTMLAreaElement;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmlformelement::{FormControl, HTMLFormElement};
|
||||
|
@ -33,15 +34,17 @@ use crate::dom::htmlpictureelement::HTMLPictureElement;
|
|||
use crate::dom::htmlsourceelement::HTMLSourceElement;
|
||||
use crate::dom::mouseevent::MouseEvent;
|
||||
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::progressevent::ProgressEvent;
|
||||
use crate::dom::values::UNSIGNED_LONG_MAX;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::dom::window::Window;
|
||||
use crate::microtask::{Microtask, MicrotaskRunnable};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::script_thread::ScriptThread;
|
||||
use crate::task_source::TaskSource;
|
||||
use cssparser::{Parser, ParserInput};
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::Point2D;
|
||||
use html5ever::{LocalName, Prefix};
|
||||
|
@ -54,6 +57,7 @@ use net_traits::image_cache::{CanRequestImages, ImageCache, ImageOrMetadataAvail
|
|||
use net_traits::image_cache::{ImageResponder, ImageResponse, ImageState, PendingImageId};
|
||||
use net_traits::request::RequestInit;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use num_traits::ToPrimitive;
|
||||
use servo_url::origin::MutableOrigin;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -164,6 +168,11 @@ struct ImageContext {
|
|||
id: PendingImageId,
|
||||
/// Used to mark abort
|
||||
aborted: Cell<bool>,
|
||||
/// The document associated with this request
|
||||
doc: Trusted<Document>,
|
||||
/// timing data for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
url: ServoUrl,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for ImageContext {
|
||||
|
@ -213,10 +222,35 @@ impl FetchResponseListener for ImageContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
self.image_cache
|
||||
.notify_pending_response(self.id, FetchResponseMsg::ProcessResponseEOF(response));
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for ImageContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::LocalName("img".to_string()),
|
||||
self.url.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.doc.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for ImageContext {
|
||||
|
@ -306,6 +340,9 @@ impl HTMLImageElement {
|
|||
status: Ok(()),
|
||||
id: id,
|
||||
aborted: Cell::new(false),
|
||||
doc: Trusted::new(&document),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
url: img_url.clone(),
|
||||
}));
|
||||
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
|
|
|
@ -25,16 +25,18 @@ use crate::dom::blob::Blob;
|
|||
use crate::dom::document::Document;
|
||||
use crate::dom::element::{AttributeMutation, Element};
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmlsourceelement::HTMLSourceElement;
|
||||
use crate::dom::htmlvideoelement::HTMLVideoElement;
|
||||
use crate::dom::mediaerror::MediaError;
|
||||
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::microtask::{Microtask, MicrotaskRunnable};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::script_thread::ScriptThread;
|
||||
use crate::task_source::TaskSource;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -46,8 +48,8 @@ use ipc_channel::ipc;
|
|||
use ipc_channel::router::ROUTER;
|
||||
use mime::{self, Mime};
|
||||
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
||||
use net_traits::NetworkError;
|
||||
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata};
|
||||
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
|
||||
use script_layout_interface::HTMLMediaData;
|
||||
use servo_media::player::frame::{Frame, FrameRenderer};
|
||||
use servo_media::player::{PlaybackState, Player, PlayerEvent, StreamType};
|
||||
|
@ -706,7 +708,10 @@ impl HTMLMediaElement {
|
|||
..RequestInit::default()
|
||||
};
|
||||
|
||||
let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self)));
|
||||
let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(
|
||||
self,
|
||||
self.resource_url.borrow().as_ref().unwrap().clone(),
|
||||
)));
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
let window = window_from_node(self);
|
||||
let (task_source, canceller) = window
|
||||
|
@ -1459,6 +1464,10 @@ struct HTMLMediaElementContext {
|
|||
next_progress_event: Timespec,
|
||||
/// True if this response is invalid and should be ignored.
|
||||
ignore_response: bool,
|
||||
/// timing data for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
/// url for the resource
|
||||
url: ServoUrl,
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
|
@ -1527,7 +1536,7 @@ impl FetchResponseListener for HTMLMediaElementContext {
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, status: Result<ResourceFetchTiming, NetworkError>) {
|
||||
if self.ignore_response {
|
||||
// An error was received previously, skip processing the payload.
|
||||
return;
|
||||
|
@ -1579,6 +1588,35 @@ impl FetchResponseListener for HTMLMediaElementContext {
|
|||
elem.queue_dedicated_media_source_failure_steps();
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for HTMLMediaElementContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
let initiator_type = InitiatorType::LocalName(
|
||||
self.elem
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.local_name()
|
||||
.to_string(),
|
||||
);
|
||||
(initiator_type, self.url.clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
(document_from_node(&*self.elem.root()).global())
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for HTMLMediaElementContext {
|
||||
|
@ -1589,13 +1627,15 @@ impl PreInvoke for HTMLMediaElementContext {
|
|||
}
|
||||
|
||||
impl HTMLMediaElementContext {
|
||||
fn new(elem: &HTMLMediaElement) -> HTMLMediaElementContext {
|
||||
fn new(elem: &HTMLMediaElement, url: ServoUrl) -> HTMLMediaElementContext {
|
||||
HTMLMediaElementContext {
|
||||
elem: Trusted::new(elem),
|
||||
metadata: None,
|
||||
generation_id: elem.generation_id.get(),
|
||||
next_progress_event: time::get_time() + Duration::milliseconds(350),
|
||||
ignore_response: false,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,9 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::node::{document_from_node, window_from_node};
|
||||
use crate::dom::node::{ChildrenMutation, CloneChildrenFlag, Node};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use dom_struct::dom_struct;
|
||||
use encoding_rs::Encoding;
|
||||
use html5ever::{LocalName, Prefix};
|
||||
|
@ -33,6 +34,7 @@ use ipc_channel::router::ROUTER;
|
|||
use js::jsval::UndefinedValue;
|
||||
use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestInit, RequestMode};
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_atoms::Atom;
|
||||
use servo_config::opts;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -166,6 +168,8 @@ struct ScriptContext {
|
|||
url: ServoUrl,
|
||||
/// Indicates whether the request failed, and why
|
||||
status: Result<(), NetworkError>,
|
||||
/// Timing object for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for ScriptContext {
|
||||
|
@ -208,7 +212,7 @@ impl FetchResponseListener for ScriptContext {
|
|||
|
||||
/// <https://html.spec.whatwg.org/multipage/#fetch-a-classic-script>
|
||||
/// step 4-9
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
// Step 5.
|
||||
let load = response.and(self.status.clone()).map(|_| {
|
||||
let metadata = self.metadata.take().unwrap();
|
||||
|
@ -241,6 +245,35 @@ impl FetchResponseListener for ScriptContext {
|
|||
|
||||
document.finish_load(LoadType::Script(self.url.clone()));
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for ScriptContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
let initiator_type = InitiatorType::LocalName(
|
||||
self.elem
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.local_name()
|
||||
.to_string(),
|
||||
);
|
||||
(initiator_type, self.url.clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
(document_from_node(&*self.elem.root()).global())
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for ScriptContext {}
|
||||
|
@ -290,6 +323,7 @@ fn fetch_a_classic_script(
|
|||
metadata: None,
|
||||
url: url.clone(),
|
||||
status: Ok(()),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
}));
|
||||
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
|
|
|
@ -415,10 +415,11 @@ pub mod performance;
|
|||
pub mod performanceentry;
|
||||
pub mod performancemark;
|
||||
pub mod performancemeasure;
|
||||
pub mod performancenavigationtiming;
|
||||
pub mod performanceobserver;
|
||||
pub mod performanceobserverentrylist;
|
||||
pub mod performancepainttiming;
|
||||
pub mod performancetiming;
|
||||
pub mod performanceresourcetiming;
|
||||
pub mod permissions;
|
||||
pub mod permissionstatus;
|
||||
pub mod plugin;
|
||||
|
|
|
@ -11,15 +11,16 @@ use crate::dom::bindings::codegen::Bindings::PerformanceBinding::{
|
|||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performancemark::PerformanceMark;
|
||||
use crate::dom::performancemeasure::PerformanceMeasure;
|
||||
use crate::dom::performancenavigationtiming::PerformanceNavigationTiming;
|
||||
use crate::dom::performanceobserver::PerformanceObserver as DOMPerformanceObserver;
|
||||
use crate::dom::performancetiming::PerformanceTiming;
|
||||
use crate::dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use metrics::ToMs;
|
||||
|
@ -131,8 +132,7 @@ struct PerformanceObserver {
|
|||
|
||||
#[dom_struct]
|
||||
pub struct Performance {
|
||||
reflector_: Reflector,
|
||||
timing: Option<Dom<PerformanceTiming>>,
|
||||
eventtarget: EventTarget,
|
||||
entries: DomRefCell<PerformanceEntryList>,
|
||||
observers: DomRefCell<Vec<PerformanceObserver>>,
|
||||
pending_notification_observers_task: Cell<bool>,
|
||||
|
@ -140,22 +140,9 @@ pub struct Performance {
|
|||
}
|
||||
|
||||
impl Performance {
|
||||
fn new_inherited(
|
||||
global: &GlobalScope,
|
||||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
) -> Performance {
|
||||
fn new_inherited(navigation_start_precise: u64) -> Performance {
|
||||
Performance {
|
||||
reflector_: Reflector::new(),
|
||||
timing: if global.is::<Window>() {
|
||||
Some(Dom::from_ref(&*PerformanceTiming::new(
|
||||
global.as_window(),
|
||||
navigation_start,
|
||||
navigation_start_precise,
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
eventtarget: EventTarget::new_inherited(),
|
||||
entries: DomRefCell::new(PerformanceEntryList::new(Vec::new())),
|
||||
observers: DomRefCell::new(Vec::new()),
|
||||
pending_notification_observers_task: Cell::new(false),
|
||||
|
@ -163,17 +150,9 @@ impl Performance {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
) -> DomRoot<Performance> {
|
||||
pub fn new(global: &GlobalScope, navigation_start_precise: u64) -> DomRoot<Performance> {
|
||||
reflect_dom_object(
|
||||
Box::new(Performance::new_inherited(
|
||||
global,
|
||||
navigation_start,
|
||||
navigation_start_precise,
|
||||
)),
|
||||
Box::new(Performance::new_inherited(navigation_start_precise)),
|
||||
global,
|
||||
PerformanceBinding::Wrap,
|
||||
)
|
||||
|
@ -296,21 +275,23 @@ impl Performance {
|
|||
}
|
||||
|
||||
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() - nav_start).to_ms()
|
||||
(time::precise_time_ns() - self.navigation_start_precise).to_ms()
|
||||
}
|
||||
}
|
||||
|
||||
impl PerformanceMethods for Performance {
|
||||
// FIXME(avada): this should be deprecated in the future, but some sites still use it
|
||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#performance-timing-attribute
|
||||
fn Timing(&self) -> DomRoot<PerformanceTiming> {
|
||||
match self.timing {
|
||||
Some(ref timing) => DomRoot::from_ref(&*timing),
|
||||
None => unreachable!("Are we trying to expose Performance.timing in workers?"),
|
||||
fn Timing(&self) -> DomRoot<PerformanceNavigationTiming> {
|
||||
let entries = self.GetEntriesByType(DOMString::from("navigation"));
|
||||
if entries.len() > 0 {
|
||||
return DomRoot::from_ref(
|
||||
entries[0]
|
||||
.downcast::<PerformanceNavigationTiming>()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
unreachable!("Are we trying to expose Performance.timing in workers?");
|
||||
}
|
||||
|
||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/HighResolutionTime/Overview.html#dom-performance-now
|
||||
|
@ -318,6 +299,11 @@ impl PerformanceMethods for Performance {
|
|||
Finite::wrap(self.now())
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/hr-time-2/#dom-performance-timeorigin
|
||||
fn TimeOrigin(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.navigation_start_precise as f64)
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/performance-timeline-2/#dom-performance-getentries
|
||||
fn GetEntries(&self) -> Vec<DomRoot<PerformanceEntry>> {
|
||||
self.entries
|
||||
|
|
|
@ -59,6 +59,10 @@ impl PerformanceEntry {
|
|||
pub fn start_time(&self) -> f64 {
|
||||
self.start_time
|
||||
}
|
||||
|
||||
pub fn duration(&self) -> f64 {
|
||||
self.duration
|
||||
}
|
||||
}
|
||||
|
||||
impl PerformanceEntryMethods for PerformanceEntry {
|
||||
|
|
126
components/script/dom/performancenavigationtiming.rs
Normal file
126
components/script/dom/performancenavigationtiming.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* 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 crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceNavigationTimingBinding::PerformanceNavigationTimingMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceNavigationTimingBinding::{
|
||||
self, NavigationType,
|
||||
};
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object;
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming};
|
||||
use dom_struct::dom_struct;
|
||||
|
||||
#[dom_struct]
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming
|
||||
/// Only the current document resource is included in the performance timeline;
|
||||
/// there is only one PerformanceNavigationTiming object in the performance timeline.
|
||||
pub struct PerformanceNavigationTiming {
|
||||
// https://w3c.github.io/navigation-timing/#PerformanceResourceTiming
|
||||
performanceresourcetiming: PerformanceResourceTiming,
|
||||
navigation_start: u64,
|
||||
navigation_start_precise: u64,
|
||||
document: Dom<Document>,
|
||||
nav_type: NavigationType,
|
||||
}
|
||||
|
||||
impl PerformanceNavigationTiming {
|
||||
fn new_inherited(
|
||||
nav_start: u64,
|
||||
nav_start_precise: u64,
|
||||
document: &Document,
|
||||
) -> PerformanceNavigationTiming {
|
||||
PerformanceNavigationTiming {
|
||||
performanceresourcetiming: PerformanceResourceTiming::new_inherited(
|
||||
document.url(),
|
||||
InitiatorType::Navigation,
|
||||
None,
|
||||
nav_start_precise as f64,
|
||||
),
|
||||
navigation_start: nav_start,
|
||||
navigation_start_precise: nav_start_precise,
|
||||
document: Dom::from_ref(document),
|
||||
nav_type: NavigationType::Navigate,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
nav_start: u64,
|
||||
nav_start_precise: u64,
|
||||
document: &Document,
|
||||
) -> DomRoot<PerformanceNavigationTiming> {
|
||||
reflect_dom_object(
|
||||
Box::new(PerformanceNavigationTiming::new_inherited(
|
||||
nav_start,
|
||||
nav_start_precise,
|
||||
document,
|
||||
)),
|
||||
global,
|
||||
PerformanceNavigationTimingBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/
|
||||
impl PerformanceNavigationTimingMethods for PerformanceNavigationTiming {
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-unloadeventstart
|
||||
fn UnloadEventStart(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_unload_event_start() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-unloadeventend
|
||||
fn UnloadEventEnd(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_unload_event_end() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-dominteractive
|
||||
fn DomInteractive(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_interactive() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-domcontentloadedeventstart
|
||||
fn DomContentLoadedEventStart(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_content_loaded_event_start() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-domcontentloadedeventstart
|
||||
fn DomContentLoadedEventEnd(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_content_loaded_event_end() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-domcomplete
|
||||
fn DomComplete(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_dom_complete() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-loadeventstart
|
||||
fn LoadEventStart(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_load_event_start() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-loadeventend
|
||||
fn LoadEventEnd(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_load_event_end() as f64)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-type
|
||||
fn Type(&self) -> NavigationType {
|
||||
self.nav_type.clone()
|
||||
}
|
||||
|
||||
// https://w3c.github.io/navigation-timing/#dom-performancenavigationtiming-redirectcount
|
||||
fn RedirectCount(&self) -> u16 {
|
||||
self.document.get_redirect_count()
|
||||
}
|
||||
|
||||
// check-tidy: no specs after this line
|
||||
// Servo-only timing for when top-level content (not iframes) is complete
|
||||
fn TopLevelDomComplete(&self) -> DOMHighResTimeStamp {
|
||||
Finite::wrap(self.document.get_top_level_dom_complete() as f64)
|
||||
}
|
||||
}
|
|
@ -22,9 +22,11 @@ use std::rc::Rc;
|
|||
|
||||
/// List of allowed performance entry types.
|
||||
const VALID_ENTRY_TYPES: &'static [&'static str] = &[
|
||||
"mark", // User Timing API
|
||||
"measure", // User Timing API
|
||||
// "resource", XXX Resource Timing API
|
||||
"mark", // User Timing API
|
||||
"measure", // User Timing API
|
||||
"resource", // Resource Timing API
|
||||
"navigation", // Navigation Timing API
|
||||
// "frame", //TODO Frame Timing API
|
||||
// "server", XXX Server Timing API
|
||||
"paint", // Paint Timing API
|
||||
];
|
||||
|
|
187
components/script/dom/performanceresourcetiming.rs
Normal file
187
components/script/dom/performanceresourcetiming.rs
Normal file
|
@ -0,0 +1,187 @@
|
|||
/* 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 crate::dom::bindings::codegen::Bindings::PerformanceBinding::DOMHighResTimeStamp;
|
||||
use crate::dom::bindings::codegen::Bindings::PerformanceResourceTimingBinding::{
|
||||
self, PerformanceResourceTimingMethods,
|
||||
};
|
||||
use crate::dom::bindings::num::Finite;
|
||||
use crate::dom::bindings::reflector::reflect_dom_object;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use dom_struct::dom_struct;
|
||||
use net_traits::ResourceFetchTiming;
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
// TODO UA may choose to limit how many resources are included as PerformanceResourceTiming objects
|
||||
// recommended minimum is 150, can be changed by setResourceTimingBufferSize in performance
|
||||
// https://w3c.github.io/resource-timing/#sec-extensions-performance-interface
|
||||
|
||||
// TODO Cross origin resources MUST BE INCLUDED as PerformanceResourceTiming objects
|
||||
// https://w3c.github.io/resource-timing/#sec-cross-origin-resources
|
||||
|
||||
// TODO CSS, Beacon
|
||||
#[derive(Debug, JSTraceable, MallocSizeOf, PartialEq)]
|
||||
pub enum InitiatorType {
|
||||
LocalName(String),
|
||||
Navigation,
|
||||
XMLHttpRequest,
|
||||
Fetch,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[dom_struct]
|
||||
pub struct PerformanceResourceTiming {
|
||||
entry: PerformanceEntry,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
worker_start: f64,
|
||||
redirect_start: f64,
|
||||
redirect_end: f64,
|
||||
fetch_start: f64,
|
||||
domain_lookup_start: f64,
|
||||
domain_lookup_end: f64,
|
||||
connect_start: f64,
|
||||
connect_end: f64,
|
||||
secure_connection_start: f64,
|
||||
request_start: f64,
|
||||
response_start: f64,
|
||||
response_end: f64,
|
||||
// transfer_size: f64, //size in octets
|
||||
// encoded_body_size: f64, //size in octets
|
||||
// decoded_body_size: f64, //size in octets
|
||||
}
|
||||
|
||||
// TODO(#21254): startTime
|
||||
// TODO(#21255): duration
|
||||
// TODO(#21269): next_hop
|
||||
// TODO(#21264): worker_start
|
||||
// TODO(#21256): redirect_start
|
||||
// TODO(#21257): redirect_end
|
||||
// TODO(#21258): fetch_start
|
||||
// TODO(#21259): domain_lookup_start
|
||||
// TODO(#21260): domain_lookup_end
|
||||
// TODO(#21261): connect_start
|
||||
// TODO(#21262): connect_end
|
||||
// TODO(#21263): response_end
|
||||
impl PerformanceResourceTiming {
|
||||
pub fn new_inherited(
|
||||
url: ServoUrl,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
fetch_start: f64,
|
||||
) -> PerformanceResourceTiming {
|
||||
PerformanceResourceTiming {
|
||||
entry: PerformanceEntry::new_inherited(
|
||||
DOMString::from(url.into_string()),
|
||||
DOMString::from("resource"),
|
||||
fetch_start,
|
||||
0.,
|
||||
),
|
||||
initiator_type: initiator_type,
|
||||
next_hop: next_hop,
|
||||
worker_start: 0.,
|
||||
redirect_start: 0.,
|
||||
redirect_end: 0.,
|
||||
fetch_start: fetch_start,
|
||||
domain_lookup_start: 0.,
|
||||
domain_lookup_end: 0.,
|
||||
connect_start: 0.,
|
||||
connect_end: 0.,
|
||||
secure_connection_start: 0.,
|
||||
request_start: 0.,
|
||||
response_start: 0.,
|
||||
response_end: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
//TODO fetch start should be in RFT
|
||||
#[allow(unrooted_must_root)]
|
||||
fn from_resource_timing(
|
||||
url: ServoUrl,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
resource_timing: &ResourceFetchTiming,
|
||||
) -> PerformanceResourceTiming {
|
||||
PerformanceResourceTiming {
|
||||
entry: PerformanceEntry::new_inherited(
|
||||
DOMString::from(url.into_string()),
|
||||
DOMString::from("resource"),
|
||||
0.,
|
||||
0.,
|
||||
),
|
||||
initiator_type: initiator_type,
|
||||
next_hop: next_hop,
|
||||
worker_start: 0.,
|
||||
redirect_start: 0.,
|
||||
redirect_end: 0.,
|
||||
fetch_start: 0.,
|
||||
domain_lookup_start: 0.,
|
||||
domain_lookup_end: 0.,
|
||||
connect_start: 0.,
|
||||
connect_end: 0.,
|
||||
secure_connection_start: 0.,
|
||||
request_start: resource_timing.request_start as f64,
|
||||
response_start: resource_timing.response_start as f64,
|
||||
response_end: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
url: ServoUrl,
|
||||
initiator_type: InitiatorType,
|
||||
next_hop: Option<DOMString>,
|
||||
resource_timing: &ResourceFetchTiming,
|
||||
) -> DomRoot<PerformanceResourceTiming> {
|
||||
reflect_dom_object(
|
||||
Box::new(PerformanceResourceTiming::from_resource_timing(
|
||||
url,
|
||||
initiator_type,
|
||||
next_hop,
|
||||
resource_timing,
|
||||
)),
|
||||
global,
|
||||
PerformanceResourceTimingBinding::Wrap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/
|
||||
impl PerformanceResourceTimingMethods for PerformanceResourceTiming {
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-initiatortype
|
||||
fn InitiatorType(&self) -> DOMString {
|
||||
match self.initiator_type {
|
||||
InitiatorType::LocalName(ref n) => DOMString::from(n.clone()),
|
||||
InitiatorType::Navigation => DOMString::from("navigation"),
|
||||
InitiatorType::XMLHttpRequest => DOMString::from("xmlhttprequest"),
|
||||
InitiatorType::Fetch => DOMString::from("fetch"),
|
||||
InitiatorType::Other => DOMString::from("other"),
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-nexthopprotocol
|
||||
// returns the ALPN protocol ID of the network protocol used to fetch the resource
|
||||
// when a proxy is configured
|
||||
fn NextHopProtocol(&self) -> DOMString {
|
||||
match self.next_hop {
|
||||
Some(ref protocol) => DOMString::from(protocol.clone()),
|
||||
None => DOMString::from(""),
|
||||
}
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-requeststart
|
||||
fn RequestStart(&self) -> DOMHighResTimeStamp {
|
||||
// TODO
|
||||
Finite::wrap(self.request_start)
|
||||
}
|
||||
|
||||
// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-responsestart
|
||||
fn ResponseStart(&self) -> DOMHighResTimeStamp {
|
||||
// TODO
|
||||
Finite::wrap(self.response_start)
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
|||
use crate::dom::bindings::codegen::Bindings::ServoParserBinding;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom, RootedReference};
|
||||
use crate::dom::bindings::settings_stack::is_execution_stack_empty;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
|
@ -28,6 +28,8 @@ use crate::dom::htmlimageelement::HTMLImageElement;
|
|||
use crate::dom::htmlscriptelement::{HTMLScriptElement, ScriptResult};
|
||||
use crate::dom::htmltemplateelement::HTMLTemplateElement;
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performancenavigationtiming::PerformanceNavigationTiming;
|
||||
use crate::dom::processinginstruction::ProcessingInstruction;
|
||||
use crate::dom::text::Text;
|
||||
use crate::dom::virtualmethods::vtable_for;
|
||||
|
@ -43,8 +45,10 @@ use hyper_serde::Serde;
|
|||
use mime::{self, Mime};
|
||||
use msg::constellation_msg::PipelineId;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, Metadata, NetworkError};
|
||||
use profile_traits::time::{profile, ProfilerCategory, TimerMetadataReflowType};
|
||||
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use profile_traits::time::{
|
||||
profile, ProfilerCategory, TimerMetadata, TimerMetadataFrameType, TimerMetadataReflowType,
|
||||
};
|
||||
use script_traits::DocumentActivity;
|
||||
use servo_config::prefs::PREFS;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -656,6 +660,8 @@ pub struct ParserContext {
|
|||
id: PipelineId,
|
||||
/// The URL for this document.
|
||||
url: ServoUrl,
|
||||
/// timing data for this resource
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl ParserContext {
|
||||
|
@ -665,6 +671,7 @@ impl ParserContext {
|
|||
is_synthesized_document: false,
|
||||
id: id,
|
||||
url: url,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Navigation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +799,10 @@ impl FetchResponseListener for ParserContext {
|
|||
parser.parse_bytes_chunk(payload);
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
// This method is called via script_thread::handle_fetch_eof, so we must call
|
||||
// submit_resource_timing in this function
|
||||
// Resource listeners are called via net_traits::Action::process, which handles submission for them
|
||||
fn process_response_eof(&mut self, status: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let parser = match self.parser.as_ref() {
|
||||
Some(parser) => parser.root(),
|
||||
None => return,
|
||||
|
@ -801,15 +811,53 @@ impl FetchResponseListener for ParserContext {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Err(err) = status {
|
||||
match status {
|
||||
// are we throwing this away or can we use it?
|
||||
Ok(_) => (),
|
||||
// TODO(Savago): we should send a notification to callers #5463.
|
||||
debug!("Failed to load page URL {}, error: {:?}", self.url, err);
|
||||
Err(err) => debug!("Failed to load page URL {}, error: {:?}", self.url, err),
|
||||
}
|
||||
|
||||
parser
|
||||
.document
|
||||
.set_redirect_count(self.resource_timing.redirect_count);
|
||||
|
||||
parser.last_chunk_received.set(true);
|
||||
if !parser.suspended.get() {
|
||||
parser.parse_sync();
|
||||
}
|
||||
|
||||
//TODO only submit if this is the current document resource
|
||||
self.submit_resource_timing();
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
// store a PerformanceNavigationTiming entry in the globalscope's Performance buffer
|
||||
fn submit_resource_timing(&mut self) {
|
||||
let parser = match self.parser.as_ref() {
|
||||
Some(parser) => parser.root(),
|
||||
None => return,
|
||||
};
|
||||
if parser.aborted.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
let document = &parser.document;
|
||||
|
||||
//TODO nav_start and nav_start_precise
|
||||
let performance_entry =
|
||||
PerformanceNavigationTiming::new(&document.global(), 0, 0, &document);
|
||||
document
|
||||
.global()
|
||||
.performance()
|
||||
.queue_entry(performance_entry.upcast::<PerformanceEntry>(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,14 +10,10 @@ typedef double DOMHighResTimeStamp;
|
|||
typedef sequence<PerformanceEntry> PerformanceEntryList;
|
||||
|
||||
[Exposed=(Window, Worker)]
|
||||
interface Performance {
|
||||
interface Performance : EventTarget {
|
||||
DOMHighResTimeStamp now();
|
||||
};
|
||||
|
||||
[Exposed=(Window)]
|
||||
partial interface Performance {
|
||||
readonly attribute PerformanceTiming timing;
|
||||
/* readonly attribute PerformanceNavigation navigation; */
|
||||
readonly attribute DOMHighResTimeStamp timeOrigin;
|
||||
// [Default] object toJSON();
|
||||
};
|
||||
|
||||
// https://w3c.github.io/performance-timeline/#extensions-to-the-performance-interface
|
||||
|
@ -39,3 +35,10 @@ partial interface Performance {
|
|||
void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);
|
||||
void clearMeasures(optional DOMString measureName);
|
||||
};
|
||||
|
||||
// FIXME(avada): this should be deprecated, but is currently included for web compat
|
||||
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#performance-timing-attribute
|
||||
[Exposed=(Window)]
|
||||
partial interface Performance {
|
||||
PerformanceNavigationTiming timing();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* 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/navigation-timing/#dom-performancenavigationtiming
|
||||
*/
|
||||
|
||||
enum NavigationType {
|
||||
"navigate",
|
||||
"reload",
|
||||
"back_forward",
|
||||
"prerender"
|
||||
};
|
||||
|
||||
[Exposed=Window]
|
||||
interface PerformanceNavigationTiming : PerformanceResourceTiming {
|
||||
readonly attribute DOMHighResTimeStamp unloadEventStart;
|
||||
readonly attribute DOMHighResTimeStamp unloadEventEnd;
|
||||
readonly attribute DOMHighResTimeStamp domInteractive;
|
||||
readonly attribute DOMHighResTimeStamp domContentLoadedEventStart;
|
||||
readonly attribute DOMHighResTimeStamp domContentLoadedEventEnd;
|
||||
readonly attribute DOMHighResTimeStamp domComplete;
|
||||
readonly attribute DOMHighResTimeStamp loadEventStart;
|
||||
readonly attribute DOMHighResTimeStamp loadEventEnd;
|
||||
readonly attribute NavigationType type;
|
||||
readonly attribute unsigned short redirectCount;
|
||||
// [Default] object toJSON();
|
||||
/* Servo-only attribute for measuring when the top-level document (not iframes) is complete. */
|
||||
[Pref="dom.testperf.enabled"]
|
||||
readonly attribute DOMHighResTimeStamp topLevelDomComplete;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
/* 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/resource-timing/
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface PerformanceResourceTiming : PerformanceEntry {
|
||||
readonly attribute DOMString initiatorType;
|
||||
readonly attribute DOMString nextHopProtocol;
|
||||
// readonly attribute DOMHighResTimeStamp workerStart;
|
||||
// readonly attribute DOMHighResTimeStamp redirectStart;
|
||||
// readonly attribute DOMHighResTimeStamp redirectEnd;
|
||||
// readonly attribute DOMHighResTimeStamp fetchStart;
|
||||
// readonly attribute DOMHighResTimeStamp domainLookupStart;
|
||||
// readonly attribute DOMHighResTimeStamp domainLookupEnd;
|
||||
// readonly attribute DOMHighResTimeStamp connectStart;
|
||||
// readonly attribute DOMHighResTimeStamp connectEnd;
|
||||
// readonly attribute DOMHighResTimeStamp secureConnectionStart;
|
||||
readonly attribute DOMHighResTimeStamp requestStart;
|
||||
readonly attribute DOMHighResTimeStamp responseStart;
|
||||
// readonly attribute DOMHighResTimeStamp responseEnd;
|
||||
/// readonly attribute unsigned long long transferSize;
|
||||
/// readonly attribute unsigned long long encodedBodySize;
|
||||
/// readonly attribute unsigned long long decodedBodySize;
|
||||
// [Default] object toJSON();
|
||||
};
|
||||
|
||||
// partial interface Performance {
|
||||
// void clearResourceTimings();
|
||||
// void setResourceTimingBufferSize(unsigned long maxSize);
|
||||
// attribute EventHandler onresourcetimingbufferfull;
|
||||
// };
|
|
@ -1,35 +0,0 @@
|
|||
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||
/*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html#sec-navigation-timing-interface
|
||||
*/
|
||||
|
||||
[Exposed=(Window)]
|
||||
interface PerformanceTiming {
|
||||
readonly attribute unsigned long long navigationStart;
|
||||
/* readonly attribute unsigned long long unloadEventStart;
|
||||
readonly attribute unsigned long long unloadEventEnd;
|
||||
readonly attribute unsigned long long redirectStart;
|
||||
readonly attribute unsigned long long redirectEnd;
|
||||
readonly attribute unsigned long long fetchStart;
|
||||
readonly attribute unsigned long long domainLookupStart;
|
||||
readonly attribute unsigned long long domainLookupEnd;
|
||||
readonly attribute unsigned long long connectStart;
|
||||
readonly attribute unsigned long long connectEnd;
|
||||
readonly attribute unsigned long long secureConnectionStart;
|
||||
readonly attribute unsigned long long requestStart;
|
||||
readonly attribute unsigned long long responseStart;
|
||||
readonly attribute unsigned long long responseEnd; */
|
||||
readonly attribute unsigned long long domLoading;
|
||||
readonly attribute unsigned long long domInteractive;
|
||||
readonly attribute unsigned long long domContentLoadedEventStart;
|
||||
readonly attribute unsigned long long domContentLoadedEventEnd;
|
||||
readonly attribute unsigned long long domComplete;
|
||||
readonly attribute unsigned long long loadEventStart;
|
||||
readonly attribute unsigned long long loadEventEnd;
|
||||
/* Servo-onnly attribute for measuring when the top-level document (not iframes) is complete. */
|
||||
[Pref="dom.testperf.enabled"]
|
||||
readonly attribute unsigned long long topLevelDomComplete;
|
||||
};
|
|
@ -812,11 +812,7 @@ impl WindowMethods for Window {
|
|||
fn Performance(&self) -> DomRoot<Performance> {
|
||||
self.performance.or_init(|| {
|
||||
let global_scope = self.upcast::<GlobalScope>();
|
||||
Performance::new(
|
||||
global_scope,
|
||||
self.navigation_start.get(),
|
||||
self.navigation_start_precise.get(),
|
||||
)
|
||||
Performance::new(global_scope, self.navigation_start_precise.get())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -357,11 +357,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope {
|
|||
fn Performance(&self) -> DomRoot<Performance> {
|
||||
self.performance.or_init(|| {
|
||||
let global_scope = self.upcast::<GlobalScope>();
|
||||
Performance::new(
|
||||
global_scope,
|
||||
0, /* navigation start is not used in workers */
|
||||
self.navigation_start_precise,
|
||||
)
|
||||
Performance::new(global_scope, self.navigation_start_precise)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::headers::is_forbidden_header_name;
|
||||
use crate::dom::htmlformelement::{encode_multipart_form_data, generate_boundary};
|
||||
use crate::dom::node::Node;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::progressevent::ProgressEvent;
|
||||
use crate::dom::servoparser::ServoParser;
|
||||
use crate::dom::urlsearchparams::URLSearchParams;
|
||||
|
@ -36,7 +37,7 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
|
|||
use crate::dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
|
||||
use crate::dom::xmlhttprequestupload::XMLHttpRequestUpload;
|
||||
use crate::fetch::FetchCanceller;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::task_source::networking::NetworkingTaskSource;
|
||||
use crate::task_source::TaskSourceName;
|
||||
use crate::timers::{OneshotTimerCallback, OneshotTimerHandle};
|
||||
|
@ -63,6 +64,7 @@ use net_traits::trim_http_whitespace;
|
|||
use net_traits::CoreResourceMsg::Fetch;
|
||||
use net_traits::{FetchChannels, FetchMetadata, FilteredMetadata};
|
||||
use net_traits::{FetchResponseListener, NetworkError, ReferrerPolicy};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use script_traits::DocumentActivity;
|
||||
use servo_atoms::Atom;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -95,6 +97,7 @@ struct XHRContext {
|
|||
gen_id: GenerationId,
|
||||
buf: DomRefCell<Vec<u8>>,
|
||||
sync_status: DomRefCell<Option<ErrorResult>>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -257,13 +260,41 @@ impl XMLHttpRequest {
|
|||
.process_data_available(self.gen_id, self.buf.borrow().clone());
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(
|
||||
&mut self,
|
||||
response: Result<ResourceFetchTiming, NetworkError>,
|
||||
) {
|
||||
let rv = self
|
||||
.xhr
|
||||
.root()
|
||||
.process_response_complete(self.gen_id, response);
|
||||
.process_response_complete(self.gen_id, response.map(|_| ()));
|
||||
*self.sync_status.borrow_mut() = Some(rv);
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for XHRContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::XMLHttpRequest,
|
||||
self.resource_timing_global().get_url().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.xhr.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for XHRContext {
|
||||
|
@ -1424,6 +1455,7 @@ impl XMLHttpRequest {
|
|||
gen_id: self.generation_id.get(),
|
||||
buf: DomRefCell::new(vec![]),
|
||||
sync_status: DomRefCell::new(None),
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
}));
|
||||
|
||||
let (task_source, script_port) = if self.sync.get() {
|
||||
|
|
|
@ -14,11 +14,12 @@ use crate::dom::bindings::root::DomRoot;
|
|||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::headers::Guard;
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::request::Request;
|
||||
use crate::dom::response::Response;
|
||||
use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use crate::task_source::TaskSourceName;
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
|
@ -28,6 +29,7 @@ use net_traits::request::{Request as NetTraitsRequest, ServiceWorkersMode};
|
|||
use net_traits::CoreResourceMsg::Fetch as NetTraitsFetch;
|
||||
use net_traits::{FetchChannels, FetchResponseListener, NetworkError};
|
||||
use net_traits::{FetchMetadata, FilteredMetadata, Metadata};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
@ -37,6 +39,7 @@ struct FetchContext {
|
|||
fetch_promise: Option<TrustedPromise>,
|
||||
response_object: Trusted<Response>,
|
||||
body: Vec<u8>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
/// RAII fetch canceller object. By default initialized to not having a canceller
|
||||
|
@ -143,6 +146,8 @@ pub fn Fetch(
|
|||
},
|
||||
Ok(r) => r.get_request(),
|
||||
};
|
||||
let timing_type = request.timing_type();
|
||||
|
||||
let mut request_init = request_init_from_request(request);
|
||||
|
||||
// Step 3
|
||||
|
@ -159,6 +164,7 @@ pub fn Fetch(
|
|||
fetch_promise: Some(TrustedPromise::new(promise.clone())),
|
||||
response_object: Trusted::new(&*response),
|
||||
body: vec![],
|
||||
resource_timing: ResourceFetchTiming::new(timing_type),
|
||||
}));
|
||||
let listener = NetworkListener {
|
||||
context: fetch_context,
|
||||
|
@ -250,7 +256,7 @@ impl FetchResponseListener for FetchContext {
|
|||
self.body.append(&mut chunk);
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, _response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, _response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let response = self.response_object.root();
|
||||
let global = response.global();
|
||||
let cx = global.get_cx();
|
||||
|
@ -259,6 +265,35 @@ impl FetchResponseListener for FetchContext {
|
|||
// TODO
|
||||
// ... trailerObject is not supported in Servo yet.
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
// navigation submission is handled in servoparser/mod.rs
|
||||
match self.resource_timing.timing_type {
|
||||
ResourceTimingType::Resource => network_listener::submit_timing(self),
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for FetchContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::Fetch,
|
||||
self.resource_timing_global().get_url().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.response_object.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_headers_with_metadata(r: DomRoot<Response>, m: Metadata) {
|
||||
|
|
|
@ -7,20 +7,28 @@
|
|||
//! no guarantee that the responsible nodes will still exist in the future if the
|
||||
//! layout thread holds on to them during asynchronous operations.
|
||||
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::node::{document_from_node, Node};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use ipc_channel::ipc;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use net_traits::image_cache::{ImageCache, PendingImageId};
|
||||
use net_traits::request::{Destination, RequestInit as FetchRequestInit};
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg, NetworkError};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct LayoutImageContext {
|
||||
id: PendingImageId,
|
||||
cache: Arc<dyn ImageCache>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
doc: Trusted<Document>,
|
||||
}
|
||||
|
||||
impl FetchResponseListener for LayoutImageContext {
|
||||
|
@ -36,10 +44,35 @@ impl FetchResponseListener for LayoutImageContext {
|
|||
.notify_pending_response(self.id, FetchResponseMsg::ProcessResponseChunk(payload));
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, response: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, response: Result<ResourceFetchTiming, NetworkError>) {
|
||||
self.cache
|
||||
.notify_pending_response(self.id, FetchResponseMsg::ProcessResponseEOF(response));
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for LayoutImageContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
(
|
||||
InitiatorType::Other,
|
||||
self.resource_timing_global().get_url().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
self.doc.root().global()
|
||||
}
|
||||
}
|
||||
|
||||
impl PreInvoke for LayoutImageContext {}
|
||||
|
@ -50,9 +83,13 @@ pub fn fetch_image_for_layout(
|
|||
id: PendingImageId,
|
||||
cache: Arc<dyn ImageCache>,
|
||||
) {
|
||||
let document = document_from_node(node);
|
||||
|
||||
let context = Arc::new(Mutex::new(LayoutImageContext {
|
||||
id: id,
|
||||
cache: cache,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
doc: Trusted::new(&document),
|
||||
}));
|
||||
|
||||
let document = document_from_node(node);
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::performanceentry::PerformanceEntry;
|
||||
use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming};
|
||||
use crate::task::{TaskCanceller, TaskOnce};
|
||||
use crate::task_source::networking::NetworkingTaskSource;
|
||||
use crate::task_source::TaskSource;
|
||||
use net_traits::{Action, FetchResponseListener, FetchResponseMsg};
|
||||
use net_traits::{Action, FetchResponseListener, FetchResponseMsg, ResourceTimingType};
|
||||
use servo_url::ServoUrl;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// An off-thread sink for async network event tasks. All such events are forwarded to
|
||||
|
@ -16,6 +22,39 @@ pub struct NetworkListener<Listener: PreInvoke + Send + 'static> {
|
|||
pub canceller: Option<TaskCanceller>,
|
||||
}
|
||||
|
||||
pub trait ResourceTimingListener {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl);
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope>;
|
||||
}
|
||||
|
||||
pub fn submit_timing<T: ResourceTimingListener + FetchResponseListener>(listener: &T) {
|
||||
if listener.resource_timing().timing_type != ResourceTimingType::Resource {
|
||||
warn!(
|
||||
"Submitting non-resource ({:?}) timing as resource",
|
||||
listener.resource_timing().timing_type
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let (initiator_type, url) = listener.resource_timing_information();
|
||||
if initiator_type == InitiatorType::Other {
|
||||
warn!("Ignoring InitiatorType::Other resource {:?}", url);
|
||||
return;
|
||||
}
|
||||
|
||||
let global = listener.resource_timing_global();
|
||||
let performance_entry = PerformanceResourceTiming::new(
|
||||
&global,
|
||||
url,
|
||||
initiator_type,
|
||||
None,
|
||||
&listener.resource_timing(),
|
||||
);
|
||||
global
|
||||
.performance()
|
||||
.queue_entry(performance_entry.upcast::<PerformanceEntry>(), false);
|
||||
}
|
||||
|
||||
impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
|
||||
pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
|
||||
let task = ListenerTask {
|
||||
|
|
|
@ -107,7 +107,10 @@ use net_traits::image_cache::{ImageCache, PendingImageResponse};
|
|||
use net_traits::request::{CredentialsMode, Destination, RedirectMode, RequestInit};
|
||||
use net_traits::storage_thread::StorageType;
|
||||
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg};
|
||||
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||
use net_traits::{
|
||||
Metadata, NetworkError, ReferrerPolicy, ResourceFetchTiming, ResourceThreads,
|
||||
ResourceTimingType,
|
||||
};
|
||||
use profile_traits::mem::{self as profile_mem, OpaqueSender, ReportsChan};
|
||||
use profile_traits::time::{self as profile_time, profile, ProfilerCategory};
|
||||
use script_layout_interface::message::{self, Msg, NewLayoutThreadInfo, ReflowGoal};
|
||||
|
@ -3097,9 +3100,12 @@ impl ScriptThread {
|
|||
fetch_metadata: Result<FetchMetadata, NetworkError>,
|
||||
) {
|
||||
match fetch_metadata {
|
||||
Ok(_) => {},
|
||||
Err(ref e) => warn!("Network error: {:?}", e),
|
||||
Ok(_) => (),
|
||||
Err(ref e) => {
|
||||
warn!("Network error: {:?}", e);
|
||||
},
|
||||
};
|
||||
|
||||
let mut incomplete_parser_contexts = self.incomplete_parser_contexts.borrow_mut();
|
||||
let parser = incomplete_parser_contexts
|
||||
.iter_mut()
|
||||
|
@ -3119,12 +3125,13 @@ impl ScriptThread {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_fetch_eof(&self, id: PipelineId, eof: Result<(), NetworkError>) {
|
||||
fn handle_fetch_eof(&self, id: PipelineId, eof: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let idx = self
|
||||
.incomplete_parser_contexts
|
||||
.borrow()
|
||||
.iter()
|
||||
.position(|&(pipeline_id, _)| pipeline_id == id);
|
||||
|
||||
if let Some(idx) = idx {
|
||||
let (_, mut ctxt) = self.incomplete_parser_contexts.borrow_mut().remove(idx);
|
||||
ctxt.process_response_eof(eof);
|
||||
|
@ -3161,7 +3168,7 @@ impl ScriptThread {
|
|||
|
||||
context.process_response(Ok(FetchMetadata::Unfiltered(meta)));
|
||||
context.process_response_chunk(chunk);
|
||||
context.process_response_eof(Ok(()));
|
||||
context.process_response_eof(Ok(ResourceFetchTiming::new(ResourceTimingType::None)));
|
||||
}
|
||||
|
||||
fn handle_css_error_reporting(
|
||||
|
|
|
@ -6,13 +6,16 @@ use crate::document_loader::LoadType;
|
|||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::Trusted;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::htmlelement::HTMLElement;
|
||||
use crate::dom::htmllinkelement::{HTMLLinkElement, RequestGenerationId};
|
||||
use crate::dom::node::{document_from_node, window_from_node};
|
||||
use crate::network_listener::{NetworkListener, PreInvoke};
|
||||
use crate::dom::performanceresourcetiming::InitiatorType;
|
||||
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
|
||||
use cssparser::SourceLocation;
|
||||
use encoding_rs::UTF_8;
|
||||
use ipc_channel::ipc;
|
||||
|
@ -22,6 +25,7 @@ use net_traits::request::{CorsSettings, CredentialsMode, Destination, RequestIni
|
|||
use net_traits::{
|
||||
FetchMetadata, FetchResponseListener, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy,
|
||||
};
|
||||
use net_traits::{ResourceFetchTiming, ResourceTimingType};
|
||||
use parking_lot::RwLock;
|
||||
use servo_arc::Arc;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -79,6 +83,7 @@ pub struct StylesheetContext {
|
|||
/// A token which must match the generation id of the `HTMLLinkElement` for it to load the stylesheet.
|
||||
/// This is ignored for `HTMLStyleElement` and imports.
|
||||
request_generation_id: Option<RequestGenerationId>,
|
||||
resource_timing: ResourceFetchTiming,
|
||||
}
|
||||
|
||||
impl PreInvoke for StylesheetContext {}
|
||||
|
@ -108,7 +113,7 @@ impl FetchResponseListener for StylesheetContext {
|
|||
self.data.append(&mut payload);
|
||||
}
|
||||
|
||||
fn process_response_eof(&mut self, status: Result<(), NetworkError>) {
|
||||
fn process_response_eof(&mut self, status: Result<ResourceFetchTiming, NetworkError>) {
|
||||
let elem = self.elem.root();
|
||||
let document = self.document.root();
|
||||
let mut successful = false;
|
||||
|
@ -207,6 +212,35 @@ impl FetchResponseListener for StylesheetContext {
|
|||
elem.upcast::<EventTarget>().fire_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
fn resource_timing_mut(&mut self) -> &mut ResourceFetchTiming {
|
||||
&mut self.resource_timing
|
||||
}
|
||||
|
||||
fn resource_timing(&self) -> &ResourceFetchTiming {
|
||||
&self.resource_timing
|
||||
}
|
||||
|
||||
fn submit_resource_timing(&mut self) {
|
||||
network_listener::submit_timing(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceTimingListener for StylesheetContext {
|
||||
fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
|
||||
let initiator_type = InitiatorType::LocalName(
|
||||
self.elem
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.local_name()
|
||||
.to_string(),
|
||||
);
|
||||
(initiator_type, self.url.clone())
|
||||
}
|
||||
|
||||
fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
|
||||
document_from_node(&*self.elem.root()).global()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StylesheetLoader<'a> {
|
||||
|
@ -241,6 +275,7 @@ impl<'a> StylesheetLoader<'a> {
|
|||
document: Trusted::new(&*document),
|
||||
origin_clean: true,
|
||||
request_generation_id: gen,
|
||||
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
|
||||
}));
|
||||
|
||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue