Skip to content

Commit

Permalink
Implement non-visible pipeline and iframe visibility methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jmr0 committed Jun 16, 2016
1 parent ce88b8e commit 2bff131
Show file tree
Hide file tree
Showing 14 changed files with 383 additions and 25 deletions.
29 changes: 22 additions & 7 deletions components/compositing/compositor.rs
Expand Up @@ -290,6 +290,9 @@ 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
visible: bool,
} }


impl PipelineDetails { impl PipelineDetails {
Expand All @@ -299,6 +302,7 @@ impl PipelineDetails {
current_epoch: Epoch(0), current_epoch: Epoch(0),
animations_running: false, animations_running: false,
animation_callbacks_running: false, animation_callbacks_running: false,
visible: true,
} }
} }
} }
Expand Down Expand Up @@ -760,6 +764,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
reports_chan.send(reports); reports_chan.send(reports);
} }


(Msg::PipelineVisibilityChanged(pipeline_id, visible), ShutdownState::NotShuttingDown) => {
self.pipeline_details(pipeline_id).visible = visible;
if visible {
self.process_animations();
}
}

(Msg::PipelineExited(pipeline_id, sender), _) => { (Msg::PipelineExited(pipeline_id, sender), _) => {
debug!("Compositor got pipeline exited: {:?}", pipeline_id); debug!("Compositor got pipeline exited: {:?}", pipeline_id);
self.pending_subpages.remove(&pipeline_id); self.pending_subpages.remove(&pipeline_id);
Expand Down Expand Up @@ -795,13 +806,16 @@ impl<Window: WindowMethods> IOCompositor<Window> {
animation_state: AnimationState) { animation_state: AnimationState) {
match animation_state { match animation_state {
AnimationState::AnimationsPresent => { AnimationState::AnimationsPresent => {
let visible = self.pipeline_details(pipeline_id).visible;
self.pipeline_details(pipeline_id).animations_running = true; self.pipeline_details(pipeline_id).animations_running = true;
self.composite_if_necessary(CompositingReason::Animation); if visible {
self.composite_if_necessary(CompositingReason::Animation);
}
} }
AnimationState::AnimationCallbacksPresent => { AnimationState::AnimationCallbacksPresent => {
if !self.pipeline_details(pipeline_id).animation_callbacks_running { let visible = self.pipeline_details(pipeline_id).visible;
self.pipeline_details(pipeline_id).animation_callbacks_running = self.pipeline_details(pipeline_id).animation_callbacks_running = true;
true; if visible {
self.tick_animations_for_pipeline(pipeline_id); self.tick_animations_for_pipeline(pipeline_id);
} }
} }
Expand Down Expand Up @@ -1712,9 +1726,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn process_animations(&mut self) { fn process_animations(&mut self) {
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 || if (pipeline_details.animations_running ||
pipeline_details.animation_callbacks_running { pipeline_details.animation_callbacks_running) &&
pipeline_ids.push(*pipeline_id); pipeline_details.visible {
pipeline_ids.push(*pipeline_id);
} }
} }
for pipeline_id in &pipeline_ids { for pipeline_id in &pipeline_ids {
Expand Down
3 changes: 3 additions & 0 deletions components/compositing/compositor_thread.rs
Expand Up @@ -183,6 +183,8 @@ pub enum Msg {
ResizeTo(Size2D<u32>), ResizeTo(Size2D<u32>),
/// Get scroll offset of a layer /// Get scroll offset of a layer
GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>), GetScrollOffset(PipelineId, LayerId, IpcSender<Point2D<f32>>),
/// Pipeline visibility changed
PipelineVisibilityChanged(PipelineId, bool),
/// A pipeline was shut down. /// A pipeline was shut down.
// This message acts as a synchronization point between the constellation, // This message acts as a synchronization point between the constellation,
// when it shuts down a pipeline, to the compositor; when the compositor // when it shuts down a pipeline, to the compositor; when the compositor
Expand Down Expand Up @@ -223,6 +225,7 @@ impl Debug for Msg {
Msg::GetClientWindow(..) => write!(f, "GetClientWindow"), Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
Msg::MoveTo(..) => write!(f, "MoveTo"), Msg::MoveTo(..) => write!(f, "MoveTo"),
Msg::ResizeTo(..) => write!(f, "ResizeTo"), Msg::ResizeTo(..) => write!(f, "ResizeTo"),
Msg::PipelineVisibilityChanged(..) => write!(f, "PipelineVisibilityChanged"),
Msg::PipelineExited(..) => write!(f, "PipelineExited"), Msg::PipelineExited(..) => write!(f, "PipelineExited"),
Msg::GetScrollOffset(..) => write!(f, "GetScrollOffset"), Msg::GetScrollOffset(..) => write!(f, "GetScrollOffset"),
} }
Expand Down
47 changes: 46 additions & 1 deletion components/constellation/constellation.rs
Expand Up @@ -407,6 +407,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
load_data: LoadData) { load_data: LoadData) {
if self.shutting_down { return; } 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 { let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState {
id: pipeline_id, id: pipeline_id,
parent_info: parent_info, parent_info: parent_info,
Expand All @@ -427,6 +433,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
load_data: load_data, load_data: load_data,
device_pixel_ratio: self.window_size.device_pixel_ratio, device_pixel_ratio: self.window_size.device_pixel_ratio,
pipeline_namespace_id: self.next_pipeline_namespace_id(), pipeline_namespace_id: self.next_pipeline_namespace_id(),
parent_visibility: parent_visibility,
webrender_api_sender: self.webrender_api_sender.clone(), webrender_api_sender: self.webrender_api_sender.clone(),
}); });


Expand Down Expand Up @@ -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) => { FromScriptMsg::RemoveIFrame(pipeline_id, sender) => {
debug!("constellation got remove iframe message"); debug!("constellation got remove iframe message");
self.handle_remove_iframe_msg(pipeline_id); self.handle_remove_iframe_msg(pipeline_id);
Expand Down Expand Up @@ -943,7 +958,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let window_size = self.window_size.visible_viewport; let window_size = self.window_size.visible_viewport;
let root_pipeline_id = PipelineId::new(); let root_pipeline_id = PipelineId::new();
debug_assert!(PipelineId::fake_root_pipeline_id() == root_pipeline_id); 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.handle_load_start_msg(&root_pipeline_id);
self.push_pending_frame(root_pipeline_id, None); self.push_pending_frame(root_pipeline_id, None);
self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url)); self.compositor_proxy.send(ToCompositorMsg::ChangePageUrl(root_pipeline_id, url));
Expand Down Expand Up @@ -1482,6 +1498,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( fn handle_create_canvas_paint_thread_msg(
&mut self, &mut self,
size: &Size2D<i32>, size: &Size2D<i32>,
Expand Down
30 changes: 28 additions & 2 deletions components/constellation/pipeline.rs
Expand Up @@ -65,6 +65,9 @@ pub struct Pipeline {
pub running_animations: bool, pub running_animations: bool,
pub children: Vec<FrameId>, pub children: Vec<FrameId>,
pub is_private: bool, 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. /// Initial setup data needed to construct a pipeline.
Expand Down Expand Up @@ -112,6 +115,8 @@ pub struct InitialPipelineState {
pub load_data: LoadData, pub load_data: LoadData,
/// The ID of the pipeline namespace for this script thread. /// The ID of the pipeline namespace for this script thread.
pub pipeline_namespace_id: PipelineNamespaceId, pub pipeline_namespace_id: PipelineNamespaceId,
/// Pipeline visibility is inherited from parent
pub parent_visibility: Option<bool>,
/// Optional webrender api (if enabled). /// Optional webrender api (if enabled).
pub webrender_api_sender: Option<webrender_traits::RenderApiSender>, pub webrender_api_sender: Option<webrender_traits::RenderApiSender>,
} }
Expand Down Expand Up @@ -250,7 +255,10 @@ impl Pipeline {
state.compositor_proxy, state.compositor_proxy,
chrome_to_paint_chan, chrome_to_paint_chan,
state.load_data.url, state.load_data.url,
state.window_size); state.window_size,
state.parent_visibility.unwrap_or(true));

pipeline.notify_visibility();


Ok((pipeline, child_process)) Ok((pipeline, child_process))
} }
Expand All @@ -262,7 +270,8 @@ impl Pipeline {
compositor_proxy: Box<CompositorProxy + 'static + Send>, compositor_proxy: Box<CompositorProxy + 'static + Send>,
chrome_to_paint_chan: Sender<ChromeToPaintMsg>, chrome_to_paint_chan: Sender<ChromeToPaintMsg>,
url: Url, url: Url,
size: Option<TypedSize2D<PagePx, f32>>) size: Option<TypedSize2D<PagePx, f32>>,
visible: bool)
-> Pipeline { -> Pipeline {
Pipeline { Pipeline {
id: id, id: id,
Expand All @@ -277,6 +286,7 @@ impl Pipeline {
size: size, size: size,
running_animations: false, running_animations: false,
is_private: false, is_private: false,
visible: visible,
} }
} }


Expand Down Expand Up @@ -367,6 +377,22 @@ impl Pipeline {
warn!("Sending mozbrowser event to script failed ({}).", e); 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)] #[derive(Deserialize, Serialize)]
Expand Down
54 changes: 53 additions & 1 deletion components/script/dom/htmliframeelement.rs
Expand Up @@ -11,12 +11,13 @@ use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementLocat
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenTabEventDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenTabEventDetail;
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenWindowEventDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementOpenWindowEventDetail;
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementSecurityChangeDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementSecurityChangeDetail;
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserElementVisibilityChangeEventDetail;
use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail; use dom::bindings::codegen::Bindings::BrowserElementBinding::BrowserShowModalPromptEventDetail;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding; use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods; use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::inheritance::Castable; use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, LayoutJS}; use dom::bindings::js::{Root, LayoutJS};
Expand Down Expand Up @@ -66,6 +67,7 @@ pub struct HTMLIFrameElement {
subpage_id: Cell<Option<SubpageId>>, subpage_id: Cell<Option<SubpageId>>,
sandbox: Cell<Option<u8>>, sandbox: Cell<Option<u8>>,
load_blocker: DOMRefCell<Option<LoadBlocker>>, load_blocker: DOMRefCell<Option<LoadBlocker>>,
visibility: Cell<bool>,
} }


impl HTMLIFrameElement { impl HTMLIFrameElement {
Expand Down Expand Up @@ -196,6 +198,7 @@ impl HTMLIFrameElement {
subpage_id: Cell::new(None), subpage_id: Cell::new(None),
sandbox: Cell::new(None), sandbox: Cell::new(None),
load_blocker: DOMRefCell::new(None), load_blocker: DOMRefCell::new(None),
visibility: Cell::new(true),
} }
} }


Expand All @@ -221,6 +224,26 @@ impl HTMLIFrameElement {
self.pipeline_id.get() self.pipeline_id.get()
} }


pub fn change_visibility_status(&self, visibility: bool) {
if self.visibility.get() != visibility {
self.visibility.set(visibility);

// Visibility changes are only exposed to Mozbrowser iframes
if self.Mozbrowser() {
self.dispatch_mozbrowser_event(MozBrowserEvent::VisibilityChange(visibility));
}
}
}

pub fn set_visible(&self, visible: bool) {
if let Some(pipeline_id) = self.pipeline_id.get() {
let window = window_from_node(self);
let window = window.r();
let msg = ConstellationMsg::SetVisible(pipeline_id, visible);
window.constellation_chan().send(msg).unwrap();
}
}

/// https://html.spec.whatwg.org/multipage/#iframe-load-event-steps steps 1-4 /// https://html.spec.whatwg.org/multipage/#iframe-load-event-steps steps 1-4
pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) { pub fn iframe_load_event_steps(&self, loaded_pipeline: PipelineId) {
// TODO(#9592): assert that the load blocker is present at all times when we // TODO(#9592): assert that the load blocker is present at all times when we
Expand Down Expand Up @@ -387,6 +410,11 @@ impl MozBrowserEventDetailBuilder for HTMLIFrameElement {
returnValue: Some(DOMString::from(return_value)), returnValue: Some(DOMString::from(return_value)),
}.to_jsval(cx, rval) }.to_jsval(cx, rval)
} }
MozBrowserEvent::VisibilityChange(visibility) => {
BrowserElementVisibilityChangeEventDetail {
visible: Some(visibility),
}.to_jsval(cx, rval);
}
} }
} }
} }
Expand Down Expand Up @@ -498,6 +526,30 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement {
} }
} }


// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/setVisible
fn SetVisible(&self, visible: bool) -> ErrorResult {
if self.Mozbrowser() {
self.set_visible(visible);
Ok(())
} else {
debug!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top
level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)");
Err(Error::NotSupported)
}
}

// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/getVisible
fn GetVisible(&self) -> Fallible<bool> {
if self.Mozbrowser() {
Ok(self.visibility.get())
} else {
debug!("this frame is not mozbrowser: mozbrowser attribute missing, or not a top
level window, or mozbrowser preference not set (use --pref dom.mozbrowser.enabled)");
Err(Error::NotSupported)
}
}


// https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/stop // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/stop
fn Stop(&self) -> ErrorResult { fn Stop(&self) -> ErrorResult {
Err(Error::NotSupported) Err(Error::NotSupported)
Expand Down
22 changes: 13 additions & 9 deletions components/script/dom/webidls/BrowserElement.webidl
Expand Up @@ -96,20 +96,24 @@ dictionary BrowserElementOpenWindowEventDetail {
// Element frameElement; // Element frameElement;
}; };


dictionary BrowserElementVisibilityChangeEventDetail {
boolean visible;
};

BrowserElement implements BrowserElementCommon; BrowserElement implements BrowserElementCommon;
BrowserElement implements BrowserElementPrivileged; BrowserElement implements BrowserElementPrivileged;


[NoInterfaceObject] [NoInterfaceObject]
interface BrowserElementCommon { interface BrowserElementCommon {
//[Throws, [Throws,
// Pref="dom.mozBrowserFramesEnabled", Pref="dom.mozbrowser.enabled",
// CheckAnyPermissions="browser embed-widgets"] CheckAnyPermissions="browser embed-widgets"]
//void setVisible(boolean visible); void setVisible(boolean visible);


//[Throws, [Throws,
// Pref="dom.mozBrowserFramesEnabled", Pref="dom.mozbrowser.enabled",
// CheckAnyPermissions="browser embed-widgets"] CheckAnyPermissions="browser embed-widgets"]
//DOMRequest getVisible(); boolean getVisible();


//[Throws, //[Throws,
// Pref="dom.mozBrowserFramesEnabled", // Pref="dom.mozBrowserFramesEnabled",
Expand Down
8 changes: 8 additions & 0 deletions components/script/dom/window.rs
Expand Up @@ -1477,6 +1477,14 @@ impl Window {
self.timers.suspend(); self.timers.suspend();
} }


pub fn slow_down_timers(&self) {
self.timers.slow_down();
}

pub fn speed_up_timers(&self) {
self.timers.speed_up();
}

pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool { pub fn need_emit_timeline_marker(&self, timeline_type: TimelineMarkerType) -> bool {
let markers = self.devtools_markers.borrow(); let markers = self.devtools_markers.borrow();
markers.contains(&timeline_type) markers.contains(&timeline_type)
Expand Down

0 comments on commit 2bff131

Please sign in to comment.