The constellation notifies the script thread about documents becoming inactive, active and fully active.

This commit is contained in:
Alan Jeffrey 2017-01-10 14:35:25 -06:00
parent 556a46f537
commit a43c842099
14 changed files with 162 additions and 98 deletions

View file

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

View file

@ -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()
self.activity.get() == DocumentActivity::FullyActive
}
pub fn fully_activate(&self) {
self.is_fully_active.set(true)
pub fn is_active(&self) -> bool {
self.activity.get() != DocumentActivity::Inactive
}
pub fn fully_deactivate(&self) {
self.is_fully_active.set(false)
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,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,19 @@ 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) {
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 +1740,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 +1800,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 {

View file

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