Rewild Your Web
web
browser
dweb
1--- original
2+++ modified
3@@ -45,6 +45,11 @@
4 /// The [`Theme`] that this [`ConstellationWebView`] uses. This is communicated to all
5 /// `ScriptThread`s so that they know how to render the contents of a particular `WebView.
6 theme: Theme,
7+
8+ /// Whether this webview should never receive focus (hidefocus attribute on the iframe).
9+ /// When true, focus-related events are processed but focus is not transferred to
10+ /// elements in this webview's documents.
11+ pub hide_focus: bool,
12 }
13
14 impl ConstellationWebView {
15@@ -53,6 +58,20 @@
16 focused_browsing_context_id: BrowsingContextId,
17 user_content_manager_id: Option<UserContentManagerId>,
18 ) -> Self {
19+ Self::new_with_hide_focus(
20+ webview_id,
21+ focused_browsing_context_id,
22+ user_content_manager_id,
23+ false,
24+ )
25+ }
26+
27+ pub(crate) fn new_with_hide_focus(
28+ webview_id: WebViewId,
29+ focused_browsing_context_id: BrowsingContextId,
30+ user_content_manager_id: Option<UserContentManagerId>,
31+ hide_focus: bool,
32+ ) -> Self {
33 Self {
34 webview_id,
35 user_content_manager_id,
36@@ -61,6 +80,7 @@
37 last_mouse_move_point: Default::default(),
38 session_history: JointSessionHistory::new(),
39 theme: Theme::Light,
40+ hide_focus,
41 }
42 }
43
44@@ -80,12 +100,41 @@
45 event: &ConstellationInputEvent,
46 browsing_contexts: &FxHashMap<BrowsingContextId, BrowsingContext>,
47 ) -> Option<PipelineId> {
48+ // For pointer events with coordinates (mouse, touch, wheel), we always route to
49+ // the ROOT browsing context of this webview, not the focused one.
50+ // This is because:
51+ // 1. WebRender hit testing doesn't respect CSS z-index/stacking contexts
52+ // 2. When an embedded webview is focused, we still want pointer events to go through
53+ // the parent's DOM hit testing first to respect z-index of overlays
54+ // 3. The parent's DOM hit testing will forward events to embedded webviews if the
55+ // hit target is an embedded iframe element
56+ //
57+ // The root browsing context ID is the same as the webview ID (WebViewId wraps
58+ // TopLevelBrowsingContextId which wraps BrowsingContextId).
59+ let has_pointer_coordinates = matches!(
60+ event.event.event,
61+ InputEvent::MouseButton(_) |
62+ InputEvent::MouseMove(_) |
63+ InputEvent::Touch(_) |
64+ InputEvent::Wheel(_)
65+ );
66+
67+ if has_pointer_coordinates {
68+ // Route to the root/parent browsing context of this webview
69+ let root_browsing_context_id: BrowsingContextId = self.webview_id.into();
70+ return Some(
71+ browsing_contexts
72+ .get(&root_browsing_context_id)?
73+ .pipeline_id,
74+ );
75+ }
76+
77+ // For non-pointer events (keyboard, etc.), use hit test result if available
78 if let Some(hit_test_result) = &event.hit_test_result {
79 return Some(hit_test_result.pipeline_id);
80 }
81
82- // If there's no hit test, send the event to either the hovered or focused browsing context,
83- // depending on the event type.
84+ // Otherwise, send to either the hovered or focused browsing context
85 let browsing_context_id = if matches!(event.event.event, InputEvent::MouseLeftViewport(_)) {
86 self.hovered_browsing_context_id
87 .unwrap_or(self.focused_browsing_context_id)
88@@ -155,11 +204,9 @@
89
90 if let InputEvent::MouseMove(_) = &event.event.event {
91 update_hovered_browsing_context(Some(pipeline.browsing_context_id), true);
92- self.last_mouse_move_point = event
93- .hit_test_result
94- .as_ref()
95- .expect("MouseMove events should always have hit tests.")
96- .point_in_viewport;
97+ if let Some(ref hit_test_result) = event.hit_test_result {
98+ self.last_mouse_move_point = hit_test_result.point_in_viewport;
99+ }
100 }
101
102 let _ = pipeline