1#![cfg_attr(crown, allow(crown::jscontext_first_arg))]
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use js::jsapi::{Heap, JSObject};
10use js::jsval::UndefinedValue;
11use js::rust::{CustomAutoRooterGuard, HandleValue, MutableHandleValue};
12use script_bindings::interfaces::HasOrigin;
13use servo_base::generic_channel;
14use servo_base::id::PipelineId;
15use servo_constellation_traits::{
16 RemoteFocusOperation, ScriptToConstellationMessage, StructuredSerializedData,
17};
18use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
19
20use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding;
21use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarOriginWindowMethods;
22use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowPostMessageOptions;
23use crate::dom::bindings::error::{Error, ErrorResult};
24use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
25use crate::dom::bindings::str::USVString;
26use crate::dom::bindings::structuredclone;
27use crate::dom::bindings::trace::RootedTraceableBox;
28use crate::dom::globalscope::GlobalScope;
29use crate::dom::location::Location;
30use crate::dom::windowproxy::WindowProxy;
31
32#[dom_struct]
42pub(crate) struct DissimilarOriginWindow {
43 globalscope: GlobalScope,
45
46 window_proxy: Dom<WindowProxy>,
48
49 location: MutNullableDom<Location>,
51
52 #[no_trace]
53 pipeline_id: PipelineId,
54
55 #[no_trace]
56 origin: MutableOrigin,
57}
58
59impl DissimilarOriginWindow {
60 pub(crate) fn new(
61 cx: &mut js::context::JSContext,
62 global_to_clone_from: &GlobalScope,
63 window_proxy: &WindowProxy,
64 ) -> DomRoot<Self> {
65 let opaque_origin = MutableOrigin::new(ImmutableOrigin::new_opaque());
70 let win = Box::new(Self {
71 globalscope: GlobalScope::new_inherited(
72 global_to_clone_from.devtools_chan().cloned(),
73 global_to_clone_from.mem_profiler_chan().clone(),
74 global_to_clone_from.time_profiler_chan().clone(),
75 global_to_clone_from.script_to_constellation_chan().sender,
76 global_to_clone_from.script_to_embedder_chan().clone(),
77 global_to_clone_from.resource_threads().clone(),
78 global_to_clone_from.storage_threads().clone(),
79 global_to_clone_from.creation_url(),
80 global_to_clone_from.top_level_creation_url(),
81 #[cfg(feature = "webgpu")]
82 global_to_clone_from.wgpu_id_hub(),
83 Some(global_to_clone_from.is_secure_context()),
84 false,
85 ),
86 window_proxy: Dom::from_ref(window_proxy),
87 location: Default::default(),
88 pipeline_id: PipelineId::new(),
89 origin: opaque_origin.clone(),
90 });
91 DissimilarOriginWindowBinding::Wrap::<crate::DomTypeHolder>(cx, &opaque_origin, win)
92 }
93
94 pub(crate) fn origin(&self) -> MutableOrigin {
95 self.origin.clone()
96 }
97
98 pub(crate) fn window_proxy(&self) -> DomRoot<WindowProxy> {
99 DomRoot::from_ref(&*self.window_proxy)
100 }
101
102 pub(crate) fn pipeline_id(&self) -> PipelineId {
103 self.pipeline_id
104 }
105}
106
107impl DissimilarOriginWindowMethods<crate::DomTypeHolder> for DissimilarOriginWindow {
108 fn Window(&self) -> DomRoot<WindowProxy> {
110 self.window_proxy()
111 }
112
113 fn Self_(&self) -> DomRoot<WindowProxy> {
115 self.window_proxy()
116 }
117
118 fn Frames(&self) -> DomRoot<WindowProxy> {
120 self.window_proxy()
121 }
122
123 fn GetParent(&self) -> Option<DomRoot<WindowProxy>> {
125 if self.window_proxy.is_browsing_context_discarded() {
127 return None;
128 }
129 if let Some(parent) = self.window_proxy.parent() {
131 return Some(DomRoot::from_ref(parent));
132 }
133 Some(DomRoot::from_ref(&*self.window_proxy))
135 }
136
137 fn GetTop(&self) -> Option<DomRoot<WindowProxy>> {
139 if self.window_proxy.is_browsing_context_discarded() {
141 return None;
142 }
143 Some(DomRoot::from_ref(self.window_proxy.top()))
145 }
146
147 fn Length(&self) -> u32 {
149 if let Some(document) = self.window_proxy.document() {
151 return document.iframes().active_iframe_count() as u32;
152 }
153
154 let parent_browsing_context_id = self.window_proxy.browsing_context_id();
156 let (result_sender, result_receiver) = generic_channel::channel().unwrap();
157 let _ = self.globalscope.script_to_constellation_chan().send(
158 ScriptToConstellationMessage::GetChildBrowsingContextCount(
159 parent_browsing_context_id,
160 result_sender,
161 ),
162 );
163 result_receiver.recv().unwrap_or_default() as u32
164 }
165
166 fn Close(&self) {
168 }
170
171 fn Closed(&self) -> bool {
173 false
175 }
176
177 fn PostMessage(
179 &self,
180 cx: &mut JSContext,
181 message: HandleValue,
182 target_origin: USVString,
183 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
184 ) -> ErrorResult {
185 self.post_message_impl(&target_origin, cx, message, transfer)
186 }
187
188 fn PostMessage_(
190 &self,
191 cx: &mut JSContext,
192 message: HandleValue,
193 options: &WindowPostMessageOptions,
194 ) -> ErrorResult {
195 auto_root!(&in(cx) let transfer =
196 options
197 .parent
198 .transfer
199 .iter()
200 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
201 .collect::<Vec<_>>());
202
203 self.post_message_impl(&options.targetOrigin, cx, message, transfer)
204 }
205
206 fn Opener(&self, _: &mut JSContext, mut retval: MutableHandleValue) {
208 retval.set(UndefinedValue());
210 }
211
212 fn SetOpener(&self, _: &mut JSContext, _: HandleValue) {
214 }
216
217 fn Blur(&self) {
219 }
222
223 fn Focus(&self) {
225 let browsing_context_id = self.window_proxy.browsing_context_id();
226 debug!("Initiating a focus operation for {browsing_context_id:?}");
227 let _ = self.globalscope.script_to_constellation_chan().send(
228 ScriptToConstellationMessage::FocusRemoteBrowsingContext(
229 browsing_context_id,
230 RemoteFocusOperation::Viewport,
231 ),
232 );
233 }
234
235 fn Location(&self, cx: &mut js::context::JSContext) -> DomRoot<Location> {
237 self.location
238 .or_init(|| Location::new_dissimilar_origin(cx, self))
239 }
240}
241
242impl DissimilarOriginWindow {
243 fn post_message_impl(
245 &self,
246 target_origin: &USVString,
247 cx: &mut JSContext,
248 message: HandleValue,
249 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
250 ) -> ErrorResult {
251 let data = structuredclone::write(cx, message, Some(transfer))?;
253
254 self.post_message(target_origin, data)
255 }
256
257 pub(crate) fn post_message(
259 &self,
260 target_origin: &USVString,
261 data: StructuredSerializedData,
262 ) -> ErrorResult {
263 let target = self.window_proxy.browsing_context_id();
265 let incumbent = match GlobalScope::incumbent() {
267 None => panic!("postMessage called with no incumbent global"),
268 Some(incumbent) => incumbent,
269 };
270
271 let source_origin = incumbent.origin().immutable().clone();
272
273 let target_origin = match target_origin.0[..].as_ref() {
275 "*" => None,
276 "/" => Some(source_origin.clone()),
277 url => match ServoUrl::parse(url) {
278 Ok(url) => Some(url.origin()),
279 Err(_) => return Err(Error::Syntax(None)),
280 },
281 };
282 let msg = ScriptToConstellationMessage::PostMessage {
283 target,
284 source: incumbent.pipeline_id(),
285 source_origin,
286 target_origin,
287 data,
288 };
289 let _ = incumbent.script_to_constellation_chan().send(msg);
291 Ok(())
292 }
293}
294
295impl HasOrigin for DissimilarOriginWindow {
296 fn origin(&self) -> MutableOrigin {
297 DissimilarOriginWindow::origin(self)
298 }
299}