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