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