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::{ScriptToConstellationMessage, StructuredSerializedData};
13use servo_url::ServoUrl;
14
15use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding;
16use crate::dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarOriginWindowMethods;
17use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowPostMessageOptions;
18use crate::dom::bindings::error::{Error, ErrorResult};
19use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
20use crate::dom::bindings::str::USVString;
21use crate::dom::bindings::structuredclone;
22use crate::dom::bindings::trace::RootedTraceableBox;
23use crate::dom::dissimilaroriginlocation::DissimilarOriginLocation;
24use crate::dom::globalscope::GlobalScope;
25use crate::dom::windowproxy::WindowProxy;
26use crate::script_runtime::CanGc;
27
28#[dom_struct]
38pub(crate) struct DissimilarOriginWindow {
39 globalscope: GlobalScope,
41
42 window_proxy: Dom<WindowProxy>,
44
45 location: MutNullableDom<DissimilarOriginLocation>,
47}
48
49impl DissimilarOriginWindow {
50 pub(crate) fn new(
51 cx: &mut js::context::JSContext,
52 global_to_clone_from: &GlobalScope,
53 window_proxy: &WindowProxy,
54 ) -> DomRoot<Self> {
55 let win = Box::new(Self {
56 globalscope: GlobalScope::new_inherited(
57 PipelineId::new(),
58 global_to_clone_from.devtools_chan().cloned(),
59 global_to_clone_from.mem_profiler_chan().clone(),
60 global_to_clone_from.time_profiler_chan().clone(),
61 global_to_clone_from.script_to_constellation_chan().clone(),
62 global_to_clone_from.script_to_embedder_chan().clone(),
63 global_to_clone_from.resource_threads().clone(),
64 global_to_clone_from.storage_threads().clone(),
65 global_to_clone_from.origin().clone(),
66 global_to_clone_from.creation_url(),
67 global_to_clone_from.top_level_creation_url().clone(),
68 #[cfg(feature = "webgpu")]
69 global_to_clone_from.wgpu_id_hub(),
70 Some(global_to_clone_from.is_secure_context()),
71 false,
72 global_to_clone_from.font_context().cloned(),
73 HttpsState::None,
74 ),
75 window_proxy: Dom::from_ref(window_proxy),
76 location: Default::default(),
77 });
78 DissimilarOriginWindowBinding::Wrap::<crate::DomTypeHolder>(cx, win)
79 }
80
81 pub(crate) fn window_proxy(&self) -> DomRoot<WindowProxy> {
82 DomRoot::from_ref(&*self.window_proxy)
83 }
84}
85
86impl DissimilarOriginWindowMethods<crate::DomTypeHolder> for DissimilarOriginWindow {
87 fn Window(&self) -> DomRoot<WindowProxy> {
89 self.window_proxy()
90 }
91
92 fn Self_(&self) -> DomRoot<WindowProxy> {
94 self.window_proxy()
95 }
96
97 fn Frames(&self) -> DomRoot<WindowProxy> {
99 self.window_proxy()
100 }
101
102 fn GetParent(&self) -> Option<DomRoot<WindowProxy>> {
104 if self.window_proxy.is_browsing_context_discarded() {
106 return None;
107 }
108 if let Some(parent) = self.window_proxy.parent() {
110 return Some(DomRoot::from_ref(parent));
111 }
112 Some(DomRoot::from_ref(&*self.window_proxy))
114 }
115
116 fn GetTop(&self) -> Option<DomRoot<WindowProxy>> {
118 if self.window_proxy.is_browsing_context_discarded() {
120 return None;
121 }
122 Some(DomRoot::from_ref(self.window_proxy.top()))
124 }
125
126 fn Length(&self) -> u32 {
128 0
130 }
131
132 fn Close(&self) {
134 }
136
137 fn Closed(&self) -> bool {
139 false
141 }
142
143 fn PostMessage(
145 &self,
146 cx: &mut JSContext,
147 message: HandleValue,
148 target_origin: USVString,
149 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
150 ) -> ErrorResult {
151 self.post_message_impl(&target_origin, cx, message, transfer)
152 }
153
154 fn PostMessage_(
156 &self,
157 cx: &mut JSContext,
158 message: HandleValue,
159 options: RootedTraceableBox<WindowPostMessageOptions>,
160 ) -> ErrorResult {
161 let mut rooted = CustomAutoRooter::new(
162 options
163 .parent
164 .transfer
165 .iter()
166 .map(|js: &RootedTraceableBox<Heap<*mut JSObject>>| js.get())
167 .collect(),
168 );
169 #[expect(unsafe_code)]
170 let transfer = unsafe { CustomAutoRooterGuard::new(cx.raw_cx(), &mut rooted) };
171
172 self.post_message_impl(&options.targetOrigin, cx, message, transfer)
173 }
174
175 fn Opener(&self, _: &mut JSContext, mut retval: MutableHandleValue) {
177 retval.set(UndefinedValue());
179 }
180
181 fn SetOpener(&self, _: &mut JSContext, _: HandleValue) {
183 }
185
186 fn Blur(&self) {
188 }
191
192 fn Focus(&self) {
194 let browsing_context_id = self.window_proxy.browsing_context_id();
195 debug!("Initiating a focus operation for {browsing_context_id:?}");
196 self.globalscope
197 .script_to_constellation_chan()
198 .send(ScriptToConstellationMessage::FocusRemoteBrowsingContext(
199 browsing_context_id,
200 ))
201 .unwrap();
202 }
203
204 fn Location(&self, can_gc: CanGc) -> DomRoot<DissimilarOriginLocation> {
206 self.location
207 .or_init(|| DissimilarOriginLocation::new(self, can_gc))
208 }
209}
210
211impl DissimilarOriginWindow {
212 fn post_message_impl(
214 &self,
215 target_origin: &USVString,
216 cx: &mut JSContext,
217 message: HandleValue,
218 transfer: CustomAutoRooterGuard<Vec<*mut JSObject>>,
219 ) -> ErrorResult {
220 let data = structuredclone::write(cx.into(), message, Some(transfer))?;
222
223 self.post_message(target_origin, data)
224 }
225
226 pub(crate) fn post_message(
228 &self,
229 target_origin: &USVString,
230 data: StructuredSerializedData,
231 ) -> ErrorResult {
232 let target = self.window_proxy.browsing_context_id();
234 let incumbent = match GlobalScope::incumbent() {
236 None => panic!("postMessage called with no incumbent global"),
237 Some(incumbent) => incumbent,
238 };
239
240 let source_origin = incumbent.origin().immutable().clone();
241
242 let target_origin = match target_origin.0[..].as_ref() {
244 "*" => None,
245 "/" => Some(source_origin.clone()),
246 url => match ServoUrl::parse(url) {
247 Ok(url) => Some(url.origin()),
248 Err(_) => return Err(Error::Syntax(None)),
249 },
250 };
251 let msg = ScriptToConstellationMessage::PostMessage {
252 target,
253 source: incumbent.pipeline_id(),
254 source_origin,
255 target_origin,
256 data,
257 };
258 let _ = incumbent.script_to_constellation_chan().send(msg);
260 Ok(())
261 }
262}