1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::jsapi::{Heap, JSObject};
8use js::jsval::UndefinedValue;
9use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue, MutableHandleValue};
10use script_bindings::interfaces::HasOrigin;
11use servo_base::id::PipelineId;
12use servo_constellation_traits::{
13 RemoteFocusOperation, ScriptToConstellationMessage, StructuredSerializedData,
14};
15use servo_url::{MutableOrigin, ServoUrl};
16
17use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding;
18use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarOriginWindowMethods;
19use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowPostMessageOptions;
20use crate::dom::bindings::error::{Error, ErrorResult};
21use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
22use crate::dom::bindings::str::USVString;
23use crate::dom::bindings::structuredclone;
24use crate::dom::bindings::trace::RootedTraceableBox;
25use crate::dom::dissimilaroriginlocation::DissimilarOriginLocation;
26use crate::dom::globalscope::GlobalScope;
27use crate::dom::windowproxy::WindowProxy;
28
29#[dom_struct]
39pub(crate) struct DissimilarOriginWindow {
40 globalscope: GlobalScope,
42
43 window_proxy: Dom<WindowProxy>,
45
46 location: MutNullableDom<DissimilarOriginLocation>,
48
49 #[no_trace]
50 pipeline_id: PipelineId,
51
52 #[no_trace]
53 origin: MutableOrigin,
54}
55
56impl DissimilarOriginWindow {
57 pub(crate) fn new(
58 cx: &mut js::context::JSContext,
59 global_to_clone_from: &GlobalScope,
60 window_proxy: &WindowProxy,
61 ) -> DomRoot<Self> {
62 let win = Box::new(Self {
63 globalscope: GlobalScope::new_inherited(
64 global_to_clone_from.devtools_chan().cloned(),
65 global_to_clone_from.mem_profiler_chan().clone(),
66 global_to_clone_from.time_profiler_chan().clone(),
67 global_to_clone_from.script_to_constellation_chan().sender,
68 global_to_clone_from.script_to_embedder_chan().clone(),
69 global_to_clone_from.resource_threads().clone(),
70 global_to_clone_from.storage_threads().clone(),
71 global_to_clone_from.creation_url(),
72 global_to_clone_from.top_level_creation_url().clone(),
73 #[cfg(feature = "webgpu")]
74 global_to_clone_from.wgpu_id_hub(),
75 Some(global_to_clone_from.is_secure_context()),
76 false,
77 global_to_clone_from.font_context().cloned(),
78 ),
79 window_proxy: Dom::from_ref(window_proxy),
80 location: Default::default(),
81 pipeline_id: PipelineId::new(),
82 origin: global_to_clone_from.origin(),
83 });
84 DissimilarOriginWindowBinding::Wrap::<crate::DomTypeHolder>(cx, &win.origin(), win)
85 }
86
87 pub(crate) fn origin(&self) -> MutableOrigin {
88 self.origin.clone()
89 }
90
91 pub(crate) fn window_proxy(&self) -> DomRoot<WindowProxy> {
92 DomRoot::from_ref(&*self.window_proxy)
93 }
94
95 pub(crate) fn pipeline_id(&self) -> PipelineId {
96 self.pipeline_id
97 }
98}
99
100impl DissimilarOriginWindowMethods<crate::DomTypeHolder> for DissimilarOriginWindow {
101 fn Window(&self) -> DomRoot<WindowProxy> {
103 self.window_proxy()
104 }
105
106 fn Self_(&self) -> DomRoot<WindowProxy> {
108 self.window_proxy()
109 }
110
111 fn Frames(&self) -> DomRoot<WindowProxy> {
113 self.window_proxy()
114 }
115
116 fn GetParent(&self) -> Option<DomRoot<WindowProxy>> {
118 if self.window_proxy.is_browsing_context_discarded() {
120 return None;
121 }
122 if let Some(parent) = self.window_proxy.parent() {
124 return Some(DomRoot::from_ref(parent));
125 }
126 Some(DomRoot::from_ref(&*self.window_proxy))
128 }
129
130 fn GetTop(&self) -> Option<DomRoot<WindowProxy>> {
132 if self.window_proxy.is_browsing_context_discarded() {
134 return None;
135 }
136 Some(DomRoot::from_ref(self.window_proxy.top()))
138 }
139
140 fn Length(&self) -> u32 {
142 0
144 }
145
146 fn Close(&self) {
148 }
150
151 fn Closed(&self) -> bool {
153 false
155 }
156
157 fn PostMessage(
159 &self,
160 cx: &mut JSContext,
161 message: HandleValue,
162 target_origin: USVString,
163 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
164 ) -> ErrorResult {
165 self.post_message_impl(&target_origin, cx, message, transfer)
166 }
167
168 fn PostMessage_(
170 &self,
171 cx: &mut JSContext,
172 message: HandleValue,
173 options: RootedTraceableBox<WindowPostMessageOptions>,
174 ) -> ErrorResult {
175 let mut rooted = CustomAutoRooter::new(
176 options
177 .parent
178 .transfer
179 .iter()
180 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
181 .collect(),
182 );
183 #[expect(unsafe_code)]
184 let transfer = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
185
186 self.post_message_impl(&options.targetOrigin, cx, message, transfer)
187 }
188
189 fn Opener(&self, _: &mut JSContext, mut retval: MutableHandleValue) {
191 retval.set(UndefinedValue());
193 }
194
195 fn SetOpener(&self, _: &mut JSContext, _: HandleValue) {
197 }
199
200 fn Blur(&self) {
202 }
205
206 fn Focus(&self) {
208 let browsing_context_id = self.window_proxy.browsing_context_id();
209 debug!("Initiating a focus operation for {browsing_context_id:?}");
210 let _ = self.globalscope.script_to_constellation_chan().send(
211 ScriptToConstellationMessage::FocusRemoteBrowsingContext(
212 browsing_context_id,
213 RemoteFocusOperation::Viewport,
214 ),
215 );
216 }
217
218 fn Location(&self, cx: &mut js::context::JSContext) -> DomRoot<DissimilarOriginLocation> {
220 self.location
221 .or_init(|| DissimilarOriginLocation::new(cx, self))
222 }
223}
224
225impl DissimilarOriginWindow {
226 fn post_message_impl(
228 &self,
229 target_origin: &USVString,
230 cx: &mut JSContext,
231 message: HandleValue,
232 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
233 ) -> ErrorResult {
234 let data = structuredclone::write(cx, message, Some(transfer))?;
236
237 self.post_message(target_origin, data)
238 }
239
240 pub(crate) fn post_message(
242 &self,
243 target_origin: &USVString,
244 data: StructuredSerializedData,
245 ) -> ErrorResult {
246 let target = self.window_proxy.browsing_context_id();
248 let incumbent = match GlobalScope::incumbent() {
250 None => panic!("postMessage called with no incumbent global"),
251 Some(incumbent) => incumbent,
252 };
253
254 let source_origin = incumbent.origin().immutable().clone();
255
256 let target_origin = match target_origin.0[..].as_ref() {
258 "*" => None,
259 "/" => Some(source_origin.clone()),
260 url => match ServoUrl::parse(url) {
261 Ok(url) => Some(url.origin()),
262 Err(_) => return Err(Error::Syntax(None)),
263 },
264 };
265 let msg = ScriptToConstellationMessage::PostMessage {
266 target,
267 source: incumbent.pipeline_id(),
268 source_origin,
269 target_origin,
270 data,
271 };
272 let _ = incumbent.script_to_constellation_chan().send(msg);
274 Ok(())
275 }
276}
277
278impl HasOrigin for DissimilarOriginWindow {
279 fn origin(&self) -> MutableOrigin {
280 DissimilarOriginWindow::origin(self)
281 }
282}