script/dom/window/
dissimilaroriginwindow.rs1use 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 servo_base::id::PipelineId;
11use servo_constellation_traits::{
12 RemoteFocusOperation, ScriptToConstellationMessage, StructuredSerializedData,
13};
14use servo_url::ServoUrl;
15
16use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding;
17use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarOriginWindowMethods;
18use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowPostMessageOptions;
19use crate::dom::bindings::error::{Error, ErrorResult};
20use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
21use crate::dom::bindings::str::USVString;
22use crate::dom::bindings::structuredclone;
23use crate::dom::bindings::trace::RootedTraceableBox;
24use crate::dom::dissimilaroriginlocation::DissimilarOriginLocation;
25use crate::dom::globalscope::GlobalScope;
26use crate::dom::windowproxy::WindowProxy;
27use crate::script_runtime::CanGc;
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
53impl DissimilarOriginWindow {
54 pub(crate) fn new(
55 cx: &mut js::context::JSContext,
56 global_to_clone_from: &GlobalScope,
57 window_proxy: &WindowProxy,
58 ) -> DomRoot<Self> {
59 let win = Box::new(Self {
60 globalscope: GlobalScope::new_inherited(
61 global_to_clone_from.devtools_chan().cloned(),
62 global_to_clone_from.mem_profiler_chan().clone(),
63 global_to_clone_from.time_profiler_chan().clone(),
64 global_to_clone_from.script_to_constellation_chan().sender,
65 global_to_clone_from.script_to_embedder_chan().clone(),
66 global_to_clone_from.resource_threads().clone(),
67 global_to_clone_from.storage_threads().clone(),
68 global_to_clone_from.origin().clone(),
69 global_to_clone_from.creation_url(),
70 global_to_clone_from.top_level_creation_url().clone(),
71 #[cfg(feature = "webgpu")]
72 global_to_clone_from.wgpu_id_hub(),
73 Some(global_to_clone_from.is_secure_context()),
74 false,
75 global_to_clone_from.font_context().cloned(),
76 ),
77 window_proxy: Dom::from_ref(window_proxy),
78 location: Default::default(),
79 pipeline_id: PipelineId::new(),
80 });
81 DissimilarOriginWindowBinding::Wrap::<crate::DomTypeHolder>(cx, win)
82 }
83
84 pub(crate) fn window_proxy(&self) -> DomRoot<WindowProxy> {
85 DomRoot::from_ref(&*self.window_proxy)
86 }
87
88 pub(crate) fn pipeline_id(&self) -> PipelineId {
89 self.pipeline_id
90 }
91}
92
93impl DissimilarOriginWindowMethods<crate::DomTypeHolder> for DissimilarOriginWindow {
94 fn Window(&self) -> DomRoot<WindowProxy> {
96 self.window_proxy()
97 }
98
99 fn Self_(&self) -> DomRoot<WindowProxy> {
101 self.window_proxy()
102 }
103
104 fn Frames(&self) -> DomRoot<WindowProxy> {
106 self.window_proxy()
107 }
108
109 fn GetParent(&self) -> Option<DomRoot<WindowProxy>> {
111 if self.window_proxy.is_browsing_context_discarded() {
113 return None;
114 }
115 if let Some(parent) = self.window_proxy.parent() {
117 return Some(DomRoot::from_ref(parent));
118 }
119 Some(DomRoot::from_ref(&*self.window_proxy))
121 }
122
123 fn GetTop(&self) -> Option<DomRoot<WindowProxy>> {
125 if self.window_proxy.is_browsing_context_discarded() {
127 return None;
128 }
129 Some(DomRoot::from_ref(self.window_proxy.top()))
131 }
132
133 fn Length(&self) -> u32 {
135 0
137 }
138
139 fn Close(&self) {
141 }
143
144 fn Closed(&self) -> bool {
146 false
148 }
149
150 fn PostMessage(
152 &self,
153 cx: &mut JSContext,
154 message: HandleValue,
155 target_origin: USVString,
156 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
157 ) -> ErrorResult {
158 self.post_message_impl(&target_origin, cx, message, transfer)
159 }
160
161 fn PostMessage_(
163 &self,
164 cx: &mut JSContext,
165 message: HandleValue,
166 options: RootedTraceableBox<WindowPostMessageOptions>,
167 ) -> ErrorResult {
168 let mut rooted = CustomAutoRooter::new(
169 options
170 .parent
171 .transfer
172 .iter()
173 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
174 .collect(),
175 );
176 #[expect(unsafe_code)]
177 let transfer = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
178
179 self.post_message_impl(&options.targetOrigin, cx, message, transfer)
180 }
181
182 fn Opener(&self, _: &mut JSContext, mut retval: MutableHandleValue) {
184 retval.set(UndefinedValue());
186 }
187
188 fn SetOpener(&self, _: &mut JSContext, _: HandleValue) {
190 }
192
193 fn Blur(&self) {
195 }
198
199 fn Focus(&self) {
201 let browsing_context_id = self.window_proxy.browsing_context_id();
202 debug!("Initiating a focus operation for {browsing_context_id:?}");
203 let _ = self.globalscope.script_to_constellation_chan().send(
204 ScriptToConstellationMessage::FocusRemoteBrowsingContext(
205 browsing_context_id,
206 RemoteFocusOperation::Viewport,
207 ),
208 );
209 }
210
211 fn Location(&self, can_gc: CanGc) -> DomRoot<DissimilarOriginLocation> {
213 self.location
214 .or_init(|| DissimilarOriginLocation::new(self, can_gc))
215 }
216}
217
218impl DissimilarOriginWindow {
219 fn post_message_impl(
221 &self,
222 target_origin: &USVString,
223 cx: &mut JSContext,
224 message: HandleValue,
225 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
226 ) -> ErrorResult {
227 let data = structuredclone::write(cx, message, Some(transfer))?;
229
230 self.post_message(target_origin, data)
231 }
232
233 pub(crate) fn post_message(
235 &self,
236 target_origin: &USVString,
237 data: StructuredSerializedData,
238 ) -> ErrorResult {
239 let target = self.window_proxy.browsing_context_id();
241 let incumbent = match GlobalScope::incumbent() {
243 None => panic!("postMessage called with no incumbent global"),
244 Some(incumbent) => incumbent,
245 };
246
247 let source_origin = incumbent.origin().immutable().clone();
248
249 let target_origin = match target_origin.0[..].as_ref() {
251 "*" => None,
252 "/" => Some(source_origin.clone()),
253 url => match ServoUrl::parse(url) {
254 Ok(url) => Some(url.origin()),
255 Err(_) => return Err(Error::Syntax(None)),
256 },
257 };
258 let msg = ScriptToConstellationMessage::PostMessage {
259 target,
260 source: incumbent.pipeline_id(),
261 source_origin,
262 target_origin,
263 data,
264 };
265 let _ = incumbent.script_to_constellation_chan().send(msg);
267 Ok(())
268 }
269}