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(Clone, JSTraceable, MallocSizeOf)]
34pub(crate) enum MessageSource {
35 Client(DomRoot<Client>),
36 ServiceWorker(DomRoot<ServiceWorker>),
37 MessagePort(DomRoot<MessagePort>),
38}
39
40impl From<ClientOrServiceWorkerOrMessagePort> for MessageSource {
41 fn from(value: ClientOrServiceWorkerOrMessagePort) -> Self {
42 match value {
43 ClientOrServiceWorkerOrMessagePort::Client(client) => MessageSource::Client(client),
44 ClientOrServiceWorkerOrMessagePort::ServiceWorker(sw) => {
45 MessageSource::ServiceWorker(sw)
46 },
47 ClientOrServiceWorkerOrMessagePort::MessagePort(port) => {
48 MessageSource::MessagePort(port)
49 },
50 }
51 }
52}
53
54impl From<&ClientOrServiceWorkerOrMessagePort> for MessageSource {
55 fn from(value: &ClientOrServiceWorkerOrMessagePort) -> Self {
56 match value {
57 ClientOrServiceWorkerOrMessagePort::Client(client) => {
58 MessageSource::Client(DomRoot::from_ref(client))
59 },
60 ClientOrServiceWorkerOrMessagePort::ServiceWorker(sw) => {
61 MessageSource::ServiceWorker(DomRoot::from_ref(sw))
62 },
63 ClientOrServiceWorkerOrMessagePort::MessagePort(port) => {
64 MessageSource::MessagePort(DomRoot::from_ref(port))
65 },
66 }
67 }
68}
69
70impl From<MessageSource> for ClientOrServiceWorkerOrMessagePort {
71 fn from(value: MessageSource) -> Self {
72 match value {
73 MessageSource::Client(client) => ClientOrServiceWorkerOrMessagePort::Client(client),
74 MessageSource::ServiceWorker(sw) => {
75 ClientOrServiceWorkerOrMessagePort::ServiceWorker(sw)
76 },
77 MessageSource::MessagePort(port) => {
78 ClientOrServiceWorkerOrMessagePort::MessagePort(port)
79 },
80 }
81 }
82}
83
84#[dom_struct]
85#[expect(non_snake_case)]
86pub(crate) struct ExtendableMessageEvent {
87 event: ExtendableEvent,
89 #[ignore_malloc_size_of = "mozjs"]
91 data: Heap<JSVal>,
92 origin: DOMString,
94 lastEventId: DOMString,
96 source: Option<MessageSource>,
98 ports: Vec<Dom<MessagePort>>,
100 #[ignore_malloc_size_of = "mozjs"]
101 frozen_ports: CachedFrozenArray,
102}
103
104#[expect(non_snake_case)]
105impl ExtendableMessageEvent {
106 pub(crate) fn new_inherited(
107 origin: DOMString,
108 lastEventId: DOMString,
109 source: Option<MessageSource>,
110 ports: Vec<DomRoot<MessagePort>>,
111 ) -> ExtendableMessageEvent {
112 ExtendableMessageEvent {
113 event: ExtendableEvent::new_inherited(),
114 data: Heap::default(),
115 origin,
116 lastEventId,
117 source,
118 ports: ports
119 .into_iter()
120 .map(|port| Dom::from_ref(&*port))
121 .collect(),
122 frozen_ports: CachedFrozenArray::new(),
123 }
124 }
125
126 #[allow(clippy::too_many_arguments)]
127 pub(crate) fn new(
128 cx: &mut JSContext,
129 global: &GlobalScope,
130 type_: Atom,
131 bubbles: bool,
132 cancelable: bool,
133 data: HandleValue,
134 origin: DOMString,
135 lastEventId: DOMString,
136 source: Option<MessageSource>,
137 ports: Vec<DomRoot<MessagePort>>,
138 ) -> DomRoot<ExtendableMessageEvent> {
139 Self::new_with_proto(
140 cx,
141 global,
142 None,
143 type_,
144 bubbles,
145 cancelable,
146 data,
147 origin,
148 lastEventId,
149 source,
150 ports,
151 )
152 }
153
154 #[allow(clippy::too_many_arguments)]
155 fn new_with_proto(
156 cx: &mut JSContext,
157 global: &GlobalScope,
158 proto: Option<HandleObject>,
159 type_: Atom,
160 bubbles: bool,
161 cancelable: bool,
162 data: HandleValue,
163 origin: DOMString,
164 lastEventId: DOMString,
165 source: Option<MessageSource>,
166 ports: Vec<DomRoot<MessagePort>>,
167 ) -> DomRoot<ExtendableMessageEvent> {
168 let ev = Box::new(ExtendableMessageEvent::new_inherited(
169 origin,
170 lastEventId,
171 source,
172 ports,
173 ));
174 let ev = reflect_dom_object_with_proto_and_cx(ev, global, proto, cx);
175 {
176 let event = ev.upcast::<Event>();
177 event.init_event(type_, bubbles, cancelable);
178 }
179 ev.data.set(data.get());
180
181 ev
182 }
183}
184
185#[expect(non_snake_case)]
186impl ExtendableMessageEvent {
187 pub(crate) fn dispatch_jsval(
188 cx: &mut JSContext,
189 target: &EventTarget,
190 scope: &GlobalScope,
191 message: HandleValue,
192 source: Option<MessageSource>,
193 ports: Vec<DomRoot<MessagePort>>,
194 ) {
195 let Extendablemessageevent = ExtendableMessageEvent::new(
196 cx,
197 scope,
198 atom!("message"),
199 false,
200 false,
201 message,
202 DOMString::new(),
203 DOMString::new(),
204 source,
205 ports,
206 );
207 Extendablemessageevent.upcast::<Event>().fire(cx, target);
208 }
209
210 pub(crate) fn dispatch_error(cx: &mut JSContext, target: &EventTarget, scope: &GlobalScope) {
211 let init = ExtendableMessageEventBinding::ExtendableMessageEventInit::empty();
212 let ExtendableMsgEvent = ExtendableMessageEvent::new(
213 cx,
214 scope,
215 atom!("messageerror"),
216 init.parent.parent.bubbles,
217 init.parent.parent.cancelable,
218 init.data.handle(),
219 init.origin.clone(),
220 init.lastEventId.clone(),
221 init.source
222 .as_ref()
223 .and_then(|s| s.as_ref().map(|s| s.into())),
224 init.ports.clone(),
225 );
226 ExtendableMsgEvent.upcast::<Event>().fire(cx, target);
227 }
228}
229
230impl ExtendableMessageEventMethods<crate::DomTypeHolder> for ExtendableMessageEvent {
231 fn Constructor(
233 cx: &mut JSContext,
234 worker: &ServiceWorkerGlobalScope,
235 proto: Option<HandleObject>,
236 type_: DOMString,
237 init: RootedTraceableBox<ExtendableMessageEventBinding::ExtendableMessageEventInit>,
238 ) -> Fallible<DomRoot<ExtendableMessageEvent>> {
239 let global = worker.upcast::<GlobalScope>();
240 let ev = ExtendableMessageEvent::new_with_proto(
241 cx,
242 global,
243 proto,
244 Atom::from(type_),
245 init.parent.parent.bubbles,
246 init.parent.parent.cancelable,
247 init.data.handle(),
248 init.origin.clone(),
249 init.lastEventId.clone(),
250 init.source
251 .as_ref()
252 .and_then(|s| s.as_ref().map(|s| s.into())),
253 vec![],
254 );
255 Ok(ev)
256 }
257
258 fn Data(&self, _cx: &mut JSContext, mut retval: MutableHandleValue) {
260 retval.set(self.data.get())
261 }
262
263 fn Origin(&self) -> DOMString {
265 self.origin.clone()
266 }
267
268 fn LastEventId(&self) -> DOMString {
270 self.lastEventId.clone()
271 }
272
273 fn IsTrusted(&self) -> bool {
275 self.event.IsTrusted()
276 }
277
278 fn GetSource(&self) -> Option<ClientOrServiceWorkerOrMessagePort> {
280 self.source.clone().map(|s| s.into())
281 }
282
283 fn Ports(&self, cx: &mut JSContext, retval: MutableHandleValue) {
285 self.frozen_ports.get_or_init(
286 cx,
287 || {
288 self.ports
289 .iter()
290 .map(|port| DomRoot::from_ref(&**port))
291 .collect()
292 },
293 retval,
294 );
295 }
296}