diff options
author | Alan Jeffrey <ajeffrey@mozilla.com> | 2017-05-15 16:09:49 -0500 |
---|---|---|
committer | Alan Jeffrey <ajeffrey@mozilla.com> | 2017-05-22 09:27:07 -0500 |
commit | 42577365b7924d0af64033d852447ff61579da3a (patch) | |
tree | 107d4646c361a97a1e72e7ccf13fa9370ebea06b | |
parent | b428a94326322c88da4c32e56ee753ceeffca7d1 (diff) | |
download | servo-42577365b7924d0af64033d852447ff61579da3a.tar.gz servo-42577365b7924d0af64033d852447ff61579da3a.zip |
Added a TopLevelBrowsingContextId type.
-rw-r--r-- | components/constellation/browsingcontext.rs | 16 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 297 | ||||
-rw-r--r-- | components/constellation/pipeline.rs | 11 | ||||
-rw-r--r-- | components/layout_thread/lib.rs | 18 | ||||
-rw-r--r-- | components/layout_traits/lib.rs | 5 | ||||
-rw-r--r-- | components/msg/constellation_msg.rs | 37 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 5 | ||||
-rw-r--r-- | components/script/dom/dedicatedworkerglobalscope.rs | 6 | ||||
-rw-r--r-- | components/script/dom/document.rs | 18 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 92 | ||||
-rw-r--r-- | components/script/dom/node.rs | 2 | ||||
-rw-r--r-- | components/script/dom/windowproxy.rs | 25 | ||||
-rw-r--r-- | components/script/script_thread.rs | 78 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 21 | ||||
-rw-r--r-- | components/script_traits/script_msg.rs | 4 |
15 files changed, 404 insertions, 231 deletions
diff --git a/components/constellation/browsingcontext.rs b/components/constellation/browsingcontext.rs index 5f6f29aecf6..a75ed4900bd 100644 --- a/components/constellation/browsingcontext.rs +++ b/components/constellation/browsingcontext.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use euclid::size::TypedSize2D; -use msg::constellation_msg::{BrowsingContextId, PipelineId}; +use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, PipelineId}; use pipeline::Pipeline; use script_traits::LoadData; use std::collections::HashMap; @@ -23,6 +23,9 @@ pub struct BrowsingContext { /// The browsing context id. pub id: BrowsingContextId, + /// The top-level browsing context ancestor + pub top_level_id: TopLevelBrowsingContextId, + /// The size of the frame. pub size: Option<TypedSize2D<f32, CSSPixel>>, @@ -45,9 +48,15 @@ pub struct BrowsingContext { impl BrowsingContext { /// Create a new browsing context. /// Note this just creates the browsing context, it doesn't add it to the constellation's set of browsing contexts. - pub fn new(id: BrowsingContextId, pipeline_id: PipelineId, load_data: LoadData) -> BrowsingContext { + pub fn new(id: BrowsingContextId, + top_level_id: TopLevelBrowsingContextId, + pipeline_id: PipelineId, + load_data: LoadData) + -> BrowsingContext + { BrowsingContext { id: id, + top_level_id: top_level_id, size: None, pipeline_id: pipeline_id, instant: Instant::now(), @@ -118,6 +127,9 @@ pub struct SessionHistoryChange { /// The browsing context to change. pub browsing_context_id: BrowsingContextId, + /// The top-level browsing context ancestor. + pub top_level_browsing_context_id: TopLevelBrowsingContextId, + /// The pipeline for the document being loaded. pub new_pipeline_id: PipelineId, diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index c16ff8c2049..7567b3d12cd 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -87,7 +87,7 @@ use ipc_channel::router::ROUTER; use itertools::Itertools; use layout_traits::LayoutThreadFactory; use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord}; -use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId}; +use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection}; use net_traits::{self, IpcSend, ResourceThreads}; @@ -227,14 +227,14 @@ pub struct Constellation<Message, LTF, STF> { /// event loop for each registered domain name (aka eTLD+1) in /// each top-level browsing context. We store the event loops in a map /// indexed by top-level browsing context id - /// (as a `BrowsingContextId`) and registered + /// (as a `TopLevelBrowsingContextId`) and registered /// domain name (as a `Host`) to event loops. This double /// indirection ensures that separate tabs do not share event /// loops, even if the same domain is loaded in each. /// It is important that scripts with the same eTLD+1 /// share an event loop, since they can use `document.domain` /// to become same-origin, at which point they can share DOM objects. - event_loops: HashMap<BrowsingContextId, HashMap<Host, Weak<EventLoop>>>, + event_loops: HashMap<TopLevelBrowsingContextId, HashMap<Host, Weak<EventLoop>>>, /// The set of all the pipelines in the browser. /// (See the `pipeline` module for more details.) @@ -251,7 +251,7 @@ pub struct Constellation<Message, LTF, STF> { pending_changes: Vec<SessionHistoryChange>, /// The root browsing context. - root_browsing_context_id: BrowsingContextId, + root_browsing_context_id: TopLevelBrowsingContextId, /// The currently focused pipeline for key events. focus_pipeline_id: Option<PipelineId>, @@ -395,7 +395,7 @@ impl Log for FromScriptLogger { fn log(&self, record: &LogRecord) { if let Some(entry) = log_entry(record) { debug!("Sending log entry {:?}.", entry); - let top_level_id = BrowsingContextId::installed(); + let top_level_id = TopLevelBrowsingContextId::installed(); let thread_name = thread::current().name().map(ToOwned::to_owned); let msg = FromScriptMsg::LogEntry(top_level_id, thread_name, entry); let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); @@ -433,7 +433,7 @@ impl Log for FromCompositorLogger { fn log(&self, record: &LogRecord) { if let Some(entry) = log_entry(record) { debug!("Sending log entry {:?}.", entry); - let top_level_id = BrowsingContextId::installed(); + let top_level_id = TopLevelBrowsingContextId::installed(); let thread_name = thread::current().name().map(ToOwned::to_owned); let msg = FromCompositorMsg::LogEntry(top_level_id, thread_name, entry); let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner()); @@ -524,7 +524,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> pending_changes: vec!(), // We initialize the namespace at 1, since we reserved namespace 0 for the constellation next_pipeline_namespace_id: PipelineNamespaceId(1), - root_browsing_context_id: BrowsingContextId::new(), + root_browsing_context_id: TopLevelBrowsingContextId::new(), focus_pipeline_id: None, time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, @@ -580,6 +580,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn new_pipeline(&mut self, pipeline_id: PipelineId, browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, parent_info: Option<(PipelineId, FrameType)>, initial_window_size: Option<TypedSize2D<f32, CSSPixel>>, // TODO: we have to provide ownership of the LoadData @@ -591,15 +592,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> is_private: bool) { if self.shutting_down { return; } - // TODO: can we get a case where the child pipeline is created - // before the parent is part of the frame tree? - let top_level_id = match parent_info { - Some((_, FrameType::MozBrowserIFrame)) => browsing_context_id, - Some((parent_id, _)) => self.get_top_level_browsing_context_for_pipeline(parent_id), - None => self.root_browsing_context_id, - }; - - debug!("Creating new pipeline {} in top-level browsing context {}.", pipeline_id, top_level_id); + debug!("Creating new pipeline {} in browsing context {}.", pipeline_id, browsing_context_id); let (event_loop, host) = match sandbox { IFrameSandboxState::IFrameSandboxed => (None, None), @@ -610,7 +603,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> match reg_host(&load_data.url) { None => (None, None), Some(host) => { - let event_loop = self.event_loops.get(&top_level_id) + let event_loop = self.event_loops.get(&top_level_browsing_context_id) .and_then(|map| map.get(&host)) .and_then(|weak| weak.upgrade()); match event_loop { @@ -646,14 +639,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> .map(|pipeline| pipeline.visible) .or(parent_visibility); - // TODO: think about the case where the child pipeline is created - // before the parent is part of the frame tree. - let top_level_browsing_context_id = match parent_info { - Some((_, FrameType::MozBrowserIFrame)) => browsing_context_id, - Some((parent_id, _)) => self.get_top_level_browsing_context_for_pipeline(parent_id), - None => self.root_browsing_context_id, - }; - let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState { id: pipeline_id, browsing_context_id: browsing_context_id, @@ -697,11 +682,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.pipelines.insert(pipeline_id, pipeline); } - /// Get an iterator for browsing contexts. Specify self.root_browsing context_id to - /// iterate the entire tree, or a specific browsing context id to iterate only that sub-tree. - /// Iterates over the fully active browsing contexts in the tree. - fn fully_active_browsing_contexts_iter(&self, browsing_context_id: BrowsingContextId) - -> FullyActiveBrowsingContextsIterator + /// Get an iterator for the fully active browsing contexts in a subtree. + fn fully_active_descendant_browsing_contexts_iter(&self, browsing_context_id: BrowsingContextId) + -> FullyActiveBrowsingContextsIterator { FullyActiveBrowsingContextsIterator { stack: vec!(browsing_context_id), @@ -710,11 +693,16 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - /// Get an iterator for browsing contexts. Specify self.root_browsing_context_id to - /// iterate the entire tree, or a specific browsing context id to iterate only that sub-tree. - /// Iterates over all browsing contexts in the tree. - fn all_browsing_contexts_iter(&self, browsing_context_id: BrowsingContextId) - -> AllBrowsingContextsIterator + /// Get an iterator for the fully active browsing contexts in a tree. + fn fully_active_browsing_contexts_iter(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) + -> FullyActiveBrowsingContextsIterator + { + self.fully_active_descendant_browsing_contexts_iter(BrowsingContextId::from(top_level_browsing_context_id)) + } + + /// Get an iterator for the browsing contexts in a subtree. + fn all_descendant_browsing_contexts_iter(&self, browsing_context_id: BrowsingContextId) + -> AllBrowsingContextsIterator { AllBrowsingContextsIterator { stack: vec!(browsing_context_id), @@ -723,28 +711,35 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } + /// Get an iterator for the browsing contexts in a tree. + fn all_browsing_contexts_iter(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) + -> AllBrowsingContextsIterator + { + self.all_descendant_browsing_contexts_iter(BrowsingContextId::from(top_level_browsing_context_id)) + } + /// The joint session future is the merge of the session future of every /// browsing_context, sorted chronologically. - fn joint_session_future<'a>(&'a self, browsing_context_id: BrowsingContextId) + fn joint_session_future<'a>(&'a self, top_level_browsing_context_id: TopLevelBrowsingContextId) -> impl Iterator<Item = &'a SessionHistoryEntry> + 'a { - self.all_browsing_contexts_iter(browsing_context_id) + self.all_browsing_contexts_iter(top_level_browsing_context_id) .map(|browsing_context| browsing_context.next.iter().rev()) .kmerge_by(|a, b| a.instant.cmp(&b.instant) == Ordering::Less) } /// Is the joint session future empty? - fn joint_session_future_is_empty(&self, browsing_context_id: BrowsingContextId) -> bool { - self.all_browsing_contexts_iter(browsing_context_id) + fn joint_session_future_is_empty(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) -> bool { + self.all_browsing_contexts_iter(top_level_browsing_context_id) .all(|browsing_context| browsing_context.next.is_empty()) } /// The joint session past is the merge of the session past of every /// browsing_context, sorted reverse chronologically. - fn joint_session_past<'a>(&'a self, browsing_context_id: BrowsingContextId) + fn joint_session_past<'a>(&'a self, top_level_browsing_context_id: TopLevelBrowsingContextId) -> impl Iterator<Item = &'a SessionHistoryEntry> + 'a { - self.all_browsing_contexts_iter(browsing_context_id) + self.all_browsing_contexts_iter(top_level_browsing_context_id) .map(|browsing_context| browsing_context.prev.iter().rev() .scan(browsing_context.instant, |prev_instant, entry| { let instant = *prev_instant; @@ -756,17 +751,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } /// Is the joint session past empty? - fn joint_session_past_is_empty(&self, browsing_context_id: BrowsingContextId) -> bool { - self.all_browsing_contexts_iter(browsing_context_id) + fn joint_session_past_is_empty(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) -> bool { + self.all_browsing_contexts_iter(top_level_browsing_context_id) .all(|browsing_context| browsing_context.prev.is_empty()) } /// Create a new browsing context and update the internal bookkeeping. fn new_browsing_context(&mut self, browsing_context_id: BrowsingContextId, + top_level_id: TopLevelBrowsingContextId, pipeline_id: PipelineId, load_data: LoadData) { - let browsing_context = BrowsingContext::new(browsing_context_id, pipeline_id, load_data); + let browsing_context = BrowsingContext::new(browsing_context_id, top_level_id, pipeline_id, load_data); self.browsing_contexts.insert(browsing_context_id, browsing_context); // If a child browsing_context, add it to the parent pipeline. @@ -1187,7 +1183,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // TODO: exit before the root browsing context is initialized? debug!("Removing root browsing context."); - let root_browsing_context_id = self.root_browsing_context_id; + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); self.close_browsing_context(root_browsing_context_id, ExitPipelineMode::Normal); // Close any pending changes and pipelines @@ -1289,12 +1285,17 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IpcError) { // Treat send error the same as receiving a panic message debug!("Pipeline {:?} send error ({}).", pipeline_id, err); - let top_level_browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id); + let top_level_browsing_context_id = self.pipelines.get(&pipeline_id) + .map(|pipeline| pipeline.browsing_context_id) + .and_then(|browsing_context_id| self.browsing_contexts.get(&browsing_context_id)) + .map(|browsing_context| browsing_context.top_level_id) + .unwrap_or(self.root_browsing_context_id); let reason = format!("Send failed ({})", err); self.handle_panic(top_level_browsing_context_id, reason, None); } - fn handle_panic(&mut self, top_level_browsing_context_id: BrowsingContextId, + fn handle_panic(&mut self, + top_level_browsing_context_id: TopLevelBrowsingContextId, reason: String, backtrace: Option<String>) { @@ -1307,11 +1308,13 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> debug!("Panic handler for top-level browsing context {}: {}.", top_level_browsing_context_id, reason); + let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); + // Notify the browser chrome that the pipeline has failed self.trigger_mozbrowsererror(top_level_browsing_context_id, reason, backtrace); let (window_size, pipeline_id) = { - let browsing_context = self.browsing_contexts.get(&top_level_browsing_context_id); + let browsing_context = self.browsing_contexts.get(&browsing_context_id); let window_size = browsing_context.and_then(|browsing_context| browsing_context.size); let pipeline_id = browsing_context.map(|browsing_context| browsing_context.pipeline_id); (window_size, pipeline_id) @@ -1324,7 +1327,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> (pipeline_url, parent_info) }; - self.close_browsing_context_children(top_level_browsing_context_id, + self.close_browsing_context_children(browsing_context_id, DiscardBrowsingContext::No, ExitPipelineMode::Force); @@ -1341,10 +1344,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let new_pipeline_id = PipelineId::new(); let load_data = LoadData::new(failure_url, None, None, None); let sandbox = IFrameSandboxState::IFrameSandboxed; - self.new_pipeline(new_pipeline_id, top_level_browsing_context_id, parent_info, + self.new_pipeline(new_pipeline_id, browsing_context_id, top_level_browsing_context_id, parent_info, window_size, load_data.clone(), sandbox, false); self.pending_changes.push(SessionHistoryChange { - browsing_context_id: top_level_browsing_context_id, + top_level_browsing_context_id: top_level_browsing_context_id, + browsing_context_id: browsing_context_id, new_pipeline_id: new_pipeline_id, load_data: load_data, replace_instant: None, @@ -1352,7 +1356,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_log_entry(&mut self, - top_level_browsing_context_id: Option<BrowsingContextId>, + top_level_browsing_context_id: Option<TopLevelBrowsingContextId>, thread_name: Option<String>, entry: LogEntry) { @@ -1391,6 +1395,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let load_data = LoadData::new(url.clone(), None, None, None); let sandbox = IFrameSandboxState::IFrameUnsandboxed; self.new_pipeline(root_pipeline_id, + BrowsingContextId::from(root_browsing_context_id), root_browsing_context_id, None, Some(window_size), @@ -1399,7 +1404,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> false); self.handle_load_start_msg(root_pipeline_id); self.pending_changes.push(SessionHistoryChange { - browsing_context_id: self.root_browsing_context_id, + top_level_browsing_context_id: root_browsing_context_id, + browsing_context_id: BrowsingContextId::from(root_browsing_context_id), new_pipeline_id: root_pipeline_id, load_data: load_data, replace_instant: None, @@ -1407,14 +1413,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_iframe_size_msg(&mut self, - iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>) { + iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>) { for (browsing_context_id, size) in iframe_sizes { let window_size = WindowSizeData { initial_viewport: size, device_pixel_ratio: self.window_size.device_pixel_ratio, }; - self.resize_frame(window_size, WindowSizeType::Initial, browsing_context_id); + self.resize_browsing_context(window_size, WindowSizeType::Initial, browsing_context_id); } } @@ -1482,6 +1488,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Create the new pipeline, attached to the parent and push to pending changes self.pending_changes.push(SessionHistoryChange { + top_level_browsing_context_id: load_info.info.top_level_browsing_context_id, browsing_context_id: load_info.info.browsing_context_id, new_pipeline_id: load_info.info.new_pipeline_id, load_data: load_data.clone(), @@ -1490,6 +1497,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.new_pipeline(load_info.info.new_pipeline_id, load_info.info.browsing_context_id, + load_info.info.top_level_browsing_context_id, Some((load_info.info.parent_pipeline_id, load_info.info.frame_type)), window_size, load_data, @@ -1506,6 +1514,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> frame_type, replace, browsing_context_id, + top_level_browsing_context_id, is_private, } = load_info; @@ -1543,6 +1552,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.pipelines.insert(new_pipeline_id, pipeline); self.pending_changes.push(SessionHistoryChange { + top_level_browsing_context_id: top_level_browsing_context_id, browsing_context_id: browsing_context_id, new_pipeline_id: new_pipeline_id, load_data: load_data, @@ -1596,13 +1606,16 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let title = String::from("Alert"); let return_value = String::from(""); let event = MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value); - let top_level_browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id); + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + let top_level_browsing_context_id = self.pipelines.get(&pipeline_id) + .and_then(|pipeline| self.browsing_contexts.get(&pipeline.browsing_context_id)) + .map(|browsing_context| browsing_context.top_level_id); - match self.browsing_contexts.get(&self.root_browsing_context_id) { + match self.browsing_contexts.get(&root_browsing_context_id) { None => warn!("Alert sent after root browsing context closure."), Some(root_browsing_context) => match self.pipelines.get(&root_browsing_context.pipeline_id) { None => warn!("Alert sent after root pipeline closure."), - Some(pipeline) => pipeline.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event), + Some(pipeline) => pipeline.trigger_mozbrowser_event(top_level_browsing_context_id, event), } } } @@ -1665,7 +1678,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Make sure no pending page would be overridden. for change in &self.pending_changes { - if change.browsing_context_id == root_browsing_context_id { + if change.browsing_context_id == BrowsingContextId::from(root_browsing_context_id) { // id that sent load msg is being changed already; abort return None; } @@ -1684,7 +1697,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // changes would be overridden by changing the subframe associated with source_id. // Create the new pipeline - let window_size = self.browsing_contexts.get(&root_browsing_context_id) + let window_size = self.browsing_contexts.get(&BrowsingContextId::from(root_browsing_context_id)) .and_then(|browsing_context| browsing_context.size); let new_pipeline_id = PipelineId::new(); let sandbox = IFrameSandboxState::IFrameUnsandboxed; @@ -1694,12 +1707,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> None }; self.pending_changes.push(SessionHistoryChange { - browsing_context_id: root_browsing_context_id, + top_level_browsing_context_id: root_browsing_context_id, + browsing_context_id: BrowsingContextId::from(root_browsing_context_id), new_pipeline_id: new_pipeline_id, load_data: load_data.clone(), replace_instant: replace_instant, }); self.new_pipeline(new_pipeline_id, + BrowsingContextId::from(root_browsing_context_id), root_browsing_context_id, None, window_size, @@ -1735,7 +1750,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> pipeline_id: Option<PipelineId>, direction: TraversalDirection) { let top_level_browsing_context_id = pipeline_id - .map(|pipeline_id| self.get_top_level_browsing_context_for_pipeline(pipeline_id)) + .and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) + .and_then(|pipeline| self.browsing_contexts.get(&pipeline.browsing_context_id)) + .map(|browsing_context| browsing_context.top_level_id) .unwrap_or(self.root_browsing_context_id); let mut size = 0; @@ -1768,11 +1785,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) { - let browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id); + let top_level_browsing_context_id = self.pipelines.get(&pipeline_id) + .and_then(|pipeline| self.browsing_contexts.get(&pipeline.browsing_context_id)) + .map(|browsing_context| browsing_context.top_level_id) + .unwrap_or(self.root_browsing_context_id); // Initialize length at 1 to count for the current active entry let mut length = 1; - for browsing_context in self.all_browsing_contexts_iter(browsing_context_id) { + for browsing_context in self.all_browsing_contexts_iter(top_level_browsing_context_id) { length += browsing_context.next.len(); length += browsing_context.prev.len(); } @@ -1783,7 +1803,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Send to the explicitly focused pipeline (if it exists), or the root // browsing context's current pipeline. If neither exist, fall back to sending to // the compositor below. - let root_pipeline_id = self.browsing_contexts.get(&self.root_browsing_context_id) + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + let root_pipeline_id = self.browsing_contexts.get(&root_browsing_context_id) .map(|root_browsing_context| root_browsing_context.pipeline_id); let pipeline_id = self.focus_pipeline_id.or(root_pipeline_id); @@ -1808,7 +1829,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_reload_msg(&mut self) { // Send Reload constellation msg to root script channel. - let root_pipeline_id = self.browsing_contexts.get(&self.root_browsing_context_id) + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + let root_pipeline_id = self.browsing_contexts.get(&root_browsing_context_id) .map(|root_browsing_context| root_browsing_context.pipeline_id); if let Some(pipeline_id) = root_pipeline_id { @@ -1862,9 +1884,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // and pass the event to that script thread. // If the pipeline lookup fails, it is because we have torn down the pipeline, // so it is reasonable to silently ignore the event. - let browsing_context_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.browsing_context_id); + let top_level_browsing_context_id = self.pipelines.get(&pipeline_id) + .and_then(|pipeline| self.browsing_contexts.get(&pipeline.browsing_context_id)) + .map(|browsing_context| browsing_context.top_level_id); match self.pipelines.get(&parent_pipeline_id) { - Some(pipeline) => pipeline.trigger_mozbrowser_event(browsing_context_id, event), + Some(pipeline) => pipeline.trigger_mozbrowser_event(top_level_browsing_context_id, event), None => warn!("Pipeline {:?} handling mozbrowser event after closure.", parent_pipeline_id), } } @@ -1872,7 +1896,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_get_pipeline(&mut self, browsing_context_id: Option<BrowsingContextId>, resp_chan: IpcSender<Option<PipelineId>>) { - let browsing_context_id = browsing_context_id.unwrap_or(self.root_browsing_context_id); + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + let browsing_context_id = browsing_context_id.unwrap_or(root_browsing_context_id); let current_pipeline_id = self.browsing_contexts.get(&browsing_context_id) .map(|browsing_context| browsing_context.pipeline_id); let pipeline_id_loaded = self.pending_changes.iter().rev() @@ -1924,7 +1949,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } fn handle_remove_iframe_msg(&mut self, browsing_context_id: BrowsingContextId) -> Vec<PipelineId> { - let result = self.all_browsing_contexts_iter(browsing_context_id) + let result = self.all_descendant_browsing_contexts_iter(browsing_context_id) .flat_map(|browsing_context| browsing_context.next.iter().chain(browsing_context.prev.iter()) .filter_map(|entry| entry.pipeline_id) .chain(once(browsing_context.pipeline_id))) @@ -1939,7 +1964,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> None => return warn!("No browsing context associated with pipeline {:?}", pipeline_id), }; - let child_pipeline_ids: Vec<PipelineId> = self.all_browsing_contexts_iter(browsing_context_id) + let child_pipeline_ids: Vec<PipelineId> = self.all_descendant_browsing_contexts_iter(browsing_context_id) .flat_map(|browsing_context| browsing_context.prev.iter().chain(browsing_context.next.iter()) .filter_map(|entry| entry.pipeline_id) .chain(once(browsing_context.pipeline_id))) @@ -2042,7 +2067,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } }, WebDriverCommandMsg::TakeScreenshot(pipeline_id, reply) => { - let current_pipeline_id = self.browsing_contexts.get(&self.root_browsing_context_id) + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + let current_pipeline_id = self.browsing_contexts.get(&root_browsing_context_id) .map(|root_browsing_context| root_browsing_context.pipeline_id); if Some(pipeline_id) == current_pipeline_id { self.compositor_proxy.send(ToCompositorMsg::CreatePng(reply)); @@ -2071,16 +2097,25 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> let sandbox = IFrameSandboxState::IFrameUnsandboxed; let new_pipeline_id = PipelineId::new(); let load_data = entry.load_data; - let (parent_info, window_size, is_private) = match self.browsing_contexts.get(&browsing_context_id) { + let (top_level_id, parent_info, window_size, is_private) = + match self.browsing_contexts.get(&browsing_context_id) + { Some(browsing_context) => match self.pipelines.get(&browsing_context.pipeline_id) { - Some(pipeline) => (pipeline.parent_info, browsing_context.size, pipeline.is_private), - None => (None, browsing_context.size, false), + Some(pipeline) => (browsing_context.top_level_id, + pipeline.parent_info, + browsing_context.size, + pipeline.is_private), + None => (browsing_context.top_level_id, + None, + browsing_context.size, + false), }, None => return warn!("no browsing context to traverse"), }; - self.new_pipeline(new_pipeline_id, browsing_context_id, parent_info, + self.new_pipeline(new_pipeline_id, browsing_context_id, top_level_id, parent_info, window_size, load_data.clone(), sandbox, is_private); self.pending_changes.push(SessionHistoryChange { + top_level_browsing_context_id: top_level_id, browsing_context_id: browsing_context_id, new_pipeline_id: new_pipeline_id, load_data: load_data, @@ -2095,9 +2130,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // frame tree is modified below. let update_focus_pipeline = self.focused_pipeline_is_descendant_of(entry.browsing_context_id); - let (old_pipeline_id, replaced_pipeline_id) = match self.browsing_contexts.get_mut(&browsing_context_id) { + let (old_pipeline_id, replaced_pipeline_id, top_level_id) = + match self.browsing_contexts.get_mut(&browsing_context_id) + { Some(browsing_context) => { let old_pipeline_id = browsing_context.pipeline_id; + let top_level_id = browsing_context.top_level_id; let mut curr_entry = browsing_context.current(); if entry.instant > browsing_context.instant { @@ -2122,7 +2160,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> browsing_context.update_current(pipeline_id, entry); - (old_pipeline_id, replaced_pipeline_id) + (old_pipeline_id, replaced_pipeline_id, top_level_id) }, None => return warn!("no browsing context to traverse"), }; @@ -2147,7 +2185,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Deactivate the old pipeline, and activate the new one. self.update_activity(old_pipeline_id); self.update_activity(pipeline_id); - self.notify_history_changed(pipeline_id); + self.notify_history_changed(top_level_id); // Set paint permissions correctly for the compositor layers. self.send_frame_tree(); @@ -2171,14 +2209,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn notify_history_changed(&self, pipeline_id: PipelineId) { + fn notify_history_changed(&self, top_level_browsing_context_id: TopLevelBrowsingContextId) { // Send a flat projection of the history. // The final vector is a concatenation of the LoadData of the past entries, // the current entry and the future entries. // LoadData of inner frames are ignored and replaced with the LoadData of the parent. - let top_level_browsing_context_id = self.get_top_level_browsing_context_for_pipeline(pipeline_id); - // Ignore LoadData of non-top-level browsing contexts. let keep_load_data_if_top_browsing_context = |entry: &SessionHistoryEntry| { match entry.pipeline_id { @@ -2206,7 +2242,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> Some(load_data) }; - let current_load_data = match self.browsing_contexts.get(&top_level_browsing_context_id) { + let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); + let current_load_data = match self.browsing_contexts.get(&browsing_context_id) { Some(browsing_context) => browsing_context.load_data.clone(), None => return warn!("notify_history_changed error after top-level browsing context closed."), }; @@ -2229,27 +2266,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.compositor_proxy.send(ToCompositorMsg::HistoryChanged(entries, current_index)); } - fn get_top_level_browsing_context_for_pipeline(&self, mut pipeline_id: PipelineId) -> BrowsingContextId { - if PREFS.is_mozbrowser_enabled() { - loop { - match self.pipelines.get(&pipeline_id) { - Some(pipeline) => match pipeline.parent_info { - Some((_, FrameType::MozBrowserIFrame)) => return pipeline.browsing_context_id, - Some((parent_id, _)) => pipeline_id = parent_id, - None => return self.root_browsing_context_id, - }, - None => { - warn!("Finding top-level ancestor for pipeline {} after closure.", pipeline_id); - return self.root_browsing_context_id; - }, - } - } - } else { - // If mozbrowser is not enabled, the root browsing context is the only top-level browsing context - self.root_browsing_context_id - } - } - fn load_url_for_webdriver(&mut self, pipeline_id: PipelineId, load_data: LoadData, @@ -2301,10 +2317,11 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> if new_context { self.new_browsing_context(change.browsing_context_id, + change.top_level_browsing_context_id, change.new_pipeline_id, change.load_data); self.update_activity(change.new_pipeline_id); - self.notify_history_changed(change.new_pipeline_id); + self.notify_history_changed(change.top_level_browsing_context_id); }; if let Some(old_pipeline_id) = navigated { @@ -2312,9 +2329,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.update_activity(old_pipeline_id); self.update_activity(change.new_pipeline_id); // Clear the joint session future - let top_level_id = self.get_top_level_browsing_context_for_pipeline(change.new_pipeline_id); - self.clear_joint_session_future(top_level_id); - self.notify_history_changed(change.new_pipeline_id); + self.clear_joint_session_future(change.top_level_browsing_context_id); + self.notify_history_changed(change.top_level_browsing_context_id); } if location_changed { @@ -2356,8 +2372,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn handle_window_size_msg(&mut self, new_size: WindowSizeData, size_type: WindowSizeType) { debug!("handle_window_size_msg: {:?}", new_size.initial_viewport.to_untyped()); - let browsing_context_id = self.root_browsing_context_id; - self.resize_frame(new_size, size_type, browsing_context_id); + let browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + self.resize_browsing_context(new_size, size_type, browsing_context_id); if let Some(resize_channel) = self.webdriver.resize_channel.take() { let _ = resize_channel.send(new_size); @@ -2386,7 +2402,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // // If there is no root browsing context yet, the initial page has // not loaded, so there is nothing to save yet. - if !self.browsing_contexts.contains_key(&self.root_browsing_context_id) { + if !self.browsing_contexts.contains_key(&BrowsingContextId::from(self.root_browsing_context_id)) { return ReadyToSave::NoRootBrowsingContext; } @@ -2530,12 +2546,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> self.set_activity(pipeline_id, self.get_activity(pipeline_id)); } - /// Handle updating the size of a frame. This notifies every pipeline in the frame of the new - /// size. - fn resize_frame(&mut self, - new_size: WindowSizeData, - size_type: WindowSizeType, - browsing_context_id: BrowsingContextId) + /// Handle updating the size of a browsing context. + /// This notifies every pipeline in the context of the new size. + fn resize_browsing_context(&mut self, + new_size: WindowSizeData, + size_type: WindowSizeType, + browsing_context_id: BrowsingContextId) { if let Some(browsing_context) = self.browsing_contexts.get_mut(&browsing_context_id) { browsing_context.size = Some(new_size.initial_viewport); @@ -2582,8 +2598,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } } - fn clear_joint_session_future(&mut self, browsing_context_id: BrowsingContextId) { - let browsing_context_ids: Vec<BrowsingContextId> = self.all_browsing_contexts_iter(browsing_context_id) + fn clear_joint_session_future(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) { + let browsing_context_ids: Vec<BrowsingContextId> = + self.all_browsing_contexts_iter(top_level_browsing_context_id) .map(|browsing_context| browsing_context.id) .collect(); for browsing_context_id in browsing_context_ids { @@ -2602,23 +2619,26 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Close a browsing context (and all children) fn close_browsing_context(&mut self, browsing_context_id: BrowsingContextId, exit_mode: ExitPipelineMode) { debug!("Closing browsing context {}.", browsing_context_id); - let parent_info = self.browsing_contexts.get(&browsing_context_id) - .and_then(|browsing_context| self.pipelines.get(&browsing_context.pipeline_id)) - .and_then(|pipeline| pipeline.parent_info); self.close_browsing_context_children(browsing_context_id, DiscardBrowsingContext::Yes, exit_mode); - self.event_loops.remove(&browsing_context_id); - if self.browsing_contexts.remove(&browsing_context_id).is_none() { - warn!("Closing browsing context {:?} twice.", browsing_context_id); + let browsing_context = match self.browsing_contexts.remove(&browsing_context_id) { + None => return warn!("Closing browsing context {:?} twice.", browsing_context_id), + Some(browsing_context) => browsing_context, + }; + + if BrowsingContextId::from(browsing_context.top_level_id) == browsing_context_id { + self.event_loops.remove(&browsing_context.top_level_id); } + let parent_info = self.pipelines.get(&browsing_context.pipeline_id) + .and_then(|pipeline| pipeline.parent_info); + if let Some((parent_pipeline_id, _)) = parent_info { - let parent_pipeline = match self.pipelines.get_mut(&parent_pipeline_id) { + match self.pipelines.get_mut(&parent_pipeline_id) { None => return warn!("Pipeline {:?} child closed after parent.", parent_pipeline_id), - Some(parent_pipeline) => parent_pipeline, + Some(parent_pipeline) => parent_pipeline.remove_child(browsing_context_id), }; - parent_pipeline.remove_child(browsing_context_id); } debug!("Closed browsing context {:?}.", browsing_context_id); } @@ -2749,8 +2769,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // Note that this function can panic, due to ipc-channel creation failure. // avoiding this panic would require a mechanism for dealing // with low-resource scenarios. - debug!("Sending frame tree for browsing context {}.", self.root_browsing_context_id); - if let Some(frame_tree) = self.browsing_context_to_sendable(self.root_browsing_context_id) { + let root_browsing_context_id = BrowsingContextId::from(self.root_browsing_context_id); + debug!("Sending frame tree for browsing context {}.", root_browsing_context_id); + if let Some(frame_tree) = self.browsing_context_to_sendable(root_browsing_context_id) { let (chan, port) = ipc::channel().expect("Failed to create IPC channel!"); self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree, chan)); @@ -2768,11 +2789,14 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> Some(pipeline) => if let Some((parent_id, FrameType::MozBrowserIFrame)) = pipeline.parent_info { match self.pipelines.get(&parent_id) { Some(parent) => { - let can_go_forward = !self.joint_session_future_is_empty(pipeline.browsing_context_id); - let can_go_back = !self.joint_session_past_is_empty(pipeline.browsing_context_id); + let top_level_browsing_context_id = self.browsing_contexts.get(&pipeline.browsing_context_id) + .map(|browsing_context| browsing_context.top_level_id) + .unwrap_or(self.root_browsing_context_id); + let can_go_forward = !self.joint_session_future_is_empty(top_level_browsing_context_id); + let can_go_back = !self.joint_session_past_is_empty(top_level_browsing_context_id); let url = pipeline.url.to_string(); let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward); - parent.trigger_mozbrowser_event(Some(pipeline.browsing_context_id), event); + parent.trigger_mozbrowser_event(Some(top_level_browsing_context_id), event); }, None => warn!("triggered mozbrowser location change on closed parent {}", parent_id), } @@ -2784,7 +2808,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> // https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror // Note that this does not require the pipeline to be an immediate child of the root fn trigger_mozbrowsererror(&mut self, - top_level_browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, reason: String, backtrace: Option<String>) { @@ -2808,8 +2832,9 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> } let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, reason, report); + let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); - match self.browsing_contexts.get(&top_level_browsing_context_id) { + match self.browsing_contexts.get(&browsing_context_id) { None => warn!("Mozbrowser error after top-level browsing context closed."), Some(browsing_context) => match self.pipelines.get(&browsing_context.pipeline_id) { None => warn!("Mozbrowser error after top-level pipeline closed."), @@ -2826,7 +2851,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF> fn focused_pipeline_is_descendant_of(&self, browsing_context_id: BrowsingContextId) -> bool { self.focus_pipeline_id.map_or(false, |pipeline_id| { - self.fully_active_browsing_contexts_iter(browsing_context_id) + self.fully_active_descendant_browsing_contexts_iter(browsing_context_id) .any(|browsing_context| browsing_context.pipeline_id == pipeline_id) }) } diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 01c386779bb..85fdc54289b 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -15,7 +15,7 @@ use ipc_channel::Error; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layout_traits::LayoutThreadFactory; -use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespaceId}; +use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId, PipelineNamespaceId}; use net::image_cache::ImageCacheImpl; use net_traits::{IpcSend, ResourceThreads}; use net_traits::image_cache::ImageCache; @@ -104,7 +104,7 @@ pub struct InitialPipelineState { pub browsing_context_id: BrowsingContextId, /// The ID of the top-level browsing context that contains this Pipeline. - pub top_level_browsing_context_id: BrowsingContextId, + pub top_level_browsing_context_id: TopLevelBrowsingContextId, /// The ID of the parent pipeline and frame type, if any. /// If `None`, this is the root. @@ -201,6 +201,7 @@ impl Pipeline { parent_info: state.parent_info, new_pipeline_id: state.id, browsing_context_id: state.browsing_context_id, + top_level_browsing_context_id: state.top_level_browsing_context_id, load_data: state.load_data, window_size: window_size, pipeline_port: pipeline_port, @@ -393,7 +394,7 @@ impl Pipeline { /// This will cause an event to be fired on an iframe in the document, /// or on the `Window` if no frame is given. pub fn trigger_mozbrowser_event(&self, - child_id: Option<BrowsingContextId>, + child_id: Option<TopLevelBrowsingContextId>, event: MozBrowserEvent) { assert!(PREFS.is_mozbrowser_enabled()); @@ -433,8 +434,8 @@ impl Pipeline { #[derive(Deserialize, Serialize)] pub struct UnprivilegedPipelineContent { id: PipelineId, + top_level_browsing_context_id: TopLevelBrowsingContextId, browsing_context_id: BrowsingContextId, - top_level_browsing_context_id: BrowsingContextId, parent_info: Option<(PipelineId, FrameType)>, constellation_chan: IpcSender<ScriptMsg>, layout_to_constellation_chan: IpcSender<LayoutMsg>, @@ -491,7 +492,7 @@ impl UnprivilegedPipelineContent { }, self.load_data.clone()); LTF::create(self.id, - Some(self.top_level_browsing_context_id), + self.top_level_browsing_context_id, self.load_data.url, self.parent_info.is_some(), layout_pair, diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index 9f5b60b0045..4a3ceaab8f3 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -74,7 +74,8 @@ use layout::webrender_helpers::WebRenderDisplayListConverter; use layout::wrapper::LayoutNodeLayoutData; use layout::wrapper::drop_style_and_layout_data; use layout_traits::LayoutThreadFactory; -use msg::constellation_msg::{BrowsingContextId, PipelineId}; +use msg::constellation_msg::PipelineId; +use msg::constellation_msg::TopLevelBrowsingContextId; use net_traits::image_cache::{ImageCache, UsePlaceholder}; use parking_lot::RwLock; use profile_traits::mem::{self, Report, ReportKind, ReportsChan}; @@ -130,6 +131,9 @@ pub struct LayoutThread { /// The ID of the pipeline that we belong to. id: PipelineId, + /// The ID of the top-level browsing context that we belong to. + top_level_browsing_context_id: TopLevelBrowsingContextId, + /// The URL of the pipeline that we belong to. url: ServoUrl, @@ -244,7 +248,7 @@ impl LayoutThreadFactory for LayoutThread { /// Spawns a new layout thread. fn create(id: PipelineId, - top_level_browsing_context_id: Option<BrowsingContextId>, + top_level_browsing_context_id: TopLevelBrowsingContextId, url: ServoUrl, is_iframe: bool, chan: (Sender<Msg>, Receiver<Msg>), @@ -261,13 +265,13 @@ impl LayoutThreadFactory for LayoutThread { thread::Builder::new().name(format!("LayoutThread {:?}", id)).spawn(move || { thread_state::initialize(thread_state::LAYOUT); - if let Some(top_level_browsing_context_id) = top_level_browsing_context_id { - BrowsingContextId::install(top_level_browsing_context_id); - } + // In order to get accurate crash reports, we install the top-level bc id. + TopLevelBrowsingContextId::install(top_level_browsing_context_id); { // Ensures layout thread is destroyed before we send shutdown message let sender = chan.0; let layout = LayoutThread::new(id, + top_level_browsing_context_id, url, is_iframe, chan.1, @@ -417,6 +421,7 @@ fn add_font_face_rules(stylesheet: &Stylesheet, impl LayoutThread { /// Creates a new `LayoutThread` structure. fn new(id: PipelineId, + top_level_browsing_context_id: TopLevelBrowsingContextId, url: ServoUrl, is_iframe: bool, port: Receiver<Msg>, @@ -465,6 +470,7 @@ impl LayoutThread { LayoutThread { id: id, + top_level_browsing_context_id: top_level_browsing_context_id, url: url, is_iframe: is_iframe, port: port, @@ -732,7 +738,7 @@ impl LayoutThread { fn create_layout_thread(&self, info: NewLayoutThreadInfo) { LayoutThread::create(info.id, - BrowsingContextId::installed(), + self.top_level_browsing_context_id, info.url.clone(), info.is_parent, info.layout_pair, diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index 53aa2529cb0..61fa3ad2449 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -20,7 +20,8 @@ extern crate webrender_traits; use gfx::font_cache_thread::FontCacheThread; use ipc_channel::ipc::{IpcReceiver, IpcSender}; -use msg::constellation_msg::{BrowsingContextId, PipelineId}; +use msg::constellation_msg::PipelineId; +use msg::constellation_msg::TopLevelBrowsingContextId; use net_traits::image_cache::ImageCache; use profile_traits::{mem, time}; use script_traits::{ConstellationControlMsg, LayoutControlMsg}; @@ -34,7 +35,7 @@ use std::sync::mpsc::{Receiver, Sender}; pub trait LayoutThreadFactory { type Message; fn create(id: PipelineId, - top_level_browsing_context_id: Option<BrowsingContextId>, + top_level_browsing_context_id: TopLevelBrowsingContextId, url: ServoUrl, is_iframe: bool, chan: (Sender<Self::Message>, Receiver<Self::Message>), diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index edec5fb5231..44f23bc94b3 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -258,8 +258,6 @@ impl fmt::Display for PipelineId { } } -thread_local!(pub static TOP_LEVEL_BROWSING_CONTEXT_ID: Cell<Option<BrowsingContextId>> = Cell::new(None)); - #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] pub struct BrowsingContextIndex(pub u32); @@ -278,22 +276,45 @@ impl BrowsingContextId { new_browsing_context_id }) } +} + +impl fmt::Display for BrowsingContextId { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let PipelineNamespaceId(namespace_id) = self.namespace_id; + let BrowsingContextIndex(index) = self.index; + write!(fmt, "({},{})", namespace_id, index) + } +} + +thread_local!(pub static TOP_LEVEL_BROWSING_CONTEXT_ID: Cell<Option<TopLevelBrowsingContextId>> = Cell::new(None)); + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)] +pub struct TopLevelBrowsingContextId(BrowsingContextId); + +impl TopLevelBrowsingContextId { + pub fn new() -> TopLevelBrowsingContextId { + TopLevelBrowsingContextId(BrowsingContextId::new()) + } /// Each script and layout thread should have the top-level browsing context id installed, /// since it is used by crash reporting. - pub fn install(id: BrowsingContextId) { + pub fn install(id: TopLevelBrowsingContextId) { TOP_LEVEL_BROWSING_CONTEXT_ID.with(|tls| tls.set(Some(id))) } - pub fn installed() -> Option<BrowsingContextId> { + pub fn installed() -> Option<TopLevelBrowsingContextId> { TOP_LEVEL_BROWSING_CONTEXT_ID.with(|tls| tls.get()) } } -impl fmt::Display for BrowsingContextId { +impl fmt::Display for TopLevelBrowsingContextId { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let PipelineNamespaceId(namespace_id) = self.namespace_id; - let BrowsingContextIndex(index) = self.index; - write!(fmt, "({},{})", namespace_id, index) + self.0.fmt(fmt) + } +} + +impl From<TopLevelBrowsingContextId> for BrowsingContextId { + fn from(id: TopLevelBrowsingContextId) -> BrowsingContextId { + id.0 } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 3b96d954dcb..dca1b0e2ea5 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -58,7 +58,7 @@ use js::glue::{CallObjectTracer, CallValueTracer}; use js::jsapi::{GCTraceKindToAscii, Heap, JSObject, JSTracer, TraceKind}; use js::jsval::JSVal; use js::rust::Runtime; -use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId}; +use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, TopLevelBrowsingContextId}; use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads}; use net_traits::filemanager_thread::RelativePos; use net_traits::image::base::{Image, ImageMetadata}; @@ -336,7 +336,8 @@ unsafe_no_jsmanaged_fields!(TrustedPromise); unsafe_no_jsmanaged_fields!(PropertyDeclarationBlock); // These three are interdependent, if you plan to put jsmanaged data // in one of these make sure it is propagated properly to containing structs -unsafe_no_jsmanaged_fields!(DocumentActivity, BrowsingContextId, FrameType, WindowSizeData, WindowSizeType, PipelineId); +unsafe_no_jsmanaged_fields!(DocumentActivity, WindowSizeData, WindowSizeType); +unsafe_no_jsmanaged_fields!(BrowsingContextId, FrameType, PipelineId, TopLevelBrowsingContextId); unsafe_no_jsmanaged_fields!(TimerEventId, TimerSource); unsafe_no_jsmanaged_fields!(TimelineMarkerType); unsafe_no_jsmanaged_fields!(WorkerId); diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 6b73df12dfc..f4de73747c4 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -27,7 +27,7 @@ use js::jsapi::{HandleValue, JS_SetInterruptCallback}; use js::jsapi::{JSAutoCompartment, JSContext}; use js::jsval::UndefinedValue; use js::rust::Runtime; -use msg::constellation_msg::BrowsingContextId; +use msg::constellation_msg::TopLevelBrowsingContextId; use net_traits::{IpcSend, load_whole_resource}; use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx}; @@ -159,13 +159,13 @@ impl DedicatedWorkerGlobalScope { closing: Arc<AtomicBool>) { let serialized_worker_url = worker_url.to_string(); let name = format!("WebWorker for {}", serialized_worker_url); - let top_level_browsing_context_id = BrowsingContextId::installed(); + let top_level_browsing_context_id = TopLevelBrowsingContextId::installed(); thread::Builder::new().name(name).spawn(move || { thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER); if let Some(top_level_browsing_context_id) = top_level_browsing_context_id { - BrowsingContextId::install(top_level_browsing_context_id); + TopLevelBrowsingContextId::install(top_level_browsing_context_id); } let roots = RootCollection::new(); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 3bca1dcee9e..378dee975fa 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -100,7 +100,7 @@ use ipc_channel::ipc::{self, IpcSender}; use js::jsapi::{JSContext, JSObject, JSRuntime}; use js::jsapi::JS_GetRuntime; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; -use msg::constellation_msg::{BrowsingContextId, Key, KeyModifiers, KeyState}; +use msg::constellation_msg::{BrowsingContextId, Key, KeyModifiers, KeyState, TopLevelBrowsingContextId}; use net_traits::{FetchResponseMsg, IpcSend, ReferrerPolicy}; use net_traits::CookieSource::NonHTTP; use net_traits::CoreResourceMsg::{GetCookiesForUrl, SetCookiesForUrl}; @@ -1899,7 +1899,21 @@ impl Document { /// Find an iframe element in the document. pub fn find_iframe(&self, browsing_context_id: BrowsingContextId) -> Option<Root<HTMLIFrameElement>> { self.iter_iframes() - .find(|node| node.browsing_context_id() == browsing_context_id) + .find(|node| node.browsing_context_id() == Some(browsing_context_id)) + } + + /// Find a mozbrowser iframe element in the document. + pub fn find_mozbrowser_iframe(&self, + top_level_browsing_context_id: TopLevelBrowsingContextId) + -> Option<Root<HTMLIFrameElement>> + { + match self.find_iframe(BrowsingContextId::from(top_level_browsing_context_id)) { + None => None, + Some(iframe) => { + assert!(iframe.Mozbrowser()); + Some(iframe) + }, + } } pub fn get_dom_loading(&self) -> u64 { diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 8334b4cb421..00755213c75 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -40,7 +40,7 @@ use html5ever::{LocalName, Prefix}; use ipc_channel::ipc; use js::jsapi::{JSAutoCompartment, JSContext, MutableHandleValue}; use js::jsval::{NullValue, UndefinedValue}; -use msg::constellation_msg::{FrameType, BrowsingContextId, PipelineId, TraversalDirection}; +use msg::constellation_msg::{FrameType, BrowsingContextId, PipelineId, TopLevelBrowsingContextId, TraversalDirection}; use net_traits::response::HttpsState; use script_layout_interface::message::ReflowQueryType; use script_thread::{ScriptThread, Runnable}; @@ -84,7 +84,8 @@ enum ProcessingMode { #[dom_struct] pub struct HTMLIFrameElement { htmlelement: HTMLElement, - browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: Cell<Option<TopLevelBrowsingContextId>>, + browsing_context_id: Cell<Option<BrowsingContextId>>, pipeline_id: Cell<Option<PipelineId>>, pending_pipeline_id: Cell<Option<PipelineId>>, sandbox: MutNullableJS<DOMTokenList>, @@ -112,13 +113,6 @@ impl HTMLIFrameElement { }).unwrap_or_else(|| ServoUrl::parse("about:blank").unwrap()) } - pub fn generate_new_pipeline_id(&self) -> (Option<PipelineId>, PipelineId) { - let old_pipeline_id = self.pipeline_id.get(); - let new_pipeline_id = PipelineId::new(); - debug!("Frame {} created pipeline {}.", self.browsing_context_id, new_pipeline_id); - (old_pipeline_id, new_pipeline_id) - } - pub fn navigate_or_reload_child_browsing_context(&self, load_data: Option<LoadData>, nav_type: NavigationType, @@ -129,6 +123,16 @@ impl HTMLIFrameElement { IFrameUnsandboxed }; + let browsing_context_id = match self.browsing_context_id() { + None => return warn!("Navigating unattached iframe."), + Some(id) => id, + }; + + let top_level_browsing_context_id = match self.top_level_browsing_context_id() { + None => return warn!("Navigating unattached iframe."), + Some(id) => id, + }; + let document = document_from_node(self); let mut load_blocker = self.load_blocker.borrow_mut(); @@ -144,7 +148,8 @@ impl HTMLIFrameElement { } let window = window_from_node(self); - let (old_pipeline_id, new_pipeline_id) = self.generate_new_pipeline_id(); + let old_pipeline_id = self.pipeline_id(); + let new_pipeline_id = PipelineId::new(); self.pending_pipeline_id.set(Some(new_pipeline_id)); let private_iframe = self.privatebrowsing(); let frame_type = if self.Mozbrowser() { FrameType::MozBrowserIFrame } else { FrameType::IFrame }; @@ -152,7 +157,8 @@ impl HTMLIFrameElement { let global_scope = window.upcast::<GlobalScope>(); let load_info = IFrameLoadInfo { parent_pipeline_id: global_scope.pipeline_id(), - browsing_context_id: self.browsing_context_id, + browsing_context_id: browsing_context_id, + top_level_browsing_context_id: top_level_browsing_context_id, new_pipeline_id: new_pipeline_id, is_private: private_iframe, frame_type: frame_type, @@ -171,7 +177,8 @@ impl HTMLIFrameElement { let new_layout_info = NewLayoutInfo { parent_info: Some((global_scope.pipeline_id(), frame_type)), new_pipeline_id: new_pipeline_id, - browsing_context_id: self.browsing_context_id, + browsing_context_id: browsing_context_id, + top_level_browsing_context_id: top_level_browsing_context_id, load_data: load_data.unwrap(), pipeline_port: pipeline_receiver, content_process_shutdown_chan: None, @@ -246,11 +253,29 @@ impl HTMLIFrameElement { // Synchronously create a new context and navigate it to about:blank. let url = ServoUrl::parse("about:blank").unwrap(); let document = document_from_node(self); - let pipeline_id = Some(window_from_node(self).upcast::<GlobalScope>().pipeline_id()); + let window = window_from_node(self); + let pipeline_id = Some(window.upcast::<GlobalScope>().pipeline_id()); let load_data = LoadData::new(url, pipeline_id, document.get_referrer_policy(), Some(document.url().clone())); + let (browsing_context_id, top_level_browsing_context_id) = if self.Mozbrowser() { + let top_level_browsing_context_id = TopLevelBrowsingContextId::new(); + (BrowsingContextId::from(top_level_browsing_context_id), top_level_browsing_context_id) + } else { + (BrowsingContextId::new(), window.window_proxy().top_level_browsing_context_id()) + }; + self.pipeline_id.set(None); + self.pending_pipeline_id.set(None); + self.top_level_browsing_context_id.set(Some(top_level_browsing_context_id)); + self.browsing_context_id.set(Some(browsing_context_id)); self.navigate_or_reload_child_browsing_context(Some(load_data), NavigationType::InitialAboutBlank, false); } + fn destroy_nested_browsing_context(&self) { + self.pipeline_id.set(None); + self.pending_pipeline_id.set(None); + self.top_level_browsing_context_id.set(None); + self.browsing_context_id.set(None); + } + pub fn update_pipeline_id(&self, new_pipeline_id: PipelineId, reason: UpdatePipelineIdReason) { if self.pending_pipeline_id.get() != Some(new_pipeline_id) && reason == UpdatePipelineIdReason::Navigation { return; @@ -277,7 +302,8 @@ impl HTMLIFrameElement { document: &Document) -> HTMLIFrameElement { HTMLIFrameElement { htmlelement: HTMLElement::new_inherited(local_name, prefix, document), - browsing_context_id: BrowsingContextId::new(), + browsing_context_id: Cell::new(None), + top_level_browsing_context_id: Cell::new(None), pipeline_id: Cell::new(None), pending_pipeline_id: Cell::new(None), sandbox: Default::default(), @@ -302,8 +328,13 @@ impl HTMLIFrameElement { } #[inline] - pub fn browsing_context_id(&self) -> BrowsingContextId { - self.browsing_context_id + pub fn browsing_context_id(&self) -> Option<BrowsingContextId> { + self.browsing_context_id.get() + } + + #[inline] + pub fn top_level_browsing_context_id(&self) -> Option<TopLevelBrowsingContextId> { + self.top_level_browsing_context_id.get() } pub fn change_visibility_status(&self, visibility: bool) { @@ -364,7 +395,7 @@ impl HTMLIFrameElement { pub trait HTMLIFrameElementLayoutMethods { fn pipeline_id(&self) -> Option<PipelineId>; - fn browsing_context_id(&self) -> BrowsingContextId; + fn browsing_context_id(&self) -> Option<BrowsingContextId>; fn get_width(&self) -> LengthOrPercentageOrAuto; fn get_height(&self) -> LengthOrPercentageOrAuto; } @@ -380,9 +411,9 @@ impl HTMLIFrameElementLayoutMethods for LayoutJS<HTMLIFrameElement> { #[inline] #[allow(unsafe_code)] - fn browsing_context_id(&self) -> BrowsingContextId { + fn browsing_context_id(&self) -> Option<BrowsingContextId> { unsafe { - (*self.unsafe_get()).browsing_context_id + (*self.unsafe_get()).browsing_context_id.get() } } @@ -541,7 +572,8 @@ impl HTMLIFrameElementMethods for HTMLIFrameElement { // https://html.spec.whatwg.org/multipage/#dom-iframe-contentwindow fn GetContentWindow(&self) -> Option<Root<WindowProxy>> { - self.pipeline_id.get().and_then(|_| ScriptThread::find_window_proxy(self.browsing_context_id)) + self.browsing_context_id.get() + .and_then(|browsing_context_id| ScriptThread::find_window_proxy(browsing_context_id)) } // https://html.spec.whatwg.org/multipage/#dom-iframe-contentdocument @@ -711,7 +743,7 @@ impl VirtualMethods for HTMLIFrameElement { // is in a document tree and has a browsing context, which is what causes // the child browsing context to be created. if self.upcast::<Node>().is_in_doc_with_browsing_context() { - debug!("iframe {} src set while in browsing context.", self.browsing_context_id); + debug!("iframe src set while in browsing context."); self.process_the_iframe_attributes(ProcessingMode::NotFirstTime); } }, @@ -740,7 +772,7 @@ impl VirtualMethods for HTMLIFrameElement { // to the newly-created browsing context, and then process the // iframe attributes for the "first time"." if self.upcast::<Node>().is_in_doc_with_browsing_context() { - debug!("iframe {} bound to browsing context.", self.browsing_context_id); + debug!("iframe bound to browsing context."); debug_assert!(tree_in_doc, "is_in_doc_with_bc, but not tree_in_doc"); self.create_nested_browsing_context(); self.process_the_iframe_attributes(ProcessingMode::FirstTime); @@ -754,13 +786,18 @@ impl VirtualMethods for HTMLIFrameElement { LoadBlocker::terminate(&mut blocker); // https://html.spec.whatwg.org/multipage/#a-browsing-context-is-discarded - debug!("Unbinding frame {}.", self.browsing_context_id); let window = window_from_node(self); let (sender, receiver) = ipc::channel().unwrap(); // Ask the constellation to remove the iframe, and tell us the // pipeline ids of the closed pipelines. - let msg = ConstellationMsg::RemoveIFrame(self.browsing_context_id, sender); + let browsing_context_id = match self.browsing_context_id() { + None => return warn!("Unbinding already unbound iframe."), + Some(id) => id, + }; + debug!("Unbinding frame {}.", browsing_context_id); + + let msg = ConstellationMsg::RemoveIFrame(browsing_context_id, sender); window.upcast::<GlobalScope>().constellation_chan().send(msg).unwrap(); let exited_pipeline_ids = receiver.recv().unwrap(); @@ -769,9 +806,11 @@ impl VirtualMethods for HTMLIFrameElement { // when the `PipelineExit` message arrives. for exited_pipeline_id in exited_pipeline_ids { if let Some(exited_document) = ScriptThread::find_document(exited_pipeline_id) { + debug!("Discarding browsing context for pipeline {}", exited_pipeline_id); exited_document.window().window_proxy().discard_browsing_context(); for exited_iframe in exited_document.iter_iframes() { - exited_iframe.pipeline_id.set(None); + debug!("Discarding nested browsing context"); + exited_iframe.destroy_nested_browsing_context(); } } } @@ -781,8 +820,7 @@ impl VirtualMethods for HTMLIFrameElement { // the load doesn't think that it's a navigation, but instead // a new iframe. Without this, the constellation gets very // confused. - self.pipeline_id.set(None); - self.pending_pipeline_id.set(None); + self.destroy_nested_browsing_context(); } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index ff3e5d64787..cc817587eda 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1136,7 +1136,7 @@ impl LayoutNodeHelpers for LayoutJS<Node> { fn iframe_browsing_context_id(&self) -> BrowsingContextId { let iframe_element = self.downcast::<HTMLIFrameElement>() .expect("not an iframe element!"); - iframe_element.browsing_context_id() + iframe_element.browsing_context_id().unwrap() } fn iframe_pipeline_id(&self) -> PipelineId { diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index e022e69a810..2578bb3b46c 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -30,6 +30,7 @@ use js::jsval::{UndefinedValue, PrivateValue}; use js::rust::get_object_class; use msg::constellation_msg::BrowsingContextId; use msg::constellation_msg::PipelineId; +use msg::constellation_msg::TopLevelBrowsingContextId; use std::cell::Cell; use std::ptr; @@ -50,6 +51,10 @@ pub struct WindowProxy { /// of the container. browsing_context_id: BrowsingContextId, + /// The frame id of the top-level ancestor browsing context. + /// In the case that this is a top-level window, this is our id. + top_level_browsing_context_id: TopLevelBrowsingContextId, + /// The pipeline id of the currently active document. /// May be None, when the currently active document is in another script thread. /// We do not try to keep the pipeline id for documents in other threads, @@ -69,6 +74,7 @@ pub struct WindowProxy { impl WindowProxy { pub fn new_inherited(browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, currently_active: Option<PipelineId>, frame_element: Option<&Element>, parent: Option<&WindowProxy>) @@ -77,6 +83,7 @@ impl WindowProxy { WindowProxy { reflector: Reflector::new(), browsing_context_id: browsing_context_id, + top_level_browsing_context_id: top_level_browsing_context_id, currently_active: Cell::new(currently_active), discarded: Cell::new(false), frame_element: frame_element.map(JS::from_ref), @@ -87,6 +94,7 @@ impl WindowProxy { #[allow(unsafe_code)] pub fn new(window: &Window, browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, frame_element: Option<&Element>, parent: Option<&WindowProxy>) -> Root<WindowProxy> @@ -107,7 +115,11 @@ impl WindowProxy { // Create a new browsing context. let current = Some(window.global().pipeline_id()); - let mut window_proxy = box WindowProxy::new_inherited(browsing_context_id, current, frame_element, parent); + let mut window_proxy = box WindowProxy::new_inherited(browsing_context_id, + top_level_browsing_context_id, + current, + frame_element, + parent); // The window proxy owns the browsing context. // When we finalize the window proxy, it drops the browsing context it owns. @@ -126,6 +138,7 @@ impl WindowProxy { #[allow(unsafe_code)] pub fn new_dissimilar_origin(global_to_clone_from: &GlobalScope, browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, parent: Option<&WindowProxy>) -> Root<WindowProxy> { @@ -136,7 +149,11 @@ impl WindowProxy { let cx = global_to_clone_from.get_cx(); // Create a new browsing context. - let mut window_proxy = box WindowProxy::new_inherited(browsing_context_id, None, None, parent); + let mut window_proxy = box WindowProxy::new_inherited(browsing_context_id, + top_level_browsing_context_id, + None, + None, + parent); // Create a new dissimilar-origin window. let window = DissimilarOriginWindow::new(global_to_clone_from, &*window_proxy); @@ -175,6 +192,10 @@ impl WindowProxy { self.browsing_context_id } + pub fn top_level_browsing_context_id(&self) -> TopLevelBrowsingContextId { + self.top_level_browsing_context_id + } + pub fn frame_element(&self) -> Option<&Element> { self.frame_element.r() } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index eeab44c4c71..d66baaeda81 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -73,7 +73,7 @@ use js::jsval::UndefinedValue; use js::rust::Runtime; use mem::heap_size_of_self_and_children; use microtask::{MicrotaskQueue, Microtask}; -use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespace}; +use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespace, TopLevelBrowsingContextId}; use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener}; use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads}; use net_traits::image_cache::{ImageCache, PendingImageResponse}; @@ -143,8 +143,10 @@ pub unsafe fn trace_thread(tr: *mut JSTracer) { struct InProgressLoad { /// The pipeline which requested this load. pipeline_id: PipelineId, - /// The frame being loaded into. + /// The browsing context being loaded into. browsing_context_id: BrowsingContextId, + /// The top level ancestor browsing context. + top_level_browsing_context_id: TopLevelBrowsingContextId, /// The parent pipeline and frame type associated with this load, if any. parent_info: Option<(PipelineId, FrameType)>, /// The current window size associated with this pipeline. @@ -165,6 +167,7 @@ impl InProgressLoad { /// Create a new InProgressLoad object. fn new(id: PipelineId, browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, parent_info: Option<(PipelineId, FrameType)>, layout_chan: Sender<message::Msg>, window_size: Option<WindowSizeData>, @@ -173,6 +176,7 @@ impl InProgressLoad { InProgressLoad { pipeline_id: id, browsing_context_id: browsing_context_id, + top_level_browsing_context_id: top_level_browsing_context_id, parent_info: parent_info, layout_chan: layout_chan, window_size: window_size, @@ -548,11 +552,12 @@ impl ScriptThreadFactory for ScriptThread { thread::Builder::new().name(format!("ScriptThread {:?}", state.id)).spawn(move || { thread_state::initialize(thread_state::SCRIPT); PipelineNamespace::install(state.pipeline_namespace_id); - BrowsingContextId::install(state.top_level_browsing_context_id); + TopLevelBrowsingContextId::install(state.top_level_browsing_context_id); let roots = RootCollection::new(); let _stack_roots_tls = StackRootTLS::new(&roots); let id = state.id; let browsing_context_id = state.browsing_context_id; + let top_level_browsing_context_id = state.top_level_browsing_context_id; let parent_info = state.parent_info; let mem_profiler_chan = state.mem_profiler_chan.clone(); let window_size = state.window_size; @@ -567,7 +572,7 @@ impl ScriptThreadFactory for ScriptThread { let mut failsafe = ScriptMemoryFailsafe::new(&script_thread); let origin = MutableOrigin::new(load_data.url.origin()); - let new_load = InProgressLoad::new(id, browsing_context_id, parent_info, + let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info, layout_chan, window_size, load_data.url.clone(), origin); script_thread.start_page_load(new_load, load_data); @@ -1117,10 +1122,10 @@ impl ScriptThread { ConstellationControlMsg::PostMessage(pipeline_id, origin, data) => self.handle_post_message_msg(pipeline_id, origin, data), ConstellationControlMsg::MozBrowserEvent(parent_pipeline_id, - browsing_context_id, + top_level_browsing_context_id, event) => self.handle_mozbrowser_event_msg(parent_pipeline_id, - browsing_context_id, + top_level_browsing_context_id, event), ConstellationControlMsg::UpdatePipelineId(parent_pipeline_id, browsing_context_id, @@ -1344,6 +1349,7 @@ impl ScriptThread { parent_info, new_pipeline_id, browsing_context_id, + top_level_browsing_context_id, load_data, window_size, pipeline_port, @@ -1379,9 +1385,14 @@ impl ScriptThread { }; // Kick off the fetch for the new resource. - let new_load = InProgressLoad::new(new_pipeline_id, browsing_context_id, parent_info, - layout_chan, window_size, - load_data.url.clone(), origin); + let new_load = InProgressLoad::new(new_pipeline_id, + browsing_context_id, + top_level_browsing_context_id, + parent_info, + layout_chan, + window_size, + load_data.url.clone(), + origin); if load_data.url.as_str() == "about:blank" { self.start_page_load_about_blank(new_load); } else { @@ -1495,17 +1506,18 @@ impl ScriptThread { /// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart fn handle_mozbrowser_event_msg(&self, parent_pipeline_id: PipelineId, - browsing_context_id: Option<BrowsingContextId>, + top_level_browsing_context_id: Option<TopLevelBrowsingContextId>, event: MozBrowserEvent) { let doc = match { self.documents.borrow().find_document(parent_pipeline_id) } { None => return warn!("Mozbrowser event after pipeline {} closed.", parent_pipeline_id), Some(doc) => doc, }; - match browsing_context_id { + match top_level_browsing_context_id { None => doc.window().dispatch_mozbrowser_event(event), - Some(browsing_context_id) => match doc.find_iframe(browsing_context_id) { - None => warn!("Mozbrowser event after iframe {}/{} closed.", parent_pipeline_id, browsing_context_id), + Some(top_level_browsing_context_id) => match doc.find_mozbrowser_iframe(top_level_browsing_context_id) { + None => warn!("Mozbrowser event after iframe {}/{} closed.", + parent_pipeline_id, top_level_browsing_context_id), Some(frame_element) => frame_element.dispatch_mozbrowser_event(event), }, } @@ -1779,9 +1791,10 @@ impl ScriptThread { // construct a new dissimilar-origin browsing context, add it // to the `window_proxies` map, and return it. fn remote_window_proxy(&self, - global_to_clone: &GlobalScope, - pipeline_id: PipelineId) - -> Option<Root<WindowProxy>> + global_to_clone: &GlobalScope, + top_level_browsing_context_id: TopLevelBrowsingContextId, + pipeline_id: PipelineId) + -> Option<Root<WindowProxy>> { let browsing_context_id = match self.ask_constellation_for_browsing_context_id(pipeline_id) { Some(browsing_context_id) => browsing_context_id, @@ -1791,10 +1804,15 @@ impl ScriptThread { return Some(Root::from_ref(window_proxy)); } let parent = match self.ask_constellation_for_parent_info(pipeline_id) { - Some((parent_id, FrameType::IFrame)) => self.remote_window_proxy(global_to_clone, parent_id), + Some((parent_id, FrameType::IFrame)) => self.remote_window_proxy(global_to_clone, + top_level_browsing_context_id, + parent_id), _ => None, }; - let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone, browsing_context_id, parent.r()); + let window_proxy = WindowProxy::new_dissimilar_origin(global_to_clone, + browsing_context_id, + top_level_browsing_context_id, + parent.r()); self.window_proxies.borrow_mut().insert(browsing_context_id, JS::from_ref(&*window_proxy)); Some(window_proxy) } @@ -1806,10 +1824,11 @@ impl ScriptThread { // construct a new similar-origin browsing context, add it // to the `window_proxies` map, and return it. fn local_window_proxy(&self, - window: &Window, - browsing_context_id: BrowsingContextId, - parent_info: Option<(PipelineId, FrameType)>) - -> Root<WindowProxy> + window: &Window, + browsing_context_id: BrowsingContextId, + top_level_browsing_context_id: TopLevelBrowsingContextId, + parent_info: Option<(PipelineId, FrameType)>) + -> Root<WindowProxy> { if let Some(window_proxy) = self.window_proxies.borrow().get(&browsing_context_id) { window_proxy.set_currently_active(&*window); @@ -1821,10 +1840,16 @@ impl ScriptThread { }; let parent = match (parent_info, iframe.as_ref()) { (_, Some(iframe)) => Some(window_from_node(&**iframe).window_proxy()), - (Some((parent_id, FrameType::IFrame)), _) => self.remote_window_proxy(window.upcast(), parent_id), + (Some((parent_id, FrameType::IFrame)), _) => self.remote_window_proxy(window.upcast(), + top_level_browsing_context_id, + parent_id), _ => None, }; - let window_proxy = WindowProxy::new(&window, browsing_context_id, iframe.r().map(Castable::upcast), parent.r()); + let window_proxy = WindowProxy::new(&window, + browsing_context_id, + top_level_browsing_context_id, + iframe.r().map(Castable::upcast), + parent.r()); self.window_proxies.borrow_mut().insert(browsing_context_id, JS::from_ref(&*window_proxy)); window_proxy } @@ -1882,7 +1907,10 @@ impl ScriptThread { self.webvr_thread.clone()); // Initialize the browsing context for the window. - let window_proxy = self.local_window_proxy(&window, incomplete.browsing_context_id, incomplete.parent_info); + let window_proxy = self.local_window_proxy(&window, + incomplete.browsing_context_id, + incomplete.top_level_browsing_context_id, + incomplete.parent_info); window.init_window_proxy(&window_proxy); let last_modified = metadata.headers.as_ref().and_then(|headers| { diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 889a06e5cb3..98e66ab8044 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -53,7 +53,7 @@ use hyper::header::Headers; use hyper::method::Method; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use libc::c_void; -use msg::constellation_msg::{BrowsingContextId, FrameType, Key, KeyModifiers, KeyState}; +use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, Key, KeyModifiers, KeyState}; use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection}; use net_traits::{ReferrerPolicy, ResourceThreads}; use net_traits::image::base::Image; @@ -181,6 +181,8 @@ pub struct NewLayoutInfo { pub new_pipeline_id: PipelineId, /// Id of the browsing context associated with this pipeline. pub browsing_context_id: BrowsingContextId, + /// Id of the top-level browsing context associated with this pipeline. + pub top_level_browsing_context_id: TopLevelBrowsingContextId, /// Network request data which will be initiated by the script thread. pub load_data: LoadData, /// Information about the initial window size. @@ -260,9 +262,9 @@ pub enum ConstellationControlMsg { Navigate(PipelineId, BrowsingContextId, LoadData, bool), /// Post a message to a given window. PostMessage(PipelineId, Option<ImmutableOrigin>, Vec<u8>), - /// Requests the script thread forward a mozbrowser event to an iframe it owns, + /// Requests the script thread forward a mozbrowser event to a mozbrowser iframe it owns, /// or to the window if no browsing context id is provided. - MozBrowserEvent(PipelineId, Option<BrowsingContextId>, MozBrowserEvent), + MozBrowserEvent(PipelineId, Option<TopLevelBrowsingContextId>, MozBrowserEvent), /// Updates the current pipeline ID of a given iframe. /// First PipelineId is for the parent, second is the new PipelineId for the frame. UpdatePipelineId(PipelineId, BrowsingContextId, PipelineId, UpdatePipelineIdReason), @@ -488,10 +490,10 @@ pub struct InitialScriptState { /// The subpage ID of this pipeline to create in its pipeline parent. /// If `None`, this is the root. pub parent_info: Option<(PipelineId, FrameType)>, - /// The ID of the frame this script is part of. + /// The ID of the browsing context this script is part of. pub browsing_context_id: BrowsingContextId, - /// The ID of the top-level frame this script is part of. - pub top_level_browsing_context_id: BrowsingContextId, + /// The ID of the top-level browsing context this script is part of. + pub top_level_browsing_context_id: TopLevelBrowsingContextId, /// A channel with which messages can be sent to us (the script thread). pub control_chan: IpcSender<ConstellationControlMsg>, /// A port on which messages sent by the constellation to script can be received. @@ -548,8 +550,11 @@ pub enum IFrameSandboxState { pub struct IFrameLoadInfo { /// Pipeline ID of the parent of this iframe pub parent_pipeline_id: PipelineId, - /// The ID for this iframe. + /// The ID for this iframe's nested browsing context. pub browsing_context_id: BrowsingContextId, + /// The ID for the top-level ancestor browsing context of this iframe's nested browsing context. + /// Note: this is the same as the browsing_context_id for mozbrowser iframes. + pub top_level_browsing_context_id: TopLevelBrowsingContextId, /// The new pipeline ID that the iframe has generated. pub new_pipeline_id: PipelineId, /// Whether this iframe should be considered private @@ -761,7 +766,7 @@ pub enum ConstellationMsg { /// Reload the current page. Reload, /// A log entry, with the top-level browsing context id and thread name - LogEntry(Option<BrowsingContextId>, Option<String>, LogEntry), + LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry), /// Set the WebVR thread channel. SetWebVRThread(IpcSender<WebVRMsg>), /// Dispatch WebVR events to the subscribed script threads. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index d34f2feeb5f..1ebe6c17b5f 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -17,7 +17,7 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use euclid::point::Point2D; use euclid::size::{Size2D, TypedSize2D}; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, TraversalDirection}; +use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId, TraversalDirection}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; use net_traits::CoreResourceMsg; use net_traits::storage_thread::StorageType; @@ -148,7 +148,7 @@ pub enum ScriptMsg { /// Script has handled a touch event, and either prevented or allowed default actions. TouchEventProcessed(EventResult), /// A log entry, with the top-level browsing context id and thread name - LogEntry(Option<BrowsingContextId>, Option<String>, LogEntry), + LogEntry(Option<TopLevelBrowsingContextId>, Option<String>, LogEntry), /// Notifies the constellation that this pipeline has exited. PipelineExited(PipelineId), /// Send messages from postMessage calls from serviceworker |