libservo: Let UserContentManager be per WebView and add basic support for mutations. (#41352)

This change moves the `UserContentManager` abstraction from the
`ServoBuilder` to `WebViewBuilder` so that embedders can inject content
for each `WebView` independently. It also adds basic support for runtime
mutations to the `UserContentManager` API. Only adding new scripts is
currently supported, but future changes will add support for both other
mutations such as removal of scripts and addition & removal of
stylesheets. Future changes could also optimize the way mutations are
propagated to `ScriptThread`s by sending just the "delta" rather than
the whole `UserContents` structure for each mutation.

The `UserContentManager` now becomes just a convenient handle for the
embedders to invoke the mutation API while the actual management of the
manager's content is handled by the Constellation. The mutations are
relayed to the constellation via messages. The change also separates the
serialized version containg the user contents into a new `UserContent`
structure so that the API cannot be misused.

Testing: New unit tests have been added for the different scenarios
involving UserContentManager.

---------

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Mukilan Thiyagarajan
2025-12-23 11:45:01 +05:30
committed by GitHub
parent 4323a42ade
commit 2ccd9f54ad
25 changed files with 486 additions and 94 deletions

View File

@@ -35,7 +35,7 @@ use crossbeam_channel::{Sender, unbounded};
use cssparser::SourceLocation;
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
use dom_struct::dom_struct;
use embedder_traits::user_content_manager::{UserContentManager, UserScript};
use embedder_traits::user_contents::{UserContents, UserScript};
use embedder_traits::{
AlertResponse, ConfirmResponse, EmbedderMsg, JavaScriptEvaluationError, PromptResponse,
ScriptToEmbedderChan, SimpleDialogRequest, Theme, UntrustedNodeAddress, ViewportDetails,
@@ -418,9 +418,10 @@ pub(crate) struct Window {
/// Unminify Css.
unminify_css: bool,
/// User content manager
/// The [`UserContents`] that is potentially shared with other `WebView`s in this `ScriptThread`.
#[no_trace]
user_content_manager: UserContentManager,
#[conditional_malloc_size_of]
user_contents: Option<Rc<UserContents>>,
/// Window's GL context from application
#[ignore_malloc_size_of = "defined in script_thread"]
@@ -749,7 +750,10 @@ impl Window {
}
pub(crate) fn userscripts(&self) -> &[UserScript] {
self.user_content_manager.scripts()
self.user_contents
.as_ref()
.map(|user_contents| user_contents.scripts.as_slice())
.unwrap_or(&[])
}
pub(crate) fn get_player_context(&self) -> WindowGLContext {
@@ -3479,7 +3483,7 @@ impl Window {
unminify_js: bool,
unminify_css: bool,
local_script_source: Option<String>,
user_content_manager: UserContentManager,
user_contents: Option<Rc<UserContents>>,
player_context: WindowGLContext,
#[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
inherited_secure_context: Option<bool>,
@@ -3561,7 +3565,7 @@ impl Window {
paint_api,
has_sent_idle_message: Cell::new(false),
unminify_css,
user_content_manager,
user_contents,
player_context,
throttled: Cell::new(false),
layout_marker: DomRefCell::new(Rc::new(Cell::new(true))),