diff --git a/components/script/document_loader.rs b/components/script/document_loader.rs index 65e875b538b3..2cfa9096d9c6 100644 --- a/components/script/document_loader.rs +++ b/components/script/document_loader.rs @@ -8,9 +8,7 @@ use msg::constellation_msg::{PipelineId}; use net_traits::AsyncResponseTarget; use net_traits::{Metadata, PendingAsyncLoad, ResourceTask, load_whole_resource}; -use script_task::MainThreadScriptMsg; use std::sync::Arc; -use std::sync::mpsc::Sender; use url::Url; #[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)] @@ -40,15 +38,9 @@ pub struct DocumentLoader { /// are lots of iframes. #[ignore_heap_size_of = "channels are hard"] pub resource_task: Arc, - notifier_data: Option, + pipeline: Option, blocking_loads: Vec, -} - -#[derive(JSTraceable, HeapSizeOf)] -pub struct NotifierData { - #[ignore_heap_size_of = "trait objects are hard"] - pub script_chan: Sender, - pub pipeline: PipelineId, + events_inhibited: bool, } impl DocumentLoader { @@ -59,15 +51,16 @@ impl DocumentLoader { /// We use an `Arc` here in order to avoid file descriptor exhaustion when there /// are lots of iframes. pub fn new_with_task(resource_task: Arc, - data: Option, + pipeline: Option, initial_load: Option) -> DocumentLoader { let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect(); DocumentLoader { resource_task: resource_task, - notifier_data: data, + pipeline: pipeline, blocking_loads: initial_loads, + events_inhibited: false, } } @@ -76,8 +69,7 @@ impl DocumentLoader { pub fn prepare_async_load(&mut self, load: LoadType) -> PendingAsyncLoad { let url = load.url().clone(); self.blocking_loads.push(load); - let pipeline = self.notifier_data.as_ref().map(|data| data.pipeline); - PendingAsyncLoad::new((*self.resource_task).clone(), url, pipeline) + PendingAsyncLoad::new((*self.resource_task).clone(), url, self.pipeline) } /// Create and initiate a new network request. @@ -98,12 +90,6 @@ impl DocumentLoader { pub fn finish_load(&mut self, load: LoadType) { let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == load); self.blocking_loads.remove(idx.expect(&format!("unknown completed load {:?}", load))); - - if let Some(NotifierData { ref script_chan, pipeline }) = self.notifier_data { - if !self.is_blocked() { - script_chan.send(MainThreadScriptMsg::DocumentLoadsComplete(pipeline)).unwrap(); - } - } } pub fn is_blocked(&self) -> bool { @@ -112,6 +98,9 @@ impl DocumentLoader { } pub fn inhibit_events(&mut self) { - self.notifier_data = None; + self.events_inhibited = true; + } + pub fn events_inhibited(&self) -> bool { + self.events_inhibited } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 3a9c256155a5..156239eb2732 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -53,6 +53,7 @@ use layout_interface::{LayoutChan, LayoutRPC}; use libc; use msg::constellation_msg::ConstellationChan; use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData, WorkerId}; +use net_traits::Metadata; use net_traits::image::base::Image; use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; use net_traits::storage_task::StorageType; @@ -277,6 +278,7 @@ no_jsmanaged_fields!(Rect); no_jsmanaged_fields!(Size2D); no_jsmanaged_fields!(Arc); no_jsmanaged_fields!(Image, ImageCacheChan, ImageCacheTask); +no_jsmanaged_fields!(Metadata); no_jsmanaged_fields!(Atom, Namespace); no_jsmanaged_fields!(Trusted); no_jsmanaged_fields!(PropertyDeclarationBlock); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 23d455a19034..4767732723b3 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -81,9 +81,9 @@ use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{ConstellationChan, FocusType, Key, KeyModifiers, KeyState, MozBrowserEvent, SubpageId}; use net_traits::ControlMsg::{GetCookiesForUrl, SetCookiesForUrl}; use net_traits::CookieSource::NonHTTP; -use net_traits::{AsyncResponseTarget, Metadata, PendingAsyncLoad}; +use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; -use script_task::Runnable; +use script_task::{MainThreadScriptMsg, Runnable}; use script_traits::{MouseButton, UntrustedNodeAddress}; use std::ascii::AsciiExt; use std::borrow::ToOwned; @@ -107,6 +107,12 @@ pub enum IsHTMLDocument { NonHTMLDocument, } +#[derive(PartialEq)] +enum ParserBlockedByScript { + Blocked, + Unblocked, +} + // https://dom.spec.whatwg.org/#document #[dom_struct] pub struct Document { @@ -129,12 +135,24 @@ pub struct Document { anchors: MutNullableHeap>, applets: MutNullableHeap>, ready_state: Cell, + /// Whether the DOMContentLoaded event has already been dispatched. + domcontentloaded_dispatched: Cell, /// The element that has most recently requested focus for itself. possibly_focused: MutNullableHeap>, /// The element that currently has the document focus context. focused: MutNullableHeap>, /// The script element that is currently executing. current_script: MutNullableHeap>, + /// https://html.spec.whatwg.org/multipage/#pending-parsing-blocking-script + pending_parsing_blocking_script: MutNullableHeap>, + /// Number of stylesheets that block executing the next parser-inserted script + script_blocking_stylesheets_count: Cell, + /// https://html.spec.whatwg.org/multipage/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing + deferred_scripts: DOMRefCell>>, + /// https://html.spec.whatwg.org/multipage/#list-of-scripts-that-will-execute-in-order-as-soon-as-possible + asap_in_order_scripts_list: DOMRefCell>>, + /// https://html.spec.whatwg.org/multipage/#set-of-scripts-that-will-execute-as-soon-as-possible + asap_scripts_set: DOMRefCell>>, /// https://html.spec.whatwg.org/multipage/#concept-n-noscript /// True if scripting is enabled for all scripts in this document scripting_enabled: Cell, @@ -892,6 +910,42 @@ impl Document { self.current_script.set(script); } + pub fn get_script_blocking_stylesheets_count(&self) -> u32 { + self.script_blocking_stylesheets_count.get() + } + + pub fn increment_script_blocking_stylesheet_count(&self) { + let count_cell = &self.script_blocking_stylesheets_count; + count_cell.set(count_cell.get() + 1); + } + + pub fn decrement_script_blocking_stylesheet_count(&self) { + let count_cell = &self.script_blocking_stylesheets_count; + assert!(count_cell.get() > 0); + count_cell.set(count_cell.get() - 1); + } + + pub fn set_pending_parsing_blocking_script(&self, script: Option<&HTMLScriptElement>) { + assert!(self.get_pending_parsing_blocking_script().is_none() || script.is_none()); + self.pending_parsing_blocking_script.set(script); + } + + pub fn get_pending_parsing_blocking_script(&self) -> Option> { + self.pending_parsing_blocking_script.get() + } + + pub fn add_deferred_script(&self, script: &HTMLScriptElement) { + self.deferred_scripts.borrow_mut().push(JS::from_ref(script)); + } + + pub fn add_asap_script(&self, script: &HTMLScriptElement) { + self.asap_scripts_set.borrow_mut().push(JS::from_ref(script)); + } + + pub fn push_asap_in_order_script(&self, script: &HTMLScriptElement) { + self.asap_in_order_scripts_list.borrow_mut().push(JS::from_ref(script)); + } + pub fn trigger_mozbrowser_event(&self, event: MozBrowserEvent) { if htmliframeelement::mozbrowser_enabled() { if let Some((containing_pipeline_id, subpage_id)) = self.window.parent_info() { @@ -966,14 +1020,120 @@ impl Document { loader.load_async(load, listener) } - pub fn load_sync(&self, load: LoadType) -> Result<(Metadata, Vec), String> { - let mut loader = self.loader.borrow_mut(); - loader.load_sync(load) + pub fn finish_load(&self, load: LoadType) { + // The parser might need the loader, so restrict the lifetime of the borrow. + { + let mut loader = self.loader.borrow_mut(); + loader.finish_load(load.clone()); + } + + if let LoadType::Script(_) = load { + self.process_deferred_scripts(); + self.process_asap_scripts(); + } + + if self.maybe_execute_parser_blocking_script() == ParserBlockedByScript::Blocked { + return; + } + + // A finished resource load can potentially unblock parsing. In that case, resume the + // parser so its loop can find out. + if let Some(parser) = self.current_parser.get_rooted() { + if parser.is_suspended() { + parser.resume(); + } + } + + let loader = self.loader.borrow(); + if !loader.is_blocked() && !loader.events_inhibited() { + let win = self.window(); + let msg = MainThreadScriptMsg::DocumentLoadsComplete(win.pipeline()); + win.main_thread_script_chan().send(msg).unwrap(); + } } - pub fn finish_load(&self, load: LoadType) { - let mut loader = self.loader.borrow_mut(); - loader.finish_load(load); + /// If document parsing is blocked on a script, and that script is ready to run, + /// execute it. + /// https://html.spec.whatwg.org/multipage/#ready-to-be-parser-executed + fn maybe_execute_parser_blocking_script(&self) -> ParserBlockedByScript { + let script = match self.pending_parsing_blocking_script.get_rooted() { + None => return ParserBlockedByScript::Unblocked, + Some(script) => script, + }; + + if self.script_blocking_stylesheets_count.get() == 0 && + script.r().is_ready_to_be_executed() { + script.r().execute(); + self.pending_parsing_blocking_script.set(None); + return ParserBlockedByScript::Unblocked; + } + ParserBlockedByScript::Blocked + } + + /// https://html.spec.whatwg.org/multipage/#the-end step 3 + pub fn process_deferred_scripts(&self) { + if self.ready_state.get() != DocumentReadyState::Interactive { + return; + } + // Part of substep 1. + if self.script_blocking_stylesheets_count.get() > 0 { + return; + } + let mut deferred_scripts = self.deferred_scripts.borrow_mut(); + while !deferred_scripts.is_empty() { + let script = deferred_scripts[0].root(); + // Part of substep 1. + if !script.is_ready_to_be_executed() { + return; + } + // Substep 2. + script.execute(); + // Substep 3. + deferred_scripts.remove(0); + // Substep 4 (implicit). + } + // https://html.spec.whatwg.org/multipage/#the-end step 4. + self.maybe_dispatch_dom_content_loaded(); + } + + /// https://html.spec.whatwg.org/multipage/#the-end step 5 and the latter parts of + /// https://html.spec.whatwg.org/multipage/#prepare-a-script 15.d and 15.e. + pub fn process_asap_scripts(&self) { + // Execute the first in-order asap-executed script if it's ready, repeat as required. + // Re-borrowing the list for each step because it can also be borrowed under execute. + while self.asap_in_order_scripts_list.borrow().len() > 0 { + let script = self.asap_in_order_scripts_list.borrow()[0].root(); + if !script.r().is_ready_to_be_executed() { + break; + } + script.r().execute(); + self.asap_in_order_scripts_list.borrow_mut().remove(0); + } + + let mut idx = 0; + // Re-borrowing the set for each step because it can also be borrowed under execute. + while idx < self.asap_scripts_set.borrow().len() { + let script = self.asap_scripts_set.borrow()[idx].root(); + if !script.r().is_ready_to_be_executed() { + idx += 1; + continue; + } + script.r().execute(); + self.asap_scripts_set.borrow_mut().swap_remove(idx); + } + } + + pub fn maybe_dispatch_dom_content_loaded(&self) { + if self.domcontentloaded_dispatched.get() { + return; + } + self.domcontentloaded_dispatched.set(true); + let event = Event::new(GlobalRef::Window(self.window()), "DOMContentLoaded".to_owned(), + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable); + let doctarget = self.upcast::(); + let _ = doctarget.DispatchEvent(event.r()); + self.window().reflow(ReflowGoal::ForDisplay, ReflowQueryType::NoQuery, ReflowReason::DOMContentLoaded); } pub fn notify_constellation_load(&self) { @@ -1039,10 +1199,10 @@ impl Document { doc_loader: DocumentLoader) -> Document { let url = url.unwrap_or_else(|| Url::parse("about:blank").unwrap()); - let ready_state = if source == DocumentSource::FromParser { - DocumentReadyState::Loading + let (ready_state, domcontentloaded_dispatched) = if source == DocumentSource::FromParser { + (DocumentReadyState::Loading, false) } else { - DocumentReadyState::Complete + (DocumentReadyState::Complete, true) }; Document { @@ -1075,9 +1235,15 @@ impl Document { anchors: Default::default(), applets: Default::default(), ready_state: Cell::new(ready_state), + domcontentloaded_dispatched: Cell::new(domcontentloaded_dispatched), possibly_focused: Default::default(), focused: Default::default(), current_script: Default::default(), + pending_parsing_blocking_script: Default::default(), + script_blocking_stylesheets_count: Cell::new(0u32), + deferred_scripts: DOMRefCell::new(vec!()), + asap_in_order_scripts_list: DOMRefCell::new(vec!()), + asap_scripts_set: DOMRefCell::new(vec!()), scripting_enabled: Cell::new(true), animation_frame_ident: Cell::new(0), animation_frame_list: RefCell::new(HashMap::new()), @@ -1875,7 +2041,6 @@ fn is_scheme_host_port_tuple(url: &Url) -> bool { #[derive(HeapSizeOf)] pub enum DocumentProgressTask { - DOMContentLoaded, Load, } @@ -1892,20 +2057,6 @@ impl DocumentProgressHandler { } } - fn dispatch_dom_content_loaded(&self) { - let document = self.addr.root(); - let window = document.r().window(); - let event = Event::new(GlobalRef::Window(window), "DOMContentLoaded".to_owned(), - EventBubbles::DoesNotBubble, - EventCancelable::NotCancelable); - let doctarget = document.upcast::(); - let _ = doctarget.DispatchEvent(event.r()); - - window.reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::DOMContentLoaded); - } - fn set_ready_state_complete(&self) { let document = self.addr.root(); document.r().set_ready_state(DocumentReadyState::Complete); @@ -1949,9 +2100,6 @@ impl Runnable for DocumentProgressHandler { let window = document.r().window(); if window.is_alive() { match self.task { - DocumentProgressTask::DOMContentLoaded => { - self.dispatch_dom_content_loaded(); - } DocumentProgressTask::Load => { self.set_ready_state_complete(); self.dispatch_load(); diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index a32b481d2520..97fefdf30e26 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -37,7 +37,7 @@ use network_listener::{NetworkListener, PreInvoke}; use script_task::ScriptTaskEventCategory::ScriptEvent; use script_task::{CommonScriptMsg, Runnable, ScriptChan}; use std::ascii::AsciiExt; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::mem; use std::sync::{Arc, Mutex}; use url::{Url, UrlParser}; @@ -59,13 +59,14 @@ pub struct HTMLScriptElement { non_blocking: Cell, /// https://html.spec.whatwg.org/multipage/#ready-to-be-parser-executed - /// - /// (currently unused) ready_to_be_parser_executed: Cell, /// Document of the parser that created this element parser_document: JS, + /// The source this script was loaded from + load: RefCell>, + #[ignore_heap_size_of = "Defined in rust-encoding"] /// https://html.spec.whatwg.org/multipage/#concept-script-encoding block_character_encoding: DOMRefCell, @@ -82,6 +83,7 @@ impl HTMLScriptElement { non_blocking: Cell::new(creator != ElementCreator::ParserCreated), ready_to_be_parser_executed: Cell::new(false), parser_document: JS::from_ref(document), + load: RefCell::new(None), block_character_encoding: DOMRefCell::new(UTF_8 as EncodingRef), } } @@ -116,7 +118,7 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[ "text/x-javascript", ]; -#[derive(HeapSizeOf)] +#[derive(HeapSizeOf, JSTraceable)] pub enum ScriptOrigin { Internal(String, Url), External(Result<(Metadata, Vec), String>), @@ -130,8 +132,6 @@ struct ScriptContext { data: Vec, /// The response metadata received to date. metadata: Option, - /// Whether the owning document's parser should resume once the response completes. - resume_on_completion: bool, /// The initial URL requested. url: Url, } @@ -153,23 +153,20 @@ impl AsyncResponseListener for ScriptContext { (metadata, data) }); let elem = self.elem.root(); - - elem.r().execute(ScriptOrigin::External(load)); + // TODO: maybe set this to None again after script execution to save memory. + *elem.r().load.borrow_mut() = Some(ScriptOrigin::External(load)); + elem.ready_to_be_parser_executed.set(true); let document = document_from_node(elem.r()); document.r().finish_load(LoadType::Script(self.url.clone())); - - if self.resume_on_completion { - document.r().get_current_parser().unwrap().r().resume(); - } } } impl PreInvoke for ScriptContext {} impl HTMLScriptElement { + /// https://html.spec.whatwg.org/multipage/#prepare-a-script pub fn prepare(&self) -> NextParserState { - // https://html.spec.whatwg.org/multipage/#prepare-a-script // Step 1. if self.already_started.get() { return NextParserState::Continue; @@ -180,7 +177,9 @@ impl HTMLScriptElement { // Step 3. let element = self.upcast::(); - if was_parser_inserted && element.has_attribute(&atom!("async")) { + let async = element.has_attribute(&atom!("async")); + // Note: confusingly, this is done if the element does *not* have an "async" attribute. + if was_parser_inserted && !async { self.non_blocking.set(true); } // Step 4. @@ -205,8 +204,8 @@ impl HTMLScriptElement { self.already_started.set(true); // Step 10. - let document_from_node_ref = document_from_node(self); - let document_from_node_ref = document_from_node_ref.r(); + let doc = document_from_node(self); + let document_from_node_ref = doc.r(); if self.parser_inserted.get() && &*self.parser_document != document_from_node_ref { return NextParserState::Continue; } @@ -247,8 +246,9 @@ impl HTMLScriptElement { let window = window_from_node(self); let window = window.r(); let base_url = window.get_url(); + let deferred = element.has_attribute(&atom!("defer")); - let load = match element.get_attribute(&ns!(""), &atom!("src")) { + let is_external = match element.get_attribute(&ns!(""), &atom!("src")) { // Step 14. Some(ref src) => { // Step 14.1 @@ -274,8 +274,6 @@ impl HTMLScriptElement { // state of the element's `crossorigin` content attribute, the origin being // the origin of the script element's node document, and the default origin // behaviour set to taint. - let doc = document_from_node(self); - let script_chan = window.script_chan(); let elem = Trusted::new(window.get_cx(), self, script_chan.clone()); @@ -283,7 +281,6 @@ impl HTMLScriptElement { elem: elem, data: vec!(), metadata: None, - resume_on_completion: self.parser_inserted.get(), url: url.clone(), })); @@ -300,36 +297,85 @@ impl HTMLScriptElement { }); doc.r().load_async(LoadType::Script(url), response_target); - - if self.parser_inserted.get() { - doc.r().get_current_parser().unwrap().r().suspend(); - } - return NextParserState::Suspend; } } + true }, - None => ScriptOrigin::Internal(text, base_url), + None => false, }; // Step 15. - // TODO: Add support for the `defer` and `async` attributes. (For now, we fetch all - // scripts synchronously and execute them immediately.) - self.execute(load); - NextParserState::Continue + // Step 15.a, has src, has defer, was parser-inserted, is not async. + if is_external && + deferred && + was_parser_inserted && + !async { + doc.r().add_deferred_script(self); + // Second part implemented in Document::process_deferred_scripts. + return NextParserState::Continue; + // Step 15.b, has src, was parser-inserted, is not async. + } else if is_external && + was_parser_inserted && + !async { + doc.r().set_pending_parsing_blocking_script(Some(self)); + // Second part implemented in the load result handler. + // Step 15.c, doesn't have src, was parser-inserted, is blocked on stylesheet. + } else if !is_external && + was_parser_inserted && + // TODO: check for script nesting levels. + doc.r().get_script_blocking_stylesheets_count() > 0 { + doc.r().set_pending_parsing_blocking_script(Some(self)); + *self.load.borrow_mut() = Some(ScriptOrigin::Internal(text, base_url)); + self.ready_to_be_parser_executed.set(true); + // Step 15.d, has src, isn't async, isn't non-blocking. + } else if is_external && + !async && + !self.non_blocking.get() { + doc.r().push_asap_in_order_script(self); + // Second part implemented in Document::process_asap_scripts. + // Step 15.e, has src. + } else if is_external { + doc.r().add_asap_script(self); + // Second part implemented in Document::process_asap_scripts. + // Step 15.f, otherwise. + } else { + assert!(!text.is_empty()); + self.ready_to_be_parser_executed.set(true); + *self.load.borrow_mut() = Some(ScriptOrigin::Internal(text, base_url)); + self.execute(); + return NextParserState::Continue; + } + // TODO: make this suspension happen automatically. + if was_parser_inserted { + if let Some(parser) = doc.r().get_current_parser() { + parser.r().suspend(); + } + } + return NextParserState::Suspend; } - pub fn execute(&self, load: ScriptOrigin) { + pub fn is_ready_to_be_executed(&self) -> bool { + self.ready_to_be_parser_executed.get() + } + + /// https://html.spec.whatwg.org/multipage/#execute-the-script-block + pub fn execute(&self) { + assert!(self.ready_to_be_parser_executed.get()); + // Step 1. - // TODO: If the element is flagged as "parser-inserted", but the - // element's node document is not the Document of the parser that - // created the element, then abort these steps. + let doc = document_from_node(self); + if self.parser_inserted.get() && doc.r() != self.parser_document.root().r() { + return; + } + + let load = self.load.borrow_mut().take().unwrap(); // Step 2. let (source, external, url) = match load { // Step 2.a. ScriptOrigin::External(Err(e)) => { error!("error loading script {}", e); - self.queue_error_event(); + self.dispatch_error_event(); return; } diff --git a/components/script/dom/servohtmlparser.rs b/components/script/dom/servohtmlparser.rs index 4999d600a208..3a4a59ba3afe 100644 --- a/components/script/dom/servohtmlparser.rs +++ b/components/script/dom/servohtmlparser.rs @@ -159,7 +159,9 @@ impl AsyncResponseListener for ParserContext { } parser.r().last_chunk_received.set(true); - parser.r().parse_sync(); + if !parser.r().is_suspended() { + parser.r().parse_sync(); + } } } @@ -188,7 +190,9 @@ impl<'a> Parser for &'a ServoHTMLParser { fn parse_chunk(self, input: String) { self.document.set_current_parser(Some(self)); self.pending_input.borrow_mut().push(input); - self.parse_sync(); + if !self.is_suspended() { + self.parse_sync(); + } } fn finish(self) { @@ -282,21 +286,10 @@ impl ServoHTMLParser { impl ServoHTMLParser { fn parse_sync(&self) { - let mut first = true; - // This parser will continue to parse while there is either pending input or // the parser remains unsuspended. loop { - if self.suspended.get() { - return; - } - - if self.pending_input.borrow().is_empty() && !first { - break; - } - - self.document.reflow_if_reflow_timer_expired(); - + self.document.reflow_if_reflow_timer_expired(); let mut pending_input = self.pending_input.borrow_mut(); if !pending_input.is_empty() { let chunk = pending_input.remove(0); @@ -305,7 +298,14 @@ impl ServoHTMLParser { self.tokenizer.borrow_mut().run(); } - first = false; + // Document parsing is blocked on an external resource. + if self.suspended.get() { + return; + } + + if pending_input.is_empty() { + break; + } } if self.last_chunk_received.get() { @@ -330,6 +330,10 @@ impl ServoHTMLParser { self.suspended.set(false); self.parse_sync(); } + + pub fn is_suspended(&self) -> bool { + self.suspended.get() + } } struct Tracer { diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 802d8aa8d3e9..26446af7f9d5 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -20,7 +20,7 @@ use devtools; use devtools_traits::ScriptToDevtoolsControlMsg; use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo}; -use document_loader::{DocumentLoader, LoadType, NotifierData}; +use document_loader::{DocumentLoader, LoadType}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; use dom::bindings::conversions::{Castable, FromJSValConvertible, StringificationBehavior}; @@ -1614,15 +1614,8 @@ impl ScriptTask { _ => None }; - let notifier_data = { - let MainThreadScriptChan(ref sender) = self.chan; - NotifierData { - script_chan: sender.clone(), - pipeline: page.pipeline(), - } - }; let loader = DocumentLoader::new_with_task(self.resource_task.clone(), - Some(notifier_data), + Some(page.pipeline()), Some(incomplete.url.clone())); let document = Document::new(window.r(), Some(final_url.clone()), @@ -1935,8 +1928,11 @@ impl ScriptTask { let document = page.document(); let final_url = document.r().url(); + // https://html.spec.whatwg.org/multipage/#the-end step 1 document.r().set_ready_state(DocumentReadyState::Interactive); + // TODO: Execute step 2 here. + // Kick off the initial reflow of the page. debug!("kicking off initial reflow of {:?}", final_url); document.r().disarm_reflow_timeout(); @@ -1948,14 +1944,14 @@ impl ScriptTask { // No more reflow required page.set_reflow_status(false); - // https://html.spec.whatwg.org/multipage/#the-end step 4 - let addr: Trusted = Trusted::new(self.get_cx(), document.r(), self.chan.clone()); - let handler = box DocumentProgressHandler::new(addr, DocumentProgressTask::DOMContentLoaded); - self.chan.send(CommonScriptMsg::RunnableMsg(ScriptTaskEventCategory::DocumentEvent, handler)).unwrap(); + // https://html.spec.whatwg.org/multipage/#the-end steps 3-4. + document.r().process_deferred_scripts(); window.r().set_fragment_name(final_url.fragment.clone()); // Notify devtools that a new script global exists. + //TODO: should this happen as soon as the global is created, or at least once the first + // script runs? self.notify_devtools(document.r().Title(), (*final_url).clone(), (id, None)); } } diff --git a/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/085.html.ini b/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/085.html.ini deleted file mode 100644 index 989c0d479744..000000000000 --- a/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/085.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[085.html] - type: testharness - [ scheduler: async script and slow-loading defer script] - expected: FAIL - diff --git a/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/103.html.ini b/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/103.html.ini deleted file mode 100644 index e14710c6d770..000000000000 --- a/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/103.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[103.html] - type: testharness - [ scheduler: removing defer attribute at runtime] - expected: FAIL - diff --git a/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/110.html.ini b/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/110.html.ini deleted file mode 100644 index 6a6079d54814..000000000000 --- a/tests/wpt/metadata/old-tests/submission/Opera/script_scheduling/110.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[110.html] - type: testharness - [ scheduler: removing defer script at runtime] - expected: FAIL -