From 83418ff8613ebacc27d0aa122b50d879373e50c2 Mon Sep 17 00:00:00 2001 From: mandreyel Date: Sat, 27 Oct 2018 11:06:22 +0200 Subject: [PATCH 1/3] Update Constellation to track each browser's focused browsing context --- components/constellation/constellation.rs | 83 +++++++++++++++++------ 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 581f72240bd..127f6b2ff39 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -204,6 +204,20 @@ pub struct Constellation { /// The last frame tree sent to WebRender. active_browser_id: Option, + /// All the browsers in constellation. Since the active browser + /// (`active_browser_id`) may change with the `SelectBrowser` message (e.g. + /// when user switches to another tab), we must keep track of each browser's + /// focused browsing context so that we can restore the + /// `focused_browsing_context_id` to point to the active browser's focused + /// browsing context. + browser_ids: HashMap, + + /// The currently focused browsing context for key events. The focused + /// pipeline is the current entry of the focused browsing context. This + /// field is always updated to be the focused browsing context of the + /// current active browser. + focused_browsing_context_id: Option, + /// Channels for the constellation to send messages to the public /// resource-related threads. There are two groups of resource /// threads: one for public browsing, and one for private @@ -289,11 +303,6 @@ pub struct Constellation { /// we store a `SessionHistoryChange` object for the navigation in progress. pending_changes: Vec, - /// 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. next_pipeline_namespace_id: PipelineNamespaceId, @@ -591,6 +600,8 @@ where embedder_proxy: state.embedder_proxy, compositor_proxy: state.compositor_proxy, active_browser_id: None, + browser_ids: HashMap::new(), + focused_browsing_context_id: None, debugger_chan: state.debugger_chan, devtools_chan: state.devtools_chan, bluetooth_thread: state.bluetooth_thread, @@ -608,7 +619,6 @@ 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), - focused_browsing_context_id: None, time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, window_size: WindowSizeData { @@ -964,14 +974,9 @@ where self.handle_get_pipeline(browsing_context_id, resp_chan); }, FromCompositorMsg::GetFocusTopLevelBrowsingContext(resp_chan) => { - 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); + // The focused browsing context's top-level browsing context is + // the active browser's id itself. + let _ = resp_chan.send(self.active_browser_id); }, FromCompositorMsg::Keyboard(key_event) => { self.handle_key_msg(key_event); @@ -1650,6 +1655,9 @@ where let is_private = false; let is_visible = true; + // Register this new top-level browsing context id as a browser and set + // its focused browsing context to be itself. + self.browser_ids.insert(top_level_browsing_context_id, browsing_context_id); if self.focused_browsing_context_id.is_none() { self.focused_browsing_context_id = Some(browsing_context_id); } @@ -1687,6 +1695,11 @@ where ) { let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); self.close_browsing_context(browsing_context_id, ExitPipelineMode::Normal); + self.browser_ids.remove(&top_level_browsing_context_id); + if self.active_browser_id == Some(top_level_browsing_context_id) { + self.focused_browsing_context_id = None; + self.active_browser_id = None; + } } fn handle_iframe_size_msg( @@ -2741,11 +2754,28 @@ where } fn handle_focus_msg(&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); + let (browsing_context_id, top_level_browsing_context_id) = + match self.pipelines.get(&pipeline_id) { + Some(pipeline) => ( + pipeline.browsing_context_id, + pipeline.top_level_browsing_context_id, + ), + None => return warn!("Pipeline {:?} focus parent after closure.", pipeline_id), + }; + + // Only update `focused_browsing_context_id` if the browsing context for + // which the focus was requested is in the current active browser. + if Some(top_level_browsing_context_id) == self.active_browser_id { + self.focused_browsing_context_id = Some(browsing_context_id); + } + + // But we always need to update the focused browsing context in its + // browser in `browser_ids`. However, there is an opportunity to avoid + // the look up if the focus request targets an already focused browsing + // context. + if Some(browsing_context_id) != self.focused_browsing_context_id { + self.browser_ids.insert(top_level_browsing_context_id, browsing_context_id); + } // Focus parent iframes recursively self.focus_parent_pipeline(browsing_context_id); @@ -3120,7 +3150,7 @@ where // 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. + // browsing context to be the one where the page is being loaded. if self.focused_browsing_context_is_descendant_of(change.browsing_context_id) { self.focused_browsing_context_id = Some(change.browsing_context_id); } @@ -3899,9 +3929,20 @@ where /// Send the current frame tree to compositor fn send_frame_tree(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) { - self.active_browser_id = Some(top_level_browsing_context_id); let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); + // Update the active browser and focused browsing context ids if we're + // sending a frame tree of a different browser than the currently active + // one (i.e. another browser was selected since the last call to + // `send_frame_tree`). + if Some(top_level_browsing_context_id) != self.active_browser_id { + self.active_browser_id = Some(top_level_browsing_context_id); + self.focused_browsing_context_id = self.browser_ids + .get(&top_level_browsing_context_id) + .map(|focus_id| *focus_id) + .or(Some(browsing_context_id)); + } + // 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. From 7be7f18d48d54e8a0288e0f28ddbb3845233bbc7 Mon Sep 17 00:00:00 2001 From: mandreyel Date: Fri, 2 Nov 2018 18:55:16 +0100 Subject: [PATCH 2/3] Add browsers map to Constellation for per browser bookkeeping --- components/constellation/constellation.rs | 141 +++++++++++++--------- 1 file changed, 85 insertions(+), 56 deletions(-) diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 127f6b2ff39..4c7c881a1ca 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -155,6 +155,17 @@ use timer_scheduler::TimerScheduler; use webrender_api; use webvr_traits::{WebVREvent, WebVRMsg}; +/// Servo supports tabs (referred to as browsers), so `Constellation` needs to +/// store browser specific data for bookkeeping. +struct Browser { + /// The currently focused browsing context for key events. The focused + /// pipeline is the current entry of the focused browsing context. + focused_browsing_context_id: BrowsingContextId, + + /// The joint session history for this browser. + session_history: JointSessionHistory, +} + /// The `Constellation` itself. In the servo browser, there is one /// constellation, which maintains all of the browser global data. /// In embedded applications, there may be more than one constellation, @@ -201,16 +212,21 @@ pub struct Constellation { /// constellation to send messages to the compositor thread. compositor_proxy: CompositorProxy, - /// The last frame tree sent to WebRender. + /// The last frame tree sent to WebRender, denoting the browser (tab) user + /// has currently selected. This also serves as a key to the retrieve data + /// about the current active browser from the `browsers` hash map. active_browser_id: Option, - /// All the browsers in constellation. Since the active browser - /// (`active_browser_id`) may change with the `SelectBrowser` message (e.g. - /// when user switches to another tab), we must keep track of each browser's - /// focused browsing context so that we can restore the - /// `focused_browsing_context_id` to point to the active browser's focused - /// browsing context. - browser_ids: HashMap, + /// All the browsers in constellation. + /// + /// TODO: update docs + /// + /// Since the active browser (`active_browser_id`) may change with the + /// `SelectBrowser` message (e.g. when user switches to another tab), we + /// must keep track of each browser's focused browsing context so that we + /// can restore the `focused_browsing_context_id` to point to the active + /// browser's focused browsing context. + browsers: HashMap, /// The currently focused browsing context for key events. The focused /// pipeline is the current entry of the focused browsing context. This @@ -287,10 +303,8 @@ pub struct Constellation { /// to become same-origin, at which point they can share DOM objects. event_loops: HashMap>, - joint_session_histories: HashMap, - - /// The set of all the pipelines in the browser. - /// (See the `pipeline` module for more details.) + /// The set of all the pipelines in the browser. (See the `pipeline` module + /// for more details.) pipelines: HashMap, /// The set of all the browsing contexts in the browser. @@ -600,7 +614,7 @@ where embedder_proxy: state.embedder_proxy, compositor_proxy: state.compositor_proxy, active_browser_id: None, - browser_ids: HashMap::new(), + browsers: HashMap::new(), focused_browsing_context_id: None, debugger_chan: state.debugger_chan, devtools_chan: state.devtools_chan, @@ -612,7 +626,6 @@ where swmanager_receiver: swmanager_receiver, swmanager_sender: sw_mgr_clone, event_loops: HashMap::new(), - joint_session_histories: HashMap::new(), pipelines: HashMap::new(), browsing_contexts: HashMap::new(), pending_changes: vec![], @@ -1657,13 +1670,14 @@ where // Register this new top-level browsing context id as a browser and set // its focused browsing context to be itself. - self.browser_ids.insert(top_level_browsing_context_id, browsing_context_id); + self.browsers.insert(top_level_browsing_context_id, Browser { + focused_browsing_context_id: browsing_context_id, + session_history: JointSessionHistory::new(), + }); 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( pipeline_id, browsing_context_id, @@ -1695,7 +1709,7 @@ where ) { let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); self.close_browsing_context(browsing_context_id, ExitPipelineMode::Normal); - self.browser_ids.remove(&top_level_browsing_context_id); + self.browsers.remove(&top_level_browsing_context_id); if self.active_browser_id == Some(top_level_browsing_context_id) { self.focused_browsing_context_id = None; self.active_browser_id = None; @@ -1979,7 +1993,10 @@ where assert!(!self.pipelines.contains_key(&new_pipeline_id)); self.pipelines.insert(new_pipeline_id, pipeline); - self.joint_session_histories.insert(new_top_level_browsing_context_id, JointSessionHistory::new()); + self.browsers.insert(new_top_level_browsing_context_id, Browser { + focused_browsing_context_id: new_browsing_context_id, + session_history: JointSessionHistory::new(), + }); self.add_pending_change(SessionHistoryChange { top_level_browsing_context_id: new_top_level_browsing_context_id, browsing_context_id: new_browsing_context_id, @@ -2571,9 +2588,9 @@ where sender: IpcSender, ) { let length = self - .joint_session_histories + .browsers .get(&top_level_browsing_context_id) - .map(JointSessionHistory::history_length) + .map(|browser| browser.session_history.history_length()) .unwrap_or(1); let _ = sender.send(length as u32); } @@ -2770,11 +2787,18 @@ where } // But we always need to update the focused browsing context in its - // browser in `browser_ids`. However, there is an opportunity to avoid - // the look up if the focus request targets an already focused browsing + // browser in `browsers`. However, there is an opportunity to avoid the + // look up if the focus request targets an already focused browsing // context. if Some(browsing_context_id) != self.focused_browsing_context_id { - self.browser_ids.insert(top_level_browsing_context_id, browsing_context_id); + let browser = match self.browsers.get_mut(&top_level_browsing_context_id) { + Some(browser) => browser, + None => return warn!( + "Browser {} for focus msg does not exist", + top_level_browsing_context_id + ), + }; + browser.focused_browsing_context_id = browsing_context_id; } // Focus parent iframes recursively @@ -3000,11 +3024,8 @@ where // LoadData of inner frames are ignored and replaced with the LoadData // of the parent. - let session_history = match self - .joint_session_histories - .get(&top_level_browsing_context_id) - { - Some(session_history) => session_history, + let session_history = match self.browsers.get(&top_level_browsing_context_id) { + Some(browser) => &browser.session_history, None => { return warn!( "Session history does not exist for {}", @@ -3199,24 +3220,17 @@ where let (pipelines_to_close, states_to_close) = if let Some(replace_reloader) = change.replace { - let session_history = self - .joint_session_histories - .entry(change.top_level_browsing_context_id) - .or_insert(JointSessionHistory::new()); - session_history.replace_reloader( - replace_reloader.clone(), - NeedsToReload::No(change.new_pipeline_id), - ); + self.get_joint_session_history(change.top_level_browsing_context_id) + .replace_reloader( + replace_reloader.clone(), + NeedsToReload::No(change.new_pipeline_id), + ); match replace_reloader { NeedsToReload::No(pipeline_id) => (Some(vec![pipeline_id]), None), NeedsToReload::Yes(..) => (None, None), } } else { - let session_history = self - .joint_session_histories - .entry(change.top_level_browsing_context_id) - .or_insert(JointSessionHistory::new()); let diff = SessionHistoryDiff::BrowsingContextDiff { browsing_context_id: change.browsing_context_id, new_reloader: NeedsToReload::No(change.new_pipeline_id), @@ -3226,7 +3240,9 @@ where let mut pipelines_to_close = vec![]; let mut states_to_close = HashMap::new(); - let diffs_to_close = session_history.push_diff(diff); + let diffs_to_close = self + .get_joint_session_history(change.top_level_browsing_context_id) + .push_diff(diff); for diff in diffs_to_close { match diff { @@ -3749,17 +3765,23 @@ where top_level_browsing_context_id: TopLevelBrowsingContextId, pipeline_id: PipelineId, ) { - let load_data = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.load_data.clone(), - None => return, + match self.browsers.get_mut(&top_level_browsing_context_id) { + Some(browser) => { + let load_data = match self.pipelines.get(&pipeline_id) { + Some(pipeline) => pipeline.load_data.clone(), + None => return warn!("Discarding closed pipeline {}", pipeline_id), + }; + browser.session_history.replace_reloader( + NeedsToReload::No(pipeline_id), + NeedsToReload::Yes(pipeline_id, load_data), + ); + }, + None => return warn!( + "Discarding pipeline {} after browser {} closure", + pipeline_id, + top_level_browsing_context_id, + ), }; - self.joint_session_histories - .entry(top_level_browsing_context_id) - .or_insert(JointSessionHistory::new()) - .replace_reloader( - NeedsToReload::No(pipeline_id), - NeedsToReload::Yes(pipeline_id, load_data), - ); self.close_pipeline( pipeline_id, DiscardBrowsingContext::No, @@ -3878,9 +3900,16 @@ where &mut self, top_level_id: TopLevelBrowsingContextId, ) -> &mut JointSessionHistory { - self.joint_session_histories + &mut self.browsers .entry(top_level_id) - .or_insert(JointSessionHistory::new()) + // This shouldn't be necessary since `get_joint_session_history` is + // invoked for existing browsers but we need this to satisfy the + // type system. + .or_insert_with(|| Browser { + focused_browsing_context_id: BrowsingContextId::from(top_level_id), + session_history: JointSessionHistory::new(), + }) + .session_history } // Convert a browsing context to a sendable form to pass to the compositor @@ -3937,9 +3966,9 @@ where // `send_frame_tree`). if Some(top_level_browsing_context_id) != self.active_browser_id { self.active_browser_id = Some(top_level_browsing_context_id); - self.focused_browsing_context_id = self.browser_ids + self.focused_browsing_context_id = self.browsers .get(&top_level_browsing_context_id) - .map(|focus_id| *focus_id) + .map(|browser| browser.focused_browsing_context_id) .or(Some(browsing_context_id)); } From 0ed9b682a25c8ba888ad544bfe3b636075401169 Mon Sep 17 00:00:00 2001 From: mandreyel Date: Fri, 2 Nov 2018 19:54:22 +0100 Subject: [PATCH 3/3] Remove Constellation::focused_browsing_context_id --- components/constellation/constellation.rs | 108 ++++++++-------------- 1 file changed, 39 insertions(+), 69 deletions(-) diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 4c7c881a1ca..440deea7877 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -158,8 +158,9 @@ use webvr_traits::{WebVREvent, WebVRMsg}; /// Servo supports tabs (referred to as browsers), so `Constellation` needs to /// store browser specific data for bookkeeping. struct Browser { - /// The currently focused browsing context for key events. The focused - /// pipeline is the current entry of the focused browsing context. + /// The currently focused browsing context in this browser for key events. + /// The focused pipeline is the current entry of the focused browsing + /// context. focused_browsing_context_id: BrowsingContextId, /// The joint session history for this browser. @@ -213,31 +214,16 @@ pub struct Constellation { compositor_proxy: CompositorProxy, /// The last frame tree sent to WebRender, denoting the browser (tab) user - /// has currently selected. This also serves as a key to the retrieve data - /// about the current active browser from the `browsers` hash map. + /// has currently selected. This also serves as the key to retrieve data + /// about the current active browser from `browsers`. active_browser_id: Option, - /// All the browsers in constellation. - /// - /// TODO: update docs - /// - /// Since the active browser (`active_browser_id`) may change with the - /// `SelectBrowser` message (e.g. when user switches to another tab), we - /// must keep track of each browser's focused browsing context so that we - /// can restore the `focused_browsing_context_id` to point to the active - /// browser's focused browsing context. + /// Bookkeeping data for all browsers in constellation. browsers: HashMap, - /// The currently focused browsing context for key events. The focused - /// pipeline is the current entry of the focused browsing context. This - /// field is always updated to be the focused browsing context of the - /// current active browser. - focused_browsing_context_id: Option, - /// Channels for the constellation to send messages to the public - /// resource-related threads. There are two groups of resource - /// threads: one for public browsing, and one for private - /// browsing. + /// resource-related threads. There are two groups of resource threads: one + /// for public browsing, and one for private browsing. public_resource_threads: ResourceThreads, /// Channels for the constellation to send messages to the private @@ -615,7 +601,6 @@ where compositor_proxy: state.compositor_proxy, active_browser_id: None, browsers: HashMap::new(), - focused_browsing_context_id: None, debugger_chan: state.debugger_chan, devtools_chan: state.devtools_chan, bluetooth_thread: state.bluetooth_thread, @@ -1674,9 +1659,6 @@ where focused_browsing_context_id: browsing_context_id, session_history: JointSessionHistory::new(), }); - if self.focused_browsing_context_id.is_none() { - self.focused_browsing_context_id = Some(browsing_context_id); - } self.new_pipeline( pipeline_id, @@ -1711,7 +1693,6 @@ where self.close_browsing_context(browsing_context_id, ExitPipelineMode::Normal); self.browsers.remove(&top_level_browsing_context_id); if self.active_browser_id == Some(top_level_browsing_context_id) { - self.focused_browsing_context_id = None; self.active_browser_id = None; } } @@ -2661,7 +2642,11 @@ where fn handle_key_msg(&mut self, event: KeyboardEvent) { // 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 { + let focused_browsing_context_id = self + .active_browser_id + .and_then(|browser_id| self.browsers.get(&browser_id)) + .map(|browser| browser.focused_browsing_context_id); + match focused_browsing_context_id { Some(browsing_context_id) => { let event = CompositorEvent::KeyboardEvent(event); let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { @@ -2674,9 +2659,10 @@ where let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); let result = match self.pipelines.get(&pipeline_id) { Some(pipeline) => pipeline.event_loop.send(msg), - None => { - return debug!("Pipeline {:?} got key event after closure.", pipeline_id) - }, + None => return debug!( + "Pipeline {:?} got key event after closure.", + pipeline_id + ), }; if let Err(e) = result { self.handle_send_error(pipeline_id, e); @@ -2780,26 +2766,16 @@ where None => return warn!("Pipeline {:?} focus parent after closure.", pipeline_id), }; - // Only update `focused_browsing_context_id` if the browsing context for - // which the focus was requested is in the current active browser. - if Some(top_level_browsing_context_id) == self.active_browser_id { - self.focused_browsing_context_id = Some(browsing_context_id); - } - - // But we always need to update the focused browsing context in its - // browser in `browsers`. However, there is an opportunity to avoid the - // look up if the focus request targets an already focused browsing - // context. - if Some(browsing_context_id) != self.focused_browsing_context_id { - let browser = match self.browsers.get_mut(&top_level_browsing_context_id) { - Some(browser) => browser, - None => return warn!( - "Browser {} for focus msg does not exist", - top_level_browsing_context_id - ), - }; - browser.focused_browsing_context_id = browsing_context_id; - } + // Update the focused browsing context in its browser in `browsers`. + match self.browsers.get_mut(&top_level_browsing_context_id) { + Some(browser) => { + browser.focused_browsing_context_id = browsing_context_id; + }, + None => return warn!( + "Browser {} for focus msg does not exist", + top_level_browsing_context_id + ), + }; // Focus parent iframes recursively self.focus_parent_pipeline(browsing_context_id); @@ -3173,7 +3149,11 @@ where // context in which the page is being loaded, then update the focused // browsing context to be the one where the page is being loaded. if self.focused_browsing_context_is_descendant_of(change.browsing_context_id) { - self.focused_browsing_context_id = Some(change.browsing_context_id); + self.browsers + .entry(change.top_level_browsing_context_id) + .and_modify(|browser| { + browser.focused_browsing_context_id = change.browsing_context_id + }); } let (old_pipeline_id, top_level_id) = @@ -3316,7 +3296,11 @@ where &self, browsing_context_id: BrowsingContextId ) -> bool { - self.focused_browsing_context_id.map_or(false, |focus_ctx_id| { + let focused_browsing_context_id = self + .active_browser_id + .and_then(|browser_id| self.browsers.get(&browser_id)) + .map(|browser| browser.focused_browsing_context_id); + 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) @@ -3479,10 +3463,7 @@ where // // 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.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 { + let top_level_browsing_context_id = match self.active_browser_id { Some(id) => id, None => return ReadyToSave::NoTopLevelBrowsingContext, }; @@ -3958,20 +3939,9 @@ where /// Send the current frame tree to compositor fn send_frame_tree(&mut self, top_level_browsing_context_id: TopLevelBrowsingContextId) { + self.active_browser_id = Some(top_level_browsing_context_id); let browsing_context_id = BrowsingContextId::from(top_level_browsing_context_id); - // Update the active browser and focused browsing context ids if we're - // sending a frame tree of a different browser than the currently active - // one (i.e. another browser was selected since the last call to - // `send_frame_tree`). - if Some(top_level_browsing_context_id) != self.active_browser_id { - self.active_browser_id = Some(top_level_browsing_context_id); - self.focused_browsing_context_id = self.browsers - .get(&top_level_browsing_context_id) - .map(|browser| browser.focused_browsing_context_id) - .or(Some(browsing_context_id)); - } - // 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.