Rewild Your Web
web
browser
dweb
1--- original
2+++ modified
3@@ -38,7 +38,7 @@
4 use embedder_traits::{
5 AlertResponse, ConfirmResponse, EmbedderMsg, JavaScriptEvaluationError, PromptResponse,
6 ScriptToEmbedderChan, SimpleDialogRequest, Theme, UntrustedNodeAddress, ViewportDetails,
7- WebDriverJSResult, WebDriverLoadStatus,
8+ WebDriverJSResult, WebDriverLoadStatus, WebViewPoint,
9 };
10 use euclid::default::Rect as UntypedRect;
11 use euclid::{Point2D, Rect, Scale, Size2D, Vector2D};
12@@ -1139,12 +1139,22 @@
13
14 let (sender, receiver) =
15 ProfiledGenericChannel::channel(self.global().time_profiler_chan().clone()).unwrap();
16+
17 let dialog = SimpleDialogRequest::Alert {
18 id: self.Document().embedder_controls().next_control_id(),
19 message: message.to_string(),
20 response_sender: sender,
21 };
22- self.send_to_embedder(EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog));
23+
24+ // For embedded webviews, route through constellation to parent shell
25+ if self.as_global_scope().is_embedded_webview() {
26+ self.Document()
27+ .embedder_controls()
28+ .show_simple_dialog_for_embedded_webview(dialog);
29+ } else {
30+ self.send_to_embedder(EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog));
31+ }
32+
33 receiver.recv().unwrap_or_else(|_| {
34 // If the receiver is closed, we assume the dialog was cancelled.
35 debug!("Alert dialog was cancelled or failed to show.");
36@@ -1172,13 +1182,22 @@
37 // the user to respond with a positive or negative response.
38 let (sender, receiver) =
39 ProfiledGenericChannel::channel(self.global().time_profiler_chan().clone()).unwrap();
40+
41 let dialog = SimpleDialogRequest::Confirm {
42 id: self.Document().embedder_controls().next_control_id(),
43 message: message.to_string(),
44 response_sender: sender,
45 };
46- self.send_to_embedder(EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog));
47
48+ // For embedded webviews, route through constellation to parent shell
49+ if self.as_global_scope().is_embedded_webview() {
50+ self.Document()
51+ .embedder_controls()
52+ .show_simple_dialog_for_embedded_webview(dialog);
53+ } else {
54+ self.send_to_embedder(EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog));
55+ }
56+
57 // Step 5: Let userPromptHandler be WebDriver BiDi user prompt opened with this,
58 // "confirm", and message.
59 //
60@@ -1223,6 +1242,7 @@
61 // defaulted to the value given by default.
62 let (sender, receiver) =
63 ProfiledGenericChannel::channel(self.global().time_profiler_chan().clone()).unwrap();
64+
65 let dialog = SimpleDialogRequest::Prompt {
66 id: self.Document().embedder_controls().next_control_id(),
67 message: message.to_string(),
68@@ -1229,8 +1249,16 @@
69 default: default.to_string(),
70 response_sender: sender,
71 };
72- self.send_to_embedder(EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog));
73
74+ // For embedded webviews, route through constellation to parent shell
75+ if self.as_global_scope().is_embedded_webview() {
76+ self.Document()
77+ .embedder_controls()
78+ .show_simple_dialog_for_embedded_webview(dialog);
79+ } else {
80+ self.send_to_embedder(EmbedderMsg::ShowSimpleDialog(self.webview_id(), dialog));
81+ }
82+
83 // Step 6: Let userPromptHandler be WebDriver BiDi user prompt opened with this,
84 // "prompt", and message.
85 // TODO: Add support for WebDriver BiDi.
86@@ -3053,9 +3081,33 @@
87 &self,
88 input_event: &ConstellationInputEvent,
89 ) -> Option<HitTestResult> {
90- self.hit_test_from_point_in_viewport(
91- input_event.hit_test_result.as_ref()?.point_in_viewport,
92- )
93+ // For pointer events with coordinates, prefer the original event point over the
94+ // WebRender hit test result's point_in_viewport. This is because the WebRender
95+ // hit test might have computed coordinates relative to an embedded iframe's
96+ // viewport, not the parent document's viewport.
97+ //
98+ // For events without coordinates or when the original point is unavailable,
99+ // fall back to the WebRender hit test result's point.
100+ let point_in_viewport = input_event
101+ .event
102+ .event
103+ .point()
104+ .map(|point| match point {
105+ WebViewPoint::Page(css_point) => css_point,
106+ WebViewPoint::Device(device_point) => {
107+ let scale = self.device_pixel_ratio();
108+ Point2D::new(device_point.x / scale.get(), device_point.y / scale.get())
109+ },
110+ })
111+ .or_else(|| {
112+ // Fall back to the WebRender hit test result's point if the original
113+ // event point is not available.
114+ input_event
115+ .hit_test_result
116+ .as_ref()
117+ .map(|r| r.point_in_viewport)
118+ })?;
119+ self.hit_test_from_point_in_viewport(point_in_viewport)
120 }
121
122 #[expect(unsafe_code)]
123@@ -3074,8 +3126,25 @@
124 // SAFETY: This is safe because `Window::query_elements_from_point` has ensured that
125 // layout has run and any OpaqueNodes that no longer refer to real nodes are gone.
126 let address = UntrustedNodeAddress(result.node.0 as *const c_void);
127+ let node = unsafe { from_untrusted_node_address(address) };
128+
129+ // Verify the node belongs to this window's document
130+ let node_doc = node.owner_doc();
131+ let our_doc = self.Document();
132+ if &*node_doc != &*our_doc {
133+ warn!(
134+ "hit_test_from_point_in_viewport: node {:?} belongs to different document! \
135+ Node doc URL: {:?}, Our doc URL: {:?}",
136+ node.debug_str(),
137+ node_doc.url(),
138+ our_doc.url()
139+ );
140+ // Return None to indicate hit test failed for this document
141+ return None;
142+ }
143+
144 Some(HitTestResult {
145- node: unsafe { from_untrusted_node_address(address) },
146+ node,
147 cursor: result.cursor,
148 point_in_node: result.point_in_target,
149 point_in_frame,
150@@ -3755,6 +3824,8 @@
151 player_context: WindowGLContext,
152 #[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
153 inherited_secure_context: Option<bool>,
154+ is_embedded_webview: bool,
155+ hide_focus: bool,
156 theme: Theme,
157 weak_script_thread: Weak<ScriptThread>,
158 ) -> DomRoot<Self> {
159@@ -3781,6 +3852,8 @@
160 gpu_id_hub,
161 inherited_secure_context,
162 unminify_js,
163+ is_embedded_webview,
164+ hide_focus,
165 Some(font_context.clone()),
166 ),
167 ongoing_navigation: Default::default(),