script/dom/serviceworker/
extendablemessageevent.rs1use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::jsapi::Heap;
8use js::jsval::JSVal;
9use js::rust::{HandleObject, HandleValue, MutableHandleValue};
10use script_bindings::reflector::reflect_dom_object_with_proto_and_cx;
11use stylo_atoms::Atom;
12
13use crate::dom::bindings::codegen::Bindings::ExtendableEventBinding::ExtendableEvent_Binding::ExtendableEventMethods;
14use crate::dom::bindings::codegen::Bindings::ExtendableMessageEventBinding;
15use crate::dom::bindings::codegen::Bindings::ExtendableMessageEventBinding::ExtendableMessageEventMethods;
16use crate::dom::bindings::codegen::UnionTypes::ClientOrServiceWorkerOrMessagePort;
17use crate::dom::bindings::error::Fallible;
18use crate::dom::bindings::frozenarray::CachedFrozenArray;
19use crate::dom::bindings::inheritance::Castable;
20use crate::dom::bindings::root::{Dom, DomRoot};
21use crate::dom::bindings::str::DOMString;
22use crate::dom::bindings::trace::RootedTraceableBox;
23use crate::dom::client::Client;
24use crate::dom::event::Event;
25use crate::dom::eventtarget::EventTarget;
26use crate::dom::extendableevent::ExtendableEvent;
27use crate::dom::globalscope::GlobalScope;
28use crate::dom::messageport::MessagePort;
29use crate::dom::serviceworker::ServiceWorker;
30use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
31
32#[derive(JSTraceable, MallocSizeOf)]
34#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
35enum MessageSourceUnrooted {
36 Client(Dom<Client>),
37 ServiceWorker(Dom<ServiceWorker>),
38 MessagePort(Dom<MessagePort>),
39}
40
41impl MessageSourceUnrooted {
42 fn root(&self) -> MessageSource {
43 match self {
44 MessageSourceUnrooted::Client(client) => {
45 MessageSource::Client(DomRoot::from_ref(client))
46 },
47 MessageSourceUnrooted::ServiceWorker(sw) => {
48 MessageSource::ServiceWorker(DomRoot::from_ref(sw))
49 },
50 MessageSourceUnrooted::MessagePort(port) => {
51 MessageSource::MessagePort(DomRoot::from_ref(port))
52 },
53 }
54 }
55}
56
57#[derive(JSTraceable, MallocSizeOf)]
58pub(crate) enum MessageSource {
59 Client(DomRoot<Client>),
60 ServiceWorker(DomRoot<ServiceWorker>),
61 MessagePort(DomRoot<MessagePort>),
62}
63
64impl From<&ClientOrServiceWorkerOrMessagePort> for MessageSource {
65 fn from(value: &ClientOrServiceWorkerOrMessagePort) -> Self {
66 match value {
67 ClientOrServiceWorkerOrMessagePort::Client(client) => {
68 MessageSource::Client(DomRoot::from_ref(client))
69 },
70 ClientOrServiceWorkerOrMessagePort::ServiceWorker(sw) => {
71 MessageSource::ServiceWorker(DomRoot::from_ref(sw))
72 },
73 ClientOrServiceWorkerOrMessagePort::MessagePort(port) => {
74 MessageSource::MessagePort(DomRoot::from_ref(port))
75 },
76 }
77 }
78}
79
80impl From<MessageSource> for ClientOrServiceWorkerOrMessagePort {
81 fn from(value: MessageSource) -> Self {
82 match value {
83 MessageSource::Client(client) => ClientOrServiceWorkerOrMessagePort::Client(client),
84 MessageSource::ServiceWorker(sw) => {
85 ClientOrServiceWorkerOrMessagePort::ServiceWorker(sw)
86 },
87 MessageSource::MessagePort(port) => {
88 ClientOrServiceWorkerOrMessagePort::MessagePort(port)
89 },
90 }
91 }
92}
93
94#[dom_struct]
95#[expect(non_snake_case)]
96pub(crate) struct ExtendableMessageEvent {
97 event: ExtendableEvent,
99 #[ignore_malloc_size_of = "mozjs"]
101 data: Heap<JSVal>,
102 origin: DOMString,
104 lastEventId: DOMString,
106 source: Option<MessageSourceUnrooted>,
108 ports: Vec<Dom<MessagePort>>,
110 #[ignore_malloc_size_of = "mozjs"]
111 frozen_ports: CachedFrozenArray,
112}
113
114#[expect(non_snake_case)]
115impl ExtendableMessageEvent {
116 pub(crate) fn new_inherited(
117 origin: DOMString,
118 lastEventId: DOMString,
119 source: Option<MessageSource>,
120 ports: Vec<DomRoot<MessagePort>>,
121 ) -> ExtendableMessageEvent {
122 ExtendableMessageEvent {
123 event: ExtendableEvent::new_inherited(),
124 data: Heap::default(),
125 origin,
126 lastEventId,
127 source: source.map(|source| match source {
128 MessageSource::Client(client) => MessageSourceUnrooted::Client(client.as_traced()),
129 MessageSource::ServiceWorker(sw) => {
130 MessageSourceUnrooted::ServiceWorker(sw.as_traced())
131 },
132 MessageSource::MessagePort(port) => {
133 MessageSourceUnrooted::MessagePort(port.as_traced())
134 },
135 }),
136 ports: ports
137 .into_iter()
138 .map(|port| Dom::from_ref(&*port))
139 .collect(),
140 frozen_ports: CachedFrozenArray::new(),
141 }
142 }
143
144 #[allow(clippy::too_many_arguments)]
145 fn new(
146 cx: &mut JSContext,
147 global: &GlobalScope,
148 type_: Atom,
149 bubbles: bool,
150 cancelable: bool,
151 data: HandleValue,
152 origin: DOMString,
153 lastEventId: DOMString,
154 source: Option<MessageSource>,
155 ports: Vec<DomRoot<MessagePort>>,
156 ) -> DomRoot<ExtendableMessageEvent> {
157 Self::new_with_proto(
158 cx,
159 global,
160 None,
161 type_,
162 bubbles,
163 cancelable,
164 data,
165 origin,
166 lastEventId,
167 source,
168 ports,
169 )
170 }
171
172 #[allow(clippy::too_many_arguments)]
173 fn new_with_proto(
174 cx: &mut JSContext,
175 global: &GlobalScope,
176 proto: Option<HandleObject>,
177 type_: Atom,
178 bubbles: bool,
179 cancelable: bool,
180 data: HandleValue,
181 origin: DOMString,
182 lastEventId: DOMString,
183 source: Option<MessageSource>,
184 ports: Vec<DomRoot<MessagePort>>,
185 ) -> DomRoot<ExtendableMessageEvent> {
186 let ev = Box::new(ExtendableMessageEvent::new_inherited(
187 origin,
188 lastEventId,
189 source,
190 ports,
191 ));
192 let ev = reflect_dom_object_with_proto_and_cx(ev, global, proto, cx);
193 {
194 let event = ev.upcast::<Event>();
195 event.init_event(type_, bubbles, cancelable);
196 }
197 ev.data.set(data.get());
198
199 ev
200 }
201
202 pub(crate) fn dispatch_jsval(
203 cx: &mut JSContext,
204 target: &EventTarget,
205 scope: &GlobalScope,
206 message: HandleValue,
207 source: Option<MessageSource>,
208 ports: Vec<DomRoot<MessagePort>>,
209 ) {
210 let Extendablemessageevent = ExtendableMessageEvent::new(
211 cx,
212 scope,
213 atom!("message"),
214 false,
215 false,
216 message,
217 DOMString::new(),
218 DOMString::new(),
219 source,
220 ports,
221 );
222 Extendablemessageevent.upcast::<Event>().fire(cx, target);
223 }
224
225 pub(crate) fn dispatch_error(cx: &mut JSContext, target: &EventTarget, scope: &GlobalScope) {
226 let ExtendableMsgEvent = ExtendableMessageEvent::new(
227 cx,
228 scope,
229 atom!("messageerror"),
230 false,
231 false,
232 HandleValue::null(),
233 DOMString::new(),
234 DOMString::new(),
235 None,
236 Vec::new(),
237 );
238 ExtendableMsgEvent.upcast::<Event>().fire(cx, target);
239 }
240}
241
242impl ExtendableMessageEventMethods<crate::DomTypeHolder> for ExtendableMessageEvent {
243 fn Constructor(
245 cx: &mut JSContext,
246 worker: &ServiceWorkerGlobalScope,
247 proto: Option<HandleObject>,
248 type_: DOMString,
249 init: RootedTraceableBox<ExtendableMessageEventBinding::ExtendableMessageEventInit>,
250 ) -> Fallible<DomRoot<ExtendableMessageEvent>> {
251 let global = worker.upcast::<GlobalScope>();
252 let ev = ExtendableMessageEvent::new_with_proto(
253 cx,
254 global,
255 proto,
256 Atom::from(type_),
257 init.parent.parent.bubbles,
258 init.parent.parent.cancelable,
259 init.data.handle(),
260 init.origin.clone(),
261 init.lastEventId.clone(),
262 init.source
263 .as_ref()
264 .and_then(|s| s.as_ref().map(|s| s.into())),
265 vec![],
266 );
267 Ok(ev)
268 }
269
270 fn Data(&self, _cx: &mut JSContext, mut retval: MutableHandleValue) {
272 retval.set(self.data.get())
273 }
274
275 fn Origin(&self) -> DOMString {
277 self.origin.clone()
278 }
279
280 fn LastEventId(&self) -> DOMString {
282 self.lastEventId.clone()
283 }
284
285 fn IsTrusted(&self) -> bool {
287 self.event.IsTrusted()
288 }
289
290 fn GetSource(&self) -> Option<ClientOrServiceWorkerOrMessagePort> {
292 self.source
293 .as_ref()
294 .map(|source| source.root())
295 .map(|s| s.into())
296 }
297
298 fn Ports(&self, cx: &mut JSContext, retval: MutableHandleValue) {
300 self.frozen_ports.get_or_init(
301 cx,
302 || {
303 self.ports
304 .iter()
305 .map(|port| DomRoot::from_ref(&**port))
306 .collect()
307 },
308 retval,
309 );
310 }
311}