Skip to main content

script/dom/serviceworker/
extendablemessageevent.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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/// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-source>
33#[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    /// <https://w3c.github.io/ServiceWorker/#extendableevent>
77    event: ExtendableEvent,
78    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-data>
79    #[ignore_malloc_size_of = "mozjs"]
80    data: Heap<JSVal>,
81    /// <https://w3c.github.io/ServiceWorker/#extendablemessage-event-origin>
82    origin: DOMString,
83    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-lasteventid>
84    lastEventId: DOMString,
85    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-source>
86    source: Option<MessageSource>,
87    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-ports>
88    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    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-extendablemessageevent>
215    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    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-data>
240    fn Data(&self, _cx: &mut JSContext, mut retval: MutableHandleValue) {
241        retval.set(self.data.get())
242    }
243
244    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-origin>
245    fn Origin(&self) -> DOMString {
246        self.origin.clone()
247    }
248
249    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-lasteventid>
250    fn LastEventId(&self) -> DOMString {
251        self.lastEventId.clone()
252    }
253
254    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
255    fn IsTrusted(&self) -> bool {
256        self.event.IsTrusted()
257    }
258
259    /// <https://w3c.github.io/ServiceWorker/#dom-extendablemessageevent-source>
260    fn GetSource(&self) -> Option<ClientOrServiceWorkerOrMessagePort> {
261        self.source.as_ref().map(Into::into)
262    }
263
264    /// <https://w3c.github.io/ServiceWorker/#extendablemessage-event-ports>
265    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}