1use std::cell::RefCell;
6use std::collections::hash_map::Entry::{Occupied, Vacant};
7use std::default::Default;
8use std::ffi::CString;
9use std::mem;
10use std::ops::{Deref, DerefMut};
11use std::rc::Rc;
12
13use deny_public_fields::DenyPublicFields;
14use dom_struct::dom_struct;
15use js::jsapi::JS::CompileFunction;
16use js::jsapi::{JS_GetFunctionObject, SupportUnscopables};
17use js::jsval::JSVal;
18use js::rust::{CompileOptionsWrapper, HandleObject, transform_u16_to_source_text};
19use libc::c_char;
20use rustc_hash::FxBuildHasher;
21use servo_url::ServoUrl;
22use style::str::HTML_SPACE_CHARACTERS;
23use stylo_atoms::Atom;
24
25use crate::conversions::Convert;
26use crate::dom::abortsignal::{AbortAlgorithm, RemovableDomEventListener};
27use crate::dom::beforeunloadevent::BeforeUnloadEvent;
28use crate::dom::bindings::callback::{CallbackContainer, CallbackFunction, ExceptionHandling};
29use crate::dom::bindings::cell::DomRefCell;
30use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnloadEventMethods;
31use crate::dom::bindings::codegen::Bindings::ErrorEventBinding::ErrorEventMethods;
32use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
33use crate::dom::bindings::codegen::Bindings::EventHandlerBinding::{
34 EventHandlerNonNull, OnBeforeUnloadEventHandlerNonNull, OnErrorEventHandlerNonNull,
35};
36use crate::dom::bindings::codegen::Bindings::EventListenerBinding::EventListener;
37use crate::dom::bindings::codegen::Bindings::EventTargetBinding::{
38 AddEventListenerOptions, EventListenerOptions, EventTargetMethods,
39};
40use crate::dom::bindings::codegen::Bindings::NodeBinding::GetRootNodeOptions;
41use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods;
42use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods;
43use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
44use crate::dom::bindings::codegen::GenericBindings::DocumentBinding::Document_Binding::DocumentMethods;
45use crate::dom::bindings::codegen::UnionTypes::{
46 AddEventListenerOptionsOrBoolean, EventListenerOptionsOrBoolean, EventOrString,
47};
48use crate::dom::bindings::error::{Error, Fallible, report_pending_exception};
49use crate::dom::bindings::inheritance::Castable;
50use crate::dom::bindings::refcounted::Trusted;
51use crate::dom::bindings::reflector::{
52 DomGlobal, DomObject, Reflector, reflect_dom_object_with_proto,
53};
54use crate::dom::bindings::root::DomRoot;
55use crate::dom::bindings::str::DOMString;
56use crate::dom::bindings::trace::HashMapTracedValues;
57use crate::dom::csp::{CspReporting, InlineCheckType};
58use crate::dom::document::Document;
59use crate::dom::element::Element;
60use crate::dom::errorevent::ErrorEvent;
61use crate::dom::event::{Event, EventBubbles, EventCancelable, EventComposed};
62use crate::dom::globalscope::GlobalScope;
63use crate::dom::html::htmlformelement::FormControlElementHelpers;
64use crate::dom::node::{Node, NodeTraits};
65use crate::dom::shadowroot::ShadowRoot;
66use crate::dom::virtualmethods::VirtualMethods;
67use crate::dom::window::Window;
68use crate::dom::workerglobalscope::WorkerGlobalScope;
69use crate::realms::{InRealm, enter_realm};
70use crate::script_runtime::CanGc;
71
72static CONTENT_EVENT_HANDLER_NAMES: [&str; 108] = [
78 "onabort",
79 "onauxclick",
80 "onbeforeinput",
81 "onbeforematch",
82 "onbeforetoggle",
83 "onblur",
84 "oncancel",
85 "oncanplay",
86 "oncanplaythrough",
87 "onchange",
88 "onclick",
89 "onclose",
90 "oncommand",
91 "oncontextlost",
92 "oncontextmenu",
93 "oncontextrestored",
94 "oncopy",
95 "oncuechange",
96 "oncut",
97 "ondblclick",
98 "ondrag",
99 "ondragend",
100 "ondragenter",
101 "ondragleave",
102 "ondragover",
103 "ondragstart",
104 "ondrop",
105 "ondurationchange",
106 "onemptied",
107 "onended",
108 "onerror",
109 "onfocus",
110 "onformdata",
111 "oninput",
112 "oninvalid",
113 "onkeydown",
114 "onkeypress",
115 "onkeyup",
116 "onload",
117 "onloadeddata",
118 "onloadedmetadata",
119 "onloadstart",
120 "onmousedown",
121 "onmouseenter",
122 "onmouseleave",
123 "onmousemove",
124 "onmouseout",
125 "onmouseover",
126 "onmouseup",
127 "onpaste",
128 "onpause",
129 "onplay",
130 "onplaying",
131 "onprogress",
132 "onratechange",
133 "onreset",
134 "onresize",
135 "onscroll",
136 "onscrollend",
137 "onsecuritypolicyviolation",
138 "onseeked",
139 "onseeking",
140 "onselect",
141 "onslotchange",
142 "onstalled",
143 "onsubmit",
144 "onsuspend",
145 "ontimeupdate",
146 "ontoggle",
147 "onvolumechange",
148 "onwaiting",
149 "onwebkitanimationend",
150 "onwebkitanimationiteration",
151 "onwebkitanimationstart",
152 "onwebkittransitionend",
153 "onwheel",
154 "onanimationstart",
156 "onanimationiteration",
157 "onanimationend",
158 "onanimationcancel",
159 "ontransitionrun",
161 "ontransitionend",
162 "ontransitioncancel",
163 "onselectstart",
165 "onselectionchange",
166 "onafterprint",
168 "onbeforeprint",
169 "onbeforeunload",
170 "onhashchange",
171 "onlanguagechange",
172 "onmessage",
173 "onmessageerror",
174 "onoffline",
175 "ononline",
176 "onpagehide",
177 "onpagereveal",
178 "onpageshow",
179 "onpageswap",
180 "onpopstate",
181 "onrejectionhandled",
182 "onstorage",
183 "onunhandledrejection",
184 "onunload",
185 "onencrypted",
187 "onwaitingforkey",
188 "onbegin",
190 "onend",
191 "onrepeat",
192];
193
194#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
195#[allow(clippy::enum_variant_names)]
196pub(crate) enum CommonEventHandler {
197 EventHandler(#[conditional_malloc_size_of] Rc<EventHandlerNonNull>),
198
199 ErrorEventHandler(#[conditional_malloc_size_of] Rc<OnErrorEventHandlerNonNull>),
200
201 BeforeUnloadEventHandler(#[conditional_malloc_size_of] Rc<OnBeforeUnloadEventHandlerNonNull>),
202}
203
204impl CommonEventHandler {
205 fn parent(&self) -> &CallbackFunction<crate::DomTypeHolder> {
206 match *self {
207 CommonEventHandler::EventHandler(ref handler) => &handler.parent,
208 CommonEventHandler::ErrorEventHandler(ref handler) => &handler.parent,
209 CommonEventHandler::BeforeUnloadEventHandler(ref handler) => &handler.parent,
210 }
211 }
212}
213
214#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
215pub(crate) enum ListenerPhase {
216 Capturing,
217 Bubbling,
218}
219
220#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
222struct InternalRawUncompiledHandler {
223 source: DOMString,
224 #[no_trace]
225 url: ServoUrl,
226 line: usize,
227}
228
229#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
231enum InlineEventListener {
232 Uncompiled(InternalRawUncompiledHandler),
233 Compiled(CommonEventHandler),
234 Null,
235}
236
237fn get_compiled_handler(
241 inline_listener: &RefCell<InlineEventListener>,
242 owner: &EventTarget,
243 ty: &Atom,
244 can_gc: CanGc,
245) -> Option<CommonEventHandler> {
246 let listener = mem::replace(
247 &mut *inline_listener.borrow_mut(),
248 InlineEventListener::Null,
249 );
250 let compiled = match listener {
251 InlineEventListener::Null => None,
252 InlineEventListener::Uncompiled(handler) => {
253 owner.get_compiled_event_handler(handler, ty, can_gc)
254 },
255 InlineEventListener::Compiled(handler) => Some(handler),
256 };
257 if let Some(ref compiled) = compiled {
258 *inline_listener.borrow_mut() = InlineEventListener::Compiled(compiled.clone());
259 }
260 compiled
261}
262
263#[derive(Clone, JSTraceable, MallocSizeOf, PartialEq)]
264enum EventListenerType {
265 Additive(#[conditional_malloc_size_of] Rc<EventListener>),
266 Inline(RefCell<InlineEventListener>),
267}
268
269impl EventListenerType {
270 fn get_compiled_listener(
271 &self,
272 owner: &EventTarget,
273 ty: &Atom,
274 can_gc: CanGc,
275 ) -> Option<CompiledEventListener> {
276 match *self {
277 EventListenerType::Inline(ref inline) => {
278 get_compiled_handler(inline, owner, ty, can_gc).map(CompiledEventListener::Handler)
279 },
280 EventListenerType::Additive(ref listener) => {
281 Some(CompiledEventListener::Listener(listener.clone()))
282 },
283 }
284 }
285}
286
287pub(crate) enum CompiledEventListener {
290 Listener(Rc<EventListener>),
291 Handler(CommonEventHandler),
292}
293
294impl CompiledEventListener {
295 #[allow(unsafe_code)]
296 pub(crate) fn associated_global(&self) -> DomRoot<GlobalScope> {
297 let obj = match self {
298 CompiledEventListener::Listener(listener) => listener.callback(),
299 CompiledEventListener::Handler(CommonEventHandler::EventHandler(handler)) => {
300 handler.callback()
301 },
302 CompiledEventListener::Handler(CommonEventHandler::ErrorEventHandler(handler)) => {
303 handler.callback()
304 },
305 CompiledEventListener::Handler(CommonEventHandler::BeforeUnloadEventHandler(
306 handler,
307 )) => handler.callback(),
308 };
309 unsafe { GlobalScope::from_object(obj) }
310 }
311
312 pub(crate) fn call_or_handle_event(
314 &self,
315 object: &EventTarget,
316 event: &Event,
317 exception_handle: ExceptionHandling,
318 can_gc: CanGc,
319 ) {
320 match *self {
322 CompiledEventListener::Listener(ref listener) => {
323 let _ = listener.HandleEvent_(object, event, exception_handle, can_gc);
324 },
325 CompiledEventListener::Handler(ref handler) => {
326 match *handler {
327 CommonEventHandler::ErrorEventHandler(ref handler) => {
328 if let Some(event) = event.downcast::<ErrorEvent>() {
329 if object.is::<Window>() || object.is::<WorkerGlobalScope>() {
330 let cx = GlobalScope::get_cx();
331 rooted!(in(*cx) let mut error: JSVal);
332 event.Error(cx, error.handle_mut());
333 rooted!(in(*cx) let mut rooted_return_value: JSVal);
334 let return_value = handler.Call_(
335 object,
336 EventOrString::String(event.Message()),
337 Some(event.Filename()),
338 Some(event.Lineno()),
339 Some(event.Colno()),
340 Some(error.handle()),
341 rooted_return_value.handle_mut(),
342 exception_handle,
343 can_gc,
344 );
345 if let Ok(()) = return_value {
347 if rooted_return_value.handle().is_boolean() &&
348 rooted_return_value.handle().to_boolean()
349 {
350 event.upcast::<Event>().PreventDefault();
351 }
352 }
353 return;
354 }
355 }
356
357 rooted!(in(*GlobalScope::get_cx()) let mut rooted_return_value: JSVal);
358 let _ = handler.Call_(
359 object,
360 EventOrString::Event(DomRoot::from_ref(event)),
361 None,
362 None,
363 None,
364 None,
365 rooted_return_value.handle_mut(),
366 exception_handle,
367 can_gc,
368 );
369 },
370
371 CommonEventHandler::BeforeUnloadEventHandler(ref handler) => {
372 if let Some(event) = event.downcast::<BeforeUnloadEvent>() {
373 if let Ok(value) = handler.Call_(
375 object,
376 event.upcast::<Event>(),
377 exception_handle,
378 can_gc,
379 ) {
380 let rv = event.ReturnValue();
381 if let Some(v) = value {
382 if rv.is_empty() {
383 event.SetReturnValue(v);
384 }
385 event.upcast::<Event>().PreventDefault();
386 }
387 }
388 } else {
389 let _ = handler.Call_(
391 object,
392 event.upcast::<Event>(),
393 exception_handle,
394 can_gc,
395 );
396 }
397 },
398
399 CommonEventHandler::EventHandler(ref handler) => {
400 let cx = GlobalScope::get_cx();
401 rooted!(in(*cx) let mut rooted_return_value: JSVal);
402 if let Ok(()) = handler.Call_(
403 object,
404 event,
405 rooted_return_value.handle_mut(),
406 exception_handle,
407 can_gc,
408 ) {
409 let value = rooted_return_value.handle();
410
411 let should_cancel = value.is_boolean() && !value.to_boolean();
413
414 if should_cancel {
415 event.PreventDefault();
419 }
420 }
421 },
422 }
423 },
424 }
425 }
426}
427
428#[derive(Clone, DenyPublicFields, JSTraceable, MallocSizeOf)]
431pub(crate) struct EventListenerEntry {
433 phase: ListenerPhase,
434 listener: EventListenerType,
435 once: bool,
436 passive: bool,
437 removed: bool,
438}
439
440impl EventListenerEntry {
441 pub(crate) fn phase(&self) -> ListenerPhase {
442 self.phase
443 }
444
445 pub(crate) fn once(&self) -> bool {
446 self.once
447 }
448
449 pub(crate) fn removed(&self) -> bool {
450 self.removed
451 }
452
453 pub(crate) fn get_compiled_listener(
455 &self,
456 owner: &EventTarget,
457 ty: &Atom,
458 can_gc: CanGc,
459 ) -> Option<CompiledEventListener> {
460 self.listener.get_compiled_listener(owner, ty, can_gc)
461 }
462}
463
464impl std::cmp::PartialEq for EventListenerEntry {
465 fn eq(&self, other: &Self) -> bool {
466 self.phase == other.phase && self.listener == other.listener
467 }
468}
469
470#[derive(Clone, JSTraceable, MallocSizeOf)]
471pub(crate) struct EventListeners(
473 #[conditional_malloc_size_of] Vec<Rc<RefCell<EventListenerEntry>>>,
474);
475
476impl Deref for EventListeners {
477 type Target = Vec<Rc<RefCell<EventListenerEntry>>>;
478 fn deref(&self) -> &Vec<Rc<RefCell<EventListenerEntry>>> {
479 &self.0
480 }
481}
482
483impl DerefMut for EventListeners {
484 fn deref_mut(&mut self) -> &mut Vec<Rc<RefCell<EventListenerEntry>>> {
485 &mut self.0
486 }
487}
488
489impl EventListeners {
490 fn get_inline_listener(
492 &self,
493 owner: &EventTarget,
494 ty: &Atom,
495 can_gc: CanGc,
496 ) -> Option<CommonEventHandler> {
497 for entry in &self.0 {
498 if let EventListenerType::Inline(ref inline) = entry.borrow().listener {
499 return get_compiled_handler(inline, owner, ty, can_gc);
501 }
502 }
503
504 None
506 }
507
508 fn has_listeners(&self) -> bool {
509 !self.0.is_empty()
510 }
511}
512
513#[dom_struct]
514pub struct EventTarget {
515 reflector_: Reflector,
516 handlers: DomRefCell<HashMapTracedValues<Atom, EventListeners, FxBuildHasher>>,
517}
518
519impl EventTarget {
520 pub(crate) fn new_inherited() -> EventTarget {
521 EventTarget {
522 reflector_: Reflector::new(),
523 handlers: DomRefCell::new(Default::default()),
524 }
525 }
526
527 fn new(
528 global: &GlobalScope,
529 proto: Option<HandleObject>,
530 can_gc: CanGc,
531 ) -> DomRoot<EventTarget> {
532 reflect_dom_object_with_proto(
533 Box::new(EventTarget::new_inherited()),
534 global,
535 proto,
536 can_gc,
537 )
538 }
539
540 pub(crate) fn has_listeners_for(&self, type_: &Atom) -> bool {
543 match self.handlers.borrow().get(type_) {
544 Some(listeners) => listeners.has_listeners(),
545 None => false,
546 }
547 }
548
549 pub(crate) fn get_listeners_for(&self, type_: &Atom) -> EventListeners {
550 self.handlers
551 .borrow()
552 .get(type_)
553 .map_or(EventListeners(vec![]), |listeners| listeners.clone())
554 }
555
556 pub(crate) fn dispatch_event(&self, event: &Event, can_gc: CanGc) -> bool {
557 event.dispatch(self, false, can_gc)
558 }
559
560 pub(crate) fn remove_all_listeners(&self) {
561 let mut handlers = self.handlers.borrow_mut();
562 for (_, entries) in handlers.iter() {
563 entries
564 .iter()
565 .for_each(|entry| entry.borrow_mut().removed = true);
566 }
567
568 *handlers = Default::default();
569 }
570
571 fn default_passive_value(&self, ty: &Atom) -> bool {
573 let event_type = ty.to_ascii_lowercase();
575
576 let matches_event_type = matches!(
578 event_type.trim_matches(HTML_SPACE_CHARACTERS),
579 "touchstart" | "touchmove" | "wheel" | "mousewheel"
580 );
581
582 if !matches_event_type {
583 return false;
584 }
585
586 if self.is::<Window>() {
588 return true;
589 }
590
591 if let Some(node) = self.downcast::<Node>() {
593 let node_document = node.owner_document();
594 let event_target = self.upcast::<EventTarget>();
595
596 return event_target == node_document.upcast::<EventTarget>()
598 || node_document.GetDocumentElement().is_some_and(|n| n.upcast::<EventTarget>() == event_target)
600 || node_document.GetBody().is_some_and(|n| n.upcast::<EventTarget>() == event_target);
602 }
603
604 false
605 }
606
607 fn set_inline_event_listener(&self, ty: Atom, listener: Option<InlineEventListener>) {
609 let mut handlers = self.handlers.borrow_mut();
610 let entries = match handlers.entry(ty.clone()) {
611 Occupied(entry) => entry.into_mut(),
612 Vacant(entry) => entry.insert(EventListeners(vec![])),
613 };
614
615 let idx = entries
616 .iter()
617 .position(|entry| matches!(entry.borrow().listener, EventListenerType::Inline(_)));
618
619 match idx {
620 Some(idx) => match listener {
621 Some(listener) => {
624 entries[idx].borrow_mut().listener = EventListenerType::Inline(listener.into());
625 },
626 None => {
627 entries.remove(idx).borrow_mut().removed = true;
628 },
629 },
630 None => {
631 if let Some(listener) = listener {
632 entries.push(Rc::new(RefCell::new(EventListenerEntry {
633 phase: ListenerPhase::Bubbling,
634 listener: EventListenerType::Inline(listener.into()),
635 once: false,
636 passive: self.default_passive_value(&ty),
637 removed: false,
638 })));
639 }
640 },
641 }
642 }
643
644 pub(crate) fn remove_listener(&self, ty: &Atom, entry: &Rc<RefCell<EventListenerEntry>>) {
645 let mut handlers = self.handlers.borrow_mut();
646
647 if let Some(entries) = handlers.get_mut(ty) {
648 if let Some(position) = entries.iter().position(|e| *e == *entry) {
649 entries.remove(position).borrow_mut().removed = true;
650 }
651 }
652 }
653
654 pub(crate) fn is_passive(&self, listener: &Rc<RefCell<EventListenerEntry>>) -> bool {
656 listener.borrow().passive
657 }
658
659 fn get_inline_event_listener(&self, ty: &Atom, can_gc: CanGc) -> Option<CommonEventHandler> {
660 let handlers = self.handlers.borrow();
661 handlers
662 .get(ty)
663 .and_then(|entry| entry.get_inline_listener(self, ty, can_gc))
664 }
665
666 pub(crate) fn set_event_handler_uncompiled(
669 &self,
670 url: ServoUrl,
671 line: usize,
672 ty: &str,
673 source: &str,
674 ) {
675 if let Some(element) = self.downcast::<Element>() {
676 let doc = element.owner_document();
677 let global = &doc.global();
678 if global
679 .get_csp_list()
680 .should_elements_inline_type_behavior_be_blocked(
681 global,
682 element.upcast(),
683 InlineCheckType::ScriptAttribute,
684 source,
685 )
686 {
687 return;
688 }
689 };
690
691 let handler = InternalRawUncompiledHandler {
692 source: DOMString::from(source),
693 line,
694 url,
695 };
696 self.set_inline_event_listener(
697 Atom::from(ty),
698 Some(InlineEventListener::Uncompiled(handler)),
699 );
700 }
701
702 #[allow(unsafe_code)]
707 fn get_compiled_event_handler(
708 &self,
709 handler: InternalRawUncompiledHandler,
710 ty: &Atom,
711 can_gc: CanGc,
712 ) -> Option<CommonEventHandler> {
713 let element = self.downcast::<Element>();
715 let document = match element {
716 Some(element) => element.owner_document(),
717 None => self.downcast::<Window>().unwrap().Document(),
718 };
719
720 if !document.scripting_enabled() {
722 return None;
723 }
724
725 let body: Vec<u16> = handler.source.encode_utf16().collect();
727
728 let form_owner = element
732 .and_then(|e| e.as_maybe_form_control())
733 .and_then(|f| f.form_owner());
734
735 let window = document.window();
743 let _ac = enter_realm(window);
744
745 let name = CString::new(format!("on{}", &**ty)).unwrap();
748
749 const ARG_NAMES: &[*const c_char] = &[c"event".as_ptr()];
751 const ERROR_ARG_NAMES: &[*const c_char] = &[
752 c"event".as_ptr(),
753 c"source".as_ptr(),
754 c"lineno".as_ptr(),
755 c"colno".as_ptr(),
756 c"error".as_ptr(),
757 ];
758 let is_error = ty == &atom!("error") && self.is::<Window>();
759 let args = if is_error { ERROR_ARG_NAMES } else { ARG_NAMES };
760
761 let cx = GlobalScope::get_cx();
762 let options = unsafe {
763 CompileOptionsWrapper::new(*cx, &handler.url.to_string(), handler.line as u32)
764 };
765
766 let scopechain = js::rust::EnvironmentChain::new(*cx, SupportUnscopables::Yes);
768
769 if let Some(element) = element {
770 scopechain.append(document.reflector().get_jsobject().get());
771 if let Some(form_owner) = form_owner {
772 scopechain.append(form_owner.reflector().get_jsobject().get());
773 }
774 scopechain.append(element.reflector().get_jsobject().get());
775 }
776
777 rooted!(in(*cx) let mut handler = unsafe {
778 CompileFunction(
779 *cx,
780 scopechain.get(),
781 options.ptr,
782 name.as_ptr(),
783 args.len() as u32,
784 args.as_ptr(),
785 &mut transform_u16_to_source_text(&body),
786 )
787 });
788 if handler.get().is_null() {
789 let ar = enter_realm(self);
791 report_pending_exception(cx, false, InRealm::Entered(&ar), can_gc);
793 return None;
794 }
795
796 let funobj = unsafe { JS_GetFunctionObject(handler.get()) };
802 assert!(!funobj.is_null());
803 if is_error {
805 Some(CommonEventHandler::ErrorEventHandler(unsafe {
806 OnErrorEventHandlerNonNull::new(cx, funobj)
807 }))
808 } else if ty == &atom!("beforeunload") {
809 Some(CommonEventHandler::BeforeUnloadEventHandler(unsafe {
810 OnBeforeUnloadEventHandlerNonNull::new(cx, funobj)
811 }))
812 } else {
813 Some(CommonEventHandler::EventHandler(unsafe {
814 EventHandlerNonNull::new(cx, funobj)
815 }))
816 }
817 }
818
819 #[allow(unsafe_code)]
820 pub(crate) fn set_event_handler_common<T: CallbackContainer<crate::DomTypeHolder>>(
821 &self,
822 ty: &str,
823 listener: Option<Rc<T>>,
824 ) {
825 let cx = GlobalScope::get_cx();
826
827 let event_listener = listener.map(|listener| {
828 InlineEventListener::Compiled(CommonEventHandler::EventHandler(unsafe {
829 EventHandlerNonNull::new(cx, listener.callback())
830 }))
831 });
832 self.set_inline_event_listener(Atom::from(ty), event_listener);
833 }
834
835 #[allow(unsafe_code)]
836 pub(crate) fn set_error_event_handler<T: CallbackContainer<crate::DomTypeHolder>>(
837 &self,
838 ty: &str,
839 listener: Option<Rc<T>>,
840 ) {
841 let cx = GlobalScope::get_cx();
842
843 let event_listener = listener.map(|listener| {
844 InlineEventListener::Compiled(CommonEventHandler::ErrorEventHandler(unsafe {
845 OnErrorEventHandlerNonNull::new(cx, listener.callback())
846 }))
847 });
848 self.set_inline_event_listener(Atom::from(ty), event_listener);
849 }
850
851 #[allow(unsafe_code)]
852 pub(crate) fn set_beforeunload_event_handler<T: CallbackContainer<crate::DomTypeHolder>>(
853 &self,
854 ty: &str,
855 listener: Option<Rc<T>>,
856 ) {
857 let cx = GlobalScope::get_cx();
858
859 let event_listener = listener.map(|listener| {
860 InlineEventListener::Compiled(CommonEventHandler::BeforeUnloadEventHandler(unsafe {
861 OnBeforeUnloadEventHandlerNonNull::new(cx, listener.callback())
862 }))
863 });
864 self.set_inline_event_listener(Atom::from(ty), event_listener);
865 }
866
867 #[allow(unsafe_code)]
868 pub(crate) fn get_event_handler_common<T: CallbackContainer<crate::DomTypeHolder>>(
869 &self,
870 ty: &str,
871 can_gc: CanGc,
872 ) -> Option<Rc<T>> {
873 let cx = GlobalScope::get_cx();
874 let listener = self.get_inline_event_listener(&Atom::from(ty), can_gc);
875 unsafe {
876 listener.map(|listener| {
877 CallbackContainer::new(cx, listener.parent().callback_holder().get())
878 })
879 }
880 }
881
882 pub(crate) fn has_handlers(&self) -> bool {
883 !self.handlers.borrow().is_empty()
884 }
885
886 pub(crate) fn fire_event(&self, name: Atom, can_gc: CanGc) -> bool {
888 self.fire_event_with_params(
889 name,
890 EventBubbles::DoesNotBubble,
891 EventCancelable::NotCancelable,
892 EventComposed::NotComposed,
893 can_gc,
894 )
895 }
896
897 pub(crate) fn fire_bubbling_event(&self, name: Atom, can_gc: CanGc) -> bool {
899 self.fire_event_with_params(
900 name,
901 EventBubbles::Bubbles,
902 EventCancelable::NotCancelable,
903 EventComposed::NotComposed,
904 can_gc,
905 )
906 }
907
908 pub(crate) fn fire_cancelable_event(&self, name: Atom, can_gc: CanGc) -> bool {
910 self.fire_event_with_params(
911 name,
912 EventBubbles::DoesNotBubble,
913 EventCancelable::Cancelable,
914 EventComposed::NotComposed,
915 can_gc,
916 )
917 }
918
919 pub(crate) fn fire_bubbling_cancelable_event(&self, name: Atom, can_gc: CanGc) -> bool {
921 self.fire_event_with_params(
922 name,
923 EventBubbles::Bubbles,
924 EventCancelable::Cancelable,
925 EventComposed::NotComposed,
926 can_gc,
927 )
928 }
929
930 pub(crate) fn fire_event_with_params(
932 &self,
933 name: Atom,
934 bubbles: EventBubbles,
935 cancelable: EventCancelable,
936 composed: EventComposed,
937 can_gc: CanGc,
938 ) -> bool {
939 let event = Event::new(&self.global(), name, bubbles, cancelable, can_gc);
940 event.set_composed(composed.into());
941 event.fire(self, can_gc)
942 }
943
944 pub(crate) fn add_event_listener(
947 &self,
948 ty: DOMString,
949 listener: Option<Rc<EventListener>>,
950 options: AddEventListenerOptions,
951 ) {
952 if let Some(signal) = options.signal.as_ref() {
953 if signal.aborted() {
955 return;
956 }
957 signal.add(&AbortAlgorithm::DomEventListener(
959 RemovableDomEventListener {
960 event_target: Trusted::new(self),
961 ty: ty.clone(),
962 listener: listener.clone(),
963 options: options.parent.clone(),
964 },
965 ));
966 }
967 let listener = match listener {
969 Some(l) => l,
970 None => return,
971 };
972 let mut handlers = self.handlers.borrow_mut();
973 let ty = Atom::from(ty);
974 let entries = match handlers.entry(ty.clone()) {
975 Occupied(entry) => entry.into_mut(),
976 Vacant(entry) => entry.insert(EventListeners(vec![])),
977 };
978
979 let phase = if options.parent.capture {
980 ListenerPhase::Capturing
981 } else {
982 ListenerPhase::Bubbling
983 };
984 let new_entry = Rc::new(RefCell::new(EventListenerEntry {
986 phase,
987 listener: EventListenerType::Additive(listener),
988 once: options.once,
989 passive: options.passive.unwrap_or(self.default_passive_value(&ty)),
990 removed: false,
991 }));
992
993 if !entries.contains(&new_entry) {
997 entries.push(new_entry);
998 }
999 }
1000
1001 pub(crate) fn remove_event_listener(
1004 &self,
1005 ty: DOMString,
1006 listener: &Option<Rc<EventListener>>,
1007 options: &EventListenerOptions,
1008 ) {
1009 let Some(listener) = listener else {
1010 return;
1011 };
1012 let mut handlers = self.handlers.borrow_mut();
1013 if let Some(entries) = handlers.get_mut(&Atom::from(ty)) {
1014 let phase = if options.capture {
1015 ListenerPhase::Capturing
1016 } else {
1017 ListenerPhase::Bubbling
1018 };
1019 let listener_type = EventListenerType::Additive(listener.clone());
1020 if let Some(position) = entries
1021 .iter()
1022 .position(|e| e.borrow().listener == listener_type && e.borrow().phase == phase)
1023 {
1024 entries.remove(position).borrow_mut().removed = true;
1026 }
1027 }
1028 }
1029
1030 pub(crate) fn get_the_parent(&self, event: &Event) -> Option<DomRoot<EventTarget>> {
1032 if let Some(document) = self.downcast::<Document>() {
1033 if event.type_() == atom!("load") || !document.has_browsing_context() {
1034 return None;
1035 } else {
1036 return Some(DomRoot::from_ref(document.window().upcast::<EventTarget>()));
1037 }
1038 }
1039
1040 if let Some(shadow_root) = self.downcast::<ShadowRoot>() {
1041 if event.should_pass_shadow_boundary(shadow_root) {
1042 let host = shadow_root.Host();
1043 return Some(DomRoot::from_ref(host.upcast::<EventTarget>()));
1044 } else {
1045 return None;
1046 }
1047 }
1048
1049 if let Some(node) = self.downcast::<Node>() {
1050 return node.assigned_slot().map(DomRoot::upcast).or_else(|| {
1053 node.GetParentNode()
1054 .map(|parent| DomRoot::from_ref(parent.upcast::<EventTarget>()))
1055 });
1056 }
1057
1058 None
1059 }
1060
1061 pub(crate) fn retarget(&self, b: &Self) -> DomRoot<EventTarget> {
1065 let mut a = DomRoot::from_ref(self);
1067 loop {
1068 let Some(a_node) = a.downcast::<Node>() else {
1073 return a;
1074 };
1075 let a_root = a_node.GetRootNode(&GetRootNodeOptions::empty());
1076 if !a_root.is::<ShadowRoot>() {
1077 return a;
1078 }
1079 if let Some(b_node) = b.downcast::<Node>() {
1080 if a_root.is_shadow_including_inclusive_ancestor_of(b_node) {
1081 return a;
1082 }
1083 }
1084
1085 a = DomRoot::from_ref(
1087 a_root
1088 .downcast::<ShadowRoot>()
1089 .unwrap()
1090 .Host()
1091 .upcast::<EventTarget>(),
1092 );
1093 }
1094 }
1095
1096 pub(crate) fn is_content_event_handler(name: &str) -> bool {
1098 CONTENT_EVENT_HANDLER_NAMES.contains(&name)
1099 }
1100}
1101
1102impl EventTargetMethods<crate::DomTypeHolder> for EventTarget {
1103 fn Constructor(
1105 global: &GlobalScope,
1106 proto: Option<HandleObject>,
1107 can_gc: CanGc,
1108 ) -> Fallible<DomRoot<EventTarget>> {
1109 Ok(EventTarget::new(global, proto, can_gc))
1110 }
1111
1112 fn AddEventListener(
1114 &self,
1115 ty: DOMString,
1116 listener: Option<Rc<EventListener>>,
1117 options: AddEventListenerOptionsOrBoolean,
1118 ) {
1119 self.add_event_listener(ty, listener, options.convert())
1120 }
1121
1122 fn RemoveEventListener(
1124 &self,
1125 ty: DOMString,
1126 listener: Option<Rc<EventListener>>,
1127 options: EventListenerOptionsOrBoolean,
1128 ) {
1129 self.remove_event_listener(ty, &listener, &options.convert())
1130 }
1131
1132 fn DispatchEvent(&self, event: &Event, can_gc: CanGc) -> Fallible<bool> {
1134 if event.dispatching() || !event.initialized() {
1135 return Err(Error::InvalidState);
1136 }
1137 event.set_trusted(false);
1138 Ok(self.dispatch_event(event, can_gc))
1139 }
1140}
1141
1142impl VirtualMethods for EventTarget {
1143 fn super_type(&self) -> Option<&dyn VirtualMethods> {
1144 None
1145 }
1146}
1147
1148impl Convert<AddEventListenerOptions> for AddEventListenerOptionsOrBoolean {
1149 fn convert(self) -> AddEventListenerOptions {
1151 match self {
1154 AddEventListenerOptionsOrBoolean::AddEventListenerOptions(options) => options,
1156 AddEventListenerOptionsOrBoolean::Boolean(capture) => AddEventListenerOptions {
1157 parent: EventListenerOptions { capture },
1158 once: false,
1160 passive: None,
1162 signal: None,
1163 },
1164 }
1165 }
1166}
1167
1168impl Convert<EventListenerOptions> for EventListenerOptionsOrBoolean {
1169 fn convert(self) -> EventListenerOptions {
1170 match self {
1171 EventListenerOptionsOrBoolean::EventListenerOptions(options) => options,
1172 EventListenerOptionsOrBoolean::Boolean(capture) => EventListenerOptions { capture },
1173 }
1174 }
1175}