mirror of
https://github.com/servo/servo.git
synced 2025-07-28 17:50:37 +01:00
The constellation notifies the script thread about documents becoming inactive, active and fully active.
This commit is contained in:
parent
556a46f537
commit
a43c842099
14 changed files with 162 additions and 98 deletions
|
@ -95,7 +95,7 @@ use profile_traits::mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
|
use script_traits::{AnimationState, AnimationTickType, CompositorEvent};
|
||||||
use script_traits::{ConstellationControlMsg, ConstellationMsg as FromCompositorMsg, DiscardBrowsingContext};
|
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::{IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerEventRequest};
|
||||||
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
||||||
use script_traits::{LogEntry, ServiceWorkerMsg, webdriver_msg};
|
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);
|
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)
|
(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);
|
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)
|
Some(new_pipeline_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2050,13 +2041,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
self.focus_pipeline_id = Some(pipeline_id);
|
self.focus_pipeline_id = Some(pipeline_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suspend the old pipeline, and resume the new one.
|
// Deactivate the old pipeline, and activate the new one.
|
||||||
if let Some(pipeline) = self.pipelines.get(&old_pipeline_id) {
|
self.update_activity(old_pipeline_id);
|
||||||
pipeline.freeze();
|
self.update_activity(pipeline_id);
|
||||||
}
|
|
||||||
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
|
||||||
pipeline.thaw();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set paint permissions correctly for the compositor layers.
|
// Set paint permissions correctly for the compositor layers.
|
||||||
self.send_frame_tree();
|
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.");
|
debug!("Replacing pipeline in existing frame.");
|
||||||
let evicted_id = entry.pipeline_id;
|
let evicted_id = entry.pipeline_id;
|
||||||
entry.replace_pipeline(frame_change.new_pipeline_id, frame_change.url.clone());
|
entry.replace_pipeline(frame_change.new_pipeline_id, frame_change.url.clone());
|
||||||
self.traverse_to_entry(entry);
|
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) {
|
} else if let Some(frame) = self.frames.get_mut(&frame_change.frame_id) {
|
||||||
debug!("Adding pipeline to existing frame.");
|
debug!("Adding pipeline to existing frame.");
|
||||||
|
let old_pipeline_id = frame.pipeline_id;
|
||||||
frame.load(frame_change.new_pipeline_id, frame_change.url.clone());
|
frame.load(frame_change.new_pipeline_id, frame_change.url.clone());
|
||||||
let evicted_id = frame.prev.len()
|
let evicted_id = frame.prev.len()
|
||||||
.checked_sub(PREFS.get("session-history.max-length").as_u64().unwrap_or(20) as usize)
|
.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(|index| frame.prev.get_mut(index))
|
||||||
.and_then(|entry| entry.pipeline_id.take());
|
.and_then(|entry| entry.pipeline_id.take());
|
||||||
(evicted_id, false, true, true)
|
(evicted_id, false, Some(old_pipeline_id), true)
|
||||||
} else {
|
} else {
|
||||||
(None, true, false, true)
|
debug!("Adding pipeline to new frame.");
|
||||||
|
(None, true, None, true)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(evicted_id) = evicted_id {
|
if let Some(evicted_id) = evicted_id {
|
||||||
|
@ -2149,9 +2138,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
|
|
||||||
if new_frame {
|
if new_frame {
|
||||||
self.new_frame(frame_change.frame_id, frame_change.new_pipeline_id, frame_change.url);
|
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);
|
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);
|
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) {
|
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).
|
// Notify the parent (if there is one).
|
||||||
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
||||||
|
@ -2359,6 +2353,53 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
ReadyToSave::Ready
|
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) {
|
fn clear_joint_session_future(&mut self, frame_id: FrameId) {
|
||||||
let frame_ids: Vec<FrameId> = self.full_frame_tree_iter(frame_id)
|
let frame_ids: Vec<FrameId> = self.full_frame_tree_iter(frame_id)
|
||||||
.map(|frame| frame.id)
|
.map(|frame| frame.id)
|
||||||
|
|
|
@ -19,7 +19,8 @@ use net_traits::{IpcSend, ResourceThreads};
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use profile_traits::mem as profile_mem;
|
use profile_traits::mem as profile_mem;
|
||||||
use profile_traits::time;
|
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::{LayoutControlMsg, LayoutMsg, LoadData, MozBrowserEvent};
|
||||||
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
|
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders, ScriptMsg};
|
||||||
use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
|
use script_traits::{ScriptThreadFactory, TimerEventRequest, WindowSizeData};
|
||||||
|
@ -366,17 +367,11 @@ impl Pipeline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notify this pipeline that it is no longer fully active.
|
/// Notify this pipeline of its activity.
|
||||||
pub fn freeze(&self) {
|
pub fn set_activity(&self, activity: DocumentActivity) {
|
||||||
if let Err(e) = self.event_loop.send(ConstellationControlMsg::Freeze(self.id)) {
|
let msg = ConstellationControlMsg::SetDocumentActivity(self.id, activity);
|
||||||
warn!("Sending freeze message failed ({}).", e);
|
if let Err(e) = self.event_loop.send(msg) {
|
||||||
}
|
warn!("Sending activity 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||||
use script_layout_interface::OpaqueStyleAndLayoutData;
|
use script_layout_interface::OpaqueStyleAndLayoutData;
|
||||||
use script_layout_interface::reporter::CSSErrorReporter;
|
use script_layout_interface::reporter::CSSErrorReporter;
|
||||||
use script_layout_interface::rpc::LayoutRPC;
|
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 script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
|
@ -327,7 +327,7 @@ unsafe_no_jsmanaged_fields!(TrustedPromise);
|
||||||
unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
|
unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock);
|
||||||
// These three are interdependent, if you plan to put jsmanaged data
|
// These three are interdependent, if you plan to put jsmanaged data
|
||||||
// in one of these make sure it is propagated properly to containing structs
|
// 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!(TimerEventId, TimerSource);
|
||||||
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
|
unsafe_no_jsmanaged_fields!(TimelineMarkerType);
|
||||||
unsafe_no_jsmanaged_fields!(WorkerId);
|
unsafe_no_jsmanaged_fields!(WorkerId);
|
||||||
|
|
|
@ -108,7 +108,8 @@ use origin::Origin;
|
||||||
use script_layout_interface::message::{Msg, ReflowQueryType};
|
use script_layout_interface::message::{Msg, ReflowQueryType};
|
||||||
use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
|
use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
|
||||||
use script_thread::{MainThreadScriptMsg, Runnable};
|
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::{ScriptMsg as ConstellationMsg, TouchpadPressurePhase};
|
||||||
use script_traits::{TouchEventType, TouchId};
|
use script_traits::{TouchEventType, TouchId};
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
|
@ -191,7 +192,7 @@ pub struct Document {
|
||||||
last_modified: Option<String>,
|
last_modified: Option<String>,
|
||||||
encoding: Cell<EncodingRef>,
|
encoding: Cell<EncodingRef>,
|
||||||
is_html_document: bool,
|
is_html_document: bool,
|
||||||
is_fully_active: Cell<bool>,
|
activity: Cell<DocumentActivity>,
|
||||||
url: DOMRefCell<ServoUrl>,
|
url: DOMRefCell<ServoUrl>,
|
||||||
quirks_mode: Cell<QuirksMode>,
|
quirks_mode: Cell<QuirksMode>,
|
||||||
/// Caches for the getElement methods
|
/// Caches for the getElement methods
|
||||||
|
@ -387,17 +388,33 @@ impl Document {
|
||||||
self.trigger_mozbrowser_event(MozBrowserEvent::SecurityChange(https_state));
|
self.trigger_mozbrowser_event(MozBrowserEvent::SecurityChange(https_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#fully-active
|
|
||||||
pub fn is_fully_active(&self) -> bool {
|
pub fn is_fully_active(&self) -> bool {
|
||||||
self.is_fully_active.get()
|
self.activity.get() == DocumentActivity::FullyActive
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fully_activate(&self) {
|
pub fn is_active(&self) -> bool {
|
||||||
self.is_fully_active.set(true)
|
self.activity.get() != DocumentActivity::Inactive
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fully_deactivate(&self) {
|
pub fn set_activity(&self, activity: DocumentActivity) {
|
||||||
self.is_fully_active.set(false)
|
// 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 {
|
pub fn origin(&self) -> &Origin {
|
||||||
|
@ -1892,6 +1909,7 @@ impl Document {
|
||||||
is_html_document: IsHTMLDocument,
|
is_html_document: IsHTMLDocument,
|
||||||
content_type: Option<DOMString>,
|
content_type: Option<DOMString>,
|
||||||
last_modified: Option<String>,
|
last_modified: Option<String>,
|
||||||
|
activity: DocumentActivity,
|
||||||
source: DocumentSource,
|
source: DocumentSource,
|
||||||
doc_loader: DocumentLoader,
|
doc_loader: DocumentLoader,
|
||||||
referrer: Option<String>,
|
referrer: Option<String>,
|
||||||
|
@ -1927,7 +1945,7 @@ impl Document {
|
||||||
// https://dom.spec.whatwg.org/#concept-document-encoding
|
// https://dom.spec.whatwg.org/#concept-document-encoding
|
||||||
encoding: Cell::new(UTF_8),
|
encoding: Cell::new(UTF_8),
|
||||||
is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
|
is_html_document: is_html_document == IsHTMLDocument::HTMLDocument,
|
||||||
is_fully_active: Cell::new(false),
|
activity: Cell::new(activity),
|
||||||
id_map: DOMRefCell::new(HashMap::new()),
|
id_map: DOMRefCell::new(HashMap::new()),
|
||||||
tag_map: DOMRefCell::new(HashMap::new()),
|
tag_map: DOMRefCell::new(HashMap::new()),
|
||||||
tagns_map: DOMRefCell::new(HashMap::new()),
|
tagns_map: DOMRefCell::new(HashMap::new()),
|
||||||
|
@ -1995,6 +2013,7 @@ impl Document {
|
||||||
IsHTMLDocument::NonHTMLDocument,
|
IsHTMLDocument::NonHTMLDocument,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::NotFromParser,
|
DocumentSource::NotFromParser,
|
||||||
docloader,
|
docloader,
|
||||||
None,
|
None,
|
||||||
|
@ -2008,6 +2027,7 @@ impl Document {
|
||||||
doctype: IsHTMLDocument,
|
doctype: IsHTMLDocument,
|
||||||
content_type: Option<DOMString>,
|
content_type: Option<DOMString>,
|
||||||
last_modified: Option<String>,
|
last_modified: Option<String>,
|
||||||
|
activity: DocumentActivity,
|
||||||
source: DocumentSource,
|
source: DocumentSource,
|
||||||
doc_loader: DocumentLoader,
|
doc_loader: DocumentLoader,
|
||||||
referrer: Option<String>,
|
referrer: Option<String>,
|
||||||
|
@ -2020,6 +2040,7 @@ impl Document {
|
||||||
doctype,
|
doctype,
|
||||||
content_type,
|
content_type,
|
||||||
last_modified,
|
last_modified,
|
||||||
|
activity,
|
||||||
source,
|
source,
|
||||||
doc_loader,
|
doc_loader,
|
||||||
referrer,
|
referrer,
|
||||||
|
@ -2093,6 +2114,7 @@ impl Document {
|
||||||
doctype,
|
doctype,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::NotFromParser,
|
DocumentSource::NotFromParser,
|
||||||
DocumentLoader::new(&self.loader()),
|
DocumentLoader::new(&self.loader()),
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -23,6 +23,7 @@ use dom::htmltitleelement::HTMLTitleElement;
|
||||||
use dom::node::Node;
|
use dom::node::Node;
|
||||||
use dom::text::Text;
|
use dom::text::Text;
|
||||||
use dom::xmldocument::XMLDocument;
|
use dom::xmldocument::XMLDocument;
|
||||||
|
use script_traits::DocumentActivity;
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#domimplementation
|
// https://dom.spec.whatwg.org/#domimplementation
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -83,6 +84,7 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||||
IsHTMLDocument::NonHTMLDocument,
|
IsHTMLDocument::NonHTMLDocument,
|
||||||
Some(DOMString::from(content_type)),
|
Some(DOMString::from(content_type)),
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::NotFromParser,
|
DocumentSource::NotFromParser,
|
||||||
loader);
|
loader);
|
||||||
// Step 2-3.
|
// Step 2-3.
|
||||||
|
@ -129,6 +131,7 @@ impl DOMImplementationMethods for DOMImplementation {
|
||||||
IsHTMLDocument::HTMLDocument,
|
IsHTMLDocument::HTMLDocument,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::NotFromParser,
|
DocumentSource::NotFromParser,
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -19,6 +19,7 @@ use dom::document::{Document, IsHTMLDocument};
|
||||||
use dom::document::DocumentSource;
|
use dom::document::DocumentSource;
|
||||||
use dom::servoparser::ServoParser;
|
use dom::servoparser::ServoParser;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
|
use script_traits::DocumentActivity;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct DOMParser {
|
pub struct DOMParser {
|
||||||
|
@ -65,6 +66,7 @@ impl DOMParserMethods for DOMParser {
|
||||||
IsHTMLDocument::HTMLDocument,
|
IsHTMLDocument::HTMLDocument,
|
||||||
Some(content_type),
|
Some(content_type),
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::FromParser,
|
DocumentSource::FromParser,
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
|
@ -82,6 +84,7 @@ impl DOMParserMethods for DOMParser {
|
||||||
IsHTMLDocument::NonHTMLDocument,
|
IsHTMLDocument::NonHTMLDocument,
|
||||||
Some(content_type),
|
Some(content_type),
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::NotFromParser,
|
DocumentSource::NotFromParser,
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -65,6 +65,7 @@ use ref_slice::ref_slice;
|
||||||
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
|
use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData};
|
||||||
use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
|
use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress};
|
||||||
use script_layout_interface::message::Msg;
|
use script_layout_interface::message::Msg;
|
||||||
|
use script_traits::DocumentActivity;
|
||||||
use script_traits::UntrustedNodeAddress;
|
use script_traits::UntrustedNodeAddress;
|
||||||
use selectors::matching::{MatchingReason, matches};
|
use selectors::matching::{MatchingReason, matches};
|
||||||
use selectors::parser::SelectorList;
|
use selectors::parser::SelectorList;
|
||||||
|
@ -1730,7 +1731,8 @@ impl Node {
|
||||||
// https://github.com/whatwg/dom/issues/378
|
// https://github.com/whatwg/dom/issues/378
|
||||||
document.origin().alias(),
|
document.origin().alias(),
|
||||||
is_html_doc, None,
|
is_html_doc, None,
|
||||||
None, DocumentSource::NotFromParser, loader,
|
None, DocumentActivity::Inactive,
|
||||||
|
DocumentSource::NotFromParser, loader,
|
||||||
None, None);
|
None, None);
|
||||||
Root::upcast::<Node>(document)
|
Root::upcast::<Node>(document)
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,6 +35,7 @@ use network_listener::PreInvoke;
|
||||||
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
|
use profile_traits::time::{TimerMetadata, TimerMetadataFrameType};
|
||||||
use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
|
use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile};
|
||||||
use script_thread::ScriptThread;
|
use script_thread::ScriptThread;
|
||||||
|
use script_traits::DocumentActivity;
|
||||||
use servo_config::resource_files::read_resource_file;
|
use servo_config::resource_files::read_resource_file;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
@ -107,6 +108,7 @@ impl ServoParser {
|
||||||
IsHTMLDocument::HTMLDocument,
|
IsHTMLDocument::HTMLDocument,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::FromParser,
|
DocumentSource::FromParser,
|
||||||
loader,
|
loader,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -1488,21 +1488,17 @@ impl Window {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn freeze(&self) {
|
pub fn suspend(&self) {
|
||||||
self.upcast::<GlobalScope>().suspend();
|
self.upcast::<GlobalScope>().suspend();
|
||||||
// A hint to the JS runtime that now would be a good time to
|
// A hint to the JS runtime that now would be a good time to
|
||||||
// GC any unreachable objects generated by user script,
|
// GC any unreachable objects generated by user script,
|
||||||
// or unattached DOM nodes. Attached DOM nodes can't be GCd yet,
|
// 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();
|
self.Gc();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thaw(&self) {
|
pub fn resume(&self) {
|
||||||
self.upcast::<GlobalScope>().resume();
|
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 {
|
pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool {
|
||||||
|
|
|
@ -17,6 +17,7 @@ use dom::node::Node;
|
||||||
use dom::window::Window;
|
use dom::window::Window;
|
||||||
use js::jsapi::{JSContext, JSObject};
|
use js::jsapi::{JSContext, JSObject};
|
||||||
use origin::Origin;
|
use origin::Origin;
|
||||||
|
use script_traits::DocumentActivity;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#xmldocument
|
// https://dom.spec.whatwg.org/#xmldocument
|
||||||
|
@ -33,6 +34,7 @@ impl XMLDocument {
|
||||||
is_html_document: IsHTMLDocument,
|
is_html_document: IsHTMLDocument,
|
||||||
content_type: Option<DOMString>,
|
content_type: Option<DOMString>,
|
||||||
last_modified: Option<String>,
|
last_modified: Option<String>,
|
||||||
|
activity: DocumentActivity,
|
||||||
source: DocumentSource,
|
source: DocumentSource,
|
||||||
doc_loader: DocumentLoader) -> XMLDocument {
|
doc_loader: DocumentLoader) -> XMLDocument {
|
||||||
XMLDocument {
|
XMLDocument {
|
||||||
|
@ -43,6 +45,7 @@ impl XMLDocument {
|
||||||
is_html_document,
|
is_html_document,
|
||||||
content_type,
|
content_type,
|
||||||
last_modified,
|
last_modified,
|
||||||
|
activity,
|
||||||
source,
|
source,
|
||||||
doc_loader,
|
doc_loader,
|
||||||
None,
|
None,
|
||||||
|
@ -57,6 +60,7 @@ impl XMLDocument {
|
||||||
doctype: IsHTMLDocument,
|
doctype: IsHTMLDocument,
|
||||||
content_type: Option<DOMString>,
|
content_type: Option<DOMString>,
|
||||||
last_modified: Option<String>,
|
last_modified: Option<String>,
|
||||||
|
activity: DocumentActivity,
|
||||||
source: DocumentSource,
|
source: DocumentSource,
|
||||||
doc_loader: DocumentLoader)
|
doc_loader: DocumentLoader)
|
||||||
-> Root<XMLDocument> {
|
-> Root<XMLDocument> {
|
||||||
|
@ -68,6 +72,7 @@ impl XMLDocument {
|
||||||
doctype,
|
doctype,
|
||||||
content_type,
|
content_type,
|
||||||
last_modified,
|
last_modified,
|
||||||
|
activity,
|
||||||
source,
|
source,
|
||||||
doc_loader),
|
doc_loader),
|
||||||
window,
|
window,
|
||||||
|
|
|
@ -58,6 +58,7 @@ use net_traits::CoreResourceMsg::Fetch;
|
||||||
use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
|
use net_traits::request::{CredentialsMode, Destination, RequestInit, RequestMode};
|
||||||
use net_traits::trim_http_whitespace;
|
use net_traits::trim_http_whitespace;
|
||||||
use network_listener::{NetworkListener, PreInvoke};
|
use network_listener::{NetworkListener, PreInvoke};
|
||||||
|
use script_traits::DocumentActivity;
|
||||||
use servo_atoms::Atom;
|
use servo_atoms::Atom;
|
||||||
use servo_config::prefs::PREFS;
|
use servo_config::prefs::PREFS;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
@ -1228,6 +1229,7 @@ impl XMLHttpRequest {
|
||||||
is_html_document,
|
is_html_document,
|
||||||
content_type,
|
content_type,
|
||||||
None,
|
None,
|
||||||
|
DocumentActivity::Inactive,
|
||||||
DocumentSource::FromParser,
|
DocumentSource::FromParser,
|
||||||
docloader,
|
docloader,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -83,7 +83,8 @@ use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
||||||
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
|
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory, EnqueuedPromiseCallback};
|
||||||
use script_runtime::{ScriptPort, StackRootTLS, get_reports, new_rt_and_cx, PromiseJobQueue};
|
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::{InitialScriptState, LayoutMsg, LoadData, MouseButton, MouseEventType, MozBrowserEvent};
|
||||||
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg};
|
||||||
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource};
|
||||||
|
@ -148,8 +149,8 @@ struct InProgressLoad {
|
||||||
window_size: Option<WindowSizeData>,
|
window_size: Option<WindowSizeData>,
|
||||||
/// Channel to the layout thread associated with this pipeline.
|
/// Channel to the layout thread associated with this pipeline.
|
||||||
layout_chan: Sender<message::Msg>,
|
layout_chan: Sender<message::Msg>,
|
||||||
/// Window is frozen (navigated away while loading for example).
|
/// The activity level of the document (inactive, active or fully active).
|
||||||
is_frozen: bool,
|
activity: DocumentActivity,
|
||||||
/// Window is visible.
|
/// Window is visible.
|
||||||
is_visible: bool,
|
is_visible: bool,
|
||||||
/// The requested URL of the load.
|
/// The requested URL of the load.
|
||||||
|
@ -172,7 +173,7 @@ impl InProgressLoad {
|
||||||
parent_info: parent_info,
|
parent_info: parent_info,
|
||||||
layout_chan: layout_chan,
|
layout_chan: layout_chan,
|
||||||
window_size: window_size,
|
window_size: window_size,
|
||||||
is_frozen: false,
|
activity: DocumentActivity::FullyActive,
|
||||||
is_visible: true,
|
is_visible: true,
|
||||||
url: url,
|
url: url,
|
||||||
origin: origin,
|
origin: origin,
|
||||||
|
@ -963,10 +964,8 @@ impl ScriptThread {
|
||||||
self.handle_resize_inactive_msg(id, new_size),
|
self.handle_resize_inactive_msg(id, new_size),
|
||||||
ConstellationControlMsg::GetTitle(pipeline_id) =>
|
ConstellationControlMsg::GetTitle(pipeline_id) =>
|
||||||
self.handle_get_title_msg(pipeline_id),
|
self.handle_get_title_msg(pipeline_id),
|
||||||
ConstellationControlMsg::Freeze(pipeline_id) =>
|
ConstellationControlMsg::SetDocumentActivity(pipeline_id, activity) =>
|
||||||
self.handle_freeze_msg(pipeline_id),
|
self.handle_set_document_activity_msg(pipeline_id, activity),
|
||||||
ConstellationControlMsg::Thaw(pipeline_id) =>
|
|
||||||
self.handle_thaw_msg(pipeline_id),
|
|
||||||
ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) =>
|
ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) =>
|
||||||
self.handle_visibility_change_msg(pipeline_id, visible),
|
self.handle_visibility_change_msg(pipeline_id, visible),
|
||||||
ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, frame_id, visible) =>
|
ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, frame_id, visible) =>
|
||||||
|
@ -1303,37 +1302,19 @@ impl ScriptThread {
|
||||||
warn!("change visibility message sent to nonexistent pipeline");
|
warn!("change visibility message sent to nonexistent pipeline");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles freeze message
|
/// Handles activity change message
|
||||||
fn handle_freeze_msg(&self, id: PipelineId) {
|
fn handle_set_document_activity_msg(&self, id: PipelineId, activity: DocumentActivity) {
|
||||||
let document = self.documents.borrow().find_document(id);
|
let document = self.documents.borrow().find_document(id);
|
||||||
if let Some(document) = document {
|
if let Some(document) = document {
|
||||||
document.window().freeze();
|
document.set_activity(activity);
|
||||||
document.fully_deactivate();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut loads = self.incomplete_loads.borrow_mut();
|
let mut loads = self.incomplete_loads.borrow_mut();
|
||||||
if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
|
if let Some(ref mut load) = loads.iter_mut().find(|load| load.pipeline_id == id) {
|
||||||
load.is_frozen = true;
|
load.activity = activity;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
warn!("freeze sent to nonexistent pipeline");
|
warn!("change of activity 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_focus_iframe_msg(&self,
|
fn handle_focus_iframe_msg(&self,
|
||||||
|
@ -1759,16 +1740,13 @@ impl ScriptThread {
|
||||||
is_html_document,
|
is_html_document,
|
||||||
content_type,
|
content_type,
|
||||||
last_modified,
|
last_modified,
|
||||||
|
incomplete.activity,
|
||||||
DocumentSource::FromParser,
|
DocumentSource::FromParser,
|
||||||
loader,
|
loader,
|
||||||
referrer,
|
referrer,
|
||||||
referrer_policy);
|
referrer_policy);
|
||||||
document.set_ready_state(DocumentReadyState::Loading);
|
document.set_ready_state(DocumentReadyState::Loading);
|
||||||
|
|
||||||
if !incomplete.is_frozen {
|
|
||||||
document.fully_activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.documents.borrow_mut().insert(incomplete.pipeline_id, &*document);
|
self.documents.borrow_mut().insert(incomplete.pipeline_id, &*document);
|
||||||
|
|
||||||
window.init_document(&document);
|
window.init_document(&document);
|
||||||
|
@ -1822,8 +1800,8 @@ impl ScriptThread {
|
||||||
ServoParser::parse_html_document(&document, parse_input, final_url);
|
ServoParser::parse_html_document(&document, parse_input, final_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if incomplete.is_frozen {
|
if incomplete.activity != DocumentActivity::FullyActive {
|
||||||
window.upcast::<GlobalScope>().suspend();
|
window.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
if !incomplete.is_visible {
|
if !incomplete.is_visible {
|
||||||
|
|
|
@ -233,6 +233,7 @@ impl OneshotTimers {
|
||||||
return warn!("Suspending an already suspended timer.");
|
return warn!("Suspending an already suspended timer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("Suspending timers.");
|
||||||
self.suspended_since.set(Some(precise_time_ms()));
|
self.suspended_since.set(Some(precise_time_ms()));
|
||||||
self.invalidate_expected_event_id();
|
self.invalidate_expected_event_id();
|
||||||
}
|
}
|
||||||
|
@ -244,6 +245,7 @@ impl OneshotTimers {
|
||||||
None => return warn!("Resuming an already resumed timer."),
|
None => return warn!("Resuming an already resumed timer."),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("Resuming timers.");
|
||||||
self.suspension_offset.set(self.suspension_offset.get() + additional_offset);
|
self.suspension_offset.set(self.suspension_offset.get() + additional_offset);
|
||||||
self.suspended_since.set(None);
|
self.suspended_since.set(None);
|
||||||
|
|
||||||
|
@ -252,7 +254,7 @@ impl OneshotTimers {
|
||||||
|
|
||||||
fn schedule_timer_call(&self) {
|
fn schedule_timer_call(&self) {
|
||||||
if self.suspended_since.get().is_some() {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,22 @@ pub enum DiscardBrowsingContext {
|
||||||
No,
|
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.
|
/// Messages sent from the constellation or layout to the script thread.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum ConstellationControlMsg {
|
pub enum ConstellationControlMsg {
|
||||||
|
@ -215,10 +231,8 @@ pub enum ConstellationControlMsg {
|
||||||
SetScrollState(PipelineId, Vec<(UntrustedNodeAddress, Point2D<f32>)>),
|
SetScrollState(PipelineId, Vec<(UntrustedNodeAddress, Point2D<f32>)>),
|
||||||
/// Requests that the script thread immediately send the constellation the title of a pipeline.
|
/// Requests that the script thread immediately send the constellation the title of a pipeline.
|
||||||
GetTitle(PipelineId),
|
GetTitle(PipelineId),
|
||||||
/// Notifies script thread to suspend all its timers
|
/// Notifies script thread of a change to one of its document's activity
|
||||||
Freeze(PipelineId),
|
SetDocumentActivity(PipelineId, DocumentActivity),
|
||||||
/// Notifies script thread to resume all its timers
|
|
||||||
Thaw(PipelineId),
|
|
||||||
/// Notifies script thread whether frame is visible
|
/// Notifies script thread whether frame is visible
|
||||||
ChangeFrameVisibilityStatus(PipelineId, bool),
|
ChangeFrameVisibilityStatus(PipelineId, bool),
|
||||||
/// Notifies script thread that frame visibility change is complete
|
/// Notifies script thread that frame visibility change is complete
|
||||||
|
@ -281,8 +295,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
||||||
Viewport(..) => "Viewport",
|
Viewport(..) => "Viewport",
|
||||||
SetScrollState(..) => "SetScrollState",
|
SetScrollState(..) => "SetScrollState",
|
||||||
GetTitle(..) => "GetTitle",
|
GetTitle(..) => "GetTitle",
|
||||||
Freeze(..) => "Freeze",
|
SetDocumentActivity(..) => "SetDocumentActivity",
|
||||||
Thaw(..) => "Thaw",
|
|
||||||
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
|
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
|
||||||
NotifyVisibilityChange(..) => "NotifyVisibilityChange",
|
NotifyVisibilityChange(..) => "NotifyVisibilityChange",
|
||||||
Navigate(..) => "Navigate",
|
Navigate(..) => "Navigate",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue