1use dom_struct::dom_struct;
6use js::jsapi::Heap;
7use js::jsval::JSVal;
8use js::rust::{HandleObject, HandleValue, MutableHandleValue};
9use stylo_atoms::Atom;
10
11use crate::dom::bindings::codegen::Bindings::ExtendableEventBinding::ExtendableEvent_Binding::ExtendableEventMethods;
12use crate::dom::bindings::codegen::Bindings::ExtendableMessageEventBinding;
13use crate::dom::bindings::codegen::Bindings::ExtendableMessageEventBinding::ExtendableMessageEventMethods;
14use crate::dom::bindings::error::Fallible;
15use crate::dom::bindings::frozenarray::CachedFrozenArray;
16use crate::dom::bindings::inheritance::Castable;
17use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
18use crate::dom::bindings::root::{Dom, DomRoot};
19use crate::dom::bindings::str::DOMString;
20use crate::dom::bindings::trace::RootedTraceableBox;
21use crate::dom::event::Event;
22use crate::dom::eventtarget::EventTarget;
23use crate::dom::extendableevent::ExtendableEvent;
24use crate::dom::globalscope::GlobalScope;
25use crate::dom::messageport::MessagePort;
26use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
27use crate::script_runtime::{CanGc, JSContext};
28
29#[dom_struct]
30#[expect(non_snake_case)]
31pub(crate) struct ExtendableMessageEvent {
32 event: ExtendableEvent,
34 #[ignore_malloc_size_of = "mozjs"]
36 data: Heap<JSVal>,
37 origin: DOMString,
39 lastEventId: DOMString,
41 ports: Vec<Dom<MessagePort>>,
43 #[ignore_malloc_size_of = "mozjs"]
44 frozen_ports: CachedFrozenArray,
45}
46
47#[expect(non_snake_case)]
48impl ExtendableMessageEvent {
49 pub(crate) fn new_inherited(
50 origin: DOMString,
51 lastEventId: DOMString,
52 ports: Vec<DomRoot<MessagePort>>,
53 ) -> ExtendableMessageEvent {
54 ExtendableMessageEvent {
55 event: ExtendableEvent::new_inherited(),
56 data: Heap::default(),
57 origin,
58 lastEventId,
59 ports: ports
60 .into_iter()
61 .map(|port| Dom::from_ref(&*port))
62 .collect(),
63 frozen_ports: CachedFrozenArray::new(),
64 }
65 }
66
67 #[allow(clippy::too_many_arguments)]
68 pub(crate) fn new(
69 global: &GlobalScope,
70 type_: Atom,
71 bubbles: bool,
72 cancelable: bool,
73 data: HandleValue,
74 origin: DOMString,
75 lastEventId: DOMString,
76 ports: Vec<DomRoot<MessagePort>>,
77 can_gc: CanGc,
78 ) -> DomRoot<ExtendableMessageEvent> {
79 Self::new_with_proto(
80 global,
81 None,
82 type_,
83 bubbles,
84 cancelable,
85 data,
86 origin,
87 lastEventId,
88 ports,
89 can_gc,
90 )
91 }
92
93 #[allow(clippy::too_many_arguments)]
94 fn new_with_proto(
95 global: &GlobalScope,
96 proto: Option<HandleObject>,
97 type_: Atom,
98 bubbles: bool,
99 cancelable: bool,
100 data: HandleValue,
101 origin: DOMString,
102 lastEventId: DOMString,
103 ports: Vec<DomRoot<MessagePort>>,
104 can_gc: CanGc,
105 ) -> DomRoot<ExtendableMessageEvent> {
106 let ev = Box::new(ExtendableMessageEvent::new_inherited(
107 origin,
108 lastEventId,
109 ports,
110 ));
111 let ev = reflect_dom_object_with_proto(ev, global, proto, can_gc);
112 {
113 let event = ev.upcast::<Event>();
114 event.init_event(type_, bubbles, cancelable);
115 }
116 ev.data.set(data.get());
117
118 ev
119 }
120}
121
122#[expect(non_snake_case)]
123impl ExtendableMessageEvent {
124 pub(crate) fn dispatch_jsval(
125 target: &EventTarget,
126 scope: &GlobalScope,
127 message: HandleValue,
128 ports: Vec<DomRoot<MessagePort>>,
129 can_gc: CanGc,
130 ) {
131 let Extendablemessageevent = ExtendableMessageEvent::new(
132 scope,
133 atom!("message"),
134 false,
135 false,
136 message,
137 DOMString::new(),
138 DOMString::new(),
139 ports,
140 can_gc,
141 );
142 Extendablemessageevent
143 .upcast::<Event>()
144 .fire(target, can_gc);
145 }
146
147 pub(crate) fn dispatch_error(
148 cx: &mut js::context::JSContext,
149 target: &EventTarget,
150 scope: &GlobalScope,
151 ) {
152 let init = ExtendableMessageEventBinding::ExtendableMessageEventInit::empty();
153 let ExtendableMsgEvent = ExtendableMessageEvent::new(
154 scope,
155 atom!("messageerror"),
156 init.parent.parent.bubbles,
157 init.parent.parent.cancelable,
158 init.data.handle(),
159 init.origin.clone(),
160 init.lastEventId.clone(),
161 init.ports.clone(),
162 CanGc::from_cx(cx),
163 );
164 ExtendableMsgEvent
165 .upcast::<Event>()
166 .fire(target, CanGc::from_cx(cx));
167 }
168}
169
170impl ExtendableMessageEventMethods<crate::DomTypeHolder> for ExtendableMessageEvent {
171 fn Constructor(
173 worker: &ServiceWorkerGlobalScope,
174 proto: Option<HandleObject>,
175 can_gc: CanGc,
176 type_: DOMString,
177 init: RootedTraceableBox<ExtendableMessageEventBinding::ExtendableMessageEventInit>,
178 ) -> Fallible<DomRoot<ExtendableMessageEvent>> {
179 let global = worker.upcast::<GlobalScope>();
180 let ev = ExtendableMessageEvent::new_with_proto(
181 global,
182 proto,
183 Atom::from(type_),
184 init.parent.parent.bubbles,
185 init.parent.parent.cancelable,
186 init.data.handle(),
187 init.origin.clone(),
188 init.lastEventId.clone(),
189 vec![],
190 can_gc,
191 );
192 Ok(ev)
193 }
194
195 fn Data(&self, _cx: JSContext, mut retval: MutableHandleValue) {
197 retval.set(self.data.get())
198 }
199
200 fn Origin(&self) -> DOMString {
202 self.origin.clone()
203 }
204
205 fn LastEventId(&self) -> DOMString {
207 self.lastEventId.clone()
208 }
209
210 fn IsTrusted(&self) -> bool {
212 self.event.IsTrusted()
213 }
214
215 fn Ports(&self, cx: JSContext, can_gc: CanGc, retval: MutableHandleValue) {
217 self.frozen_ports.get_or_init(
218 || {
219 self.ports
220 .iter()
221 .map(|port| DomRoot::from_ref(&**port))
222 .collect()
223 },
224 cx,
225 retval,
226 can_gc,
227 );
228 }
229}