diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 9973e4fb923..a71a487127e 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -289,8 +289,10 @@ pub struct Constellation { /// we store a `SessionHistoryChange` object for the navigation in progress. pending_changes: Vec, - /// The currently focused pipeline for key events. - focus_pipeline_id: Option, + /// The currently focused browsing context for key events. The focused + /// pipeline is the current entry of the focused browsing + /// context. + focused_browsing_context_id: Option, /// Pipeline IDs are namespaced in order to avoid name collisions, /// and the namespaces are allocated by the constellation. @@ -606,7 +608,7 @@ where // We initialize the namespace at 2, since we reserved // namespace 0 for the embedder, and 0 for the constellation next_pipeline_namespace_id: PipelineNamespaceId(2), - focus_pipeline_id: None, + focused_browsing_context_id: None, time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, window_size: WindowSizeData { @@ -961,14 +963,12 @@ where self.handle_get_pipeline(browsing_context_id, resp_chan); }, FromCompositorMsg::GetFocusTopLevelBrowsingContext(resp_chan) => { - let focus_browsing_context = self - .focus_pipeline_id - .and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) - .map(|pipeline| pipeline.top_level_browsing_context_id) - .filter(|&top_level_browsing_context_id| { - let browsing_context_id = - BrowsingContextId::from(top_level_browsing_context_id); - self.browsing_contexts.contains_key(&browsing_context_id) + let focus_browsing_context = self.focused_browsing_context_id + .and_then(|ctx_id| self.browsing_contexts.get(&ctx_id)) + .map(|ctx| ctx.top_level_id) + .filter(|&top_level_ctx_id| { + let ctx_id = BrowsingContextId::from(top_level_ctx_id); + self.browsing_contexts.contains_key(&ctx_id) }); let _ = resp_chan.send(focus_browsing_context); }, @@ -1644,9 +1644,10 @@ where let is_private = false; let is_visible = true; - if self.focus_pipeline_id.is_none() { - self.focus_pipeline_id = Some(pipeline_id); + if self.focused_browsing_context_id.is_none() { + self.focused_browsing_context_id = Some(browsing_context_id); } + self.joint_session_histories .insert(top_level_browsing_context_id, JointSessionHistory::new()); self.new_pipeline( @@ -2622,11 +2623,18 @@ where } fn handle_key_msg(&mut self, ch: Option, key: Key, state: KeyState, mods: KeyModifiers) { - // Send to the explicitly focused pipeline. If it doesn't exist, fall back to sending to - // the compositor. - match self.focus_pipeline_id { - Some(pipeline_id) => { + // Send to the focused browsing contexts' current pipeline. If it + // doesn't exist, fall back to sending to the compositor. + match self.focused_browsing_context_id { + Some(browsing_context_id) => { let event = CompositorEvent::KeyEvent(ch, key, state, mods); + let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { + Some(ctx) => ctx.pipeline_id, + None => return warn!( + "Got key event for nonexistent browsing context {}.", + browsing_context_id, + ), + }; let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); let result = match self.pipelines.get(&pipeline_id) { Some(pipeline) => pipeline.event_loop.send(msg), @@ -2727,37 +2735,46 @@ where } fn handle_focus_msg(&mut self, pipeline_id: PipelineId) { - self.focus_pipeline_id = Some(pipeline_id); - - // Focus parent iframes recursively - self.focus_parent_pipeline(pipeline_id); - } - - fn focus_parent_pipeline(&mut self, pipeline_id: PipelineId) { let browsing_context_id = match self.pipelines.get(&pipeline_id) { Some(pipeline) => pipeline.browsing_context_id, None => return warn!("Pipeline {:?} focus parent after closure.", pipeline_id), }; + self.focused_browsing_context_id = Some(browsing_context_id); + + // Focus parent iframes recursively + self.focus_parent_pipeline(browsing_context_id); + } + + fn focus_parent_pipeline(&mut self, browsing_context_id: BrowsingContextId) { let parent_pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { Some(ctx) => ctx.parent_pipeline_id, - None => return warn!("Browsing context {:?} focus parent after closure.", browsing_context_id), + None => return warn!( + "Browsing context {:?} focus parent after closure.", + browsing_context_id + ), }; let parent_pipeline_id = match parent_pipeline_id { - Some(info) => info, - None => return debug!("Pipeline {:?} focus has no parent.", pipeline_id), + Some(parent_id) => parent_id, + None => return debug!( + "Browsing context {:?} focus has no parent.", + browsing_context_id + ), }; - // Send a message to the parent of the provided pipeline (if it exists) - // telling it to mark the iframe element as focused. + // Send a message to the parent of the provided browsing context (if it + // exists) telling it to mark the iframe element as focused. let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, browsing_context_id); - let result = match self.pipelines.get(&parent_pipeline_id) { - Some(pipeline) => pipeline.event_loop.send(msg), + let (result, parent_browsing_context_id) = match self.pipelines.get(&parent_pipeline_id) { + Some(pipeline) => { + let result = pipeline.event_loop.send(msg); + (result, pipeline.browsing_context_id) + }, None => return warn!("Pipeline {:?} focus after closure.", parent_pipeline_id), }; if let Err(e) = result { self.handle_send_error(parent_pipeline_id, e); } - self.focus_parent_pipeline(parent_pipeline_id); + self.focus_parent_pipeline(parent_browsing_context_id); } fn handle_remove_iframe_msg( @@ -3095,11 +3112,11 @@ where change.browsing_context_id, change.new_pipeline_id ); - // If the currently focused pipeline is the one being changed (or a child - // of the pipeline being changed) then update the focus pipeline to be - // the replacement. - if self.focused_pipeline_is_descendant_of(change.browsing_context_id) { - self.focus_pipeline_id = Some(change.new_pipeline_id); + // If the currently focused browsing context is a child of the browsing + // context in which the page is being loaded, then update the focused + // browsing context to that one. + if self.focused_browsing_context_is_descendant_of(change.browsing_context_id) { + self.focused_browsing_context_id = Some(change.browsing_context_id); } let (old_pipeline_id, top_level_id) = @@ -3243,6 +3260,17 @@ where self.update_frame_tree_if_active(change.top_level_browsing_context_id); } + fn focused_browsing_context_is_descendant_of( + &self, + browsing_context_id: BrowsingContextId + ) -> bool { + self.focused_browsing_context_id.map_or(false, |focus_ctx_id| { + focus_ctx_id == browsing_context_id || self + .fully_active_descendant_browsing_contexts_iter(browsing_context_id) + .any(|nested_ctx| nested_ctx.id == focus_ctx_id) + }) + } + fn trim_history(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) { let pipelines_to_evict = { let session_history = self.get_joint_session_history(top_level_browsing_context_id); @@ -3393,16 +3421,15 @@ where &mut self, pipeline_states: HashMap, ) -> ReadyToSave { - // Note that this function can panic, due to ipc-channel creation failure. - // avoiding this panic would require a mechanism for dealing + // 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. // // If there is no focus browsing context yet, the initial page has // not loaded, so there is nothing to save yet. - let top_level_browsing_context_id = self - .focus_pipeline_id - .and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) - .map(|pipeline| pipeline.top_level_browsing_context_id); + let top_level_browsing_context_id = self.focused_browsing_context_id + .and_then(|ctx_id| self.browsing_contexts.get(&ctx_id)) + .map(|ctx| ctx.top_level_id); let top_level_browsing_context_id = match top_level_browsing_context_id { Some(id) => id, None => return ReadyToSave::NoTopLevelBrowsingContext, @@ -3881,11 +3908,4 @@ where .send(ToCompositorMsg::SetFrameTree(frame_tree)); } } - - fn focused_pipeline_is_descendant_of(&self, browsing_context_id: BrowsingContextId) -> bool { - self.focus_pipeline_id.map_or(false, |pipeline_id| { - self.fully_active_descendant_browsing_contexts_iter(browsing_context_id) - .any(|browsing_context| browsing_context.pipeline_id == pipeline_id) - }) - } }