script/
script_window_proxies.rs1use base::id::{BrowsingContextId, PipelineId, WebViewId};
6use constellation_traits::ScriptToConstellationMessage;
7use ipc_channel::ipc;
8use rustc_hash::FxBuildHasher;
9use script_bindings::inheritance::Castable;
10use script_bindings::root::{Dom, DomRoot};
11use script_bindings::str::DOMString;
12
13use crate::document_collection::DocumentCollection;
14use crate::dom::bindings::cell::DomRefCell;
15use crate::dom::bindings::trace::HashMapTracedValues;
16use crate::dom::node::NodeTraits;
17use crate::dom::types::{GlobalScope, Window};
18use crate::dom::windowproxy::{CreatorBrowsingContextInfo, WindowProxy};
19use crate::messaging::ScriptThreadSenders;
20
21#[derive(JSTraceable, Default, MallocSizeOf)]
22#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_in_rc)]
23#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
24pub(crate) struct ScriptWindowProxies {
25 map: DomRefCell<HashMapTracedValues<BrowsingContextId, Dom<WindowProxy>, FxBuildHasher>>,
27}
28
29impl ScriptWindowProxies {
30 pub(crate) fn find_window_proxy(&self, id: BrowsingContextId) -> Option<DomRoot<WindowProxy>> {
31 self.map
32 .borrow()
33 .get(&id)
34 .map(|context| DomRoot::from_ref(&**context))
35 }
36
37 pub(crate) fn find_window_proxy_by_name(
38 &self,
39 name: &DOMString,
40 ) -> Option<DomRoot<WindowProxy>> {
41 for (_, proxy) in self.map.borrow().iter() {
42 if proxy.get_name() == *name {
43 return Some(DomRoot::from_ref(&**proxy));
44 }
45 }
46 None
47 }
48
49 pub(crate) fn get(&self, id: BrowsingContextId) -> Option<DomRoot<WindowProxy>> {
50 self.map
51 .borrow()
52 .get(&id)
53 .map(|context| DomRoot::from_ref(&**context))
54 }
55
56 pub(crate) fn insert(&self, id: BrowsingContextId, proxy: DomRoot<WindowProxy>) {
57 self.map.borrow_mut().insert(id, Dom::from_ref(&*proxy));
58 }
59
60 pub(crate) fn remote_window_proxy(
67 &self,
68 senders: &ScriptThreadSenders,
69 global_to_clone: &GlobalScope,
70 webview_id: WebViewId,
71 pipeline_id: PipelineId,
72 opener: Option<BrowsingContextId>,
73 ) -> Option<DomRoot<WindowProxy>> {
74 let (browsing_context_id, parent_pipeline_id) =
75 self.ask_constellation_for_browsing_context_info(senders, pipeline_id)?;
76 if let Some(window_proxy) = self.get(browsing_context_id) {
77 return Some(window_proxy);
78 }
79
80 let parent_browsing_context = parent_pipeline_id.and_then(|parent_id| {
81 self.remote_window_proxy(senders, global_to_clone, webview_id, parent_id, opener)
82 });
83
84 let opener_browsing_context = opener.and_then(|id| self.find_window_proxy(id));
85
86 let creator = CreatorBrowsingContextInfo::from(
87 parent_browsing_context.as_deref(),
88 opener_browsing_context.as_deref(),
89 );
90
91 let window_proxy = WindowProxy::new_dissimilar_origin(
92 global_to_clone,
93 browsing_context_id,
94 webview_id,
95 parent_browsing_context.as_deref(),
96 opener,
97 creator,
98 );
99 self.insert(browsing_context_id, DomRoot::from_ref(&*window_proxy));
100 Some(window_proxy)
101 }
102
103 #[allow(clippy::too_many_arguments)]
110 pub(crate) fn local_window_proxy(
111 &self,
112 senders: &ScriptThreadSenders,
113 documents: &DomRefCell<DocumentCollection>,
114 window: &Window,
115 browsing_context_id: BrowsingContextId,
116 webview_id: WebViewId,
117 parent_info: Option<PipelineId>,
118 opener: Option<BrowsingContextId>,
119 ) -> DomRoot<WindowProxy> {
120 if let Some(window_proxy) = self.get(browsing_context_id) {
121 return window_proxy;
124 }
125 let iframe = parent_info.and_then(|parent_id| {
126 documents
127 .borrow()
128 .find_iframe(parent_id, browsing_context_id)
129 });
130 let parent_browsing_context = match (parent_info, iframe.as_ref()) {
131 (_, Some(iframe)) => Some(iframe.owner_window().window_proxy()),
132 (Some(parent_id), _) => {
133 self.remote_window_proxy(senders, window.upcast(), webview_id, parent_id, opener)
134 },
135 _ => None,
136 };
137
138 let opener_browsing_context = opener.and_then(|id| self.find_window_proxy(id));
139
140 let creator = CreatorBrowsingContextInfo::from(
141 parent_browsing_context.as_deref(),
142 opener_browsing_context.as_deref(),
143 );
144
145 let window_proxy = WindowProxy::new(
146 window,
147 browsing_context_id,
148 webview_id,
149 iframe.as_deref().map(Castable::upcast),
150 parent_browsing_context.as_deref(),
151 opener,
152 creator,
153 );
154 self.insert(browsing_context_id, DomRoot::from_ref(&*window_proxy));
155 window_proxy
156 }
157
158 fn ask_constellation_for_browsing_context_info(
159 &self,
160 senders: &ScriptThreadSenders,
161 pipeline_id: PipelineId,
162 ) -> Option<(BrowsingContextId, Option<PipelineId>)> {
163 let (result_sender, result_receiver) = ipc::channel().unwrap();
164 let msg = ScriptToConstellationMessage::GetBrowsingContextInfo(pipeline_id, result_sender);
165 senders
166 .pipeline_to_constellation_sender
167 .send((pipeline_id, msg))
168 .expect("Failed to send to constellation.");
169 result_receiver
170 .recv()
171 .expect("Failed to get browsing context info from constellation.")
172 }
173}