script/dom/
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 net_traits::response::HttpsState;
11use servo_base::id::PipelineId;
12use servo_constellation_traits::{
13 RemoteFocusOperation, ScriptToConstellationMessage, StructuredSerializedData,
14};
15use servo_url::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;
28use crate::script_runtime::CanGc;
29
30#[dom_struct]
40pub(crate) struct DissimilarOriginWindow {
41 globalscope: GlobalScope,
43
44 window_proxy: Dom<WindowProxy>,
46
47 location: MutNullableDom<DissimilarOriginLocation>,
49}
50
51impl DissimilarOriginWindow {
52 pub(crate) fn new(
53 cx: &mut js::context::JSContext,
54 global_to_clone_from: &GlobalScope,
55 window_proxy: &WindowProxy,
56 ) -> DomRoot<Self> {
57 let win = Box::new(Self {
58 globalscope: GlobalScope::new_inherited(
59 PipelineId::new(),
60 global_to_clone_from.devtools_chan().cloned(),
61 global_to_clone_from.mem_profiler_chan().clone(),
62 global_to_clone_from.time_profiler_chan().clone(),
63 global_to_clone_from.script_to_constellation_chan().clone(),
64 global_to_clone_from.script_to_embedder_chan().clone(),
65 global_to_clone_from.resource_threads().clone(),
66 global_to_clone_from.storage_threads().clone(),
67 global_to_clone_from.origin().clone(),
68 global_to_clone_from.creation_url(),
69 global_to_clone_from.top_level_creation_url().clone(),
70 #[cfg(feature = "webgpu")]
71 global_to_clone_from.wgpu_id_hub(),
72 Some(global_to_clone_from.is_secure_context()),
73 false,
74 global_to_clone_from.font_context().cloned(),
75 HttpsState::None,
76 ),
77 window_proxy: Dom::from_ref(window_proxy),
78 location: Default::default(),
79 });
80 DissimilarOriginWindowBinding::Wrap::<crate::DomTypeHolder>(cx, win)
81 }
82
83 pub(crate) fn window_proxy(&self) -> DomRoot<WindowProxy> {
84 DomRoot::from_ref(&*self.window_proxy)
85 }
86}
87
88impl DissimilarOriginWindowMethods<crate::DomTypeHolder> for DissimilarOriginWindow {
89 fn Window(&self) -> DomRoot<WindowProxy> {
91 self.window_proxy()
92 }
93
94 fn Self_(&self) -> DomRoot<WindowProxy> {
96 self.window_proxy()
97 }
98
99 fn Frames(&self) -> DomRoot<WindowProxy> {
101 self.window_proxy()
102 }
103
104 fn GetParent(&self) -> Option<DomRoot<WindowProxy>> {
106 if self.window_proxy.is_browsing_context_discarded() {
108 return None;
109 }
110 if let Some(parent) = self.window_proxy.parent() {
112 return Some(DomRoot::from_ref(parent));
113 }
114 Some(DomRoot::from_ref(&*self.window_proxy))
116 }
117
118 fn GetTop(&self) -> Option<DomRoot<WindowProxy>> {
120 if self.window_proxy.is_browsing_context_discarded() {
122 return None;
123 }
124 Some(DomRoot::from_ref(self.window_proxy.top()))
126 }
127
128 fn Length(&self) -> u32 {
130 0
132 }
133
134 fn Close(&self) {
136 }
138
139 fn Closed(&self) -> bool {
141 false
143 }
144
145 fn PostMessage(
147 &self,
148 cx: &mut JSContext,
149 message: HandleValue,
150 target_origin: USVString,
151 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
152 ) -> ErrorResult {
153 self.post_message_impl(&target_origin, cx, message, transfer)
154 }
155
156 fn PostMessage_(
158 &self,
159 cx: &mut JSContext,
160 message: HandleValue,
161 options: RootedTraceableBox<WindowPostMessageOptions>,
162 ) -> ErrorResult {
163 let mut rooted = CustomAutoRooter::new(
164 options
165 .parent
166 .transfer
167 .iter()
168 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
169 .collect(),
170 );
171 #[expect(unsafe_code)]
172 let transfer = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
173
174 self.post_message_impl(&options.targetOrigin, cx, message, transfer)
175 }
176
177 fn Opener(&self, _: &mut JSContext, mut retval: MutableHandleValue) {
179 retval.set(UndefinedValue());
181 }
182
183 fn SetOpener(&self, _: &mut JSContext, _: HandleValue) {
185 }
187
188 fn Blur(&self) {
190 }
193
194 fn Focus(&self) {
196 let browsing_context_id = self.window_proxy.browsing_context_id();
197 debug!("Initiating a focus operation for {browsing_context_id:?}");
198 let _ = self.globalscope.script_to_constellation_chan().send(
199 ScriptToConstellationMessage::FocusRemoteBrowsingContext(
200 browsing_context_id,
201 RemoteFocusOperation::Viewport,
202 ),
203 );
204 }
205
206 fn Location(&self, can_gc: CanGc) -> DomRoot<DissimilarOriginLocation> {
208 self.location
209 .or_init(|| DissimilarOriginLocation::new(self, can_gc))
210 }
211}
212
213impl DissimilarOriginWindow {
214 fn post_message_impl(
216 &self,
217 target_origin: &USVString,
218 cx: &mut JSContext,
219 message: HandleValue,
220 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
221 ) -> ErrorResult {
222 let data = structuredclone::write(cx.into(), message, Some(transfer))?;
224
225 self.post_message(target_origin, data)
226 }
227
228 pub(crate) fn post_message(
230 &self,
231 target_origin: &USVString,
232 data: StructuredSerializedData,
233 ) -> ErrorResult {
234 let target = self.window_proxy.browsing_context_id();
236 let incumbent = match GlobalScope::incumbent() {
238 None => panic!("postMessage called with no incumbent global"),
239 Some(incumbent) => incumbent,
240 };
241
242 let source_origin = incumbent.origin().immutable().clone();
243
244 let target_origin = match target_origin.0[..].as_ref() {
246 "*" => None,
247 "/" => Some(source_origin.clone()),
248 url => match ServoUrl::parse(url) {
249 Ok(url) => Some(url.origin()),
250 Err(_) => return Err(Error::Syntax(None)),
251 },
252 };
253 let msg = ScriptToConstellationMessage::PostMessage {
254 target,
255 source: incumbent.pipeline_id(),
256 source_origin,
257 target_origin,
258 data,
259 };
260 let _ = incumbent.script_to_constellation_chan().send(msg);
262 Ok(())
263 }
264}