aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/constellation/constellation.rs87
-rw-r--r--components/constellation/pipeline.rs19
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/document.rs51
-rw-r--r--components/script/dom/domimplementation.rs3
-rw-r--r--components/script/dom/domparser.rs3
-rw-r--r--components/script/dom/node.rs4
-rw-r--r--components/script/dom/servoparser/mod.rs2
-rw-r--r--components/script/dom/window.rs10
-rw-r--r--components/script/dom/xmldocument.rs5
-rw-r--r--components/script/dom/xmlhttprequest.rs2
-rw-r--r--components/script/script_thread.rs53
-rw-r--r--components/script/timers.rs4
-rw-r--r--components/script_traits/lib.rs25
-rw-r--r--tests/wpt/metadata/MANIFEST.json6
-rw-r--r--tests/wpt/metadata/html/dom/dynamic-markup-insertion/document-write/write-active-document.html.ini4
-rw-r--r--tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/empty.html1
-rw-r--r--tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/write-active-document.html35
18 files changed, 214 insertions, 104 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 132bf40e1ac..621e92fb6b1 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -95,7 +95,7 @@ use profile_traits::mem;
use profile_traits::time;
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
-use script_traits::{DocumentState, LayoutControlMsg, LoadData};
+use script_traits::{DocumentActivity, DocumentState, LayoutControlMsg, LoadData};
use script_traits::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
@@ -1405,10 +1405,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let window_size = old_pipeline.and_then(|old_pipeline| old_pipeline.size);
- if let Some(old_pipeline) = old_pipeline {
- old_pipeline.freeze();
- }
-
(load_data, window_size, is_private)
};
@@ -1628,11 +1624,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
});
self.new_pipeline(new_pipeline_id, root_frame_id, None, window_size, load_data, sandbox, false);
- // Send message to ScriptThread that will suspend all timers
- match self.pipelines.get(&source_id) {
- Some(source) => source.freeze(),
- None => warn!("Pipeline {:?} loaded after closure", source_id),
- };
Some(new_pipeline_id)
}
}
@@ -2050,13 +2041,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
self.focus_pipeline_id = Some(pipeline_id);
}
- // Suspend the old pipeline, and resume the new one.
- if let Some(pipeline) = self.pipelines.get(&old_pipeline_id) {
- pipeline.freeze();
- }
- if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
- pipeline.thaw();
- }
+ // Deactivate the old pipeline, and activate the new one.
+ self.update_activity(old_pipeline_id);
+ self.update_activity(pipeline_id);
// Set paint permissions correctly for the compositor layers.
self.send_frame_tree();
@@ -2125,22 +2112,24 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
- let (evicted_id, new_frame, clear_future, location_changed) = if let Some(mut entry) = frame_change.replace {
+ let (evicted_id, new_frame, navigated, location_changed) = if let Some(mut entry) = frame_change.replace {
debug!("Replacing pipeline in existing frame.");
let evicted_id = entry.pipeline_id;
entry.replace_pipeline(frame_change.new_pipeline_id, frame_change.url.clone());
self.traverse_to_entry(entry);
- (evicted_id, false, false, false)
+ (evicted_id, false, None, false)
} else if let Some(frame) = self.frames.get_mut(&frame_change.frame_id) {
debug!("Adding pipeline to existing frame.");
+ let old_pipeline_id = frame.pipeline_id;
frame.load(frame_change.new_pipeline_id, frame_change.url.clone());
let evicted_id = frame.prev.len()
.checked_sub(PREFS.get("session-history.max-length").as_u64().unwrap_or(20) as usize)
.and_then(|index| frame.prev.get_mut(index))
.and_then(|entry| entry.pipeline_id.take());
- (evicted_id, false, true, true)
+ (evicted_id, false, Some(old_pipeline_id), true)
} else {
- (None, true, false, true)
+ debug!("Adding pipeline to new frame.");
+ (None, true, None, true)
};
if let Some(evicted_id) = evicted_id {
@@ -2149,9 +2138,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if new_frame {
self.new_frame(frame_change.frame_id, frame_change.new_pipeline_id, frame_change.url);
+ self.update_activity(frame_change.new_pipeline_id);
};
- if clear_future {
+ if let Some(old_pipeline_id) = navigated {
+ // Deactivate the old pipeline, and activate the new one.
+ self.update_activity(old_pipeline_id);
+ self.update_activity(frame_change.new_pipeline_id);
+ // Clear the joint session future
let top_level_frame_id = self.get_top_level_frame_for_pipeline(frame_change.new_pipeline_id);
self.clear_joint_session_future(top_level_frame_id);
}
@@ -2165,7 +2159,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
fn handle_activate_document_msg(&mut self, pipeline_id: PipelineId) {
- debug!("Document ready to activate {:?}", pipeline_id);
+ debug!("Document ready to activate {}", pipeline_id);
// Notify the parent (if there is one).
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
@@ -2359,6 +2353,53 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
ReadyToSave::Ready
}
+ /// Get the current activity of a pipeline.
+ fn get_activity(&self, pipeline_id: PipelineId) -> DocumentActivity {
+ let mut ancestor_id = pipeline_id;
+ loop {
+ if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
+ if let Some(frame) = self.frames.get(&ancestor.frame_id) {
+ if frame.pipeline_id == ancestor_id {
+ if let Some((parent_id, FrameType::IFrame)) = ancestor.parent_info {
+ ancestor_id = parent_id;
+ continue;
+ } else {
+ return DocumentActivity::FullyActive;
+ }
+ }
+ }
+ }
+ if pipeline_id == ancestor_id {
+ return DocumentActivity::Inactive;
+ } else {
+ return DocumentActivity::Active;
+ }
+ }
+ }
+
+ /// Set the current activity of a pipeline.
+ fn set_activity(&self, pipeline_id: PipelineId, activity: DocumentActivity) {
+ debug!("Setting activity of {} to be {:?}.", pipeline_id, activity);
+ if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
+ pipeline.set_activity(activity);
+ let child_activity = if activity == DocumentActivity::Inactive {
+ DocumentActivity::Active
+ } else {
+ activity
+ };
+ for child_id in &pipeline.children {
+ if let Some(child) = self.frames.get(child_id) {
+ self.set_activity(child.pipeline_id, child_activity);
+ }
+ }
+ }
+ }
+
+ /// Update the current activity of a pipeline.
+ fn update_activity(&self, pipeline_id: PipelineId) {
+ self.set_activity(pipeline_id, self.get_activity(pipeline_id));
+ }
+
fn clear_joint_session_future(&mut self, frame_id: FrameId) {
let frame_ids: Vec<FrameId> = self.full_frame_tree_iter(frame_id)
.map(|frame| frame.id)
diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs
index 075c53e84f8..e8a6ab3c05b 100644
--- a/components/constellation/pipeline.rs
+++ b/components/constellation/pipeline.rs
@@ -19,7 +19,8 @@ use net_traits::{IpcSend, ResourceThreads};
use net_traits::image_cache_thread::ImageCacheThread;
use profile_traits::mem as profile_mem;
use profile_traits::time;
-use script_traits::{ConstellationControlMsg, DevicePixel, DiscardBrowsingContext, InitialScriptState};
+use script_traits::{ConstellationControlMsg, DevicePixel, DiscardBrowsingContext};
+use script_traits::{DocumentActivity, InitialScriptState};
use script_traits::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent};
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
@@ -366,17 +367,11 @@ impl Pipeline {
}
}
- /// Notify this pipeline that it is no longer fully active.
- pub fn freeze(&self) {
- if let Err(e) = self.event_loop.send(ConstellationControlMsg::Freeze(self.id)) {
- warn!("Sending freeze message failed ({}).", e);
- }
- }
-
- /// Notify this pipeline that it is fully active.
- pub fn thaw(&self) {
- if let Err(e) = self.event_loop.send(ConstellationControlMsg::Thaw(self.id)) {
- warn!("Sending freeze message failed ({}).", e);
+ /// Notify this pipeline of its activity.
+ pub fn set_activity(&self, activity: DocumentActivity) {
+ let msg = ConstellationControlMsg::SetDocumentActivity(self.id, activity);
+ if let Err(e) = self.event_loop.send(msg) {
+ warn!("Sending activity message failed ({}).", e);
}
}
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 6d268823d77..6e0ce0d47dc 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -74,7 +74,7 @@ use profile_traits::time::ProfilerChan as TimeProfilerChan;
use script_layout_interface::OpaqueStyleAndLayoutData;
use script_layout_interface::reporter::CSSErrorReporter;
use script_layout_interface::rpc::LayoutRPC;
-use script_traits::{TimerEventId, TimerSource, TouchpadPressurePhase};
+use script_traits::{DocumentActivity, TimerEventId, TimerSource, TouchpadPressurePhase};
use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
use serde::{Deserialize, Serialize};
use servo_atoms::Atom;
@@ -327,7 +327,7 @@ unsafe_no_jsmanaged_fields!(TrustedPromise);
unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
// These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs
-unsafe_no_jsmanaged_fields!(FrameId, FrameType, WindowSizeData, WindowSizeType, PipelineId);
+unsafe_no_jsmanaged_fields!(DocumentActivity, FrameId, FrameType, WindowSizeData, WindowSizeType, PipelineId);
unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource);
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
unsafe_no_jsmanaged_fields!(WorkerId);
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 53aa4af882d..da4d715fe21 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -108,7 +108,8 @@ use origin::Origin;
use script_layout_interface::message::{Msg, ReflowQueryType};
use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
use script_thread::{MainThreadScriptMsg, Runnable};
-use script_traits::{AnimationState, CompositorEvent, MouseButton, MouseEventType, MozBrowserEvent};
+use script_traits::{AnimationState, CompositorEvent, DocumentActivity};
+use script_traits::{MouseButton, MouseEventType, MozBrowserEvent};
use script_traits::{ScriptMsg as ConstellationMsg, TouchpadPressurePhase};
use script_traits::{TouchEventType, TouchId};
use script_traits::UntrustedNodeAddress;
@@ -191,7 +192,7 @@ pub struct Document {
last_modified: Option<String>,
encoding: Cell<EncodingRef>,
is_html_document: bool,
- is_fully_active: Cell<bool>,
+ activity: Cell<DocumentActivity>,
url: DOMRefCell<ServoUrl>,
quirks_mode: Cell<QuirksMode>,
/// Caches for the getElement methods
@@ -387,17 +388,33 @@ impl Document {
self.trigger_mozbrowser_event(MozBrowserEvent::SecurityChange(https_state));
}
- // https://html.spec.whatwg.org/multipage/#fully-active
pub fn is_fully_active(&self) -> bool {
- self.is_fully_active.get()
- }
-
- pub fn fully_activate(&self) {
- self.is_fully_active.set(true)
- }
-
- pub fn fully_deactivate(&self) {
- self.is_fully_active.set(false)
+ self.activity.get() == DocumentActivity::FullyActive
+ }
+
+ pub fn is_active(&self) -> bool {
+ self.activity.get() != DocumentActivity::Inactive
+ }
+
+ pub fn set_activity(&self, activity: DocumentActivity) {
+ // This function should only be called on documents with a browsing context
+ assert!(self.browsing_context.is_some());
+ // Set the document's activity level, reflow if necessary, and suspend or resume timers.
+ if activity != self.activity.get() {
+ self.activity.set(activity);
+ if activity == DocumentActivity::FullyActive {
+ self.title_changed();
+ self.dirty_all_nodes();
+ self.window().reflow(
+ ReflowGoal::ForDisplay,
+ ReflowQueryType::NoQuery,
+ ReflowReason::CachedPageNeededReflow
+ );
+ self.window().resume();
+ } else {
+ self.window().suspend();
+ }
+ }
}
pub fn origin(&self) -> &Origin {
@@ -1892,6 +1909,7 @@ impl Document {
is_html_document: IsHTMLDocument,
content_type: Option<DOMString>,
last_modified: Option<String>,
+ activity: DocumentActivity,
source: DocumentSource,
doc_loader: DocumentLoader,
referrer: Option<String>,
@@ -1927,7 +1945,7 @@ impl Document {
// https://dom.spec.whatwg.org/#concept-document-encoding
encoding: Cell::new(UTF_8),
is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
- is_fully_active: Cell::new(false),
+ activity: Cell::new(activity),
id_map: DOMRefCell::new(HashMap::new()),
tag_map: DOMRefCell::new(HashMap::new()),
tagns_map: DOMRefCell::new(HashMap::new()),
@@ -1995,6 +2013,7 @@ impl Document {
IsHTMLDocument::NonHTMLDocument,
None,
None,
+ DocumentActivity::Inactive,
DocumentSource::NotFromParser,
docloader,
None,
@@ -2008,6 +2027,7 @@ impl Document {
doctype: IsHTMLDocument,
content_type: Option<DOMString>,
last_modified: Option<String>,
+ activity: DocumentActivity,
source: DocumentSource,
doc_loader: DocumentLoader,
referrer: Option<String>,
@@ -2020,6 +2040,7 @@ impl Document {
doctype,
content_type,
last_modified,
+ activity,
source,
doc_loader,
referrer,
@@ -2093,6 +2114,7 @@ impl Document {
doctype,
None,
None,
+ DocumentActivity::Inactive,
DocumentSource::NotFromParser,
DocumentLoader::new(&self.loader()),
None,
@@ -3249,8 +3271,7 @@ impl DocumentMethods for Document {
// Step 2.
// TODO: handle throw-on-dynamic-markup-insertion counter.
- // FIXME: this should check for being active rather than fully active
- if !self.is_fully_active() {
+ if !self.is_active() {
// Step 3.
return Ok(());
}
diff --git a/components/script/dom/domimplementation.rs b/components/script/dom/domimplementation.rs
index 23521b94a09..45983c3292d 100644
--- a/components/script/dom/domimplementation.rs
+++ b/components/script/dom/domimplementation.rs
@@ -23,6 +23,7 @@ use dom::htmltitleelement::HTMLTitleElement;
use dom::node::Node;
use dom::text::Text;
use dom::xmldocument::XMLDocument;
+use script_traits::DocumentActivity;
// https://dom.spec.whatwg.org/#domimplementation
#[dom_struct]
@@ -83,6 +84,7 @@ impl DOMImplementationMethods for DOMImplementation {
IsHTMLDocument::NonHTMLDocument,
Some(DOMString::from(content_type)),
None,
+ DocumentActivity::Inactive,
DocumentSource::NotFromParser,
loader);
// Step 2-3.
@@ -129,6 +131,7 @@ impl DOMImplementationMethods for DOMImplementation {
IsHTMLDocument::HTMLDocument,
None,
None,
+ DocumentActivity::Inactive,
DocumentSource::NotFromParser,
loader,
None,
diff --git a/components/script/dom/domparser.rs b/components/script/dom/domparser.rs
index c14bec8b594..54132ef94a9 100644
--- a/components/script/dom/domparser.rs
+++ b/components/script/dom/domparser.rs
@@ -19,6 +19,7 @@ use dom::document::{Document, IsHTMLDocument};
use dom::document::DocumentSource;
use dom::servoparser::ServoParser;
use dom::window::Window;
+use script_traits::DocumentActivity;
#[dom_struct]
pub struct DOMParser {
@@ -65,6 +66,7 @@ impl DOMParserMethods for DOMParser {
IsHTMLDocument::HTMLDocument,
Some(content_type),
None,
+ DocumentActivity::Inactive,
DocumentSource::FromParser,
loader,
None,
@@ -82,6 +84,7 @@ impl DOMParserMethods for DOMParser {
IsHTMLDocument::NonHTMLDocument,
Some(content_type),
None,
+ DocumentActivity::Inactive,
DocumentSource::NotFromParser,
loader,
None,
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 71547c860bc..6931fca1822 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -65,6 +65,7 @@ use ref_slice::ref_slice;
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
use script_layout_interface::message::Msg;
+use script_traits::DocumentActivity;
use script_traits::UntrustedNodeAddress;
use selectors::matching::{MatchingReason, matches};
use selectors::parser::SelectorList;
@@ -1730,7 +1731,8 @@ impl Node {
// https://github.com/whatwg/dom/issues/378
document.origin().alias(),
is_html_doc, None,
- None, DocumentSource::NotFromParser, loader,
+ None, DocumentActivity::Inactive,
+ DocumentSource::NotFromParser, loader,
None, None);
Root::upcast::<Node>(document)
},
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index aaa36a2098b..d64704b2368 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -35,6 +35,7 @@ use network_listener::PreInvoke;
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
use script_thread::ScriptThread;
+use script_traits::DocumentActivity;
use servo_config::resource_files::read_resource_file;
use servo_url::ServoUrl;
use std::cell::Cell;
@@ -107,6 +108,7 @@ impl ServoParser {
IsHTMLDocument::HTMLDocument,
None,
None,
+ DocumentActivity::Inactive,
DocumentSource::FromParser,
loader,
None,
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index cb9d5abdf07..37c62543526 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1488,21 +1488,17 @@ impl Window {
None
}
- pub fn freeze(&self) {
+ pub fn suspend(&self) {
self.upcast::<GlobalScope>().suspend();
// A hint to the JS runtime that now would be a good time to
// GC any unreachable objects generated by user script,
// or unattached DOM nodes. Attached DOM nodes can't be GCd yet,
- // as the document might be thawed later.
+ // as the document might be reactivated later.
self.Gc();
}
- pub fn thaw(&self) {
+ pub fn resume(&self) {
self.upcast::<GlobalScope>().resume();
-
- // Push the document title to the compositor since we are
- // activating this document due to a navigation.
- self.Document().title_changed();
}
pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool {
diff --git a/components/script/dom/xmldocument.rs b/components/script/dom/xmldocument.rs
index 87c639742f6..593749c4499 100644
--- a/components/script/dom/xmldocument.rs
+++ b/components/script/dom/xmldocument.rs
@@ -17,6 +17,7 @@ use dom::node::Node;
use dom::window::Window;
use js::jsapi::{JSContext, JSObject};
use origin::Origin;
+use script_traits::DocumentActivity;
use servo_url::ServoUrl;
// https://dom.spec.whatwg.org/#xmldocument
@@ -33,6 +34,7 @@ impl XMLDocument {
is_html_document: IsHTMLDocument,
content_type: Option<DOMString>,
last_modified: Option<String>,
+ activity: DocumentActivity,
source: DocumentSource,
doc_loader: DocumentLoader) -> XMLDocument {
XMLDocument {
@@ -43,6 +45,7 @@ impl XMLDocument {
is_html_document,
content_type,
last_modified,
+ activity,
source,
doc_loader,
None,
@@ -57,6 +60,7 @@ impl XMLDocument {
doctype: IsHTMLDocument,
content_type: Option<DOMString>,
last_modified: Option<String>,
+ activity: DocumentActivity,
source: DocumentSource,
doc_loader: DocumentLoader)
-> Root<XMLDocument> {
@@ -68,6 +72,7 @@ impl XMLDocument {
doctype,
content_type,
last_modified,
+ activity,
source,
doc_loader),
window,
diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs
index 95a8ba0c3ad..f42afe87f8b 100644
--- a/components/script/dom/xmlhttprequest.rs
+++ b/components/script/dom/xmlhttprequest.rs
@@ -58,6 +58,7 @@ use net_traits::CoreResourceMsg::Fetch;
use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
use net_traits::trim_http_whitespace;
use network_listener::{NetworkListener, PreInvoke};
+use script_traits::DocumentActivity;
use servo_atoms::Atom;
use servo_config::prefs::PREFS;
use servo_url::ServoUrl;
@@ -1228,6 +1229,7 @@ impl XMLHttpRequest {
is_html_document,
content_type,
None,
+ DocumentActivity::Inactive,
DocumentSource::FromParser,
docloader,
None,
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 9bab1679aa6..2bdb75a486f 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -83,7 +83,8 @@ use profile_traits::time::{self, ProfilerCategory, profile};
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue};
-use script_traits::{CompositorEvent, ConstellationControlMsg, DiscardBrowsingContext, EventResult};
+use script_traits::{CompositorEvent, ConstellationControlMsg};
+use script_traits::{DocumentActivity, DiscardBrowsingContext, EventResult};
use script_traits::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
@@ -148,8 +149,8 @@ struct InProgressLoad {
window_size: Option<WindowSizeData>,
/// Channel to the layout thread associated with this pipeline.
layout_chan: Sender<message::Msg>,
- /// Window is frozen (navigated away while loading for example).
- is_frozen: bool,
+ /// The activity level of the document (inactive, active or fully active).
+ activity: DocumentActivity,
/// Window is visible.
is_visible: bool,
/// The requested URL of the load.
@@ -172,7 +173,7 @@ impl InProgressLoad {
parent_info: parent_info,
layout_chan: layout_chan,
window_size: window_size,
- is_frozen: false,
+ activity: DocumentActivity::FullyActive,
is_visible: true,
url: url,
origin: origin,
@@ -963,10 +964,8 @@ impl ScriptThread {
self.handle_resize_inactive_msg(id, new_size),
ConstellationControlMsg::GetTitle(pipeline_id) =>
self.handle_get_title_msg(pipeline_id),
- ConstellationControlMsg::Freeze(pipeline_id) =>
- self.handle_freeze_msg(pipeline_id),
- ConstellationControlMsg::Thaw(pipeline_id) =>
- self.handle_thaw_msg(pipeline_id),
+ ConstellationControlMsg::SetDocumentActivity(pipeline_id, activity) =>
+ self.handle_set_document_activity_msg(pipeline_id, activity),
ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) =>
self.handle_visibility_change_msg(pipeline_id, visible),
ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, frame_id, visible) =>
@@ -1303,37 +1302,20 @@ impl ScriptThread {
warn!("change visibility message sent to nonexistent pipeline");
}
- /// Handles freeze message
- fn handle_freeze_msg(&self, id: PipelineId) {
+ /// Handles activity change message
+ fn handle_set_document_activity_msg(&self, id: PipelineId, activity: DocumentActivity) {
+ debug!("Setting activity of {} to be {:?}.", id, activity);
let document = self.documents.borrow().find_document(id);
if let Some(document) = document {
- document.window().freeze();
- document.fully_deactivate();
+ document.set_activity(activity);
return;
}
let mut loads = self.incomplete_loads.borrow_mut();
if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
- load.is_frozen = true;
+ load.activity = activity;
return;
}
- warn!("freeze sent to nonexistent pipeline");
- }
-
- /// Handles thaw message
- fn handle_thaw_msg(&self, id: PipelineId) {
- let document = self.documents.borrow().find_document(id);
- if let Some(document) = document {
- self.rebuild_and_force_reflow(&document, ReflowReason::CachedPageNeededReflow);
- document.window().thaw();
- document.fully_activate();
- return;
- }
- let mut loads = self.incomplete_loads.borrow_mut();
- if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
- load.is_frozen = false;
- return;
- }
- warn!("thaw sent to nonexistent pipeline");
+ warn!("change of activity sent to nonexistent pipeline");
}
fn handle_focus_iframe_msg(&self,
@@ -1759,16 +1741,13 @@ impl ScriptThread {
is_html_document,
content_type,
last_modified,
+ incomplete.activity,
DocumentSource::FromParser,
loader,
referrer,
referrer_policy);
document.set_ready_state(DocumentReadyState::Loading);
- if !incomplete.is_frozen {
- document.fully_activate();
- }
-
self.documents.borrow_mut().insert(incomplete.pipeline_id, &*document);
window.init_document(&document);
@@ -1822,8 +1801,8 @@ impl ScriptThread {
ServoParser::parse_html_document(&document, parse_input, final_url);
}
- if incomplete.is_frozen {
- window.upcast::<GlobalScope>().suspend();
+ if incomplete.activity != DocumentActivity::FullyActive {
+ window.suspend();
}
if !incomplete.is_visible {
diff --git a/components/script/timers.rs b/components/script/timers.rs
index 881fe9b6034..c1f0a1de6c4 100644
--- a/components/script/timers.rs
+++ b/components/script/timers.rs
@@ -233,6 +233,7 @@ impl OneshotTimers {
return warn!("Suspending an already suspended timer.");
}
+ debug!("Suspending timers.");
self.suspended_since.set(Some(precise_time_ms()));
self.invalidate_expected_event_id();
}
@@ -244,6 +245,7 @@ impl OneshotTimers {
None => return warn!("Resuming an already resumed timer."),
};
+ debug!("Resuming timers.");
self.suspension_offset.set(self.suspension_offset.get() + additional_offset);
self.suspended_since.set(None);
@@ -252,7 +254,7 @@ impl OneshotTimers {
fn schedule_timer_call(&self) {
if self.suspended_since.get().is_some() {
- // The timer will be scheduled when the pipeline is thawed.
+ // The timer will be scheduled when the pipeline is fully activated.
return;
}
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 295000380ca..5be4cb7d2bc 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -194,6 +194,22 @@ pub enum DiscardBrowsingContext {
No,
}
+/// Is a document fully active, active or inactive?
+/// A document is active if it is the current active document in its session history,
+/// it is fuly active if it is active and all of its ancestors are active,
+/// and it is inactive otherwise.
+/// https://html.spec.whatwg.org/multipage/#active-document
+/// https://html.spec.whatwg.org/multipage/#fully-active
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HeapSizeOf, Debug, Deserialize, Serialize)]
+pub enum DocumentActivity {
+ /// An inactive document
+ Inactive,
+ /// An active but not fully active document
+ Active,
+ /// A fully active document
+ FullyActive,
+}
+
/// Messages sent from the constellation or layout to the script thread.
#[derive(Deserialize, Serialize)]
pub enum ConstellationControlMsg {
@@ -215,10 +231,8 @@ pub enum ConstellationControlMsg {
SetScrollState(PipelineId, Vec<(UntrustedNodeAddress, Point2D<f32>)>),
/// Requests that the script thread immediately send the constellation the title of a pipeline.
GetTitle(PipelineId),
- /// Notifies script thread to suspend all its timers
- Freeze(PipelineId),
- /// Notifies script thread to resume all its timers
- Thaw(PipelineId),
+ /// Notifies script thread of a change to one of its document's activity
+ SetDocumentActivity(PipelineId, DocumentActivity),
/// Notifies script thread whether frame is visible
ChangeFrameVisibilityStatus(PipelineId, bool),
/// Notifies script thread that frame visibility change is complete
@@ -281,8 +295,7 @@ impl fmt::Debug for ConstellationControlMsg {
Viewport(..) => "Viewport",
SetScrollState(..) => "SetScrollState",
GetTitle(..) => "GetTitle",
- Freeze(..) => "Freeze",
- Thaw(..) => "Thaw",
+ SetDocumentActivity(..) => "SetDocumentActivity",
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
NotifyVisibilityChange(..) => "NotifyVisibilityChange",
Navigate(..) => "Navigate",
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index 82c13ee87e5..51d045d6c52 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -45873,6 +45873,12 @@
"url": "/cssom/stylesheet-same-origin.sub.html"
}
],
+ "html/dom/dynamic-markup-insertion/document-write/write-active-document.html": [
+ {
+ "path": "html/dom/dynamic-markup-insertion/document-write/write-active-document.html",
+ "url": "/html/dom/dynamic-markup-insertion/document-write/write-active-document.html"
+ }
+ ],
"html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html": [
{
"path": "html/semantics/embedded-content/the-iframe-element/iframe-synchronously-discard.html",
diff --git a/tests/wpt/metadata/html/dom/dynamic-markup-insertion/document-write/write-active-document.html.ini b/tests/wpt/metadata/html/dom/dynamic-markup-insertion/document-write/write-active-document.html.ini
new file mode 100644
index 00000000000..09620a4a26b
--- /dev/null
+++ b/tests/wpt/metadata/html/dom/dynamic-markup-insertion/document-write/write-active-document.html.ini
@@ -0,0 +1,4 @@
+[write-active-document.html]
+ type: testharness
+ [document.write only writes to active documents]
+ expected: FAIL
diff --git a/tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/empty.html b/tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/empty.html
new file mode 100644
index 00000000000..0dc101b5335
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/empty.html
@@ -0,0 +1 @@
+<html><body></body></html>
diff --git a/tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/write-active-document.html b/tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/write-active-document.html
new file mode 100644
index 00000000000..6faffd81de4
--- /dev/null
+++ b/tests/wpt/web-platform-tests/html/dom/dynamic-markup-insertion/document-write/write-active-document.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>document.write only writes to active documents</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body><div id="log"></div></body>
+<script>
+ async_test(function(t) {
+ var child = document.createElement("iframe");
+ child.src = "empty.html?1";
+ child.onload = t.step_func(function() {
+ var child1 = child.contentDocument;
+ var link = child1.createElement("a");
+ link.href = "data:text/html,Clicked.";
+ link.innerText = "Link.";
+ child1.body.appendChild(link);
+ var grandchild = child1.createElement("iframe");
+ grandchild.src = "empty.html?2";
+ grandchild.onload = t.step_func(function() {
+ var grandchild1 = grandchild.contentDocument;
+ child.onload = t.step_func(function() {
+ // This is a write to an inactive document
+ child1.write('WRITE HAPPENED');
+ assert_equals(child1.body.lastChild.tagName, "IFRAME");
+ // This is a write to an active but not fully active document
+ grandchild1.write('WRITE HAPPENED');
+ assert_equals(grandchild1.body.innerHTML, "WRITE HAPPENED");
+ t.done();
+ });
+ link.click();
+ });
+ child1.body.appendChild(grandchild);
+ });
+ document.body.appendChild(child);
+ });
+</script>