1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // Microsoft's API Name hackery sucks
10 #include "js/loader/LoadedScript.h"
11 #include "mozilla/BasicEvents.h"
12 #include "mozilla/CycleCollectedJSRuntime.h"
13 #include "mozilla/DOMEventTargetHelper.h"
14 #include "mozilla/EventDispatcher.h"
15 #include "mozilla/EventListenerManager.h"
16 #include "mozilla/HalSensor.h"
17 #include "mozilla/InternalMutationEvent.h"
18 #include "mozilla/JSEventHandler.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/MemoryReporting.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/PresShell.h"
23 #include "mozilla/dom/AbortSignal.h"
24 #include "mozilla/dom/BindingUtils.h"
25 #include "mozilla/dom/EventCallbackDebuggerNotification.h"
26 #include "mozilla/dom/Element.h"
27 #include "mozilla/dom/Event.h"
28 #include "mozilla/dom/EventTargetBinding.h"
29 #include "mozilla/dom/PopupBlocker.h"
30 #include "mozilla/dom/ScriptLoader.h"
31 #include "mozilla/dom/ScriptSettings.h"
32 #include "mozilla/dom/TouchEvent.h"
33 #include "mozilla/dom/UserActivation.h"
34 #include "mozilla/ScopeExit.h"
35 #include "mozilla/StaticPrefs_dom.h"
36 #include "mozilla/TimeStamp.h"
37 #include "mozilla/dom/ChromeUtils.h"
39 #include "EventListenerService.h"
41 #include "nsContentUtils.h"
44 #include "nsGenericHTMLElement.h"
45 #include "nsGkAtoms.h"
46 #include "nsIContent.h"
47 #include "nsIContentSecurityPolicy.h"
48 #include "mozilla/dom/Document.h"
49 #include "nsIScriptGlobalObject.h"
50 #include "nsISupports.h"
51 #include "nsJSUtils.h"
52 #include "nsNameSpaceManager.h"
53 #include "nsPIDOMWindow.h"
54 #include "nsPrintfCString.h"
55 #include "nsSandboxFlags.h"
56 #include "xpcpublic.h"
58 #include "nsDisplayList.h"
59 #include "nsPIWindowRoot.h"
66 #define EVENT_TYPE_EQUALS(ls, message, userType, allEvents) \
67 ((ls->mEventMessage == message && \
68 (ls->mEventMessage != eUnidentifiedEvent || ls->mTypeAtom == userType)) || \
69 (allEvents && ls->mAllEvents))
71 static const uint32_t kAllMutationBits
=
72 NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
|
73 NS_EVENT_BITS_MUTATION_NODEINSERTED
| NS_EVENT_BITS_MUTATION_NODEREMOVED
|
74 NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT
|
75 NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT
|
76 NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
77 NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED
;
79 static uint32_t MutationBitForEventType(EventMessage aEventType
) {
81 case eLegacySubtreeModified
:
82 return NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
;
83 case eLegacyNodeInserted
:
84 return NS_EVENT_BITS_MUTATION_NODEINSERTED
;
85 case eLegacyNodeRemoved
:
86 return NS_EVENT_BITS_MUTATION_NODEREMOVED
;
87 case eLegacyNodeRemovedFromDocument
:
88 return NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT
;
89 case eLegacyNodeInsertedIntoDocument
:
90 return NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT
;
91 case eLegacyAttrModified
:
92 return NS_EVENT_BITS_MUTATION_ATTRMODIFIED
;
93 case eLegacyCharacterDataModified
:
94 return NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED
;
101 uint32_t EventListenerManager::sMainThreadCreatedCount
= 0;
103 EventListenerManagerBase::EventListenerManagerBase()
104 : mMayHavePaintEventListener(false),
105 mMayHaveMutationListeners(false),
106 mMayHaveCapturingListeners(false),
107 mMayHaveSystemGroupListeners(false),
108 mMayHaveTouchEventListener(false),
109 mMayHaveMouseEnterLeaveEventListener(false),
110 mMayHavePointerEnterLeaveEventListener(false),
111 mMayHaveSelectionChangeEventListener(false),
112 mMayHaveFormSelectEventListener(false),
113 mMayHaveTransitionEventListener(false),
114 mClearingListeners(false),
115 mIsMainThreadELM(NS_IsMainThread()),
116 mMayHaveListenersForUntrustedEvents(false) {
117 ClearNoListenersForEvents();
118 static_assert(sizeof(EventListenerManagerBase
) == sizeof(uint64_t),
119 "Keep the size of EventListenerManagerBase size compact!");
122 EventListenerManager::EventListenerManager(EventTarget
* aTarget
)
123 : EventListenerManagerBase(), mTarget(aTarget
) {
124 NS_ASSERTION(aTarget
, "unexpected null pointer");
126 if (mIsMainThreadELM
) {
127 ++sMainThreadCreatedCount
;
131 EventListenerManager::~EventListenerManager() {
132 // If your code fails this assertion, a possible reason is that
133 // a class did not call our Disconnect() manually. Note that
134 // this class can have Disconnect called in one of two ways:
135 // if it is part of a cycle, then in Unlink() (such a cycle
136 // would be with one of the listeners, not mTarget which is weak).
137 // If not part of a cycle, then Disconnect must be called manually,
138 // typically from the destructor of the owner class (mTarget).
139 // XXX azakai: Is there any reason to not just call Disconnect
140 // from right here, if not previously called?
141 NS_ASSERTION(!mTarget
, "didn't call Disconnect");
142 RemoveAllListenersSilently();
145 void EventListenerManager::RemoveAllListenersSilently() {
146 if (mClearingListeners
) {
149 mClearingListeners
= true;
151 mClearingListeners
= false;
154 inline void ImplCycleCollectionTraverse(
155 nsCycleCollectionTraversalCallback
& aCallback
,
156 EventListenerManager::Listener
& aField
, const char* aName
,
158 if (MOZ_UNLIKELY(aCallback
.WantDebugInfo())) {
160 name
.AppendASCII(aName
);
161 if (aField
.mTypeAtom
) {
162 name
.AppendLiteral(" event=");
163 name
.Append(nsAtomCString(aField
.mTypeAtom
));
164 name
.AppendLiteral(" listenerType=");
165 name
.AppendInt(aField
.mListenerType
);
166 name
.AppendLiteral(" ");
168 CycleCollectionNoteChild(aCallback
, aField
.mListener
.GetISupports(),
171 CycleCollectionNoteChild(aCallback
, aField
.mListener
.GetISupports(), aName
,
175 CycleCollectionNoteChild(aCallback
, aField
.mSignalFollower
.get(),
176 "mSignalFollower", aFlags
);
179 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager
)
181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EventListenerManager
)
182 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners
)
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
185 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EventListenerManager
)
187 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
189 nsPIDOMWindowInner
* EventListenerManager::GetInnerWindowForTarget() {
190 if (nsINode
* node
= nsINode::FromEventTargetOrNull(mTarget
)) {
191 // XXX sXBL/XBL2 issue -- do we really want the owner here? What
192 // if that's the XBL document?
193 return node
->OwnerDoc()->GetInnerWindow();
196 nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow();
200 already_AddRefed
<nsPIDOMWindowInner
>
201 EventListenerManager::GetTargetAsInnerWindow() const {
202 nsCOMPtr
<nsPIDOMWindowInner
> window
=
203 nsPIDOMWindowInner::FromEventTargetOrNull(mTarget
);
204 return window
.forget();
207 void EventListenerManager::AddEventListenerInternal(
208 EventListenerHolder aListenerHolder
, EventMessage aEventMessage
,
209 nsAtom
* aTypeAtom
, const EventListenerFlags
& aFlags
, bool aHandler
,
210 bool aAllEvents
, AbortSignal
* aSignal
) {
211 MOZ_ASSERT((aEventMessage
&& aTypeAtom
) || aAllEvents
, // all-events listener
214 if (!aListenerHolder
|| mClearingListeners
) {
218 if (aSignal
&& aSignal
->Aborted()) {
222 // Since there is no public API to call us with an EventListenerHolder, we
223 // know that there's an EventListenerHolder on the stack holding a strong ref
227 uint32_t count
= mListeners
.Length();
228 for (uint32_t i
= 0; i
< count
; i
++) {
229 listener
= &mListeners
.ElementAt(i
);
230 // mListener == aListenerHolder is the last one, since it can be a bit slow.
231 if (listener
->mListenerIsHandler
== aHandler
&&
232 listener
->mFlags
.EqualsForAddition(aFlags
) &&
233 EVENT_TYPE_EQUALS(listener
, aEventMessage
, aTypeAtom
, aAllEvents
) &&
234 listener
->mListener
== aListenerHolder
) {
239 ClearNoListenersForEvents();
240 mNoListenerForEventAtom
= nullptr;
243 aAllEvents
? mListeners
.InsertElementAt(0) : mListeners
.AppendElement();
244 listener
->mEventMessage
= aEventMessage
;
245 listener
->mTypeAtom
= aTypeAtom
;
246 listener
->mFlags
= aFlags
;
247 listener
->mListenerIsHandler
= aHandler
;
248 listener
->mHandlerIsString
= false;
249 listener
->mAllEvents
= aAllEvents
;
251 if (listener
->mFlags
.mAllowUntrustedEvents
) {
252 mMayHaveListenersForUntrustedEvents
= true;
255 // Detect the type of event listener.
256 if (aFlags
.mListenerIsJSListener
) {
257 MOZ_ASSERT(!aListenerHolder
.HasWebIDLCallback());
258 listener
->mListenerType
= Listener::eJSEventListener
;
259 } else if (aListenerHolder
.HasWebIDLCallback()) {
260 listener
->mListenerType
= Listener::eWebIDLListener
;
262 listener
->mListenerType
= Listener::eNativeListener
;
264 listener
->mListener
= std::move(aListenerHolder
);
267 listener
->mSignalFollower
= new ListenerSignalFollower(this, listener
);
268 listener
->mSignalFollower
->Follow(aSignal
);
271 if (aFlags
.mInSystemGroup
) {
272 mMayHaveSystemGroupListeners
= true;
274 if (aFlags
.mCapture
) {
275 mMayHaveCapturingListeners
= true;
278 // Events which are not supported in the running environment is mapped to
279 // eUnidentifiedEvent. Then, we need to consider the proper event message
280 // with comparing the atom.
282 EventMessage resolvedEventMessage
= aEventMessage
;
283 if (resolvedEventMessage
== eUnidentifiedEvent
&& aTypeAtom
->IsStatic()) {
284 // TouchEvents are registered only when
285 // nsContentUtils::InitializeTouchEventTable() is called.
286 if (aTypeAtom
== nsGkAtoms::ontouchstart
) {
287 resolvedEventMessage
= eTouchStart
;
288 } else if (aTypeAtom
== nsGkAtoms::ontouchend
) {
289 resolvedEventMessage
= eTouchEnd
;
290 } else if (aTypeAtom
== nsGkAtoms::ontouchmove
) {
291 resolvedEventMessage
= eTouchMove
;
292 } else if (aTypeAtom
== nsGkAtoms::ontouchcancel
) {
293 resolvedEventMessage
= eTouchCancel
;
297 switch (resolvedEventMessage
) {
299 mMayHavePaintEventListener
= true;
300 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
301 window
->SetHasPaintEventListeners();
304 case eLegacySubtreeModified
:
305 case eLegacyNodeInserted
:
306 case eLegacyNodeRemoved
:
307 case eLegacyNodeRemovedFromDocument
:
308 case eLegacyNodeInsertedIntoDocument
:
309 case eLegacyAttrModified
:
310 case eLegacyCharacterDataModified
:
312 MOZ_ASSERT(!aFlags
.mInSystemGroup
,
313 "Legacy mutation events shouldn't be handled by ourselves");
314 MOZ_ASSERT(listener
->mListenerType
!= Listener::eNativeListener
,
315 "Legacy mutation events shouldn't be handled in C++ code");
316 if (nsINode
* targetNode
= nsINode::FromEventTargetOrNull(mTarget
)) {
317 MOZ_ASSERT(!nsContentUtils::IsChromeDoc(targetNode
->OwnerDoc()),
318 "Legacy mutation events shouldn't be handled in chrome "
320 MOZ_ASSERT(!targetNode
->IsInNativeAnonymousSubtree(),
321 "Legacy mutation events shouldn't listen to mutations in "
322 "native anonymous subtrees");
324 #endif // #ifdef DEBUG
325 // For mutation listeners, we need to update the global bit on the DOM
326 // window. Otherwise we won't actually fire the mutation event.
327 mMayHaveMutationListeners
= true;
328 // Go from our target to the nearest enclosing DOM window.
329 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
330 if (Document
* doc
= window
->GetExtantDoc()) {
331 doc
->WarnOnceAbout(DeprecatedOperations::eMutationEvent
);
333 // If resolvedEventMessage is eLegacySubtreeModified, we need to
334 // listen all mutations. nsContentUtils::HasMutationListeners relies
336 window
->SetMutationListeners(
337 (resolvedEventMessage
== eLegacySubtreeModified
)
339 : MutationBitForEventType(resolvedEventMessage
));
344 mMayHavePointerEnterLeaveEventListener
= true;
345 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
346 NS_WARNING_ASSERTION(
347 !nsContentUtils::IsChromeDoc(window
->GetExtantDoc()),
348 "Please do not use pointerenter/leave events in chrome. "
349 "They are slower than pointerover/out!");
350 window
->SetHasPointerEnterLeaveEventListeners();
353 case eGamepadButtonDown
:
354 case eGamepadButtonUp
:
355 case eGamepadAxisMove
:
356 case eGamepadConnected
:
357 case eGamepadDisconnected
:
358 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
359 window
->SetHasGamepadEventListener();
362 case eDeviceOrientation
:
363 case eDeviceOrientationAbsolute
:
367 #if defined(MOZ_WIDGET_ANDROID)
368 case eOrientationChange
:
369 #endif // #if defined(MOZ_WIDGET_ANDROID)
370 EnableDevice(resolvedEventMessage
);
376 mMayHaveTouchEventListener
= true;
377 // we don't want touchevent listeners added by scrollbars to flip this
378 // flag so we ignore listeners created with system event flag
379 if (!aFlags
.mInSystemGroup
) {
380 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
381 window
->SetHasTouchEventListeners();
387 mMayHaveMouseEnterLeaveEventListener
= true;
388 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
389 NS_WARNING_ASSERTION(
390 !nsContentUtils::IsChromeDoc(window
->GetExtantDoc()),
391 "Please do not use mouseenter/leave events in chrome. "
392 "They are slower than mouseover/out!");
393 window
->SetHasMouseEnterLeaveEventListeners();
396 case eEditorBeforeInput
:
397 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
398 window
->SetHasBeforeInputEventListenersForTelemetry();
401 case eSelectionChange
:
402 mMayHaveSelectionChangeEventListener
= true;
403 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
404 window
->SetHasSelectionChangeEventListeners();
408 mMayHaveFormSelectEventListener
= true;
409 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
410 window
->SetHasFormSelectEventListeners();
414 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
415 if (Document
* doc
= window
->GetExtantDoc()) {
416 doc
->SetUseCounter(eUseCounter_custom_onstart
);
421 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
422 if (Document
* doc
= window
->GetExtantDoc()) {
423 doc
->SetUseCounter(eUseCounter_custom_onbounce
);
428 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
429 if (Document
* doc
= window
->GetExtantDoc()) {
430 doc
->SetUseCounter(eUseCounter_custom_onfinish
);
434 case eScrollPortOverflow
:
435 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
436 if (Document
* doc
= window
->GetExtantDoc()) {
437 doc
->SetUseCounter(eUseCounter_custom_onoverflow
);
441 case eScrollPortUnderflow
:
442 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
443 if (Document
* doc
= window
->GetExtantDoc()) {
444 doc
->SetUseCounter(eUseCounter_custom_onunderflow
);
448 case eLegacyMouseLineOrPageScroll
:
449 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
450 if (Document
* doc
= window
->GetExtantDoc()) {
451 doc
->SetUseCounter(eUseCounter_custom_ondommousescroll
);
455 case eLegacyMousePixelScroll
:
456 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
457 if (Document
* doc
= window
->GetExtantDoc()) {
458 doc
->SetUseCounter(eUseCounter_custom_onmozmousepixelscroll
);
462 case eTransitionStart
:
465 case eTransitionCancel
:
466 case eWebkitTransitionEnd
:
467 mMayHaveTransitionEventListener
= true;
468 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
469 window
->SetHasTransitionEventListeners();
472 case eFormCheckboxStateChange
:
473 nsContentUtils::SetMayHaveFormCheckboxStateChangeListeners();
475 case eFormRadioStateChange
:
476 nsContentUtils::SetMayHaveFormRadioStateChangeListeners();
479 // XXX Use NS_ASSERTION here to print resolvedEventMessage since
480 // MOZ_ASSERT can take only string literal, not pointer to
483 resolvedEventMessage
< eLegacyMutationEventFirst
||
484 resolvedEventMessage
> eLegacyMutationEventLast
,
485 nsPrintfCString("You added new mutation event, but it's not "
486 "handled above, resolvedEventMessage=%s",
487 ToChar(resolvedEventMessage
))
489 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onpointerenter
,
490 nsPrintfCString("resolvedEventMessage=%s",
491 ToChar(resolvedEventMessage
))
493 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onpointerleave
,
494 nsPrintfCString("resolvedEventMessage=%s",
495 ToChar(resolvedEventMessage
))
498 resolvedEventMessage
< eGamepadEventFirst
||
499 resolvedEventMessage
> eGamepadEventLast
,
500 nsPrintfCString("You added new gamepad event, but it's not "
501 "handled above, resolvedEventMessage=%s",
502 ToChar(resolvedEventMessage
))
504 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondeviceorientation
,
505 nsPrintfCString("resolvedEventMessage=%s",
506 ToChar(resolvedEventMessage
))
508 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondeviceorientationabsolute
,
509 nsPrintfCString("resolvedEventMessage=%s",
510 ToChar(resolvedEventMessage
))
512 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onuserproximity
,
513 nsPrintfCString("resolvedEventMessage=%s",
514 ToChar(resolvedEventMessage
))
516 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondevicelight
,
517 nsPrintfCString("resolvedEventMessage=%s",
518 ToChar(resolvedEventMessage
))
520 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondevicemotion
,
521 nsPrintfCString("resolvedEventMessage=%s",
522 ToChar(resolvedEventMessage
))
524 #if defined(MOZ_WIDGET_ANDROID)
525 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onorientationchange
,
526 nsPrintfCString("resolvedEventMessage=%s",
527 ToChar(resolvedEventMessage
))
529 #endif // #if defined(MOZ_WIDGET_ANDROID)
530 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchstart
,
531 nsPrintfCString("resolvedEventMessage=%s",
532 ToChar(resolvedEventMessage
))
534 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchend
,
535 nsPrintfCString("resolvedEventMessage=%s",
536 ToChar(resolvedEventMessage
))
538 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchmove
,
539 nsPrintfCString("resolvedEventMessage=%s",
540 ToChar(resolvedEventMessage
))
542 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchcancel
,
543 nsPrintfCString("resolvedEventMessage=%s",
544 ToChar(resolvedEventMessage
))
546 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onmouseenter
,
547 nsPrintfCString("resolvedEventMessage=%s",
548 ToChar(resolvedEventMessage
))
550 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onmouseleave
,
551 nsPrintfCString("resolvedEventMessage=%s",
552 ToChar(resolvedEventMessage
))
554 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onbeforeinput
,
555 nsPrintfCString("resolvedEventMessage=%s",
556 ToChar(resolvedEventMessage
))
558 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onselectionchange
,
559 nsPrintfCString("resolvedEventMessage=%s",
560 ToChar(resolvedEventMessage
))
562 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onselect
,
563 nsPrintfCString("resolvedEventMessage=%s",
564 ToChar(resolvedEventMessage
))
566 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onstart
,
567 nsPrintfCString("resolvedEventMessage=%s",
568 ToChar(resolvedEventMessage
))
570 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onbounce
,
571 nsPrintfCString("resolvedEventMessage=%s",
572 ToChar(resolvedEventMessage
))
574 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onfinish
,
575 nsPrintfCString("resolvedEventMessage=%s",
576 ToChar(resolvedEventMessage
))
578 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onoverflow
,
579 nsPrintfCString("resolvedEventMessage=%s",
580 ToChar(resolvedEventMessage
))
582 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onunderflow
,
583 nsPrintfCString("resolvedEventMessage=%s",
584 ToChar(resolvedEventMessage
))
586 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onDOMMouseScroll
,
587 nsPrintfCString("resolvedEventMessage=%s",
588 ToChar(resolvedEventMessage
))
590 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onMozMousePixelScroll
,
591 nsPrintfCString("resolvedEventMessage=%s",
592 ToChar(resolvedEventMessage
))
598 if (IsApzAwareListener(listener
)) {
599 ProcessApzAwareEventListenerAdd();
603 mTarget
->EventListenerAdded(aTypeAtom
);
606 if (mIsMainThreadELM
&& mTarget
) {
607 EventListenerService::NotifyAboutMainThreadListenerChange(mTarget
,
612 void EventListenerManager::ProcessApzAwareEventListenerAdd() {
613 Document
* doc
= nullptr;
615 // Mark the node as having apz aware listeners
616 if (nsINode
* node
= nsINode::FromEventTargetOrNull(mTarget
)) {
617 node
->SetMayBeApzAware();
618 doc
= node
->OwnerDoc();
621 // Schedule a paint so event regions on the layer tree gets updated
623 if (nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow()) {
624 doc
= window
->GetExtantDoc();
628 if (nsCOMPtr
<DOMEventTargetHelper
> helper
= do_QueryInterface(mTarget
)) {
629 if (nsPIDOMWindowInner
* window
= helper
->GetOwner()) {
630 doc
= window
->GetExtantDoc();
635 if (doc
&& gfxPlatform::AsyncPanZoomEnabled()) {
636 PresShell
* presShell
= doc
->GetPresShell();
638 nsIFrame
* f
= presShell
->GetRootFrame();
646 bool EventListenerManager::IsDeviceType(EventMessage aEventMessage
) {
647 switch (aEventMessage
) {
648 case eDeviceOrientation
:
649 case eDeviceOrientationAbsolute
:
653 #if defined(MOZ_WIDGET_ANDROID)
654 case eOrientationChange
:
663 void EventListenerManager::EnableDevice(EventMessage aEventMessage
) {
664 nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow();
669 switch (aEventMessage
) {
670 case eDeviceOrientation
:
671 #ifdef MOZ_WIDGET_ANDROID
672 // Falls back to SENSOR_ROTATION_VECTOR and SENSOR_ORIENTATION if
673 // unavailable on device.
674 window
->EnableDeviceSensor(SENSOR_GAME_ROTATION_VECTOR
);
675 window
->EnableDeviceSensor(SENSOR_ROTATION_VECTOR
);
677 window
->EnableDeviceSensor(SENSOR_ORIENTATION
);
680 case eDeviceOrientationAbsolute
:
681 #ifdef MOZ_WIDGET_ANDROID
682 // Falls back to SENSOR_ORIENTATION if unavailable on device.
683 window
->EnableDeviceSensor(SENSOR_ROTATION_VECTOR
);
685 window
->EnableDeviceSensor(SENSOR_ORIENTATION
);
689 window
->EnableDeviceSensor(SENSOR_PROXIMITY
);
692 window
->EnableDeviceSensor(SENSOR_LIGHT
);
695 window
->EnableDeviceSensor(SENSOR_ACCELERATION
);
696 window
->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION
);
697 window
->EnableDeviceSensor(SENSOR_GYROSCOPE
);
699 #if defined(MOZ_WIDGET_ANDROID)
700 case eOrientationChange
:
701 window
->EnableOrientationChangeListener();
705 NS_WARNING("Enabling an unknown device sensor.");
710 void EventListenerManager::DisableDevice(EventMessage aEventMessage
) {
711 nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow();
716 switch (aEventMessage
) {
717 case eDeviceOrientation
:
718 #ifdef MOZ_WIDGET_ANDROID
719 // Disable all potential fallback sensors.
720 window
->DisableDeviceSensor(SENSOR_GAME_ROTATION_VECTOR
);
721 window
->DisableDeviceSensor(SENSOR_ROTATION_VECTOR
);
723 window
->DisableDeviceSensor(SENSOR_ORIENTATION
);
725 case eDeviceOrientationAbsolute
:
726 #ifdef MOZ_WIDGET_ANDROID
727 window
->DisableDeviceSensor(SENSOR_ROTATION_VECTOR
);
729 window
->DisableDeviceSensor(SENSOR_ORIENTATION
);
732 window
->DisableDeviceSensor(SENSOR_ACCELERATION
);
733 window
->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION
);
734 window
->DisableDeviceSensor(SENSOR_GYROSCOPE
);
737 window
->DisableDeviceSensor(SENSOR_PROXIMITY
);
740 window
->DisableDeviceSensor(SENSOR_LIGHT
);
742 #if defined(MOZ_WIDGET_ANDROID)
743 case eOrientationChange
:
744 window
->DisableOrientationChangeListener();
748 NS_WARNING("Disabling an unknown device sensor.");
753 void EventListenerManager::NotifyEventListenerRemoved(nsAtom
* aUserType
) {
754 // If the following code is changed, other callsites of EventListenerRemoved
755 // and NotifyAboutMainThreadListenerChange should be changed too.
756 ClearNoListenersForEvents();
757 mNoListenerForEventAtom
= nullptr;
759 mTarget
->EventListenerRemoved(aUserType
);
761 if (mIsMainThreadELM
&& mTarget
) {
762 EventListenerService::NotifyAboutMainThreadListenerChange(mTarget
,
767 void EventListenerManager::RemoveEventListenerInternal(
768 EventListenerHolder aListenerHolder
, EventMessage aEventMessage
,
769 nsAtom
* aUserType
, const EventListenerFlags
& aFlags
, bool aAllEvents
) {
770 if (!aListenerHolder
|| !aEventMessage
|| mClearingListeners
) {
776 uint32_t count
= mListeners
.Length();
777 bool deviceType
= IsDeviceType(aEventMessage
);
779 RefPtr
<EventListenerManager
> kungFuDeathGrip(this);
781 for (uint32_t i
= 0; i
< count
; ++i
) {
782 listener
= &mListeners
.ElementAt(i
);
783 if (EVENT_TYPE_EQUALS(listener
, aEventMessage
, aUserType
, aAllEvents
)) {
784 if (listener
->mListener
== aListenerHolder
&&
785 listener
->mFlags
.EqualsForRemoval(aFlags
)) {
786 mListeners
.RemoveElementAt(i
);
787 NotifyEventListenerRemoved(aUserType
);
788 if (!aAllEvents
&& deviceType
) {
789 DisableDevice(aEventMessage
);
797 bool EventListenerManager::Listener::MatchesEventMessage(
798 const WidgetEvent
* aEvent
, EventMessage aEventMessage
) const {
799 MOZ_ASSERT(aEventMessage
== aEvent
->mMessage
||
800 aEventMessage
== EventListenerManager::GetLegacyEventMessage(
802 "aEvent and aEventMessage should agree, modulo legacyness");
804 if (MOZ_UNLIKELY(mAllEvents
)) {
808 // This is slightly different from EVENT_TYPE_EQUALS in that it returns
809 // true even when aEvent->mMessage == eUnidentifiedEvent and
810 // mEventMessage != eUnidentifiedEvent as long as the atoms are
812 if (aEvent
->mMessage
== eUnidentifiedEvent
) {
813 return mTypeAtom
== aEvent
->mSpecifiedEventType
;
815 return mEventMessage
== aEventMessage
;
818 static bool IsDefaultPassiveWhenOnRoot(EventMessage aMessage
) {
819 if (aMessage
== eTouchStart
|| aMessage
== eTouchMove
) {
822 if (aMessage
== eWheel
|| aMessage
== eLegacyMouseLineOrPageScroll
||
823 aMessage
== eLegacyMousePixelScroll
) {
824 return StaticPrefs::dom_event_default_to_passive_wheel_listeners();
829 static bool IsRootEventTarget(EventTarget
* aTarget
) {
833 if (aTarget
->IsInnerWindow()) {
836 const nsINode
* node
= nsINode::FromEventTarget(aTarget
);
840 Document
* doc
= node
->OwnerDoc();
841 return node
== doc
|| node
== doc
->GetRootElement() || node
== doc
->GetBody();
844 void EventListenerManager::MaybeMarkPassive(EventMessage aMessage
,
845 EventListenerFlags
& aFlags
) {
846 if (!mIsMainThreadELM
) {
849 if (!IsDefaultPassiveWhenOnRoot(aMessage
)) {
852 if (!IsRootEventTarget(mTarget
)) {
855 aFlags
.mPassive
= true;
858 void EventListenerManager::AddEventListenerByType(
859 EventListenerHolder aListenerHolder
, const nsAString
& aType
,
860 const EventListenerFlags
& aFlags
, const Optional
<bool>& aPassive
,
861 AbortSignal
* aSignal
) {
863 EventMessage message
=
864 GetEventMessageAndAtomForListener(aType
, getter_AddRefs(atom
));
866 EventListenerFlags flags
= aFlags
;
867 if (aPassive
.WasPassed()) {
868 flags
.mPassive
= aPassive
.Value();
870 MaybeMarkPassive(message
, flags
);
873 AddEventListenerInternal(std::move(aListenerHolder
), message
, atom
, flags
,
874 false, false, aSignal
);
877 void EventListenerManager::RemoveEventListenerByType(
878 EventListenerHolder aListenerHolder
, const nsAString
& aType
,
879 const EventListenerFlags
& aFlags
) {
881 EventMessage message
=
882 GetEventMessageAndAtomForListener(aType
, getter_AddRefs(atom
));
883 RemoveEventListenerInternal(std::move(aListenerHolder
), message
, atom
,
887 EventListenerManager::Listener
* EventListenerManager::FindEventHandler(
888 EventMessage aEventMessage
, nsAtom
* aTypeAtom
) {
889 // Run through the listeners for this type and see if a script
890 // listener is registered
892 uint32_t count
= mListeners
.Length();
893 for (uint32_t i
= 0; i
< count
; ++i
) {
894 listener
= &mListeners
.ElementAt(i
);
895 if (listener
->mListenerIsHandler
&&
896 EVENT_TYPE_EQUALS(listener
, aEventMessage
, aTypeAtom
, false)) {
903 EventListenerManager::Listener
* EventListenerManager::SetEventHandlerInternal(
904 nsAtom
* aName
, const TypedEventHandler
& aTypedHandler
,
905 bool aPermitUntrustedEvents
) {
908 EventMessage eventMessage
= GetEventMessage(aName
);
909 Listener
* listener
= FindEventHandler(eventMessage
, aName
);
912 // If we didn't find a script listener or no listeners existed
913 // create and add a new one.
914 EventListenerFlags flags
;
915 flags
.mListenerIsJSListener
= true;
916 MaybeMarkPassive(eventMessage
, flags
);
918 nsCOMPtr
<JSEventHandler
> jsEventHandler
;
919 NS_NewJSEventHandler(mTarget
, aName
, aTypedHandler
,
920 getter_AddRefs(jsEventHandler
));
921 AddEventListenerInternal(EventListenerHolder(jsEventHandler
), eventMessage
,
924 listener
= FindEventHandler(eventMessage
, aName
);
926 JSEventHandler
* jsEventHandler
= listener
->GetJSEventHandler();
927 MOZ_ASSERT(jsEventHandler
,
928 "How can we have an event handler with no JSEventHandler?");
930 bool same
= jsEventHandler
->GetTypedEventHandler() == aTypedHandler
;
931 // Possibly the same listener, but update still the context and scope.
932 jsEventHandler
->SetHandler(aTypedHandler
);
933 if (mTarget
&& !same
) {
934 mTarget
->EventListenerRemoved(aName
);
935 mTarget
->EventListenerAdded(aName
);
937 if (mIsMainThreadELM
&& mTarget
) {
938 EventListenerService::NotifyAboutMainThreadListenerChange(mTarget
, aName
);
942 // Set flag to indicate possible need for compilation later
943 listener
->mHandlerIsString
= !aTypedHandler
.HasEventHandler();
944 if (aPermitUntrustedEvents
) {
945 listener
->mFlags
.mAllowUntrustedEvents
= true;
946 mMayHaveListenersForUntrustedEvents
= true;
952 nsresult
EventListenerManager::SetEventHandler(nsAtom
* aName
,
953 const nsAString
& aBody
,
954 bool aDeferCompilation
,
955 bool aPermitUntrustedEvents
,
957 auto removeEventHandler
= MakeScopeExit([&] { RemoveEventHandler(aName
); });
959 nsCOMPtr
<Document
> doc
;
960 nsCOMPtr
<nsIScriptGlobalObject
> global
=
961 GetScriptGlobalAndDocument(getter_AddRefs(doc
));
964 // This can happen; for example this document might have been
970 // return early preventing the event listener from being added
971 // 'doc' is fetched above
973 // Don't allow adding an event listener if the document is sandboxed
974 // without 'allow-scripts'.
975 if (doc
->HasScriptsBlockedBySandbox()) {
976 return NS_ERROR_DOM_SECURITY_ERR
;
980 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= doc
->GetCsp();
981 unsigned lineNum
= 0;
982 unsigned columnNum
= 0;
984 JSContext
* cx
= nsContentUtils::GetCurrentJSContext();
985 if (cx
&& !JS::DescribeScriptedCaller(cx
, nullptr, &lineNum
, &columnNum
)) {
986 JS_ClearPendingException(cx
);
990 bool allowsInlineScript
= true;
991 rv
= csp
->GetAllowsInline(
992 nsIContentSecurityPolicy::SCRIPT_SRC_ATTR_DIRECTIVE
,
993 true, // aHasUnsafeHash
995 true, // aParserCreated (true because attribute event handler)
997 nullptr, // nsICSPEventListener
998 aBody
, lineNum
, columnNum
, &allowsInlineScript
);
999 NS_ENSURE_SUCCESS(rv
, rv
);
1001 // return early if CSP wants us to block inline scripts
1002 if (!allowsInlineScript
) {
1008 // This might be the first reference to this language in the global
1009 // We must init the language before we attempt to fetch its context.
1010 if (NS_FAILED(global
->EnsureScriptEnvironment())) {
1011 NS_WARNING("Failed to setup script environment for this language");
1012 // but fall through and let the inevitable failure below handle it.
1015 nsIScriptContext
* context
= global
->GetScriptContext();
1016 NS_ENSURE_TRUE(context
, NS_ERROR_FAILURE
);
1017 NS_ENSURE_STATE(global
->HasJSGlobal());
1019 removeEventHandler
.release();
1021 Listener
* listener
= SetEventHandlerInternal(aName
, TypedEventHandler(),
1022 aPermitUntrustedEvents
);
1024 if (!aDeferCompilation
) {
1025 return CompileEventHandlerInternal(listener
, &aBody
, aElement
);
1031 void EventListenerManager::RemoveEventHandler(nsAtom
* aName
) {
1032 if (mClearingListeners
) {
1036 EventMessage eventMessage
= GetEventMessage(aName
);
1037 Listener
* listener
= FindEventHandler(eventMessage
, aName
);
1040 mListeners
.RemoveElementAt(uint32_t(listener
- &mListeners
.ElementAt(0)));
1041 NotifyEventListenerRemoved(aName
);
1042 if (IsDeviceType(eventMessage
)) {
1043 DisableDevice(eventMessage
);
1048 nsresult
EventListenerManager::CompileEventHandlerInternal(
1049 Listener
* aListener
, const nsAString
* aBody
, Element
* aElement
) {
1050 MOZ_ASSERT(aListener
->GetJSEventHandler());
1051 MOZ_ASSERT(aListener
->mHandlerIsString
,
1052 "Why are we compiling a non-string JS listener?");
1053 JSEventHandler
* jsEventHandler
= aListener
->GetJSEventHandler();
1054 MOZ_ASSERT(!jsEventHandler
->GetTypedEventHandler().HasEventHandler(),
1055 "What is there to compile?");
1057 nsresult result
= NS_OK
;
1058 nsCOMPtr
<Document
> doc
;
1059 nsCOMPtr
<nsIScriptGlobalObject
> global
=
1060 GetScriptGlobalAndDocument(getter_AddRefs(doc
));
1061 NS_ENSURE_STATE(global
);
1063 // Activate JSAPI, and make sure that exceptions are reported on the right
1066 if (NS_WARN_IF(!jsapi
.Init(global
))) {
1067 return NS_ERROR_UNEXPECTED
;
1069 JSContext
* cx
= jsapi
.cx();
1071 RefPtr
<nsAtom
> typeAtom
= aListener
->mTypeAtom
;
1072 nsAtom
* attrName
= typeAtom
;
1074 // Flag us as not a string so we don't keep trying to compile strings which
1075 // can't be compiled.
1076 aListener
->mHandlerIsString
= false;
1078 // mTarget may not be an Element if it's a window and we're
1079 // getting an inline event listener forwarded from <html:body> or
1080 // <html:frameset> or <xul:window> or the like.
1081 // XXX I don't like that we have to reference content from
1082 // here. The alternative is to store the event handler string on
1083 // the JSEventHandler itself, and that still doesn't address
1084 // the arg names issue.
1085 RefPtr
<Element
> element
= Element::FromEventTargetOrNull(mTarget
);
1086 MOZ_ASSERT(element
|| aBody
, "Where will we get our body?");
1087 nsAutoString handlerBody
;
1088 const nsAString
* body
= aBody
;
1090 if (aListener
->mTypeAtom
== nsGkAtoms::onSVGLoad
) {
1091 attrName
= nsGkAtoms::onload
;
1092 } else if (aListener
->mTypeAtom
== nsGkAtoms::onSVGScroll
) {
1093 attrName
= nsGkAtoms::onscroll
;
1094 } else if (aListener
->mTypeAtom
== nsGkAtoms::onbeginEvent
) {
1095 attrName
= nsGkAtoms::onbegin
;
1096 } else if (aListener
->mTypeAtom
== nsGkAtoms::onrepeatEvent
) {
1097 attrName
= nsGkAtoms::onrepeat
;
1098 } else if (aListener
->mTypeAtom
== nsGkAtoms::onendEvent
) {
1099 attrName
= nsGkAtoms::onend
;
1100 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitAnimationEnd
) {
1101 attrName
= nsGkAtoms::onwebkitanimationend
;
1102 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitAnimationIteration
) {
1103 attrName
= nsGkAtoms::onwebkitanimationiteration
;
1104 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitAnimationStart
) {
1105 attrName
= nsGkAtoms::onwebkitanimationstart
;
1106 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitTransitionEnd
) {
1107 attrName
= nsGkAtoms::onwebkittransitionend
;
1110 element
->GetAttr(attrName
, handlerBody
);
1111 body
= &handlerBody
;
1114 aListener
= nullptr;
1116 nsAutoCString
url("-moz-evil:lying-event-listener"_ns
);
1118 MOZ_ASSERT(aElement
);
1119 nsIURI
* uri
= aElement
->OwnerDoc()->GetDocumentURI();
1124 nsCOMPtr
<nsPIDOMWindowInner
> win
=
1125 nsPIDOMWindowInner::FromEventTargetOrNull(mTarget
);
1127 const char** argNames
;
1128 nsContentUtils::GetEventArgNames(aElement
->GetNameSpaceID(), typeAtom
, win
,
1129 &argCount
, &argNames
);
1131 // Wrap the event target, so that we can use it as the scope for the event
1132 // handler. Note that mTarget is different from aElement in the <body> case,
1133 // where mTarget is a Window.
1135 // The wrapScope doesn't really matter here, because the target will create
1136 // its reflector in the proper scope, and then we'll enter that realm.
1137 JS::Rooted
<JSObject
*> wrapScope(cx
, global
->GetGlobalJSObject());
1138 JS::Rooted
<JS::Value
> v(cx
);
1140 JSAutoRealm
ar(cx
, wrapScope
);
1141 nsresult rv
= nsContentUtils::WrapNative(cx
, mTarget
, &v
,
1142 /* aAllowWrapping = */ false);
1143 if (NS_WARN_IF(NS_FAILED(rv
))) {
1148 JS::Rooted
<JSObject
*> target(cx
, &v
.toObject());
1149 JSAutoRealm
ar(cx
, target
);
1151 // Now that we've entered the realm we actually care about, create our
1152 // scope chain. Note that we start with |element|, not aElement, because
1153 // mTarget is different from aElement in the <body> case, where mTarget is a
1154 // Window, and in that case we do not want the scope chain to include the body
1156 JS::RootedVector
<JSObject
*> scopeChain(cx
);
1157 if (!nsJSUtils::GetScopeChainForElement(cx
, element
, &scopeChain
)) {
1158 return NS_ERROR_OUT_OF_MEMORY
;
1161 nsDependentAtomString
str(attrName
);
1162 // Most of our names are short enough that we don't even have to malloc
1163 // the JS string stuff, so don't worry about playing games with
1164 // refcounting XPCOM stringbuffers.
1165 JS::Rooted
<JSString
*> jsStr(
1166 cx
, JS_NewUCStringCopyN(cx
, str
.BeginReading(), str
.Length()));
1167 NS_ENSURE_TRUE(jsStr
, NS_ERROR_OUT_OF_MEMORY
);
1169 // Get the reflector for |aElement|, so that we can pass to setElement.
1170 if (NS_WARN_IF(!GetOrCreateDOMReflector(cx
, aElement
, &v
))) {
1171 return NS_ERROR_FAILURE
;
1174 RefPtr
<JS::loader::ScriptFetchOptions
> fetchOptions
=
1175 new JS::loader::ScriptFetchOptions(
1176 CORS_NONE
, aElement
->OwnerDoc()->GetReferrerPolicy(),
1177 aElement
->OwnerDoc()->NodePrincipal());
1179 RefPtr
<JS::loader::EventScript
> eventScript
=
1180 new JS::loader::EventScript(fetchOptions
, uri
);
1182 JS::CompileOptions
options(cx
);
1183 // Use line 0 to make the function body starts from line 1.
1184 options
.setIntroductionType("eventHandler")
1185 .setFileAndLine(url
.get(), 0)
1186 .setDeferDebugMetadata(true);
1188 JS::Rooted
<JSObject
*> handler(cx
);
1189 result
= nsJSUtils::CompileFunction(jsapi
, scopeChain
, options
,
1190 nsAtomCString(typeAtom
), argCount
,
1191 argNames
, *body
, handler
.address());
1192 NS_ENSURE_SUCCESS(result
, result
);
1193 NS_ENSURE_TRUE(handler
, NS_ERROR_FAILURE
);
1195 JS::Rooted
<JS::Value
> privateValue(cx
, JS::PrivateValue(eventScript
));
1196 result
= nsJSUtils::UpdateFunctionDebugMetadata(jsapi
, handler
, options
,
1197 jsStr
, privateValue
);
1198 NS_ENSURE_SUCCESS(result
, result
);
1200 MOZ_ASSERT(js::IsObjectInContextCompartment(handler
, cx
));
1201 JS::Rooted
<JSObject
*> handlerGlobal(cx
, JS::CurrentGlobalOrNull(cx
));
1203 if (jsEventHandler
->EventName() == nsGkAtoms::onerror
&& win
) {
1204 RefPtr
<OnErrorEventHandlerNonNull
> handlerCallback
=
1205 new OnErrorEventHandlerNonNull(static_cast<JSContext
*>(nullptr),
1206 handler
, handlerGlobal
,
1207 /* aIncumbentGlobal = */ nullptr);
1208 jsEventHandler
->SetHandler(handlerCallback
);
1209 } else if (jsEventHandler
->EventName() == nsGkAtoms::onbeforeunload
&& win
) {
1210 RefPtr
<OnBeforeUnloadEventHandlerNonNull
> handlerCallback
=
1211 new OnBeforeUnloadEventHandlerNonNull(static_cast<JSContext
*>(nullptr),
1212 handler
, handlerGlobal
,
1213 /* aIncumbentGlobal = */ nullptr);
1214 jsEventHandler
->SetHandler(handlerCallback
);
1216 RefPtr
<EventHandlerNonNull
> handlerCallback
= new EventHandlerNonNull(
1217 static_cast<JSContext
*>(nullptr), handler
, handlerGlobal
,
1218 /* aIncumbentGlobal = */ nullptr);
1219 jsEventHandler
->SetHandler(handlerCallback
);
1225 nsresult
EventListenerManager::HandleEventSubType(Listener
* aListener
,
1227 EventTarget
* aCurrentTarget
) {
1228 nsresult result
= NS_OK
;
1230 EventListenerHolder
listenerHolder(aListener
->mListener
.Clone());
1232 // If this is a script handler and we haven't yet
1233 // compiled the event handler itself
1234 if ((aListener
->mListenerType
== Listener::eJSEventListener
) &&
1235 aListener
->mHandlerIsString
) {
1236 result
= CompileEventHandlerInternal(aListener
, nullptr, nullptr);
1237 aListener
= nullptr;
1240 if (NS_SUCCEEDED(result
)) {
1241 Maybe
<EventCallbackDebuggerNotificationGuard
> dbgGuard
;
1242 if (dom::ChromeUtils::IsDevToolsOpened()) {
1243 dbgGuard
.emplace(aCurrentTarget
, aDOMEvent
);
1247 // Event::currentTarget is set in EventDispatcher.
1248 if (listenerHolder
.HasWebIDLCallback()) {
1250 listenerHolder
.GetWebIDLCallback()->HandleEvent(aCurrentTarget
,
1252 result
= rv
.StealNSResult();
1254 // listenerHolder is holding a stack ref here.
1255 result
= MOZ_KnownLive(listenerHolder
.GetXPCOMCallback())
1256 ->HandleEvent(aDOMEvent
);
1263 /* static */ EventMessage
EventListenerManager::GetLegacyEventMessage(
1264 EventMessage aEventMessage
) {
1265 // webkit-prefixed legacy events:
1266 if (aEventMessage
== eTransitionEnd
) {
1267 return eWebkitTransitionEnd
;
1269 if (aEventMessage
== eAnimationStart
) {
1270 return eWebkitAnimationStart
;
1272 if (aEventMessage
== eAnimationEnd
) {
1273 return eWebkitAnimationEnd
;
1275 if (aEventMessage
== eAnimationIteration
) {
1276 return eWebkitAnimationIteration
;
1279 switch (aEventMessage
) {
1280 case eFullscreenChange
:
1281 return eMozFullscreenChange
;
1282 case eFullscreenError
:
1283 return eMozFullscreenError
;
1285 return aEventMessage
;
1289 EventMessage
EventListenerManager::GetEventMessage(nsAtom
* aEventName
) const {
1290 if (mIsMainThreadELM
) {
1291 return nsContentUtils::GetEventMessage(aEventName
);
1294 // The nsContentUtils event message hashtables aren't threadsafe, so just fall
1295 // back to eUnidentifiedEvent.
1296 return eUnidentifiedEvent
;
1299 EventMessage
EventListenerManager::GetEventMessageAndAtomForListener(
1300 const nsAString
& aType
, nsAtom
** aAtom
) {
1301 if (mIsMainThreadELM
) {
1302 return nsContentUtils::GetEventMessageAndAtomForListener(aType
, aAtom
);
1305 *aAtom
= NS_Atomize(u
"on"_ns
+ aType
).take();
1306 return eUnidentifiedEvent
;
1309 already_AddRefed
<nsPIDOMWindowInner
> EventListenerManager::WindowFromListener(
1310 Listener
* aListener
, bool aItemInShadowTree
) {
1311 nsCOMPtr
<nsPIDOMWindowInner
> innerWindow
;
1312 if (!aItemInShadowTree
) {
1313 if (aListener
->mListener
.HasWebIDLCallback()) {
1314 CallbackObject
* callback
= aListener
->mListener
.GetWebIDLCallback();
1315 nsIGlobalObject
* global
= nullptr;
1317 global
= callback
->IncumbentGlobalOrNull();
1320 innerWindow
= global
->AsInnerWindow(); // Can be nullptr
1323 // This ensures `window.event` can be set properly for
1324 // nsWindowRoot to handle KeyPress event.
1325 if (aListener
&& aListener
->mEventMessage
== eKeyPress
&& mTarget
&&
1326 mTarget
->IsRootWindow()) {
1327 nsPIWindowRoot
* root
= mTarget
->AsWindowRoot();
1328 if (nsPIDOMWindowOuter
* outerWindow
= root
->GetWindow()) {
1329 innerWindow
= outerWindow
->GetCurrentInnerWindow();
1332 // Can't get the global from
1333 // listener->mListener.GetXPCOMCallback().
1334 // In most cases, it would be the same as for
1335 // the target, so let's do that.
1336 innerWindow
= GetInnerWindowForTarget(); // Can be nullptr
1340 return innerWindow
.forget();
1344 * Causes a check for event listeners and processing by them if they exist.
1345 * @param an event listener
1348 void EventListenerManager::HandleEventInternal(nsPresContext
* aPresContext
,
1349 WidgetEvent
* aEvent
,
1351 EventTarget
* aCurrentTarget
,
1352 nsEventStatus
* aEventStatus
,
1353 bool aItemInShadowTree
) {
1354 MOZ_ASSERT_IF(aEvent
->mMessage
!= eUnidentifiedEvent
, mIsMainThreadELM
);
1356 // Set the value of the internal PreventDefault flag properly based on
1358 if (!aEvent
->DefaultPrevented() &&
1359 *aEventStatus
== nsEventStatus_eConsumeNoDefault
) {
1360 // Assume that if only aEventStatus claims that the event has already been
1361 // consumed, the consumer is default event handler.
1362 aEvent
->PreventDefault();
1365 Maybe
<AutoHandlingUserInputStatePusher
> userInputStatePusher
;
1366 Maybe
<AutoPopupStatePusher
> popupStatePusher
;
1367 if (mIsMainThreadELM
) {
1368 userInputStatePusher
.emplace(UserActivation::IsUserInteractionEvent(aEvent
),
1370 popupStatePusher
.emplace(
1371 PopupBlocker::GetEventPopupControlState(aEvent
, *aDOMEvent
));
1374 bool hasListener
= false;
1375 bool hasListenerForCurrentGroup
= false;
1376 bool usingLegacyMessage
= false;
1377 bool hasRemovedListener
= false;
1378 EventMessage eventMessage
= aEvent
->mMessage
;
1381 Maybe
<EventMessageAutoOverride
> legacyAutoOverride
;
1382 for (Listener
& listenerRef
: mListeners
.EndLimitedRange()) {
1383 if (aEvent
->mFlags
.mImmediatePropagationStopped
) {
1386 Listener
* listener
= &listenerRef
;
1387 if (!listener
->MatchesEventMessage(aEvent
, eventMessage
)) {
1390 if (listener
->mListenerType
== Listener::eNoListener
) {
1391 // The listener has been removed, it cannot handle anything.
1394 if (!listener
->mEnabled
) {
1395 // The listener has been disabled, for example by devtools.
1399 if (!listener
->MatchesEventGroup(aEvent
)) {
1402 hasListenerForCurrentGroup
= true;
1404 // Check that the phase is same in event and event listener. Also check
1405 // that the event is trusted or that the listener allows untrusted events.
1406 if (!listener
->MatchesEventPhase(aEvent
) ||
1407 !listener
->AllowsEventTrustedness(aEvent
)) {
1411 // Lazily create the DOM event.
1412 // This is tiny bit slow, but happens only once per event.
1413 // Similar code also in EventDispatcher.
1414 nsCOMPtr
<EventTarget
> et
= aEvent
->mOriginalTarget
;
1415 RefPtr
<Event
> event
=
1416 EventDispatcher::CreateEvent(et
, aPresContext
, aEvent
, u
""_ns
);
1417 event
.forget(aDOMEvent
);
1422 if (!aEvent
->mCurrentTarget
) {
1423 aEvent
->mCurrentTarget
= aCurrentTarget
->GetTargetForDOMEvent();
1424 if (!aEvent
->mCurrentTarget
) {
1428 if (usingLegacyMessage
&& !legacyAutoOverride
) {
1429 // Override the aDOMEvent's event-message (its .type) until we
1430 // finish traversing listeners (when legacyAutoOverride destructs)
1431 legacyAutoOverride
.emplace(*aDOMEvent
, eventMessage
);
1434 aEvent
->mFlags
.mInPassiveListener
= listener
->mFlags
.mPassive
;
1435 Maybe
<Listener
> listenerHolder
;
1436 if (listener
->mFlags
.mOnce
) {
1437 // Move the listener to the stack before handling the event.
1438 // The order is important, otherwise the listener could be
1439 // called again inside the listener.
1440 listenerHolder
.emplace(std::move(*listener
));
1441 listener
= listenerHolder
.ptr();
1442 hasRemovedListener
= true;
1445 nsCOMPtr
<nsPIDOMWindowInner
> innerWindow
=
1446 WindowFromListener(listener
, aItemInShadowTree
);
1447 mozilla::dom::Event
* oldWindowEvent
= nullptr;
1449 oldWindowEvent
= innerWindow
->SetEvent(*aDOMEvent
);
1452 nsresult rv
= HandleEventSubType(listener
, *aDOMEvent
, aCurrentTarget
);
1455 Unused
<< innerWindow
->SetEvent(oldWindowEvent
);
1458 if (NS_FAILED(rv
)) {
1459 aEvent
->mFlags
.mExceptionWasRaised
= true;
1461 aEvent
->mFlags
.mInPassiveListener
= false;
1464 // If we didn't find any matching listeners, and our event has a legacy
1465 // version, we'll now switch to looking for that legacy version and we'll
1466 // recheck our listeners.
1467 if (hasListenerForCurrentGroup
|| usingLegacyMessage
||
1468 !aEvent
->IsTrusted()) {
1469 // No need to recheck listeners, because we already found a match, we
1470 // already rechecked them, or it is not a trusted event.
1473 EventMessage legacyEventMessage
= GetLegacyEventMessage(eventMessage
);
1474 if (legacyEventMessage
== eventMessage
) {
1475 break; // There's no legacy version of our event; no need to recheck.
1478 GetLegacyEventMessage(legacyEventMessage
) == legacyEventMessage
,
1479 "Legacy event messages should not themselves have legacy versions");
1481 // Recheck our listeners, using the legacy event message we just looked up:
1482 eventMessage
= legacyEventMessage
;
1483 usingLegacyMessage
= true;
1486 aEvent
->mCurrentTarget
= nullptr;
1488 if (hasRemovedListener
) {
1489 // If there are any once listeners replaced with a placeholder in
1490 // the loop above, we need to clean up them here. Note that, this
1491 // could clear once listeners handled in some outer level as well,
1492 // but that should not affect the result.
1493 mListeners
.NonObservingRemoveElementsBy([](const Listener
& aListener
) {
1494 return aListener
.mListenerType
== Listener::eNoListener
;
1496 NotifyEventListenerRemoved(aEvent
->mSpecifiedEventType
);
1497 if (IsDeviceType(aEvent
->mMessage
)) {
1498 // This is a device-type event, we need to check whether we can
1499 // disable device after removing the once listeners.
1500 const auto [begin
, end
] = mListeners
.NonObservingRange();
1501 const bool hasAnyListener
=
1502 std::any_of(begin
, end
, [aEvent
](const Listener
& listenerRef
) {
1503 const Listener
* listener
= &listenerRef
;
1504 return EVENT_TYPE_EQUALS(listener
, aEvent
->mMessage
,
1505 aEvent
->mSpecifiedEventType
,
1506 /* all events */ false);
1509 if (!hasAnyListener
) {
1510 DisableDevice(aEvent
->mMessage
);
1515 if (mIsMainThreadELM
&& !hasListener
) {
1516 if (aEvent
->mMessage
!= eUnidentifiedEvent
) {
1517 mNoListenerForEvents
[2] = mNoListenerForEvents
[1];
1518 mNoListenerForEvents
[1] = mNoListenerForEvents
[0];
1519 mNoListenerForEvents
[0] = aEvent
->mMessage
;
1521 mNoListenerForEventAtom
= aEvent
->mSpecifiedEventType
;
1525 if (aEvent
->DefaultPrevented()) {
1526 *aEventStatus
= nsEventStatus_eConsumeNoDefault
;
1530 void EventListenerManager::Disconnect() {
1532 RemoveAllListenersSilently();
1535 void EventListenerManager::AddEventListener(const nsAString
& aType
,
1536 EventListenerHolder aListenerHolder
,
1538 bool aWantsUntrusted
) {
1539 EventListenerFlags flags
;
1540 flags
.mCapture
= aUseCapture
;
1541 flags
.mAllowUntrustedEvents
= aWantsUntrusted
;
1542 return AddEventListenerByType(std::move(aListenerHolder
), aType
, flags
);
1545 void EventListenerManager::AddEventListener(
1546 const nsAString
& aType
, EventListenerHolder aListenerHolder
,
1547 const dom::AddEventListenerOptionsOrBoolean
& aOptions
,
1548 bool aWantsUntrusted
) {
1549 EventListenerFlags flags
;
1550 Optional
<bool> passive
;
1551 AbortSignal
* signal
= nullptr;
1552 if (aOptions
.IsBoolean()) {
1553 flags
.mCapture
= aOptions
.GetAsBoolean();
1555 const auto& options
= aOptions
.GetAsAddEventListenerOptions();
1556 flags
.mCapture
= options
.mCapture
;
1557 flags
.mInSystemGroup
= options
.mMozSystemGroup
;
1558 flags
.mOnce
= options
.mOnce
;
1559 if (options
.mPassive
.WasPassed()) {
1560 passive
.Construct(options
.mPassive
.Value());
1563 if (options
.mSignal
.WasPassed()) {
1564 signal
= &options
.mSignal
.Value();
1568 flags
.mAllowUntrustedEvents
= aWantsUntrusted
;
1569 return AddEventListenerByType(std::move(aListenerHolder
), aType
, flags
,
1573 void EventListenerManager::RemoveEventListener(
1574 const nsAString
& aType
, EventListenerHolder aListenerHolder
,
1576 EventListenerFlags flags
;
1577 flags
.mCapture
= aUseCapture
;
1578 RemoveEventListenerByType(std::move(aListenerHolder
), aType
, flags
);
1581 void EventListenerManager::RemoveEventListener(
1582 const nsAString
& aType
, EventListenerHolder aListenerHolder
,
1583 const dom::EventListenerOptionsOrBoolean
& aOptions
) {
1584 EventListenerFlags flags
;
1585 if (aOptions
.IsBoolean()) {
1586 flags
.mCapture
= aOptions
.GetAsBoolean();
1588 const auto& options
= aOptions
.GetAsEventListenerOptions();
1589 flags
.mCapture
= options
.mCapture
;
1590 flags
.mInSystemGroup
= options
.mMozSystemGroup
;
1592 RemoveEventListenerByType(std::move(aListenerHolder
), aType
, flags
);
1595 void EventListenerManager::AddListenerForAllEvents(EventListener
* aDOMListener
,
1597 bool aWantsUntrusted
,
1598 bool aSystemEventGroup
) {
1599 EventListenerFlags flags
;
1600 flags
.mCapture
= aUseCapture
;
1601 flags
.mAllowUntrustedEvents
= aWantsUntrusted
;
1602 flags
.mInSystemGroup
= aSystemEventGroup
;
1603 AddEventListenerInternal(EventListenerHolder(aDOMListener
), eAllEvents
,
1604 nullptr, flags
, false, true);
1607 void EventListenerManager::RemoveListenerForAllEvents(
1608 EventListener
* aDOMListener
, bool aUseCapture
, bool aSystemEventGroup
) {
1609 EventListenerFlags flags
;
1610 flags
.mCapture
= aUseCapture
;
1611 flags
.mInSystemGroup
= aSystemEventGroup
;
1612 RemoveEventListenerInternal(EventListenerHolder(aDOMListener
), eAllEvents
,
1613 nullptr, flags
, true);
1616 bool EventListenerManager::HasMutationListeners() {
1617 if (mMayHaveMutationListeners
) {
1618 uint32_t count
= mListeners
.Length();
1619 for (uint32_t i
= 0; i
< count
; ++i
) {
1620 Listener
* listener
= &mListeners
.ElementAt(i
);
1621 if (listener
->mEventMessage
>= eLegacyMutationEventFirst
&&
1622 listener
->mEventMessage
<= eLegacyMutationEventLast
) {
1631 uint32_t EventListenerManager::MutationListenerBits() {
1633 if (mMayHaveMutationListeners
) {
1634 uint32_t count
= mListeners
.Length();
1635 for (uint32_t i
= 0; i
< count
; ++i
) {
1636 Listener
* listener
= &mListeners
.ElementAt(i
);
1637 if (listener
->mEventMessage
>= eLegacyMutationEventFirst
&&
1638 listener
->mEventMessage
<= eLegacyMutationEventLast
) {
1639 if (listener
->mEventMessage
== eLegacySubtreeModified
) {
1640 return kAllMutationBits
;
1642 bits
|= MutationBitForEventType(listener
->mEventMessage
);
1649 bool EventListenerManager::HasListenersFor(const nsAString
& aEventName
) const {
1650 RefPtr
<nsAtom
> atom
= NS_Atomize(u
"on"_ns
+ aEventName
);
1651 return HasListenersFor(atom
);
1654 bool EventListenerManager::HasListenersFor(nsAtom
* aEventNameWithOn
) const {
1655 return HasListenersForInternal(aEventNameWithOn
, false);
1658 bool EventListenerManager::HasNonSystemGroupListenersFor(
1659 nsAtom
* aEventNameWithOn
) const {
1660 return HasListenersForInternal(aEventNameWithOn
, true);
1663 bool EventListenerManager::HasListenersForInternal(
1664 nsAtom
* aEventNameWithOn
, bool aIgnoreSystemGroup
) const {
1667 aEventNameWithOn
->ToString(name
);
1669 NS_ASSERTION(StringBeginsWith(name
, u
"on"_ns
),
1670 "Event name does not start with 'on'");
1671 uint32_t count
= mListeners
.Length();
1672 for (uint32_t i
= 0; i
< count
; ++i
) {
1673 const Listener
* listener
= &mListeners
.ElementAt(i
);
1674 if (listener
->mTypeAtom
== aEventNameWithOn
) {
1675 if (aIgnoreSystemGroup
&& listener
->mFlags
.mInSystemGroup
) {
1684 bool EventListenerManager::HasListeners() const {
1685 return !mListeners
.IsEmpty();
1688 nsresult
EventListenerManager::GetListenerInfo(
1689 nsTArray
<RefPtr
<nsIEventListenerInfo
>>& aList
) {
1690 nsCOMPtr
<EventTarget
> target
= mTarget
;
1691 NS_ENSURE_STATE(target
);
1693 for (const Listener
& listener
: mListeners
.ForwardRange()) {
1694 // If this is a script handler and we haven't yet
1695 // compiled the event handler itself go ahead and compile it
1696 if (listener
.mListenerType
== Listener::eJSEventListener
&&
1697 listener
.mHandlerIsString
) {
1698 CompileEventHandlerInternal(const_cast<Listener
*>(&listener
), nullptr,
1701 nsAutoString eventType
;
1702 if (listener
.mAllEvents
) {
1703 eventType
.SetIsVoid(true);
1704 } else if (listener
.mListenerType
== Listener::eNoListener
) {
1707 eventType
.Assign(Substring(nsDependentAtomString(listener
.mTypeAtom
), 2));
1710 JS::Rooted
<JSObject
*> callback(RootingCx());
1711 JS::Rooted
<JSObject
*> callbackGlobal(RootingCx());
1712 if (JSEventHandler
* handler
= listener
.GetJSEventHandler()) {
1713 if (handler
->GetTypedEventHandler().HasEventHandler()) {
1714 CallbackFunction
* callbackFun
= handler
->GetTypedEventHandler().Ptr();
1715 callback
= callbackFun
->CallableOrNull();
1716 callbackGlobal
= callbackFun
->CallbackGlobalOrNull();
1718 // This will be null for cross-compartment event listeners
1719 // which have been destroyed.
1723 } else if (listener
.mListenerType
== Listener::eWebIDLListener
) {
1724 EventListener
* listenerCallback
= listener
.mListener
.GetWebIDLCallback();
1725 callback
= listenerCallback
->CallbackOrNull();
1726 callbackGlobal
= listenerCallback
->CallbackGlobalOrNull();
1728 // This will be null for cross-compartment event listeners
1729 // which have been destroyed.
1734 RefPtr
<EventListenerInfo
> info
= new EventListenerInfo(
1735 this, eventType
, callback
, callbackGlobal
, listener
.mFlags
.mCapture
,
1736 listener
.mFlags
.mAllowUntrustedEvents
, listener
.mFlags
.mInSystemGroup
,
1737 listener
.mListenerIsHandler
);
1738 aList
.AppendElement(info
.forget());
1743 EventListenerManager::Listener
* EventListenerManager::GetListenerFor(
1744 nsAString
& aType
, JSObject
* aListener
, bool aCapturing
,
1745 bool aAllowsUntrusted
, bool aInSystemEventGroup
, bool aIsHandler
) {
1746 NS_ENSURE_TRUE(aListener
, nullptr);
1748 for (Listener
& listener
: mListeners
.ForwardRange()) {
1749 if ((aType
.IsVoid() && !listener
.mAllEvents
) ||
1750 !Substring(nsDependentAtomString(listener
.mTypeAtom
), 2)
1752 listener
.mListenerType
== Listener::eNoListener
) {
1756 if (listener
.mFlags
.mCapture
!= aCapturing
||
1757 listener
.mFlags
.mAllowUntrustedEvents
!= aAllowsUntrusted
||
1758 listener
.mFlags
.mInSystemGroup
!= aInSystemEventGroup
) {
1763 if (JSEventHandler
* handler
= listener
.GetJSEventHandler()) {
1764 if (handler
->GetTypedEventHandler().HasEventHandler()) {
1765 if (handler
->GetTypedEventHandler().Ptr()->CallableOrNull() ==
1771 } else if (listener
.mListenerType
== Listener::eWebIDLListener
&&
1772 listener
.mListener
.GetWebIDLCallback()->CallbackOrNull() ==
1780 nsresult
EventListenerManager::IsListenerEnabled(
1781 nsAString
& aType
, JSObject
* aListener
, bool aCapturing
,
1782 bool aAllowsUntrusted
, bool aInSystemEventGroup
, bool aIsHandler
,
1784 Listener
* listener
=
1785 GetListenerFor(aType
, aListener
, aCapturing
, aAllowsUntrusted
,
1786 aInSystemEventGroup
, aIsHandler
);
1787 NS_ENSURE_TRUE(listener
, NS_ERROR_NOT_AVAILABLE
);
1788 *aEnabled
= listener
->mEnabled
;
1792 nsresult
EventListenerManager::SetListenerEnabled(
1793 nsAString
& aType
, JSObject
* aListener
, bool aCapturing
,
1794 bool aAllowsUntrusted
, bool aInSystemEventGroup
, bool aIsHandler
,
1796 Listener
* listener
=
1797 GetListenerFor(aType
, aListener
, aCapturing
, aAllowsUntrusted
,
1798 aInSystemEventGroup
, aIsHandler
);
1799 NS_ENSURE_TRUE(listener
, NS_ERROR_NOT_AVAILABLE
);
1800 listener
->mEnabled
= aEnabled
;
1802 // We may have enabled some listener, clear the cache for which events
1803 // we don't have listeners.
1804 ClearNoListenersForEvents();
1805 mNoListenerForEventAtom
= nullptr;
1810 bool EventListenerManager::HasUnloadListeners() {
1811 uint32_t count
= mListeners
.Length();
1812 for (uint32_t i
= 0; i
< count
; ++i
) {
1813 Listener
* listener
= &mListeners
.ElementAt(i
);
1814 if (listener
->mEventMessage
== eUnload
) {
1821 bool EventListenerManager::HasBeforeUnloadListeners() {
1822 uint32_t count
= mListeners
.Length();
1823 for (uint32_t i
= 0; i
< count
; ++i
) {
1824 Listener
* listener
= &mListeners
.ElementAt(i
);
1825 if (listener
->mEventMessage
== eBeforeUnload
) {
1832 void EventListenerManager::SetEventHandler(nsAtom
* aEventName
,
1833 EventHandlerNonNull
* aHandler
) {
1835 RemoveEventHandler(aEventName
);
1839 // Untrusted events are always permitted for non-chrome script
1841 SetEventHandlerInternal(
1842 aEventName
, TypedEventHandler(aHandler
),
1843 !mIsMainThreadELM
|| !nsContentUtils::IsCallerChrome());
1846 void EventListenerManager::SetEventHandler(
1847 OnErrorEventHandlerNonNull
* aHandler
) {
1849 RemoveEventHandler(nsGkAtoms::onerror
);
1853 // Untrusted events are always permitted on workers and for non-chrome script
1854 // on the main thread.
1855 bool allowUntrusted
= !mIsMainThreadELM
|| !nsContentUtils::IsCallerChrome();
1857 SetEventHandlerInternal(nsGkAtoms::onerror
, TypedEventHandler(aHandler
),
1861 void EventListenerManager::SetEventHandler(
1862 OnBeforeUnloadEventHandlerNonNull
* aHandler
) {
1864 RemoveEventHandler(nsGkAtoms::onbeforeunload
);
1868 // Untrusted events are always permitted for non-chrome script
1870 SetEventHandlerInternal(
1871 nsGkAtoms::onbeforeunload
, TypedEventHandler(aHandler
),
1872 !mIsMainThreadELM
|| !nsContentUtils::IsCallerChrome());
1875 const TypedEventHandler
* EventListenerManager::GetTypedEventHandler(
1876 nsAtom
* aEventName
) {
1877 EventMessage eventMessage
= GetEventMessage(aEventName
);
1878 Listener
* listener
= FindEventHandler(eventMessage
, aEventName
);
1884 JSEventHandler
* jsEventHandler
= listener
->GetJSEventHandler();
1886 if (listener
->mHandlerIsString
) {
1887 CompileEventHandlerInternal(listener
, nullptr, nullptr);
1890 const TypedEventHandler
& typedHandler
=
1891 jsEventHandler
->GetTypedEventHandler();
1892 return typedHandler
.HasEventHandler() ? &typedHandler
: nullptr;
1895 size_t EventListenerManager::SizeOfIncludingThis(
1896 MallocSizeOf aMallocSizeOf
) const {
1897 size_t n
= aMallocSizeOf(this);
1898 n
+= mListeners
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1899 uint32_t count
= mListeners
.Length();
1900 for (uint32_t i
= 0; i
< count
; ++i
) {
1901 JSEventHandler
* jsEventHandler
=
1902 mListeners
.ElementAt(i
).GetJSEventHandler();
1903 if (jsEventHandler
) {
1904 n
+= jsEventHandler
->SizeOfIncludingThis(aMallocSizeOf
);
1910 void EventListenerManager::MarkForCC() {
1911 uint32_t count
= mListeners
.Length();
1912 for (uint32_t i
= 0; i
< count
; ++i
) {
1913 const Listener
& listener
= mListeners
.ElementAt(i
);
1914 JSEventHandler
* jsEventHandler
= listener
.GetJSEventHandler();
1915 if (jsEventHandler
) {
1916 const TypedEventHandler
& typedHandler
=
1917 jsEventHandler
->GetTypedEventHandler();
1918 if (typedHandler
.HasEventHandler()) {
1919 typedHandler
.Ptr()->MarkForCC();
1921 } else if (listener
.mListenerType
== Listener::eWebIDLListener
) {
1922 listener
.mListener
.GetWebIDLCallback()->MarkForCC();
1925 if (mRefCnt
.IsPurple()) {
1926 mRefCnt
.RemovePurple();
1930 void EventListenerManager::TraceListeners(JSTracer
* aTrc
) {
1931 uint32_t count
= mListeners
.Length();
1932 for (uint32_t i
= 0; i
< count
; ++i
) {
1933 const Listener
& listener
= mListeners
.ElementAt(i
);
1934 JSEventHandler
* jsEventHandler
= listener
.GetJSEventHandler();
1935 if (jsEventHandler
) {
1936 const TypedEventHandler
& typedHandler
=
1937 jsEventHandler
->GetTypedEventHandler();
1938 if (typedHandler
.HasEventHandler()) {
1939 mozilla::TraceScriptHolder(typedHandler
.Ptr(), aTrc
);
1941 } else if (listener
.mListenerType
== Listener::eWebIDLListener
) {
1942 mozilla::TraceScriptHolder(listener
.mListener
.GetWebIDLCallback(), aTrc
);
1944 // We might have eWrappedJSListener, but that is the legacy type for
1945 // JS implemented event listeners, and trickier to handle here.
1949 bool EventListenerManager::HasNonSystemGroupListenersForUntrustedKeyEvents() {
1950 uint32_t count
= mListeners
.Length();
1951 for (uint32_t i
= 0; i
< count
; ++i
) {
1952 Listener
* listener
= &mListeners
.ElementAt(i
);
1953 if (!listener
->mFlags
.mInSystemGroup
&&
1954 listener
->mFlags
.mAllowUntrustedEvents
&&
1955 (listener
->mTypeAtom
== nsGkAtoms::onkeydown
||
1956 listener
->mTypeAtom
== nsGkAtoms::onkeypress
||
1957 listener
->mTypeAtom
== nsGkAtoms::onkeyup
)) {
1964 bool EventListenerManager::
1965 HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents() {
1966 uint32_t count
= mListeners
.Length();
1967 for (uint32_t i
= 0; i
< count
; ++i
) {
1968 Listener
* listener
= &mListeners
.ElementAt(i
);
1969 if (!listener
->mFlags
.mPassive
&& !listener
->mFlags
.mInSystemGroup
&&
1970 listener
->mFlags
.mAllowUntrustedEvents
&&
1971 (listener
->mTypeAtom
== nsGkAtoms::onkeydown
||
1972 listener
->mTypeAtom
== nsGkAtoms::onkeypress
||
1973 listener
->mTypeAtom
== nsGkAtoms::onkeyup
)) {
1980 bool EventListenerManager::HasApzAwareListeners() {
1981 uint32_t count
= mListeners
.Length();
1982 for (uint32_t i
= 0; i
< count
; ++i
) {
1983 Listener
* listener
= &mListeners
.ElementAt(i
);
1984 if (IsApzAwareListener(listener
)) {
1991 bool EventListenerManager::IsApzAwareListener(Listener
* aListener
) {
1992 return !aListener
->mFlags
.mPassive
&& mIsMainThreadELM
&&
1993 IsApzAwareEvent(aListener
->mTypeAtom
);
1996 static bool IsWheelEventType(nsAtom
* aEvent
) {
1997 if (aEvent
== nsGkAtoms::onwheel
|| aEvent
== nsGkAtoms::onDOMMouseScroll
||
1998 aEvent
== nsGkAtoms::onmousewheel
||
1999 aEvent
== nsGkAtoms::onMozMousePixelScroll
) {
2005 bool EventListenerManager::IsApzAwareEvent(nsAtom
* aEvent
) {
2006 if (IsWheelEventType(aEvent
)) {
2009 // In theory we should schedule a repaint if the touch event pref changes,
2010 // because the event regions might be out of date. In practice that seems like
2011 // overkill because users generally shouldn't be flipping this pref, much
2012 // less expecting touch listeners on the page to immediately start preventing
2013 // scrolling without so much as a repaint. Tests that we write can work
2014 // around this constraint easily enough.
2015 if (aEvent
== nsGkAtoms::ontouchstart
|| aEvent
== nsGkAtoms::ontouchmove
) {
2016 return TouchEvent::PrefEnabled(
2017 nsContentUtils::GetDocShellForEventTarget(mTarget
));
2022 bool EventListenerManager::HasNonPassiveWheelListener() {
2023 MOZ_ASSERT(NS_IsMainThread());
2024 uint32_t count
= mListeners
.Length();
2025 for (uint32_t i
= 0; i
< count
; ++i
) {
2026 Listener
* listener
= &mListeners
.ElementAt(i
);
2027 if (!listener
->mFlags
.mPassive
&& IsWheelEventType(listener
->mTypeAtom
)) {
2034 void EventListenerManager::RemoveAllListeners() {
2035 while (!mListeners
.IsEmpty()) {
2036 size_t idx
= mListeners
.Length() - 1;
2037 RefPtr
<nsAtom
> type
= mListeners
.ElementAt(idx
).mTypeAtom
;
2038 EventMessage message
= mListeners
.ElementAt(idx
).mEventMessage
;
2039 mListeners
.RemoveElementAt(idx
);
2040 NotifyEventListenerRemoved(type
);
2041 if (IsDeviceType(message
)) {
2042 DisableDevice(message
);
2047 already_AddRefed
<nsIScriptGlobalObject
>
2048 EventListenerManager::GetScriptGlobalAndDocument(Document
** aDoc
) {
2049 nsCOMPtr
<Document
> doc
;
2050 nsCOMPtr
<nsPIDOMWindowInner
> win
;
2051 if (nsINode
* node
= nsINode::FromEventTargetOrNull(mTarget
)) {
2052 // Try to get context from doc
2053 doc
= node
->OwnerDoc();
2054 if (doc
->IsLoadedAsData()) {
2058 win
= do_QueryInterface(doc
->GetScopeObject());
2059 } else if ((win
= GetTargetAsInnerWindow())) {
2060 doc
= win
->GetExtantDoc();
2063 if (!win
|| !win
->IsCurrentInnerWindow()) {
2068 nsCOMPtr
<nsIScriptGlobalObject
> global
= do_QueryInterface(win
);
2069 return global
.forget();
2072 EventListenerManager::ListenerSignalFollower::ListenerSignalFollower(
2073 EventListenerManager
* aListenerManager
,
2074 EventListenerManager::Listener
* aListener
)
2075 : dom::AbortFollower(),
2076 mListenerManager(aListenerManager
),
2077 mListener(aListener
->mListener
.Clone()),
2078 mTypeAtom(aListener
->mTypeAtom
),
2079 mEventMessage(aListener
->mEventMessage
),
2080 mAllEvents(aListener
->mAllEvents
),
2081 mFlags(aListener
->mFlags
){};
2083 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager::ListenerSignalFollower
)
2085 NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerManager::ListenerSignalFollower
)
2086 NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerManager::ListenerSignalFollower
)
2088 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
2089 EventListenerManager::ListenerSignalFollower
)
2090 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener
)
2091 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2093 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(
2094 EventListenerManager::ListenerSignalFollower
)
2095 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListener
)
2096 tmp
->mListenerManager
= nullptr;
2097 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2099 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
2100 EventListenerManager::ListenerSignalFollower
)
2101 NS_INTERFACE_MAP_ENTRY(nsISupports
)
2102 NS_INTERFACE_MAP_END
2104 void EventListenerManager::ListenerSignalFollower::RunAbortAlgorithm() {
2105 if (mListenerManager
) {
2106 RefPtr
<EventListenerManager
> elm
= mListenerManager
;
2107 mListenerManager
= nullptr;
2108 elm
->RemoveEventListenerInternal(std::move(mListener
), mEventMessage
,
2109 mTypeAtom
, mFlags
, mAllEvents
);
2113 } // namespace mozilla