diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index c6e7c16052f..d183b95b7ff 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -31,7 +31,7 @@ use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use layout_traits::{LayoutControlChan, LayoutThreadFactory}; use msg::constellation_msg::WebDriverCommandMsg; -use msg::constellation_msg::{FrameId, PipelineId}; +use msg::constellation_msg::{FrameId, FrameType, PipelineId}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationDirection}; use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType}; @@ -419,7 +419,7 @@ impl Constellation /// Helper function for creating a pipeline fn new_pipeline(&mut self, pipeline_id: PipelineId, - parent_info: Option<(PipelineId, SubpageId)>, + parent_info: Option<(PipelineId, SubpageId, FrameType)>, initial_window_size: Option>, script_channel: Option>, load_data: LoadData) { @@ -1084,7 +1084,7 @@ impl Constellation // Create the new pipeline, attached to the parent and push to pending frames self.new_pipeline(load_info.new_pipeline_id, - Some((load_info.containing_pipeline_id, load_info.new_subpage_id)), + Some((load_info.containing_pipeline_id, load_info.new_subpage_id, load_info.frame_type)), window_size, script_chan, load_data); @@ -1136,15 +1136,15 @@ impl Constellation .and_then(|root_frame_id| self.frames.get(&root_frame_id)) .map(|root_frame| root_frame.current); - let ancestor_info = self.get_root_pipeline_and_containing_parent(&pipeline_id); - if let Some(ancestor_info) = ancestor_info { - if root_pipeline_id == Some(ancestor_info.0) { + let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id); + if let Some((ancestor_id, subpage_id)) = ancestor_info { + if root_pipeline_id == Some(ancestor_id) { match root_pipeline_id.and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) { Some(root_pipeline) => { // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsershowmodalprompt let event = MozBrowserEvent::ShowModalPrompt("alert".to_owned(), "Alert".to_owned(), String::from(message), "".to_owned()); - root_pipeline.trigger_mozbrowser_event(ancestor_info.1, event); + root_pipeline.trigger_mozbrowser_event(subpage_id, event); } None => return warn!("Alert sent to Pipeline {:?} after closure.", root_pipeline_id), } @@ -1177,7 +1177,7 @@ impl Constellation // requested change so it can update its internal state. let parent_info = self.pipelines.get(&source_id).and_then(|source| source.parent_info); match parent_info { - Some((parent_pipeline_id, subpage_id)) => { + Some((parent_pipeline_id, subpage_id, _)) => { self.handle_load_start_msg(&source_id); // Message the constellation to find the script thread for this iframe // and issue an iframe load through there. @@ -1358,7 +1358,7 @@ impl Constellation None => return warn!("Pipeline {:?} navigated to after closure.", next_pipeline_id), Some(pipeline) => match pipeline.parent_info { None => return warn!("Pipeline {:?} has no parent info.", next_pipeline_id), - Some((_, new_subpage_id)) => new_subpage_id, + Some((_, new_subpage_id, _)) => new_subpage_id, }, }; let msg = ConstellationControlMsg::UpdateSubpageId(parent_pipeline_id, @@ -1463,7 +1463,7 @@ impl Constellation Some(pipeline) => pipeline.parent_info, None => return warn!("Pipeline {:?} focus parent after closure.", pipeline_id), }; - let (containing_pipeline_id, subpage_id) = match parent_info { + let (containing_pipeline_id, subpage_id, _) = match parent_info { Some(info) => info, None => return warn!("Pipeline {:?} focus has no parent.", pipeline_id), }; @@ -1630,7 +1630,7 @@ impl Constellation // If a child frame, add it to the parent pipeline. Otherwise // it must surely be the root frame being created! match self.pipelines.get(&frame_change.new_pipeline_id).and_then(|pipeline| pipeline.parent_info) { - Some((parent_id, _)) => { + Some((parent_id, _, _)) => { if let Some(parent) = self.pipelines.get_mut(&parent_id) { parent.add_child(frame_id); } @@ -1881,15 +1881,21 @@ impl Constellation /// Checks whether the pipeline or its ancestors are private #[allow(dead_code)] - fn check_is_pipeline_private(&self, pipeline_id: PipelineId) -> bool { - let mut pipeline_id = Some(pipeline_id); - while let Some(pipeline) = pipeline_id.and_then(|id| self.pipelines.get(&id)) { - if pipeline.is_private { - return true; + fn check_is_pipeline_private(&self, mut pipeline_id: PipelineId) -> bool { + loop { + match self.pipelines.get(&pipeline_id) { + Some(pipeline) if pipeline.is_private => return true, + Some(pipeline) => match pipeline.parent_info { + None => return false, + Some((_, _, FrameType::MozBrowserIFrame)) => return false, + Some((parent_id, _, _)) => pipeline_id = parent_id, + }, + None => { + warn!("Finding private ancestor for pipeline {} after closure.", pipeline_id); + return false; + }, } - pipeline_id = pipeline.parent_info.map(|(parent_pipeline_id, _)| parent_pipeline_id); } - false } // Close a frame (and all children) @@ -1922,7 +1928,7 @@ impl Constellation warn!("Closing frame {:?} twice.", frame_id); } - if let Some((parent_pipeline_id, _)) = parent_info { + if let Some((parent_pipeline_id, _, _)) = parent_info { let parent_pipeline = match self.pipelines.get_mut(&parent_pipeline_id) { None => return warn!("Pipeline {:?} child closed after parent.", parent_pipeline_id), Some(parent_pipeline) => parent_pipeline, @@ -1958,8 +1964,8 @@ impl Constellation }; // If a child pipeline, remove from subpage map - if let Some(info) = pipeline.parent_info { - self.subpage_map.remove(&info); + if let Some((parent_id, subpage_id, _)) = pipeline.parent_info { + self.subpage_map.remove(&(parent_id, subpage_id)); } // Remove assocation between this pipeline and its holding frame @@ -2062,42 +2068,37 @@ impl Constellation } } - /// For a given pipeline, determine the iframe in the root pipeline that transitively contains + /// For a given pipeline, determine the mozbrowser iframe that transitively contains /// it. There could be arbitrary levels of nested iframes in between them. - fn get_root_pipeline_and_containing_parent(&self, pipeline_id: &PipelineId) -> Option<(PipelineId, SubpageId)> { - if let Some(pipeline) = self.pipelines.get(pipeline_id) { - if let Some(mut ancestor_info) = pipeline.parent_info { - if let Some(mut ancestor) = self.pipelines.get(&ancestor_info.0) { - while let Some(next_info) = ancestor.parent_info { - ancestor_info = next_info; - ancestor = match self.pipelines.get(&ancestor_info.0) { - Some(ancestor) => ancestor, - None => { - warn!("Get parent pipeline before root via closed pipeline {:?}.", ancestor_info.0); - return None; - }, - }; - } - return Some(ancestor_info); - } + fn get_mozbrowser_ancestor_info(&self, mut pipeline_id: PipelineId) -> Option<(PipelineId, SubpageId)> { + loop { + match self.pipelines.get(&pipeline_id) { + Some(pipeline) => match pipeline.parent_info { + Some((parent_id, subpage_id, FrameType::MozBrowserIFrame)) => return Some((parent_id, subpage_id)), + Some((parent_id, _, _)) => pipeline_id = parent_id, + None => return None, + }, + None => { + warn!("Finding mozbrowser ancestor for pipeline {} after closure.", pipeline_id); + return None; + }, } } - None } // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange - // Note that this is a no-op if the pipeline is not an immediate child iframe of the root + // Note that this is a no-op if the pipeline is not a mozbrowser iframe fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) { if !prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { return; } let event_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| { - pipeline.parent_info.map(|(containing_pipeline_id, subpage_id)| { - (containing_pipeline_id, subpage_id, pipeline.url.to_string()) + pipeline.parent_info.map(|(containing_pipeline_id, subpage_id, frame_type)| { + (containing_pipeline_id, subpage_id, frame_type, pipeline.url.to_string()) }) }); - // If this is an iframe, then send the event with new url - if let Some((containing_pipeline_id, subpage_id, url)) = event_info { + // If this is a mozbrowser iframe, then send the event with new url + if let Some((containing_pipeline_id, subpage_id, FrameType::MozBrowserIFrame, url)) = event_info { if let Some(parent_pipeline) = self.pipelines.get(&containing_pipeline_id) { if let Some(frame_id) = self.pipeline_to_frame_map.get(&pipeline_id) { if let Some(frame) = self.frames.get(&frame_id) { @@ -2116,7 +2117,7 @@ impl Constellation fn trigger_mozbrowsererror(&self, pipeline_id: PipelineId, reason: String, backtrace: String) { if !prefs::get_pref("dom.mozbrowser.enabled").as_boolean().unwrap_or(false) { return; } - let ancestor_info = self.get_root_pipeline_and_containing_parent(&pipeline_id); + let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id); if let Some(ancestor_info) = ancestor_info { match self.pipelines.get(&ancestor_info.0) { diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index b0a321cd5f9..a5f9d952a1b 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -14,7 +14,7 @@ use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layers::geometry::DevicePixel; use layout_traits::{LayoutControlChan, LayoutThreadFactory}; -use msg::constellation_msg::{FrameId, LoadData, PanicMsg, PipelineId}; +use msg::constellation_msg::{FrameId, FrameType, LoadData, PanicMsg, PipelineId}; use msg::constellation_msg::{PipelineNamespaceId, SubpageId, WindowSizeData}; use net_traits::ResourceThreads; use net_traits::bluetooth_thread::BluetoothMethodMsg; @@ -38,7 +38,7 @@ use webrender_traits; /// A uniquely-identifiable pipeline of script thread, layout thread, and paint thread. pub struct Pipeline { pub id: PipelineId, - pub parent_info: Option<(PipelineId, SubpageId)>, + pub parent_info: Option<(PipelineId, SubpageId, FrameType)>, pub script_chan: IpcSender, /// A channel to layout, for performing reflows and shutdown. pub layout_chan: LayoutControlChan, @@ -68,7 +68,7 @@ pub struct InitialPipelineState { pub id: PipelineId, /// The subpage ID of this pipeline to create in its pipeline parent. /// If `None`, this is the root. - pub parent_info: Option<(PipelineId, SubpageId)>, + pub parent_info: Option<(PipelineId, SubpageId, FrameType)>, /// A channel to the associated constellation. pub constellation_chan: IpcSender, /// A channel for the layout thread to send messages to the constellation. @@ -156,7 +156,7 @@ impl Pipeline { let (script_chan, script_port, pipeline_port) = match state.script_chan { Some(script_chan) => { - let (containing_pipeline_id, subpage_id) = + let (containing_pipeline_id, subpage_id, _) = state.parent_info.expect("script_pipeline != None but subpage_id == None"); let new_layout_info = NewLayoutInfo { containing_pipeline_id: containing_pipeline_id, @@ -198,7 +198,7 @@ impl Pipeline { let unprivileged_pipeline_content = UnprivilegedPipelineContent { id: state.id, - parent_info: state.parent_info, + parent_info: state.parent_info.map(|(parent_id, subpage_id, _)| (parent_id, subpage_id)), constellation_chan: state.constellation_chan, scheduler_chan: state.scheduler_chan, devtools_chan: script_to_devtools_chan, @@ -246,7 +246,7 @@ impl Pipeline { } pub fn new(id: PipelineId, - parent_info: Option<(PipelineId, SubpageId)>, + parent_info: Option<(PipelineId, SubpageId, FrameType)>, script_chan: IpcSender, layout_chan: LayoutControlChan, compositor_proxy: Box, diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 543e4277f23..81229505653 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -344,6 +344,12 @@ impl fmt::Display for PipelineId { #[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct SubpageId(pub u32); +#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] +pub enum FrameType { + IFrame, + MozBrowserIFrame, +} + /// [Policies](https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states) /// for providing a referrer header for a request #[derive(HeapSizeOf, Clone, Deserialize, Serialize)] diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index e97e5cb923d..4a1c781a293 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -56,7 +56,7 @@ use js::jsval::JSVal; use js::rust::Runtime; use layout_interface::{LayoutChan, LayoutRPC}; use libc; -use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy}; +use msg::constellation_msg::{FrameType, PipelineId, SubpageId, WindowSizeData, WindowSizeType, ReferrerPolicy}; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread}; use net_traits::response::HttpsState; @@ -290,7 +290,7 @@ no_jsmanaged_fields!(PropertyDeclarationBlock); no_jsmanaged_fields!(HashSet); // These three are interdependent, if you plan to put jsmanaged data // in one of these make sure it is propagated properly to containing structs -no_jsmanaged_fields!(SubpageId, WindowSizeData, WindowSizeType, PipelineId); +no_jsmanaged_fields!(FrameType, SubpageId, WindowSizeData, WindowSizeType, PipelineId); no_jsmanaged_fields!(TimerEventId, TimerSource); no_jsmanaged_fields!(WorkerId); no_jsmanaged_fields!(QuirksMode); diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 8cec0aa6659..3913d46b884 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -34,7 +34,7 @@ use ipc_channel::ipc; use js::jsapi::{JSAutoCompartment, RootedValue, JSContext, MutableHandleValue}; use js::jsval::{UndefinedValue, NullValue}; use layout_interface::ReflowQueryType; -use msg::constellation_msg::{LoadData, NavigationDirection, PipelineId, SubpageId}; +use msg::constellation_msg::{FrameType, LoadData, NavigationDirection, PipelineId, SubpageId}; use net_traits::response::HttpsState; use script_traits::IFrameSandboxState::{IFrameSandboxed, IFrameUnsandboxed}; use script_traits::{IFrameLoadInfo, MozBrowserEvent, ScriptMsg as ConstellationMsg}; @@ -123,6 +123,7 @@ impl HTMLIFrameElement { let (new_subpage_id, old_subpage_id) = self.generate_new_subpage_id(); let new_pipeline_id = self.pipeline_id.get().unwrap(); let private_iframe = self.privatebrowsing(); + let frame_type = if self.Mozbrowser() { FrameType::MozBrowserIFrame } else { FrameType::IFrame }; let load_info = IFrameLoadInfo { load_data: load_data, @@ -132,6 +133,7 @@ impl HTMLIFrameElement { new_pipeline_id: new_pipeline_id, sandbox: sandboxed, is_private: private_iframe, + frame_type: frame_type, }; window.constellation_chan() .send(ConstellationMsg::ScriptLoadedURLInIFrame(load_info)) diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index b68d24616bc..529fc6ad715 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -41,7 +41,7 @@ use gfx_traits::Epoch; use gfx_traits::LayerId; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use libc::c_void; -use msg::constellation_msg::{FrameId, Key, KeyModifiers, KeyState, LoadData}; +use msg::constellation_msg::{FrameId, FrameType, Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{NavigationDirection, PanicMsg, PipelineId}; use msg::constellation_msg::{PipelineNamespaceId, SubpageId, WindowSizeData}; use msg::constellation_msg::{WebDriverCommandMsg, WindowSizeType}; @@ -372,6 +372,8 @@ pub struct IFrameLoadInfo { pub sandbox: IFrameSandboxState, /// Whether this iframe should be considered private pub is_private: bool, + /// Whether this iframe is a mozbrowser iframe + pub frame_type: FrameType, } // https://developer.mozilla.org/en-US/docs/Web/API/Using_the_Browser_API#Events