Rework “visible” to “throttled” in constellation + script + compositor (#31816)

This commit is contained in:
Delan Azabani 2024-03-22 14:06:28 +08:00 committed by GitHub
parent 9b26dca141
commit 8882507ad0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 124 additions and 129 deletions

View file

@ -302,8 +302,8 @@ struct PipelineDetails {
/// Whether there are animation callbacks /// Whether there are animation callbacks
animation_callbacks_running: bool, animation_callbacks_running: bool,
/// Whether this pipeline is visible /// Whether to use less resources by stopping animations.
visible: bool, throttled: bool,
/// Hit test items for this pipeline. This is used to map WebRender hit test /// Hit test items for this pipeline. This is used to map WebRender hit test
/// information to the full information necessary for Servo. /// information to the full information necessary for Servo.
@ -321,7 +321,7 @@ impl PipelineDetails {
most_recent_display_list_epoch: None, most_recent_display_list_epoch: None,
animations_running: false, animations_running: false,
animation_callbacks_running: false, animation_callbacks_running: false,
visible: true, throttled: false,
hit_test_items: Vec::new(), hit_test_items: Vec::new(),
scroll_tree: ScrollTree::default(), scroll_tree: ScrollTree::default(),
} }
@ -579,8 +579,8 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
self.composite_if_necessary(CompositingReason::Headless); self.composite_if_necessary(CompositingReason::Headless);
}, },
CompositorMsg::PipelineVisibilityChanged(pipeline_id, visible) => { CompositorMsg::SetThrottled(pipeline_id, throttled) => {
self.pipeline_details(pipeline_id).visible = visible; self.pipeline_details(pipeline_id).throttled = throttled;
self.process_animations(true); self.process_animations(true);
}, },
@ -982,17 +982,17 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
) { ) {
match animation_state { match animation_state {
AnimationState::AnimationsPresent => { AnimationState::AnimationsPresent => {
let visible = self.pipeline_details(pipeline_id).visible; let throttled = self.pipeline_details(pipeline_id).throttled;
self.pipeline_details(pipeline_id).animations_running = true; self.pipeline_details(pipeline_id).animations_running = true;
if visible { if !throttled {
self.composite_if_necessary(CompositingReason::Animation); self.composite_if_necessary(CompositingReason::Animation);
} }
}, },
AnimationState::AnimationCallbacksPresent => { AnimationState::AnimationCallbacksPresent => {
let visible = self.pipeline_details(pipeline_id).visible; let throttled = self.pipeline_details(pipeline_id).throttled;
self.pipeline_details(pipeline_id) self.pipeline_details(pipeline_id)
.animation_callbacks_running = true; .animation_callbacks_running = true;
if visible { if !throttled {
self.tick_animations_for_pipeline(pipeline_id); self.tick_animations_for_pipeline(pipeline_id);
} }
}, },
@ -1583,7 +1583,7 @@ impl<Window: WindowMethods + ?Sized> IOCompositor<Window> {
let mut pipeline_ids = vec![]; let mut pipeline_ids = vec![];
for (pipeline_id, pipeline_details) in &self.pipeline_details { for (pipeline_id, pipeline_details) in &self.pipeline_details {
if (pipeline_details.animations_running || pipeline_details.animation_callbacks_running) && if (pipeline_details.animations_running || pipeline_details.animation_callbacks_running) &&
pipeline_details.visible !pipeline_details.throttled
{ {
pipeline_ids.push(*pipeline_id); pipeline_ids.push(*pipeline_id);
} }

View file

@ -32,9 +32,9 @@ pub struct NewBrowsingContextInfo {
/// Whether this browsing context inherits a secure context. /// Whether this browsing context inherits a secure context.
pub inherited_secure_context: Option<bool>, pub inherited_secure_context: Option<bool>,
/// Whether this browsing context should be treated as visible for the /// Whether this browsing context should be throttled, using less resources
/// purposes of scheduling and resource management. /// by stopping animations and running timers at a heavily limited rate.
pub is_visible: bool, pub throttled: bool,
} }
/// The constellation's view of a browsing context. /// The constellation's view of a browsing context.
@ -62,9 +62,9 @@ pub struct BrowsingContext {
/// Whether this browsing context inherits a secure context. /// Whether this browsing context inherits a secure context.
pub inherited_secure_context: Option<bool>, pub inherited_secure_context: Option<bool>,
/// Whether this browsing context should be treated as visible for the /// Whether this browsing context should be throttled, using less resources
/// purposes of scheduling and resource management. /// by stopping animations and running timers at a heavily limited rate.
pub is_visible: bool, pub throttled: bool,
/// The pipeline for the current session history entry. /// The pipeline for the current session history entry.
pub pipeline_id: PipelineId, pub pipeline_id: PipelineId,
@ -90,7 +90,7 @@ impl BrowsingContext {
size: Size2D<f32, CSSPixel>, size: Size2D<f32, CSSPixel>,
is_private: bool, is_private: bool,
inherited_secure_context: Option<bool>, inherited_secure_context: Option<bool>,
is_visible: bool, throttled: bool,
) -> BrowsingContext { ) -> BrowsingContext {
let mut pipelines = HashSet::new(); let mut pipelines = HashSet::new();
pipelines.insert(pipeline_id); pipelines.insert(pipeline_id);
@ -101,7 +101,7 @@ impl BrowsingContext {
size, size,
is_private, is_private,
inherited_secure_context, inherited_secure_context,
is_visible, throttled,
pipeline_id, pipeline_id,
parent_pipeline_id, parent_pipeline_id,
pipelines, pipelines,

View file

@ -127,7 +127,7 @@ use msg::constellation_msg::{
BackgroundHangMonitorControlMsg, BackgroundHangMonitorRegister, BroadcastChannelRouterId, BackgroundHangMonitorControlMsg, BackgroundHangMonitorRegister, BroadcastChannelRouterId,
BrowsingContextGroupId, BrowsingContextId, HangMonitorAlert, HistoryStateId, MessagePortId, BrowsingContextGroupId, BrowsingContextId, HangMonitorAlert, HistoryStateId, MessagePortId,
MessagePortRouterId, PipelineId, PipelineNamespace, PipelineNamespaceId, MessagePortRouterId, PipelineId, PipelineNamespace, PipelineNamespaceId,
PipelineNamespaceRequest, TopLevelBrowsingContextId, TraversalDirection, PipelineNamespaceRequest, TopLevelBrowsingContextId, TraversalDirection, WebViewId,
}; };
use net_traits::pub_domains::reg_host; use net_traits::pub_domains::reg_host;
use net_traits::request::{Referrer, RequestBuilder}; use net_traits::request::{Referrer, RequestBuilder};
@ -956,7 +956,7 @@ where
load_data: LoadData, load_data: LoadData,
sandbox: IFrameSandboxState, sandbox: IFrameSandboxState,
is_private: bool, is_private: bool,
is_visible: bool, throttled: bool,
) { ) {
if self.shutting_down { if self.shutting_down {
return; return;
@ -1051,7 +1051,7 @@ where
}, },
event_loop, event_loop,
load_data, load_data,
prev_visibility: is_visible, prev_throttled: throttled,
webrender_api_sender: self.webrender_api_ipc_sender.clone(), webrender_api_sender: self.webrender_api_ipc_sender.clone(),
webrender_image_api_sender: self.webrender_image_api_sender.clone(), webrender_image_api_sender: self.webrender_image_api_sender.clone(),
webrender_document: self.webrender_document, webrender_document: self.webrender_document,
@ -1135,7 +1135,7 @@ where
size: Size2D<f32, CSSPixel>, size: Size2D<f32, CSSPixel>,
is_private: bool, is_private: bool,
inherited_secure_context: Option<bool>, inherited_secure_context: Option<bool>,
is_visible: bool, throttled: bool,
) { ) {
debug!("{}: Creating new browsing context", browsing_context_id); debug!("{}: Creating new browsing context", browsing_context_id);
let bc_group_id = match self let bc_group_id = match self
@ -1168,7 +1168,7 @@ where
size, size,
is_private, is_private,
inherited_secure_context, inherited_secure_context,
is_visible, throttled,
); );
self.browsing_contexts self.browsing_contexts
.insert(browsing_context_id, browsing_context); .insert(browsing_context_id, browsing_context);
@ -1536,7 +1536,7 @@ where
self.handle_media_session_action_msg(action); self.handle_media_session_action_msg(action);
}, },
FromCompositorMsg::SetWebViewThrottled(webview_id, throttled) => { FromCompositorMsg::SetWebViewThrottled(webview_id, throttled) => {
self.notify_webview_visibility(webview_id, !throttled); self.set_webview_throttled(webview_id, throttled);
}, },
FromCompositorMsg::ReadyToPresent(top_level_browsing_context_id) => { FromCompositorMsg::ReadyToPresent(top_level_browsing_context_id) => {
self.embedder_proxy.send(( self.embedder_proxy.send((
@ -1712,8 +1712,8 @@ where
FromScriptMsg::Focus => { FromScriptMsg::Focus => {
self.handle_focus_msg(source_pipeline_id); self.handle_focus_msg(source_pipeline_id);
}, },
FromScriptMsg::VisibilityChangeComplete(is_visible) => { FromScriptMsg::SetThrottledComplete(throttled) => {
self.handle_visibility_change_complete(source_pipeline_id, is_visible); self.handle_set_throttled_complete(source_pipeline_id, throttled);
}, },
FromScriptMsg::RemoveIFrame(browsing_context_id, response_sender) => { FromScriptMsg::RemoveIFrame(browsing_context_id, response_sender) => {
let removed_pipeline_ids = self.handle_remove_iframe_msg(browsing_context_id); let removed_pipeline_ids = self.handle_remove_iframe_msg(browsing_context_id);
@ -2790,7 +2790,7 @@ where
}; };
let window_size = browsing_context.size; let window_size = browsing_context.size;
let pipeline_id = browsing_context.pipeline_id; let pipeline_id = browsing_context.pipeline_id;
let is_visible = browsing_context.is_visible; let throttled = browsing_context.throttled;
let pipeline = match self.pipelines.get(&pipeline_id) { let pipeline = match self.pipelines.get(&pipeline_id) {
Some(p) => p, Some(p) => p,
@ -2837,7 +2837,7 @@ where
new_load_data, new_load_data,
sandbox, sandbox,
is_private, is_private,
is_visible, throttled,
); );
self.add_pending_change(SessionHistoryChange { self.add_pending_change(SessionHistoryChange {
top_level_browsing_context_id, top_level_browsing_context_id,
@ -2953,7 +2953,7 @@ where
); );
let sandbox = IFrameSandboxState::IFrameUnsandboxed; let sandbox = IFrameSandboxState::IFrameUnsandboxed;
let is_private = false; let is_private = false;
let is_visible = true; let throttled = false;
// Register this new top-level browsing context id as a webview and set // Register this new top-level browsing context id as a webview and set
// its focused browsing context to be itself. // its focused browsing context to be itself.
@ -2984,7 +2984,7 @@ where
load_data, load_data,
sandbox, sandbox,
is_private, is_private,
is_visible, throttled,
); );
self.add_pending_change(SessionHistoryChange { self.add_pending_change(SessionHistoryChange {
top_level_browsing_context_id, top_level_browsing_context_id,
@ -2995,7 +2995,7 @@ where
parent_pipeline_id: None, parent_pipeline_id: None,
is_private, is_private,
inherited_secure_context: None, inherited_secure_context: None,
is_visible, throttled,
}), }),
window_size, window_size,
}); });
@ -3197,7 +3197,7 @@ where
// https://github.com/rust-lang/rust/issues/59159 // https://github.com/rust-lang/rust/issues/59159
let browsing_context_size = browsing_context.size; let browsing_context_size = browsing_context.size;
let browsing_context_is_visible = browsing_context.is_visible; let browsing_context_throttled = browsing_context.throttled;
// TODO(servo#30571) revert to debug_assert_eq!() once underlying bug is fixed // TODO(servo#30571) revert to debug_assert_eq!() once underlying bug is fixed
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
if !(browsing_context_size == load_info.window_size.initial_viewport) { if !(browsing_context_size == load_info.window_size.initial_viewport) {
@ -3215,7 +3215,7 @@ where
load_info.load_data, load_info.load_data,
load_info.sandbox, load_info.sandbox,
is_private, is_private,
browsing_context_is_visible, browsing_context_throttled,
); );
self.add_pending_change(SessionHistoryChange { self.add_pending_change(SessionHistoryChange {
top_level_browsing_context_id, top_level_browsing_context_id,
@ -3248,9 +3248,9 @@ where
) )
}, },
}; };
let (is_parent_private, is_parent_visible, is_parent_secure) = let (is_parent_private, is_parent_throttled, is_parent_secure) =
match self.browsing_contexts.get(&parent_browsing_context_id) { match self.browsing_contexts.get(&parent_browsing_context_id) {
Some(ctx) => (ctx.is_private, ctx.is_visible, ctx.inherited_secure_context), Some(ctx) => (ctx.is_private, ctx.throttled, ctx.inherited_secure_context),
None => { None => {
return warn!( return warn!(
"{}: New iframe {} loaded in closed parent browsing context", "{}: New iframe {} loaded in closed parent browsing context",
@ -3266,7 +3266,7 @@ where
None, None,
script_sender, script_sender,
self.compositor_proxy.clone(), self.compositor_proxy.clone(),
is_parent_visible, is_parent_throttled,
load_info.load_data, load_info.load_data,
); );
@ -3282,7 +3282,7 @@ where
parent_pipeline_id: Some(parent_pipeline_id), parent_pipeline_id: Some(parent_pipeline_id),
is_private, is_private,
inherited_secure_context: is_parent_secure, inherited_secure_context: is_parent_secure,
is_visible: is_parent_visible, throttled: is_parent_throttled,
}), }),
window_size: load_info.window_size.initial_viewport, window_size: load_info.window_size.initial_viewport,
}); });
@ -3307,9 +3307,9 @@ where
); );
}, },
}; };
let (is_opener_private, is_opener_visible, is_opener_secure) = let (is_opener_private, is_opener_throttled, is_opener_secure) =
match self.browsing_contexts.get(&opener_browsing_context_id) { match self.browsing_contexts.get(&opener_browsing_context_id) {
Some(ctx) => (ctx.is_private, ctx.is_visible, ctx.inherited_secure_context), Some(ctx) => (ctx.is_private, ctx.throttled, ctx.inherited_secure_context),
None => { None => {
return warn!( return warn!(
"{}: New auxiliary {} loaded in closed opener browsing context", "{}: New auxiliary {} loaded in closed opener browsing context",
@ -3324,7 +3324,7 @@ where
Some(opener_browsing_context_id), Some(opener_browsing_context_id),
script_sender, script_sender,
self.compositor_proxy.clone(), self.compositor_proxy.clone(),
is_opener_visible, is_opener_throttled,
load_data, load_data,
); );
@ -3367,7 +3367,7 @@ where
parent_pipeline_id: None, parent_pipeline_id: None,
is_private: is_opener_private, is_private: is_opener_private,
inherited_secure_context: is_opener_secure, inherited_secure_context: is_opener_secure,
is_visible: is_opener_visible, throttled: is_opener_throttled,
}), }),
window_size: self.window_size.initial_viewport, window_size: self.window_size.initial_viewport,
}); });
@ -3470,14 +3470,14 @@ where
return None; return None;
}, },
}; };
let (window_size, pipeline_id, parent_pipeline_id, is_private, is_visible) = let (window_size, pipeline_id, parent_pipeline_id, is_private, is_throttled) =
match self.browsing_contexts.get(&browsing_context_id) { match self.browsing_contexts.get(&browsing_context_id) {
Some(ctx) => ( Some(ctx) => (
ctx.size, ctx.size,
ctx.pipeline_id, ctx.pipeline_id,
ctx.parent_pipeline_id, ctx.parent_pipeline_id,
ctx.is_private, ctx.is_private,
ctx.is_visible, ctx.throttled,
), ),
None => { None => {
// This should technically never happen (since `load_url` is // This should technically never happen (since `load_url` is
@ -3553,7 +3553,7 @@ where
load_data, load_data,
sandbox, sandbox,
is_private, is_private,
is_visible, is_throttled,
); );
self.add_pending_change(SessionHistoryChange { self.add_pending_change(SessionHistoryChange {
top_level_browsing_context_id, top_level_browsing_context_id,
@ -3827,7 +3827,7 @@ where
parent_pipeline_id, parent_pipeline_id,
window_size, window_size,
is_private, is_private,
is_visible, throttled,
) = match self.browsing_contexts.get(&browsing_context_id) { ) = match self.browsing_contexts.get(&browsing_context_id) {
Some(ctx) => ( Some(ctx) => (
ctx.top_level_id, ctx.top_level_id,
@ -3835,7 +3835,7 @@ where
ctx.parent_pipeline_id, ctx.parent_pipeline_id,
ctx.size, ctx.size,
ctx.is_private, ctx.is_private,
ctx.is_visible, ctx.throttled,
), ),
None => return warn!("No browsing context to traverse!"), None => return warn!("No browsing context to traverse!"),
}; };
@ -3854,7 +3854,7 @@ where
load_data.clone(), load_data.clone(),
sandbox, sandbox,
is_private, is_private,
is_visible, throttled,
); );
self.add_pending_change(SessionHistoryChange { self.add_pending_change(SessionHistoryChange {
top_level_browsing_context_id: top_level_id, top_level_browsing_context_id: top_level_id,
@ -3886,7 +3886,7 @@ where
}; };
if let Some(old_pipeline) = self.pipelines.get(&old_pipeline_id) { if let Some(old_pipeline) = self.pipelines.get(&old_pipeline_id) {
old_pipeline.notify_visibility(false); old_pipeline.set_throttled(true);
} }
if let Some(new_pipeline) = self.pipelines.get(&new_pipeline_id) { if let Some(new_pipeline) = self.pipelines.get(&new_pipeline_id) {
if let Some(ref chan) = self.devtools_sender { if let Some(ref chan) = self.devtools_sender {
@ -3904,7 +3904,7 @@ where
)); ));
} }
new_pipeline.notify_visibility(true); new_pipeline.set_throttled(false);
} }
self.update_activity(old_pipeline_id); self.update_activity(old_pipeline_id);
@ -4267,7 +4267,7 @@ where
result result
} }
fn handle_visibility_change_complete(&mut self, pipeline_id: PipelineId, visibility: bool) { fn handle_set_throttled_complete(&mut self, pipeline_id: PipelineId, throttled: bool) {
let browsing_context_id = match self.pipelines.get(&pipeline_id) { let browsing_context_id = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.browsing_context_id, Some(pipeline) => pipeline.browsing_context_id,
None => { None => {
@ -4285,14 +4285,14 @@ where
}; };
if let Some(parent_pipeline_id) = parent_pipeline_id { if let Some(parent_pipeline_id) = parent_pipeline_id {
let visibility_msg = ConstellationControlMsg::NotifyVisibilityChange( let msg = ConstellationControlMsg::SetThrottledInContainingIframe(
parent_pipeline_id, parent_pipeline_id,
browsing_context_id, browsing_context_id,
visibility, throttled,
); );
let result = match self.pipelines.get(&parent_pipeline_id) { let result = match self.pipelines.get(&parent_pipeline_id) {
None => return warn!("{}: Parent pipeline closed", parent_pipeline_id), None => return warn!("{}: Parent pipeline closed", parent_pipeline_id),
Some(parent_pipeline) => parent_pipeline.event_loop.send(visibility_msg), Some(parent_pipeline) => parent_pipeline.event_loop.send(msg),
}; };
if let Err(e) = result { if let Err(e) = result {
@ -4454,21 +4454,17 @@ where
} }
} }
fn notify_webview_visibility( fn set_webview_throttled(&mut self, webview_id: WebViewId, throttled: bool) {
&mut self, let browsing_context_id = BrowsingContextId::from(webview_id);
top_level_browsing_context_id: TopLevelBrowsingContextId,
visible: bool,
) {
let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id);
let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) {
Some(browsing_context) => browsing_context.pipeline_id, Some(browsing_context) => browsing_context.pipeline_id,
None => { None => {
return warn!("{browsing_context_id}: Tried to notify visibility after closure"); return warn!("{browsing_context_id}: Tried to SetWebViewThrottled after closure");
}, },
}; };
match self.pipelines.get(&pipeline_id) { match self.pipelines.get(&pipeline_id) {
None => warn!("{pipeline_id}: Tried to notify visibility after closure"), None => warn!("{pipeline_id}: Tried to SetWebViewThrottled after closure"),
Some(pipeline) => pipeline.notify_visibility(visible), Some(pipeline) => pipeline.set_throttled(throttled),
} }
} }
@ -4664,13 +4660,13 @@ where
change.window_size, change.window_size,
new_context_info.is_private, new_context_info.is_private,
new_context_info.inherited_secure_context, new_context_info.inherited_secure_context,
new_context_info.is_visible, new_context_info.throttled,
); );
self.update_activity(change.new_pipeline_id); self.update_activity(change.new_pipeline_id);
}, },
Some(old_pipeline_id) => { Some(old_pipeline_id) => {
if let Some(pipeline) = self.pipelines.get(&old_pipeline_id) { if let Some(pipeline) = self.pipelines.get(&old_pipeline_id) {
pipeline.notify_visibility(false); pipeline.set_throttled(true);
} }
// https://html.spec.whatwg.org/multipage/#unload-a-document // https://html.spec.whatwg.org/multipage/#unload-a-document

View file

@ -178,11 +178,11 @@ pub struct InitialPipelineState {
/// Information about the page to load. /// Information about the page to load.
pub load_data: LoadData, pub load_data: LoadData,
/// Whether the browsing context in which pipeline is embedded is visible /// Whether the browsing context in which pipeline is embedded is throttled,
/// for the purposes of scheduling and resource management. This field is /// using less resources by stopping animations and running timers at a
/// only used to notify script and compositor threads after spawning /// heavily limited rate. This field is only used to notify script and
/// a pipeline. /// compositor threads after spawning a pipeline.
pub prev_visibility: bool, pub prev_throttled: bool,
/// Webrender api. /// Webrender api.
pub webrender_image_api_sender: net_traits::WebrenderIpcSender, pub webrender_image_api_sender: net_traits::WebrenderIpcSender,
@ -339,7 +339,7 @@ impl Pipeline {
state.opener, state.opener,
script_chan, script_chan,
state.compositor_proxy, state.compositor_proxy,
state.prev_visibility, state.prev_throttled,
state.load_data, state.load_data,
); );
Ok(NewPipeline { Ok(NewPipeline {
@ -356,7 +356,7 @@ impl Pipeline {
opener: Option<BrowsingContextId>, opener: Option<BrowsingContextId>,
event_loop: Rc<EventLoop>, event_loop: Rc<EventLoop>,
compositor_proxy: CompositorProxy, compositor_proxy: CompositorProxy,
is_visible: bool, throttled: bool,
load_data: LoadData, load_data: LoadData,
) -> Pipeline { ) -> Pipeline {
let pipeline = Pipeline { let pipeline = Pipeline {
@ -377,7 +377,7 @@ impl Pipeline {
layout_epoch: Epoch(0), layout_epoch: Epoch(0),
}; };
pipeline.notify_visibility(is_visible); pipeline.set_throttled(throttled);
pipeline pipeline
} }
@ -458,13 +458,14 @@ impl Pipeline {
} }
} }
/// Notify the script thread that this pipeline is visible. /// Set whether to make pipeline use less resources, by stopping animations and
pub fn notify_visibility(&self, is_visible: bool) { /// running timers at a heavily limited rate.
let script_msg = ConstellationControlMsg::ChangeFrameVisibilityStatus(self.id, is_visible); pub fn set_throttled(&self, throttled: bool) {
let compositor_msg = CompositorMsg::PipelineVisibilityChanged(self.id, is_visible); let script_msg = ConstellationControlMsg::SetThrottled(self.id, throttled);
let compositor_msg = CompositorMsg::SetThrottled(self.id, throttled);
let err = self.event_loop.send(script_msg); let err = self.event_loop.send(script_msg);
if let Err(e) = err { if let Err(e) = err {
warn!("Sending visibility change failed ({}).", e); warn!("Sending SetThrottled to script failed ({}).", e);
} }
self.compositor_proxy.send(compositor_msg); self.compositor_proxy.send(compositor_msg);
} }

View file

@ -165,7 +165,7 @@ mod from_script {
Self::ReplaceHistoryState(_, _) => target!("ReplaceHistoryState"), Self::ReplaceHistoryState(_, _) => target!("ReplaceHistoryState"),
Self::JointSessionHistoryLength(_) => target!("JointSessionHistoryLength"), Self::JointSessionHistoryLength(_) => target!("JointSessionHistoryLength"),
Self::RemoveIFrame(_, _) => target!("RemoveIFrame"), Self::RemoveIFrame(_, _) => target!("RemoveIFrame"),
Self::VisibilityChangeComplete(_) => target!("VisibilityChangeComplete"), Self::SetThrottledComplete(_) => target!("SetThrottledComplete"),
Self::ScriptLoadedURLInIFrame(_) => target!("ScriptLoadedURLInIFrame"), Self::ScriptLoadedURLInIFrame(_) => target!("ScriptLoadedURLInIFrame"),
Self::ScriptNewIFrame(_) => target!("ScriptNewIFrame"), Self::ScriptNewIFrame(_) => target!("ScriptNewIFrame"),
Self::ScriptNewAuxiliary(_) => target!("ScriptNewAuxiliary"), Self::ScriptNewAuxiliary(_) => target!("ScriptNewAuxiliary"),

View file

@ -1966,7 +1966,7 @@ impl Document {
// If we are running 'fake' animation frames, we unconditionally // If we are running 'fake' animation frames, we unconditionally
// set up a one-shot timer for script to execute the rAF callbacks. // set up a one-shot timer for script to execute the rAF callbacks.
if self.is_faking_animation_frames() && self.window().visible() { if self.is_faking_animation_frames() && !self.window().throttled() {
warn!("Scheduling fake animation frame. Animation frames tick too fast."); warn!("Scheduling fake animation frame. Animation frames tick too fast.");
let callback = FakeRequestAnimationFrameCallback { let callback = FakeRequestAnimationFrameCallback {
document: Trusted::new(self), document: Trusted::new(self),

View file

@ -87,7 +87,7 @@ pub struct HTMLIFrameElement {
sandbox: MutNullableDom<DOMTokenList>, sandbox: MutNullableDom<DOMTokenList>,
sandbox_allowance: Cell<Option<SandboxAllowance>>, sandbox_allowance: Cell<Option<SandboxAllowance>>,
load_blocker: DomRefCell<Option<LoadBlocker>>, load_blocker: DomRefCell<Option<LoadBlocker>>,
visibility: Cell<bool>, throttled: Cell<bool>,
} }
impl HTMLIFrameElement { impl HTMLIFrameElement {
@ -438,7 +438,7 @@ impl HTMLIFrameElement {
sandbox: Default::default(), sandbox: Default::default(),
sandbox_allowance: Cell::new(None), sandbox_allowance: Cell::new(None),
load_blocker: DomRefCell::new(None), load_blocker: DomRefCell::new(None),
visibility: Cell::new(true), throttled: Cell::new(false),
} }
} }
@ -473,9 +473,9 @@ impl HTMLIFrameElement {
self.top_level_browsing_context_id.get() self.top_level_browsing_context_id.get()
} }
pub fn change_visibility_status(&self, visibility: bool) { pub fn set_throttled(&self, throttled: bool) {
if self.visibility.get() != visibility { if self.throttled.get() != throttled {
self.visibility.set(visibility); self.throttled.set(throttled);
} }
} }

View file

@ -349,7 +349,7 @@ pub struct Window {
#[no_trace] #[no_trace]
player_context: WindowGLContext, player_context: WindowGLContext,
visible: Cell<bool>, throttled: Cell<bool>,
/// A shared marker for the validity of any cached layout values. A value of true /// A shared marker for the validity of any cached layout values. A value of true
/// indicates that any such values remain valid; any new layout that invalidates /// indicates that any such values remain valid; any new layout that invalidates
@ -2454,18 +2454,18 @@ impl Window {
self.Document().react_to_environment_changes(); self.Document().react_to_environment_changes();
} }
/// Slow down/speed up timers based on visibility. /// Set whether to use less resources by running timers at a heavily limited rate.
pub fn alter_resource_utilization(&self, visible: bool) { pub fn set_throttled(&self, throttled: bool) {
self.visible.set(visible); self.throttled.set(throttled);
if visible { if throttled {
self.upcast::<GlobalScope>().speed_up_timers();
} else {
self.upcast::<GlobalScope>().slow_down_timers(); self.upcast::<GlobalScope>().slow_down_timers();
} else {
self.upcast::<GlobalScope>().speed_up_timers();
} }
} }
pub fn visible(&self) -> bool { pub fn throttled(&self) -> bool {
self.visible.get() self.throttled.get()
} }
pub fn unminified_js_dir(&self) -> Option<String> { pub fn unminified_js_dir(&self) -> Option<String> {
@ -2621,7 +2621,7 @@ impl Window {
userscripts_path, userscripts_path,
replace_surrogates, replace_surrogates,
player_context, player_context,
visible: Cell::new(true), throttled: Cell::new(false),
layout_marker: DomRefCell::new(Rc::new(Cell::new(true))), layout_marker: DomRefCell::new(Rc::new(Cell::new(true))),
current_event: DomRefCell::new(None), current_event: DomRefCell::new(None),
}); });

View file

@ -206,8 +206,8 @@ struct InProgressLoad {
/// The activity level of the document (inactive, active or fully active). /// The activity level of the document (inactive, active or fully active).
#[no_trace] #[no_trace]
activity: DocumentActivity, activity: DocumentActivity,
/// Window is visible. /// Window is throttled, running timers at a heavily limited rate.
is_visible: bool, throttled: bool,
/// The requested URL of the load. /// The requested URL of the load.
#[no_trace] #[no_trace]
url: ServoUrl, url: ServoUrl,
@ -250,7 +250,7 @@ impl InProgressLoad {
opener, opener,
window_size, window_size,
activity: DocumentActivity::FullyActive, activity: DocumentActivity::FullyActive,
is_visible: true, throttled: false,
url, url,
origin, origin,
navigation_start: navigation_start as u64, navigation_start: navigation_start as u64,
@ -1832,8 +1832,8 @@ impl ScriptThread {
SetScrollState(id, ..) => Some(id), SetScrollState(id, ..) => Some(id),
GetTitle(id) => Some(id), GetTitle(id) => Some(id),
SetDocumentActivity(id, ..) => Some(id), SetDocumentActivity(id, ..) => Some(id),
ChangeFrameVisibilityStatus(id, ..) => Some(id), SetThrottled(id, ..) => Some(id),
NotifyVisibilityChange(id, ..) => Some(id), SetThrottledInContainingIframe(id, ..) => Some(id),
NavigateIframe(id, ..) => Some(id), NavigateIframe(id, ..) => Some(id),
PostMessage { target: id, .. } => Some(id), PostMessage { target: id, .. } => Some(id),
UpdatePipelineId(_, _, _, id, _) => Some(id), UpdatePipelineId(_, _, _, id, _) => Some(id),
@ -1991,17 +1991,17 @@ impl ScriptThread {
ConstellationControlMsg::SetDocumentActivity(pipeline_id, activity) => { ConstellationControlMsg::SetDocumentActivity(pipeline_id, activity) => {
self.handle_set_document_activity_msg(pipeline_id, activity) self.handle_set_document_activity_msg(pipeline_id, activity)
}, },
ConstellationControlMsg::ChangeFrameVisibilityStatus(pipeline_id, visible) => { ConstellationControlMsg::SetThrottled(pipeline_id, throttled) => {
self.handle_visibility_change_msg(pipeline_id, visible) self.handle_set_throttled_msg(pipeline_id, throttled)
}, },
ConstellationControlMsg::NotifyVisibilityChange( ConstellationControlMsg::SetThrottledInContainingIframe(
parent_pipeline_id, parent_pipeline_id,
browsing_context_id, browsing_context_id,
visible, throttled,
) => self.handle_visibility_change_complete_msg( ) => self.handle_set_throttled_in_containing_iframe_msg(
parent_pipeline_id, parent_pipeline_id,
browsing_context_id, browsing_context_id,
visible, throttled,
), ),
ConstellationControlMsg::PostMessage { ConstellationControlMsg::PostMessage {
target: target_pipeline_id, target: target_pipeline_id,
@ -2556,45 +2556,44 @@ impl ScriptThread {
} }
/// Updates iframe element after a change in visibility /// Updates iframe element after a change in visibility
fn handle_visibility_change_complete_msg( fn handle_set_throttled_in_containing_iframe_msg(
&self, &self,
parent_pipeline_id: PipelineId, parent_pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId, browsing_context_id: BrowsingContextId,
visible: bool, throttled: bool,
) { ) {
let iframe = self let iframe = self
.documents .documents
.borrow() .borrow()
.find_iframe(parent_pipeline_id, browsing_context_id); .find_iframe(parent_pipeline_id, browsing_context_id);
if let Some(iframe) = iframe { if let Some(iframe) = iframe {
iframe.change_visibility_status(visible); iframe.set_throttled(throttled);
} }
} }
/// Handle visibility change message fn handle_set_throttled_msg(&self, id: PipelineId, throttled: bool) {
fn handle_visibility_change_msg(&self, id: PipelineId, visible: bool) {
// Separate message sent since parent script thread could be different (Iframe of different // Separate message sent since parent script thread could be different (Iframe of different
// domain) // domain)
self.script_sender self.script_sender
.send((id, ScriptMsg::VisibilityChangeComplete(visible))) .send((id, ScriptMsg::SetThrottledComplete(throttled)))
.unwrap(); .unwrap();
let window = self.documents.borrow().find_window(id); let window = self.documents.borrow().find_window(id);
match window { match window {
Some(window) => { Some(window) => {
window.alter_resource_utilization(visible); window.set_throttled(throttled);
return; return;
}, },
None => { None => {
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_visible = visible; load.throttled = throttled;
return; return;
} }
}, },
} }
warn!("change visibility message sent to nonexistent pipeline"); warn!("SetThrottled sent to nonexistent pipeline");
} }
/// Handles activity change message /// Handles activity change message
@ -3435,8 +3434,8 @@ impl ScriptThread {
window.suspend(); window.suspend();
} }
if !incomplete.is_visible { if incomplete.throttled {
window.alter_resource_utilization(false); window.set_throttled(true);
} }
document.get_current_parser().unwrap() document.get_current_parser().unwrap()

View file

@ -81,8 +81,8 @@ pub enum CompositorMsg {
CreatePng(Option<Rect<f32, CSSPixel>>, IpcSender<Option<Image>>), CreatePng(Option<Rect<f32, CSSPixel>>, IpcSender<Option<Image>>),
/// A reply to the compositor asking if the output image is stable. /// A reply to the compositor asking if the output image is stable.
IsReadyToSaveImageReply(bool), IsReadyToSaveImageReply(bool),
/// Pipeline visibility changed /// Set whether to use less resources by stopping animations.
PipelineVisibilityChanged(PipelineId, bool), SetThrottled(PipelineId, bool),
/// WebRender has produced a new frame. This message informs the compositor that /// WebRender has produced a new frame. This message informs the compositor that
/// the frame is ready, so that it may trigger a recomposite. /// the frame is ready, so that it may trigger a recomposite.
NewWebRenderFrameReady(bool /* composite_needed */), NewWebRenderFrameReady(bool /* composite_needed */),
@ -157,7 +157,7 @@ impl Debug for CompositorMsg {
CompositorMsg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"), CompositorMsg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"),
CompositorMsg::CreatePng(..) => write!(f, "CreatePng"), CompositorMsg::CreatePng(..) => write!(f, "CreatePng"),
CompositorMsg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"), CompositorMsg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"),
CompositorMsg::PipelineVisibilityChanged(..) => write!(f, "PipelineVisibilityChanged"), CompositorMsg::SetThrottled(..) => write!(f, "SetThrottled"),
CompositorMsg::PipelineExited(..) => write!(f, "PipelineExited"), CompositorMsg::PipelineExited(..) => write!(f, "PipelineExited"),
CompositorMsg::NewWebRenderFrameReady(..) => write!(f, "NewWebRenderFrameReady"), CompositorMsg::NewWebRenderFrameReady(..) => write!(f, "NewWebRenderFrameReady"),
CompositorMsg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"), CompositorMsg::PendingPaintMetric(..) => write!(f, "PendingPaintMetric"),

View file

@ -312,11 +312,10 @@ pub enum ConstellationControlMsg {
GetTitle(PipelineId), GetTitle(PipelineId),
/// Notifies script thread of a change to one of its document's activity /// Notifies script thread of a change to one of its document's activity
SetDocumentActivity(PipelineId, DocumentActivity), SetDocumentActivity(PipelineId, DocumentActivity),
/// Notifies script thread whether frame is visible /// Set whether to use less resources by running timers at a heavily limited rate.
ChangeFrameVisibilityStatus(PipelineId, bool), SetThrottled(PipelineId, bool),
/// Notifies script thread that frame visibility change is complete /// Notify the containing iframe (in PipelineId) that the nested browsing context (BrowsingContextId) is throttled.
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context SetThrottledInContainingIframe(PipelineId, BrowsingContextId, bool),
NotifyVisibilityChange(PipelineId, BrowsingContextId, bool),
/// Notifies script thread that a url should be loaded in this iframe. /// Notifies script thread that a url should be loaded in this iframe.
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
NavigateIframe( NavigateIframe(
@ -416,8 +415,8 @@ impl fmt::Debug for ConstellationControlMsg {
SetScrollState(..) => "SetScrollState", SetScrollState(..) => "SetScrollState",
GetTitle(..) => "GetTitle", GetTitle(..) => "GetTitle",
SetDocumentActivity(..) => "SetDocumentActivity", SetDocumentActivity(..) => "SetDocumentActivity",
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus", SetThrottled(..) => "SetThrottled",
NotifyVisibilityChange(..) => "NotifyVisibilityChange", SetThrottledInContainingIframe(..) => "SetThrottledInContainingIframe",
NavigateIframe(..) => "NavigateIframe", NavigateIframe(..) => "NavigateIframe",
PostMessage { .. } => "PostMessage", PostMessage { .. } => "PostMessage",
UpdatePipelineId(..) => "UpdatePipelineId", UpdatePipelineId(..) => "UpdatePipelineId",

View file

@ -215,8 +215,8 @@ pub enum ScriptMsg {
/// Notification that this iframe should be removed. /// Notification that this iframe should be removed.
/// Returns a list of pipelines which were closed. /// Returns a list of pipelines which were closed.
RemoveIFrame(BrowsingContextId, IpcSender<Vec<PipelineId>>), RemoveIFrame(BrowsingContextId, IpcSender<Vec<PipelineId>>),
/// Notifies constellation that an iframe's visibility has been changed. /// Successful response to [crate::ConstellationControlMsg::SetThrottled].
VisibilityChangeComplete(bool), SetThrottledComplete(bool),
/// A load has been requested in an IFrame. /// A load has been requested in an IFrame.
ScriptLoadedURLInIFrame(IFrameLoadInfoWithData), ScriptLoadedURLInIFrame(IFrameLoadInfoWithData),
/// A load of the initial `about:blank` has been completed in an IFrame. /// A load of the initial `about:blank` has been completed in an IFrame.
@ -304,7 +304,7 @@ impl fmt::Debug for ScriptMsg {
ReplaceHistoryState(..) => "ReplaceHistoryState", ReplaceHistoryState(..) => "ReplaceHistoryState",
JointSessionHistoryLength(..) => "JointSessionHistoryLength", JointSessionHistoryLength(..) => "JointSessionHistoryLength",
RemoveIFrame(..) => "RemoveIFrame", RemoveIFrame(..) => "RemoveIFrame",
VisibilityChangeComplete(..) => "VisibilityChangeComplete", SetThrottledComplete(..) => "SetThrottledComplete",
ScriptLoadedURLInIFrame(..) => "ScriptLoadedURLInIFrame", ScriptLoadedURLInIFrame(..) => "ScriptLoadedURLInIFrame",
ScriptNewIFrame(..) => "ScriptNewIFrame", ScriptNewIFrame(..) => "ScriptNewIFrame",
ScriptNewAuxiliary(..) => "ScriptNewAuxiliary", ScriptNewAuxiliary(..) => "ScriptNewAuxiliary",