mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #10225 - jmr0:visibility_api, r=jdm
Implement non-visible pipeline and iframe visibility methods This addresses #9566 and a good part of #9751, specifically: * Pipeline has a notion of visibility * IFrame setVisible/getVisible interface with IFrame's pipeline visibility * IFrame mozbrowservisibilitychange responds to changes in visibility * Pipeline visibility is used to limit animations (requestAnimationFrame does not tick animations when hidden) and to increase timer intervals (currently set to a minimum of 1 second while hidden) Absent for now are any changes to the Document API and general implementation of the Page Visibility API, since the more interesting parts require knowledge of whether the user agent is minimized, OS screen locked, etc. cc @paulrouget @jdm <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10225) <!-- Reviewable:end -->
This commit is contained in:
commit
d620ab71c4
14 changed files with 382 additions and 24 deletions
|
@ -407,6 +407,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
load_data: LoadData) {
|
||||
if self.shutting_down { return; }
|
||||
|
||||
let parent_visibility = if let Some((parent_pipeline_id, _, _)) = parent_info {
|
||||
self.pipelines.get(&parent_pipeline_id).map(|pipeline| pipeline.visible)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState {
|
||||
id: pipeline_id,
|
||||
parent_info: parent_info,
|
||||
|
@ -427,6 +433,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
load_data: load_data,
|
||||
device_pixel_ratio: self.window_size.device_pixel_ratio,
|
||||
pipeline_namespace_id: self.next_pipeline_namespace_id(),
|
||||
parent_visibility: parent_visibility,
|
||||
webrender_api_sender: self.webrender_api_sender.clone(),
|
||||
});
|
||||
|
||||
|
@ -710,6 +717,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
}
|
||||
FromScriptMsg::SetVisible(pipeline_id, visible) => {
|
||||
debug!("constellation got set visible messsage");
|
||||
self.handle_set_visible_msg(pipeline_id, visible);
|
||||
}
|
||||
FromScriptMsg::VisibilityChangeComplete(pipeline_id, visible) => {
|
||||
debug!("constellation got set visibility change complete message");
|
||||
self.handle_visibility_change_complete(pipeline_id, visible);
|
||||
}
|
||||
FromScriptMsg::RemoveIFrame(pipeline_id, sender) => {
|
||||
debug!("constellation got remove iframe message");
|
||||
self.handle_remove_iframe_msg(pipeline_id);
|
||||
|
@ -949,7 +964,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
let window_size = self.window_size.visible_viewport;
|
||||
let root_pipeline_id = PipelineId::new();
|
||||
debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id);
|
||||
self.new_pipeline(root_pipeline_id, None, Some(window_size), None, LoadData::new(url.clone(), None, None));
|
||||
self.new_pipeline(root_pipeline_id, None, Some(window_size), None,
|
||||
LoadData::new(url.clone(), None, None));
|
||||
self.handle_load_start_msg(&root_pipeline_id);
|
||||
self.push_pending_frame(root_pipeline_id, None);
|
||||
self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url));
|
||||
|
@ -1488,6 +1504,35 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_set_visible_msg(&mut self, pipeline_id: PipelineId, visible: bool) {
|
||||
let frame_id = self.pipeline_to_frame_map.get(&pipeline_id).map(|frame_id| *frame_id);
|
||||
let child_pipeline_ids: Vec<PipelineId> = self.current_frame_tree_iter(frame_id)
|
||||
.map(|frame| frame.current)
|
||||
.collect();
|
||||
for id in child_pipeline_ids {
|
||||
if let Some(pipeline) = self.pipelines.get_mut(&id) {
|
||||
pipeline.change_visibility(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_visibility_change_complete(&mut self, pipeline_id: PipelineId, visibility: bool) {
|
||||
let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info);
|
||||
if let Some((parent_pipeline_id, _, _)) = parent_pipeline_info {
|
||||
let visibility_msg = ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id,
|
||||
pipeline_id,
|
||||
visibility);
|
||||
let result = match self.pipelines.get(&parent_pipeline_id) {
|
||||
None => return warn!("Parent pipeline {:?} closed", parent_pipeline_id),
|
||||
Some(parent_pipeline) => parent_pipeline.script_chan.send(visibility_msg),
|
||||
};
|
||||
|
||||
if let Err(e) = result {
|
||||
self.handle_send_error(parent_pipeline_id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_create_canvas_paint_thread_msg(
|
||||
&mut self,
|
||||
size: &Size2D<i32>,
|
||||
|
|
|
@ -65,6 +65,9 @@ pub struct Pipeline {
|
|||
pub running_animations: bool,
|
||||
pub children: Vec<FrameId>,
|
||||
pub is_private: bool,
|
||||
/// Whether this pipeline should be treated as visible for the purposes of scheduling and
|
||||
/// resource management.
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
/// Initial setup data needed to construct a pipeline.
|
||||
|
@ -112,6 +115,8 @@ pub struct InitialPipelineState {
|
|||
pub load_data: LoadData,
|
||||
/// The ID of the pipeline namespace for this script thread.
|
||||
pub pipeline_namespace_id: PipelineNamespaceId,
|
||||
/// Pipeline visibility is inherited from parent
|
||||
pub parent_visibility: Option<bool>,
|
||||
/// Optional webrender api (if enabled).
|
||||
pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
|
||||
}
|
||||
|
@ -250,7 +255,10 @@ impl Pipeline {
|
|||
state.compositor_proxy,
|
||||
chrome_to_paint_chan,
|
||||
state.load_data.url,
|
||||
state.window_size);
|
||||
state.window_size,
|
||||
state.parent_visibility.unwrap_or(true));
|
||||
|
||||
pipeline.notify_visibility();
|
||||
|
||||
Ok((pipeline, child_process))
|
||||
}
|
||||
|
@ -262,7 +270,8 @@ impl Pipeline {
|
|||
compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||
chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
|
||||
url: Url,
|
||||
size: Option<TypedSize2D<PagePx, f32>>)
|
||||
size: Option<TypedSize2D<PagePx, f32>>,
|
||||
visible: bool)
|
||||
-> Pipeline {
|
||||
Pipeline {
|
||||
id: id,
|
||||
|
@ -277,6 +286,7 @@ impl Pipeline {
|
|||
size: size,
|
||||
running_animations: false,
|
||||
is_private: false,
|
||||
visible: visible,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,6 +377,22 @@ impl Pipeline {
|
|||
warn!("Sending mozbrowser event to script failed ({}).", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_visibility(&self) {
|
||||
self.script_chan.send(ConstellationControlMsg::ChangeFrameVisibilityStatus(self.id, self.visible))
|
||||
.expect("Pipeline script chan");
|
||||
|
||||
self.compositor_proxy.send(CompositorMsg::PipelineVisibilityChanged(self.id, self.visible));
|
||||
}
|
||||
|
||||
pub fn change_visibility(&mut self, visible: bool) {
|
||||
if visible == self.visible {
|
||||
return;
|
||||
}
|
||||
self.visible = visible;
|
||||
self.notify_visibility();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue