diff options
author | Shubham Gupta <32428749+shubhamg13@users.noreply.github.com> | 2025-04-04 15:34:19 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-04 07:34:19 +0000 |
commit | df9efde1c377f0ff701fdd72814b628e73397464 (patch) | |
tree | fa3ae808ca3102600b891abe342dc053e1dff629 | |
parent | b4079b3ff33a3f7e2b35ac3aacc4467f8da42242 (diff) | |
download | servo-df9efde1c377f0ff701fdd72814b628e73397464.tar.gz servo-df9efde1c377f0ff701fdd72814b628e73397464.zip |
Separate `WebviewManager` from `Webview` in `compositor` and `constellation` (#36302)
Create a separate file for `WebviewManager` to improve clarity.
Testing: This change is just a refactor, so no new tests are needed.
Signed-off-by: Shubham Gupta <shubham13297@gmail.com>
-rw-r--r-- | components/compositing/compositor.rs | 3 | ||||
-rw-r--r-- | components/compositing/lib.rs | 1 | ||||
-rw-r--r-- | components/compositing/webview.rs | 236 | ||||
-rw-r--r-- | components/compositing/webview_manager.rs | 246 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 2 | ||||
-rw-r--r-- | components/constellation/lib.rs | 2 | ||||
-rw-r--r-- | components/constellation/webview_manager.rs (renamed from components/constellation/webview.rs) | 2 |
7 files changed, 253 insertions, 239 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index fc9cd16ebc9..90a7bb24cd1 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -58,7 +58,8 @@ use webrender_traits::rendering_context::RenderingContext; use webrender_traits::{CrossProcessCompositorMessage, ImageUpdate, RendererWebView}; use crate::InitialCompositorState; -use crate::webview::{UnknownWebView, WebView, WebViewManager}; +use crate::webview::{UnknownWebView, WebView}; +use crate::webview_manager::WebViewManager; use crate::windowing::{self, WebRenderDebugOption, WindowMethods}; #[derive(Debug, PartialEq)] diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index 683677d437d..78b5355b6ad 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -24,6 +24,7 @@ mod tracing; mod compositor; mod touch; pub mod webview; +pub mod webview_manager; pub mod windowing; /// Data used to construct a compositor. diff --git a/components/compositing/webview.rs b/components/compositing/webview.rs index 58fda6d20e5..a3140425563 100644 --- a/components/compositing/webview.rs +++ b/components/compositing/webview.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use std::collections::HashMap; -use std::collections::hash_map::{Entry, Keys, Values, ValuesMut}; +use std::collections::hash_map::Keys; use std::rc::Rc; use base::id::{PipelineId, WebViewId}; @@ -845,240 +845,6 @@ impl WebView { .push(ScrollZoomEvent::PinchZoom(magnification)); } } -#[derive(Debug)] -pub struct WebViewManager<WebView> { - /// Our top-level browsing contexts. In the WebRender scene, their pipelines are the children of - /// a single root pipeline that also applies any pinch zoom transformation. - webviews: HashMap<WebViewId, WebView>, - - /// The order to paint them in, topmost last. - pub(crate) painting_order: Vec<WebViewId>, -} #[derive(Clone, Copy, Debug, PartialEq)] pub struct UnknownWebView(pub WebViewId); - -impl<WebView> Default for WebViewManager<WebView> { - fn default() -> Self { - Self { - webviews: Default::default(), - painting_order: Default::default(), - } - } -} - -impl<WebView> WebViewManager<WebView> { - pub fn remove(&mut self, webview_id: WebViewId) -> Result<WebView, UnknownWebView> { - self.painting_order.retain(|b| *b != webview_id); - self.webviews - .remove(&webview_id) - .ok_or(UnknownWebView(webview_id)) - } - - pub fn get(&self, webview_id: WebViewId) -> Option<&WebView> { - self.webviews.get(&webview_id) - } - - pub fn get_mut(&mut self, webview_id: WebViewId) -> Option<&mut WebView> { - self.webviews.get_mut(&webview_id) - } - - /// Returns true iff the painting order actually changed. - pub fn show(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> { - if !self.webviews.contains_key(&webview_id) { - return Err(UnknownWebView(webview_id)); - } - if !self.painting_order.contains(&webview_id) { - self.painting_order.push(webview_id); - return Ok(true); - } - Ok(false) - } - - /// Returns true iff the painting order actually changed. - pub fn hide(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> { - if !self.webviews.contains_key(&webview_id) { - return Err(UnknownWebView(webview_id)); - } - if self.painting_order.contains(&webview_id) { - self.painting_order.retain(|b| *b != webview_id); - return Ok(true); - } - Ok(false) - } - - /// Returns true iff the painting order actually changed. - pub fn hide_all(&mut self) -> bool { - if !self.painting_order.is_empty() { - self.painting_order.clear(); - return true; - } - false - } - - /// Returns true iff the painting order actually changed. - pub fn raise_to_top(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> { - if !self.webviews.contains_key(&webview_id) { - return Err(UnknownWebView(webview_id)); - } - if self.painting_order.last() != Some(&webview_id) { - self.hide(webview_id)?; - self.show(webview_id)?; - return Ok(true); - } - Ok(false) - } - - pub fn painting_order(&self) -> impl Iterator<Item = (&WebViewId, &WebView)> { - self.painting_order - .iter() - .flat_map(move |webview_id| self.get(*webview_id).map(|b| (webview_id, b))) - } - - pub fn entry(&mut self, webview_id: WebViewId) -> Entry<'_, WebViewId, WebView> { - self.webviews.entry(webview_id) - } - - pub fn iter(&self) -> Values<'_, WebViewId, WebView> { - self.webviews.values() - } - - pub fn iter_mut(&mut self) -> ValuesMut<'_, WebViewId, WebView> { - self.webviews.values_mut() - } -} - -#[cfg(test)] -mod test { - use std::num::NonZeroU32; - - use base::id::{ - BrowsingContextId, BrowsingContextIndex, PipelineNamespace, PipelineNamespaceId, WebViewId, - }; - - use crate::webview::{UnknownWebView, WebViewManager}; - - fn top_level_id(namespace_id: u32, index: u32) -> WebViewId { - WebViewId(BrowsingContextId { - namespace_id: PipelineNamespaceId(namespace_id), - index: BrowsingContextIndex(NonZeroU32::new(index).unwrap()), - }) - } - - fn webviews_sorted<WebView: Clone>( - webviews: &WebViewManager<WebView>, - ) -> Vec<(WebViewId, WebView)> { - let mut keys = webviews.webviews.keys().collect::<Vec<_>>(); - keys.sort(); - keys.iter() - .map(|&id| (*id, webviews.webviews.get(id).cloned().unwrap())) - .collect() - } - - #[test] - fn test() { - PipelineNamespace::install(PipelineNamespaceId(0)); - let mut webviews = WebViewManager::default(); - - // entry() adds the webview to the map, but not the painting order. - webviews.entry(WebViewId::new()).or_insert('a'); - webviews.entry(WebViewId::new()).or_insert('b'); - webviews.entry(WebViewId::new()).or_insert('c'); - assert!(webviews.get(top_level_id(0, 1)).is_some()); - assert!(webviews.get(top_level_id(0, 2)).is_some()); - assert!(webviews.get(top_level_id(0, 3)).is_some()); - assert_eq!( - webviews_sorted(&webviews), - vec![ - (top_level_id(0, 1), 'a'), - (top_level_id(0, 2), 'b'), - (top_level_id(0, 3), 'c'), - ] - ); - assert!(webviews.painting_order.is_empty()); - - // add() returns WebViewAlreadyExists if the webview id already exists. - webviews.entry(top_level_id(0, 3)).or_insert('d'); - assert!(webviews.get(top_level_id(0, 3)).is_some()); - - // Other methods return UnknownWebView or None if the webview id doesn’t exist. - assert_eq!( - webviews.remove(top_level_id(1, 1)), - Err(UnknownWebView(top_level_id(1, 1))) - ); - assert_eq!(webviews.get(top_level_id(1, 1)), None); - assert_eq!(webviews.get_mut(top_level_id(1, 1)), None); - assert_eq!( - webviews.show(top_level_id(1, 1)), - Err(UnknownWebView(top_level_id(1, 1))) - ); - assert_eq!( - webviews.hide(top_level_id(1, 1)), - Err(UnknownWebView(top_level_id(1, 1))) - ); - assert_eq!( - webviews.raise_to_top(top_level_id(1, 1)), - Err(UnknownWebView(top_level_id(1, 1))) - ); - - // For webviews not yet visible, both show() and raise_to_top() add the given webview on top. - assert_eq!(webviews.show(top_level_id(0, 2)), Ok(true)); - assert_eq!(webviews.show(top_level_id(0, 2)), Ok(false)); - assert_eq!(webviews.painting_order, vec![top_level_id(0, 2)]); - assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(true)); - assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(false)); - assert_eq!( - webviews.painting_order, - vec![top_level_id(0, 2), top_level_id(0, 1)] - ); - assert_eq!(webviews.show(top_level_id(0, 3)), Ok(true)); - assert_eq!(webviews.show(top_level_id(0, 3)), Ok(false)); - assert_eq!( - webviews.painting_order, - vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)] - ); - - // For webviews already visible, show() does nothing, while raise_to_top() makes it on top. - assert_eq!(webviews.show(top_level_id(0, 1)), Ok(false)); - assert_eq!( - webviews.painting_order, - vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)] - ); - assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(true)); - assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(false)); - assert_eq!( - webviews.painting_order, - vec![top_level_id(0, 2), top_level_id(0, 3), top_level_id(0, 1)] - ); - - // hide() removes the webview from the painting order, but not the map. - assert_eq!(webviews.hide(top_level_id(0, 3)), Ok(true)); - assert_eq!(webviews.hide(top_level_id(0, 3)), Ok(false)); - assert_eq!( - webviews.painting_order, - vec![top_level_id(0, 2), top_level_id(0, 1)] - ); - assert_eq!( - webviews_sorted(&webviews), - vec![ - (top_level_id(0, 1), 'a'), - (top_level_id(0, 2), 'b'), - (top_level_id(0, 3), 'c'), - ] - ); - - // painting_order() returns only the visible webviews, in painting order. - let mut painting_order = webviews.painting_order(); - assert_eq!(painting_order.next(), Some((&top_level_id(0, 2), &'b'))); - assert_eq!(painting_order.next(), Some((&top_level_id(0, 1), &'a'))); - assert_eq!(painting_order.next(), None); - drop(painting_order); - - // remove() removes the given webview from both the map and the painting order. - assert!(webviews.remove(top_level_id(0, 1)).is_ok()); - assert!(webviews.remove(top_level_id(0, 2)).is_ok()); - assert!(webviews.remove(top_level_id(0, 3)).is_ok()); - assert!(webviews_sorted(&webviews).is_empty()); - assert!(webviews.painting_order.is_empty()); - } -} diff --git a/components/compositing/webview_manager.rs b/components/compositing/webview_manager.rs new file mode 100644 index 00000000000..1f1ced3a468 --- /dev/null +++ b/components/compositing/webview_manager.rs @@ -0,0 +1,246 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use std::collections::HashMap; +use std::collections::hash_map::{Entry, Values, ValuesMut}; + +use base::id::WebViewId; + +use crate::webview::UnknownWebView; + +#[derive(Debug)] +pub struct WebViewManager<WebView> { + /// Our top-level browsing contexts. In the WebRender scene, their pipelines are the children of + /// a single root pipeline that also applies any pinch zoom transformation. + webviews: HashMap<WebViewId, WebView>, + + /// The order to paint them in, topmost last. + pub(crate) painting_order: Vec<WebViewId>, +} + +impl<WebView> Default for WebViewManager<WebView> { + fn default() -> Self { + Self { + webviews: Default::default(), + painting_order: Default::default(), + } + } +} + +impl<WebView> WebViewManager<WebView> { + pub fn remove(&mut self, webview_id: WebViewId) -> Result<WebView, UnknownWebView> { + self.painting_order.retain(|b| *b != webview_id); + self.webviews + .remove(&webview_id) + .ok_or(UnknownWebView(webview_id)) + } + + pub fn get(&self, webview_id: WebViewId) -> Option<&WebView> { + self.webviews.get(&webview_id) + } + + pub fn get_mut(&mut self, webview_id: WebViewId) -> Option<&mut WebView> { + self.webviews.get_mut(&webview_id) + } + + /// Returns true iff the painting order actually changed. + pub fn show(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> { + if !self.webviews.contains_key(&webview_id) { + return Err(UnknownWebView(webview_id)); + } + if !self.painting_order.contains(&webview_id) { + self.painting_order.push(webview_id); + return Ok(true); + } + Ok(false) + } + + /// Returns true iff the painting order actually changed. + pub fn hide(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> { + if !self.webviews.contains_key(&webview_id) { + return Err(UnknownWebView(webview_id)); + } + if self.painting_order.contains(&webview_id) { + self.painting_order.retain(|b| *b != webview_id); + return Ok(true); + } + Ok(false) + } + + /// Returns true iff the painting order actually changed. + pub fn hide_all(&mut self) -> bool { + if !self.painting_order.is_empty() { + self.painting_order.clear(); + return true; + } + false + } + + /// Returns true iff the painting order actually changed. + pub fn raise_to_top(&mut self, webview_id: WebViewId) -> Result<bool, UnknownWebView> { + if !self.webviews.contains_key(&webview_id) { + return Err(UnknownWebView(webview_id)); + } + if self.painting_order.last() != Some(&webview_id) { + self.hide(webview_id)?; + self.show(webview_id)?; + return Ok(true); + } + Ok(false) + } + + pub fn painting_order(&self) -> impl Iterator<Item = (&WebViewId, &WebView)> { + self.painting_order + .iter() + .flat_map(move |webview_id| self.get(*webview_id).map(|b| (webview_id, b))) + } + + pub fn entry(&mut self, webview_id: WebViewId) -> Entry<'_, WebViewId, WebView> { + self.webviews.entry(webview_id) + } + + pub fn iter(&self) -> Values<'_, WebViewId, WebView> { + self.webviews.values() + } + + pub fn iter_mut(&mut self) -> ValuesMut<'_, WebViewId, WebView> { + self.webviews.values_mut() + } +} + +#[cfg(test)] +mod test { + use std::num::NonZeroU32; + + use base::id::{ + BrowsingContextId, BrowsingContextIndex, PipelineNamespace, PipelineNamespaceId, WebViewId, + }; + + use crate::webview::UnknownWebView; + use crate::webview_manager::WebViewManager; + + fn top_level_id(namespace_id: u32, index: u32) -> WebViewId { + WebViewId(BrowsingContextId { + namespace_id: PipelineNamespaceId(namespace_id), + index: BrowsingContextIndex(NonZeroU32::new(index).unwrap()), + }) + } + + fn webviews_sorted<WebView: Clone>( + webviews: &WebViewManager<WebView>, + ) -> Vec<(WebViewId, WebView)> { + let mut keys = webviews.webviews.keys().collect::<Vec<_>>(); + keys.sort(); + keys.iter() + .map(|&id| (*id, webviews.webviews.get(id).cloned().unwrap())) + .collect() + } + + #[test] + fn test() { + PipelineNamespace::install(PipelineNamespaceId(0)); + let mut webviews = WebViewManager::default(); + + // entry() adds the webview to the map, but not the painting order. + webviews.entry(WebViewId::new()).or_insert('a'); + webviews.entry(WebViewId::new()).or_insert('b'); + webviews.entry(WebViewId::new()).or_insert('c'); + assert!(webviews.get(top_level_id(0, 1)).is_some()); + assert!(webviews.get(top_level_id(0, 2)).is_some()); + assert!(webviews.get(top_level_id(0, 3)).is_some()); + assert_eq!( + webviews_sorted(&webviews), + vec![ + (top_level_id(0, 1), 'a'), + (top_level_id(0, 2), 'b'), + (top_level_id(0, 3), 'c'), + ] + ); + assert!(webviews.painting_order.is_empty()); + + // add() returns WebViewAlreadyExists if the webview id already exists. + webviews.entry(top_level_id(0, 3)).or_insert('d'); + assert!(webviews.get(top_level_id(0, 3)).is_some()); + + // Other methods return UnknownWebView or None if the webview id doesn’t exist. + assert_eq!( + webviews.remove(top_level_id(1, 1)), + Err(UnknownWebView(top_level_id(1, 1))) + ); + assert_eq!(webviews.get(top_level_id(1, 1)), None); + assert_eq!(webviews.get_mut(top_level_id(1, 1)), None); + assert_eq!( + webviews.show(top_level_id(1, 1)), + Err(UnknownWebView(top_level_id(1, 1))) + ); + assert_eq!( + webviews.hide(top_level_id(1, 1)), + Err(UnknownWebView(top_level_id(1, 1))) + ); + assert_eq!( + webviews.raise_to_top(top_level_id(1, 1)), + Err(UnknownWebView(top_level_id(1, 1))) + ); + + // For webviews not yet visible, both show() and raise_to_top() add the given webview on top. + assert_eq!(webviews.show(top_level_id(0, 2)), Ok(true)); + assert_eq!(webviews.show(top_level_id(0, 2)), Ok(false)); + assert_eq!(webviews.painting_order, vec![top_level_id(0, 2)]); + assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(true)); + assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(false)); + assert_eq!( + webviews.painting_order, + vec![top_level_id(0, 2), top_level_id(0, 1)] + ); + assert_eq!(webviews.show(top_level_id(0, 3)), Ok(true)); + assert_eq!(webviews.show(top_level_id(0, 3)), Ok(false)); + assert_eq!( + webviews.painting_order, + vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)] + ); + + // For webviews already visible, show() does nothing, while raise_to_top() makes it on top. + assert_eq!(webviews.show(top_level_id(0, 1)), Ok(false)); + assert_eq!( + webviews.painting_order, + vec![top_level_id(0, 2), top_level_id(0, 1), top_level_id(0, 3)] + ); + assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(true)); + assert_eq!(webviews.raise_to_top(top_level_id(0, 1)), Ok(false)); + assert_eq!( + webviews.painting_order, + vec![top_level_id(0, 2), top_level_id(0, 3), top_level_id(0, 1)] + ); + + // hide() removes the webview from the painting order, but not the map. + assert_eq!(webviews.hide(top_level_id(0, 3)), Ok(true)); + assert_eq!(webviews.hide(top_level_id(0, 3)), Ok(false)); + assert_eq!( + webviews.painting_order, + vec![top_level_id(0, 2), top_level_id(0, 1)] + ); + assert_eq!( + webviews_sorted(&webviews), + vec![ + (top_level_id(0, 1), 'a'), + (top_level_id(0, 2), 'b'), + (top_level_id(0, 3), 'c'), + ] + ); + + // painting_order() returns only the visible webviews, in painting order. + let mut painting_order = webviews.painting_order(); + assert_eq!(painting_order.next(), Some((&top_level_id(0, 2), &'b'))); + assert_eq!(painting_order.next(), Some((&top_level_id(0, 1), &'a'))); + assert_eq!(painting_order.next(), None); + drop(painting_order); + + // remove() removes the given webview from both the map and the painting order. + assert!(webviews.remove(top_level_id(0, 1)).is_ok()); + assert!(webviews.remove(top_level_id(0, 2)).is_ok()); + assert!(webviews.remove(top_level_id(0, 3)).is_ok()); + assert!(webviews_sorted(&webviews).is_empty()); + assert!(webviews.painting_order.is_empty()); + } +} diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 3c3a9f761b0..20ff87f8a82 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -175,7 +175,7 @@ use crate::serviceworker::ServiceWorkerUnprivilegedContent; use crate::session_history::{ JointSessionHistory, NeedsToReload, SessionHistoryChange, SessionHistoryDiff, }; -use crate::webview::WebViewManager; +use crate::webview_manager::WebViewManager; type PendingApprovalNavigations = HashMap<PipelineId, (LoadData, NavigationHistoryBehavior)>; diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index e00bc060cd5..20f7b23af46 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -15,7 +15,7 @@ mod pipeline; mod sandboxing; mod serviceworker; mod session_history; -mod webview; +mod webview_manager; pub use crate::constellation::{Constellation, InitialConstellationState}; pub use crate::logging::{FromCompositorLogger, FromScriptLogger}; diff --git a/components/constellation/webview.rs b/components/constellation/webview_manager.rs index 8b134b62f2e..e5e427d40a1 100644 --- a/components/constellation/webview.rs +++ b/components/constellation/webview_manager.rs @@ -87,7 +87,7 @@ mod test { BrowsingContextId, BrowsingContextIndex, PipelineNamespace, PipelineNamespaceId, WebViewId, }; - use crate::webview::WebViewManager; + use crate::webview_manager::WebViewManager; fn id(namespace_id: u32, index: u32) -> WebViewId { WebViewId(BrowsingContextId { |