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