aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShubham Gupta <32428749+shubhamg13@users.noreply.github.com>2025-04-04 15:34:19 +0800
committerGitHub <noreply@github.com>2025-04-04 07:34:19 +0000
commitdf9efde1c377f0ff701fdd72814b628e73397464 (patch)
treefa3ae808ca3102600b891abe342dc053e1dff629
parentb4079b3ff33a3f7e2b35ac3aacc4467f8da42242 (diff)
downloadservo-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.rs3
-rw-r--r--components/compositing/lib.rs1
-rw-r--r--components/compositing/webview.rs236
-rw-r--r--components/compositing/webview_manager.rs246
-rw-r--r--components/constellation/constellation.rs2
-rw-r--r--components/constellation/lib.rs2
-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 {