Rewild Your Web
web
browser
dweb
1--- original
2+++ modified
3@@ -41,9 +41,9 @@
4 use canvas_traits::webgl::WebGLPipeline;
5 use chrono::{DateTime, Local};
6 use constellation_traits::{
7- JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior, ScreenshotReadinessResponse,
8- ScriptToConstellationChan, ScriptToConstellationMessage, StructuredSerializedData,
9- WindowSizeType,
10+ EmbeddedWebViewEventType, JsEvalResult, LoadData, LoadOrigin, NavigationHistoryBehavior,
11+ ScreenshotReadinessResponse, ScriptToConstellationChan, ScriptToConstellationMessage,
12+ StructuredSerializedData, WindowSizeType,
13 };
14 use crossbeam_channel::unbounded;
15 use data_url::mime::Mime;
16@@ -54,8 +54,8 @@
17 use embedder_traits::user_contents::{UserContentManagerId, UserContents, UserScript};
18 use embedder_traits::{
19 EmbedderControlId, EmbedderControlResponse, EmbedderMsg, FocusSequenceNumber,
20- JavaScriptEvaluationError, JavaScriptEvaluationId, MediaSessionActionType, Theme,
21- ViewportDetails, WebDriverScriptCommand,
22+ JavaScriptEvaluationError, JavaScriptEvaluationId, MediaSessionActionType, ServoErrorType,
23+ Theme, ViewportDetails, WebDriverScriptCommand,
24 };
25 use encoding_rs::Encoding;
26 use fonts::{FontContext, SystemFontServiceProxy};
27@@ -92,6 +92,7 @@
28 UpdatePipelineIdReason,
29 };
30 use servo_arc::Arc as ServoArc;
31+use servo_config::pref_util::PrefValue;
32 use servo_config::{opts, prefs};
33 use servo_url::{ImmutableOrigin, MutableOrigin, OriginSnapshot, ServoUrl};
34 use storage_traits::StorageThreads;
35@@ -1940,11 +1941,22 @@
36 self.handle_refresh_cursor(pipeline_id);
37 },
38 ScriptThreadMessage::PreferencesUpdated(updates) => {
39- let mut current_preferences = prefs::get().clone();
40- for (name, value) in updates {
41- current_preferences.set_value(&name, value);
42+ // Only update core preferences (those without namespace separator)
43+ // Embedder preferences are already stored in the embedder prefs registry
44+ let core_updates: Vec<_> = updates
45+ .iter()
46+ .filter(|(name, _)| !name.contains('.'))
47+ .collect();
48+ if !core_updates.is_empty() {
49+ let mut current_preferences = prefs::get().clone();
50+ for (name, value) in core_updates {
51+ current_preferences.set_value(name, value.clone());
52+ }
53+ prefs::set(current_preferences);
54 }
55- prefs::set(current_preferences);
56+
57+ // Dispatch preferencechanged events to all Embedder instances
58+ self.dispatch_preference_changed_to_embedders(&updates, CanGc::from_cx(cx));
59 },
60 ScriptThreadMessage::ForwardKeyboardScroll(pipeline_id, scroll) => {
61 if let Some(document) = self.documents.borrow().find_document(pipeline_id) {
62@@ -1979,6 +1991,16 @@
63 ScriptThreadMessage::UpdatePinchZoomInfos(id, pinch_zoom_infos) => {
64 self.handle_update_pinch_zoom_infos(id, pinch_zoom_infos, CanGc::from_cx(cx));
65 },
66+ ScriptThreadMessage::DispatchEmbeddedWebViewEvent {
67+ target,
68+ parent,
69+ event,
70+ } => {
71+ self.handle_embedded_webview_event(parent, target, event, CanGc::from_cx(cx));
72+ },
73+ ScriptThreadMessage::DispatchServoError(error_type, message) => {
74+ self.handle_dispatch_servo_error(error_type, message, CanGc::from_cx(cx));
75+ },
76 }
77 }
78
79@@ -2925,6 +2947,9 @@
80 .documents
81 .borrow()
82 .find_iframe(parent_pipeline_id, browsing_context_id);
83+ let is_embedded_webview = frame_element
84+ .as_ref()
85+ .is_some_and(|iframe| iframe.is_embedded_webview());
86 if let Some(frame_element) = frame_element {
87 frame_element.update_pipeline_id(new_pipeline_id, reason, can_gc);
88 }
89@@ -2943,6 +2968,7 @@
90 // is no need to pass along existing opener information that
91 // will be discarded.
92 None,
93+ is_embedded_webview,
94 );
95 }
96 }
97@@ -3222,6 +3248,44 @@
98 }
99 }
100
101+ /// Handle an embedded webview event that should be dispatched on an iframe element.
102+ fn handle_embedded_webview_event(
103+ &self,
104+ parent_id: PipelineId,
105+ browsing_context_id: BrowsingContextId,
106+ event: EmbeddedWebViewEventType,
107+ can_gc: CanGc,
108+ ) {
109+ let iframe = self
110+ .documents
111+ .borrow()
112+ .find_iframe(parent_id, browsing_context_id);
113+ match iframe {
114+ Some(iframe) => iframe.dispatch_embedded_webview_event(event, can_gc),
115+ None => warn!(
116+ "Embedded webview event sent to closed pipeline {}.",
117+ parent_id
118+ ),
119+ }
120+ }
121+
122+ /// Handle a servo error by dispatching servoerror events to all navigator.embedder instances.
123+ fn handle_dispatch_servo_error(
124+ &self,
125+ error_type: ServoErrorType,
126+ message: String,
127+ can_gc: CanGc,
128+ ) {
129+ // Dispatch servoerror event to windows that already have an Embedder created
130+ for (_, document) in self.documents.borrow().iter() {
131+ if let Some(embedder) = document.window().Navigator().get_embedder() {
132+ // Enter the realm of the embedder's global before dispatching JS events
133+ let _ac = enter_realm(&*embedder);
134+ embedder.dispatch_servo_error(&error_type, &message, can_gc);
135+ }
136+ }
137+ }
138+
139 fn ask_constellation_for_top_level_info(
140 &self,
141 sender_webview_id: WebViewId,
142@@ -3334,7 +3398,13 @@
143 self.senders.pipeline_to_embedder_sender.clone(),
144 self.senders.constellation_sender.clone(),
145 incomplete.pipeline_id,
146- incomplete.parent_info,
147+ // For embedded webviews, don't pass parent_info to Window so that
148+ // is_top_level() returns true (they are top-level browsing contexts).
149+ if incomplete.is_embedded_webview {
150+ None
151+ } else {
152+ incomplete.parent_info
153+ },
154 incomplete.viewport_details,
155 origin.clone(),
156 final_url.clone(),
157@@ -3356,6 +3426,8 @@
158 #[cfg(feature = "webgpu")]
159 self.gpu_id_hub.clone(),
160 incomplete.load_data.inherited_secure_context,
161+ incomplete.is_embedded_webview,
162+ incomplete.hide_focus,
163 incomplete.theme,
164 self.this.clone(),
165 );
166@@ -3377,6 +3449,7 @@
167 incomplete.webview_id,
168 incomplete.parent_info,
169 incomplete.opener,
170+ incomplete.is_embedded_webview,
171 );
172 if window_proxy.parent().is_some() {
173 // https://html.spec.whatwg.org/multipage/#navigating-across-documents:delaying-load-events-mode-2
174@@ -4084,6 +4157,24 @@
175 document.event_handler().handle_refresh_cursor();
176 }
177
178+ /// Dispatch preferencechanged events to all Embedder instances in this script thread.
179+ fn dispatch_preference_changed_to_embedders(
180+ &self,
181+ changes: &[(String, PrefValue)],
182+ can_gc: CanGc,
183+ ) {
184+ // Dispatch preferencechanged event to windows that already have an Embedder created
185+ for (_, document) in self.documents.borrow().iter() {
186+ if let Some(embedder) = document.window().Navigator().get_embedder() {
187+ // Enter the realm of the embedder's global before dispatching JS events
188+ let _ac = enter_realm(&*embedder);
189+ for (name, value) in changes {
190+ embedder.dispatch_preference_changed(name, value, can_gc);
191+ }
192+ }
193+ }
194+ }
195+
196 pub(crate) fn is_servo_privileged(url: ServoUrl) -> bool {
197 with_script_thread(|script_thread| script_thread.privileged_urls.contains(&url))
198 }