script/event_loop/
script_window_proxies.rs1use rustc_hash::FxBuildHasher;
6use script_bindings::cell::DomRefCell;
7use script_bindings::inheritance::Castable;
8use script_bindings::root::{Dom, DomRoot};
9use servo_base::generic_channel;
10use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
11use servo_constellation_traits::ScriptToConstellationMessage;
12
13use crate::dom::bindings::trace::HashMapTracedValues;
14use crate::dom::html::htmliframeelement::HTMLIFrameElement;
15use crate::dom::node::NodeTraits;
16use crate::dom::types::{GlobalScope, Window};
17use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy};
18use crate::messaging::ScriptThreadSenders;
19
20#[derive(JSTraceable, Default, MallocSizeOf)]
21#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_in_rc)]
22#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
23pub(crate) struct ScriptWindowProxies {
24 map: DomRefCell<HashMapTracedValues<BrowsingContextId, Dom<WindowProxy>, FxBuildHasher>>,
25}
26
27impl ScriptWindowProxies {
28 pub(crate) fn find_window_proxy(&self, id: BrowsingContextId) -> Option<DomRoot<WindowProxy>> {
29 self.map
30 .borrow()
31 .get(&id)
32 .map(|context| DomRoot::from_ref(&**context))
33 }
34
35 pub(crate) fn top_level_window_proxies(&self) -> Vec<DomRoot<WindowProxy>> {
36 self.map
37 .borrow()
38 .values()
39 .filter(|proxy| proxy.parent().is_none())
40 .map(|proxy| proxy.as_rooted())
41 .collect()
42 }
43
44 pub(crate) fn insert(&self, id: BrowsingContextId, proxy: &WindowProxy) {
45 self.map.borrow_mut().insert(id, Dom::from_ref(proxy));
46 }
47
48 pub(crate) fn remove(&self, id: BrowsingContextId) {
49 self.map.borrow_mut().remove(&id);
50 }
51
52 pub(crate) fn remote_window_proxy(
59 &self,
60 cx: &mut js::context::JSContext,
61 senders: &ScriptThreadSenders,
62 global_to_clone: &GlobalScope,
63 webview_id: WebViewId,
64 pipeline_id: PipelineId,
65 opener: Option<BrowsingContextId>,
66 ) -> Option<DomRoot<WindowProxy>> {
67 let (browsing_context_id, parent_pipeline_id) =
68 self.ask_constellation_for_browsing_context_info(senders, webview_id, pipeline_id)?;
69 if let Some(window_proxy) = self.find_window_proxy(browsing_context_id) {
70 return Some(window_proxy);
71 }
72
73 let parent_browsing_context = parent_pipeline_id.and_then(|parent_id| {
74 self.remote_window_proxy(cx, senders, global_to_clone, webview_id, parent_id, opener)
75 });
76
77 let opener_browsing_context = opener.and_then(|id| self.find_window_proxy(id));
78
79 let creator = CreatorBrowsingContextInfo::from(
80 parent_browsing_context.as_deref(),
81 opener_browsing_context.as_deref(),
82 );
83
84 let window_proxy = WindowProxy::new_dissimilar_origin(
85 cx,
86 global_to_clone,
87 browsing_context_id,
88 webview_id,
89 parent_browsing_context.as_deref(),
90 opener,
91 creator,
92 );
93 self.insert(browsing_context_id, &window_proxy);
94 Some(window_proxy)
95 }
96
97 #[expect(clippy::too_many_arguments)]
104 pub(crate) fn local_window_proxy(
105 &self,
106 cx: &mut js::context::JSContext,
107 senders: &ScriptThreadSenders,
108 window: &Window,
109 browsing_context_id: BrowsingContextId,
110 webview_id: WebViewId,
111 parent_info: Option<PipelineId>,
112 iframe: Option<DomRoot<HTMLIFrameElement>>,
113 opener: Option<BrowsingContextId>,
114 ) -> DomRoot<WindowProxy> {
115 if let Some(window_proxy) = self.find_window_proxy(browsing_context_id) {
116 return window_proxy;
119 }
120 let parent_browsing_context = match (parent_info, iframe.as_ref()) {
121 (_, Some(iframe)) => Some(iframe.owner_window().window_proxy()),
122 (Some(parent_id), _) => self.remote_window_proxy(
123 cx,
124 senders,
125 window.upcast(),
126 webview_id,
127 parent_id,
128 opener,
129 ),
130 _ => None,
131 };
132
133 let opener_browsing_context = opener.and_then(|id| self.find_window_proxy(id));
134
135 let creator = CreatorBrowsingContextInfo::from(
136 parent_browsing_context.as_deref(),
137 opener_browsing_context.as_deref(),
138 );
139
140 let window_proxy = WindowProxy::new(
141 cx,
142 window,
143 browsing_context_id,
144 webview_id,
145 iframe.as_deref().map(Castable::upcast),
146 parent_browsing_context.as_deref(),
147 opener,
148 creator,
149 );
150 self.insert(browsing_context_id, &window_proxy);
151 window_proxy
152 }
153
154 fn ask_constellation_for_browsing_context_info(
155 &self,
156 senders: &ScriptThreadSenders,
157 webview_id: WebViewId,
158 pipeline_id: PipelineId,
159 ) -> Option<(BrowsingContextId, Option<PipelineId>)> {
160 let (result_sender, result_receiver) = generic_channel::channel().unwrap();
161 let msg = ScriptToConstellationMessage::GetBrowsingContextInfo(pipeline_id, result_sender);
162 senders
163 .pipeline_to_constellation_sender
164 .send((webview_id, pipeline_id, msg))
165 .expect("Failed to send to constellation.");
166 result_receiver
167 .recv()
168 .expect("Failed to get browsing context info from constellation.")
169 }
170}