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"
65 #define EVENT_TYPE_EQUALS(ls, message, userType, allEvents) \
66 ((ls->mEventMessage == message && \
67 (ls->mEventMessage != eUnidentifiedEvent || ls->mTypeAtom == userType)) || \
68 (allEvents && ls->mAllEvents))
70 static const uint32_t kAllMutationBits
=
71 NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
|
72 NS_EVENT_BITS_MUTATION_NODEINSERTED
| NS_EVENT_BITS_MUTATION_NODEREMOVED
|
73 NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT
|
74 NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT
|
75 NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
76 NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED
;
78 static uint32_t MutationBitForEventType(EventMessage aEventType
) {
80 case eLegacySubtreeModified
:
81 return NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED
;
82 case eLegacyNodeInserted
:
83 return NS_EVENT_BITS_MUTATION_NODEINSERTED
;
84 case eLegacyNodeRemoved
:
85 return NS_EVENT_BITS_MUTATION_NODEREMOVED
;
86 case eLegacyNodeRemovedFromDocument
:
87 return NS_EVENT_BITS_MUTATION_NODEREMOVEDFROMDOCUMENT
;
88 case eLegacyNodeInsertedIntoDocument
:
89 return NS_EVENT_BITS_MUTATION_NODEINSERTEDINTODOCUMENT
;
90 case eLegacyAttrModified
:
91 return NS_EVENT_BITS_MUTATION_ATTRMODIFIED
;
92 case eLegacyCharacterDataModified
:
93 return NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED
;
100 uint32_t EventListenerManager::sMainThreadCreatedCount
= 0;
102 EventListenerManagerBase::EventListenerManagerBase()
103 : mNoListenerForEvent(eVoidEvent
),
104 mMayHavePaintEventListener(false),
105 mMayHaveMutationListeners(false),
106 mMayHaveCapturingListeners(false),
107 mMayHaveSystemGroupListeners(false),
108 mMayHaveTouchEventListener(false),
109 mMayHaveMouseEnterLeaveEventListener(false),
110 mMayHavePointerEnterLeaveEventListener(false),
111 mMayHaveKeyEventListener(false),
112 mMayHaveInputOrCompositionEventListener(false),
113 mMayHaveSelectionChangeEventListener(false),
114 mMayHaveFormSelectEventListener(false),
115 mMayHaveTransitionEventListener(false),
116 mClearingListeners(false),
117 mIsMainThreadELM(NS_IsMainThread()),
118 mHasNonPrivilegedClickListeners(false),
119 mUnknownNonPrivilegedClickListeners(false) {
120 static_assert(sizeof(EventListenerManagerBase
) == sizeof(uint32_t),
121 "Keep the size of EventListenerManagerBase size compact!");
124 EventListenerManager::EventListenerManager(EventTarget
* aTarget
)
125 : EventListenerManagerBase(), mTarget(aTarget
) {
126 NS_ASSERTION(aTarget
, "unexpected null pointer");
128 if (mIsMainThreadELM
) {
129 ++sMainThreadCreatedCount
;
133 EventListenerManager::~EventListenerManager() {
134 // If your code fails this assertion, a possible reason is that
135 // a class did not call our Disconnect() manually. Note that
136 // this class can have Disconnect called in one of two ways:
137 // if it is part of a cycle, then in Unlink() (such a cycle
138 // would be with one of the listeners, not mTarget which is weak).
139 // If not part of a cycle, then Disconnect must be called manually,
140 // typically from the destructor of the owner class (mTarget).
141 // XXX azakai: Is there any reason to not just call Disconnect
142 // from right here, if not previously called?
143 NS_ASSERTION(!mTarget
, "didn't call Disconnect");
144 RemoveAllListenersSilently();
147 void EventListenerManager::RemoveAllListenersSilently() {
148 if (mClearingListeners
) {
151 mClearingListeners
= true;
153 mClearingListeners
= false;
156 inline void ImplCycleCollectionTraverse(
157 nsCycleCollectionTraversalCallback
& aCallback
,
158 EventListenerManager::Listener
& aField
, const char* aName
,
160 if (MOZ_UNLIKELY(aCallback
.WantDebugInfo())) {
162 name
.AppendASCII(aName
);
163 if (aField
.mTypeAtom
) {
164 name
.AppendLiteral(" event=");
165 name
.Append(nsAtomCString(aField
.mTypeAtom
));
166 name
.AppendLiteral(" listenerType=");
167 name
.AppendInt(aField
.mListenerType
);
168 name
.AppendLiteral(" ");
170 CycleCollectionNoteChild(aCallback
, aField
.mListener
.GetISupports(),
173 CycleCollectionNoteChild(aCallback
, aField
.mListener
.GetISupports(), aName
,
177 CycleCollectionNoteChild(aCallback
, aField
.mSignalFollower
.get(),
178 "mSignalFollower", aFlags
);
181 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager
)
183 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EventListenerManager
)
184 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners
)
185 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
187 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EventListenerManager
)
189 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
191 nsPIDOMWindowInner
* EventListenerManager::GetInnerWindowForTarget() {
192 if (nsINode
* node
= nsINode::FromEventTargetOrNull(mTarget
)) {
193 // XXX sXBL/XBL2 issue -- do we really want the owner here? What
194 // if that's the XBL document?
195 return node
->OwnerDoc()->GetInnerWindow();
198 nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow();
202 already_AddRefed
<nsPIDOMWindowInner
>
203 EventListenerManager::GetTargetAsInnerWindow() const {
204 nsCOMPtr
<nsPIDOMWindowInner
> window
=
205 nsPIDOMWindowInner::FromEventTargetOrNull(mTarget
);
206 return window
.forget();
209 void EventListenerManager::AddEventListenerInternal(
210 EventListenerHolder aListenerHolder
, EventMessage aEventMessage
,
211 nsAtom
* aTypeAtom
, const EventListenerFlags
& aFlags
, bool aHandler
,
212 bool aAllEvents
, AbortSignal
* aSignal
) {
213 MOZ_ASSERT((aEventMessage
&& aTypeAtom
) || aAllEvents
, // all-events listener
216 if (!aListenerHolder
|| mClearingListeners
) {
220 if (aSignal
&& aSignal
->Aborted()) {
224 // Since there is no public API to call us with an EventListenerHolder, we
225 // know that there's an EventListenerHolder on the stack holding a strong ref
229 uint32_t count
= mListeners
.Length();
230 for (uint32_t i
= 0; i
< count
; i
++) {
231 listener
= &mListeners
.ElementAt(i
);
232 // mListener == aListenerHolder is the last one, since it can be a bit slow.
233 if (listener
->mListenerIsHandler
== aHandler
&&
234 listener
->mFlags
.EqualsForAddition(aFlags
) &&
235 EVENT_TYPE_EQUALS(listener
, aEventMessage
, aTypeAtom
, aAllEvents
) &&
236 listener
->mListener
== aListenerHolder
) {
241 mNoListenerForEvent
= eVoidEvent
;
242 mNoListenerForEventAtom
= nullptr;
245 aAllEvents
? mListeners
.InsertElementAt(0) : mListeners
.AppendElement();
246 listener
->mEventMessage
= aEventMessage
;
247 listener
->mTypeAtom
= aTypeAtom
;
248 listener
->mFlags
= aFlags
;
249 listener
->mListenerIsHandler
= aHandler
;
250 listener
->mHandlerIsString
= false;
251 listener
->mAllEvents
= aAllEvents
;
252 listener
->mIsChrome
=
253 mIsMainThreadELM
&& nsContentUtils::LegacyIsCallerChromeOrNativeCode();
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
:
311 // For mutation listeners, we need to update the global bit on the DOM
312 // window. Otherwise we won't actually fire the mutation event.
313 mMayHaveMutationListeners
= true;
314 // Go from our target to the nearest enclosing DOM window.
315 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
316 if (Document
* doc
= window
->GetExtantDoc()) {
317 doc
->WarnOnceAbout(DeprecatedOperations::eMutationEvent
);
319 // If resolvedEventMessage is eLegacySubtreeModified, we need to
320 // listen all mutations. nsContentUtils::HasMutationListeners relies
322 window
->SetMutationListeners(
323 (resolvedEventMessage
== eLegacySubtreeModified
)
325 : MutationBitForEventType(resolvedEventMessage
));
330 mMayHavePointerEnterLeaveEventListener
= true;
331 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
332 NS_WARNING_ASSERTION(
333 !nsContentUtils::IsChromeDoc(window
->GetExtantDoc()),
334 "Please do not use pointerenter/leave events in chrome. "
335 "They are slower than pointerover/out!");
336 window
->SetHasPointerEnterLeaveEventListeners();
339 case eGamepadButtonDown
:
340 case eGamepadButtonUp
:
341 case eGamepadAxisMove
:
342 case eGamepadConnected
:
343 case eGamepadDisconnected
:
344 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
345 window
->SetHasGamepadEventListener();
348 case eDeviceOrientation
:
349 case eDeviceOrientationAbsolute
:
353 #if defined(MOZ_WIDGET_ANDROID)
354 case eOrientationChange
:
355 #endif // #if defined(MOZ_WIDGET_ANDROID)
356 EnableDevice(resolvedEventMessage
);
362 mMayHaveTouchEventListener
= true;
363 // we don't want touchevent listeners added by scrollbars to flip this
364 // flag so we ignore listeners created with system event flag
365 if (!aFlags
.mInSystemGroup
) {
366 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
367 window
->SetHasTouchEventListeners();
373 mMayHaveMouseEnterLeaveEventListener
= true;
374 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
375 NS_WARNING_ASSERTION(
376 !nsContentUtils::IsChromeDoc(window
->GetExtantDoc()),
377 "Please do not use mouseenter/leave events in chrome. "
378 "They are slower than mouseover/out!");
379 window
->SetHasMouseEnterLeaveEventListeners();
385 if (!aFlags
.mInSystemGroup
) {
386 mMayHaveKeyEventListener
= true;
389 case eCompositionEnd
:
390 case eCompositionStart
:
391 case eCompositionUpdate
:
393 if (!aFlags
.mInSystemGroup
) {
394 mMayHaveInputOrCompositionEventListener
= true;
397 case eEditorBeforeInput
:
398 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
399 window
->SetHasBeforeInputEventListenersForTelemetry();
402 case eSelectionChange
:
403 mMayHaveSelectionChangeEventListener
= true;
404 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
405 window
->SetHasSelectionChangeEventListeners();
409 mMayHaveFormSelectEventListener
= true;
410 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
411 window
->SetHasFormSelectEventListeners();
415 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
416 if (Document
* doc
= window
->GetExtantDoc()) {
417 doc
->SetUseCounter(eUseCounter_custom_onstart
);
422 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
423 if (Document
* doc
= window
->GetExtantDoc()) {
424 doc
->SetUseCounter(eUseCounter_custom_onbounce
);
429 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
430 if (Document
* doc
= window
->GetExtantDoc()) {
431 doc
->SetUseCounter(eUseCounter_custom_onfinish
);
435 case eScrollPortOverflow
:
436 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
437 if (Document
* doc
= window
->GetExtantDoc()) {
438 doc
->SetUseCounter(eUseCounter_custom_onoverflow
);
442 case eScrollPortUnderflow
:
443 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
444 if (Document
* doc
= window
->GetExtantDoc()) {
445 doc
->SetUseCounter(eUseCounter_custom_onunderflow
);
449 case eLegacyMouseLineOrPageScroll
:
450 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
451 if (Document
* doc
= window
->GetExtantDoc()) {
452 doc
->SetUseCounter(eUseCounter_custom_ondommousescroll
);
456 case eLegacyMousePixelScroll
:
457 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
458 if (Document
* doc
= window
->GetExtantDoc()) {
459 doc
->SetUseCounter(eUseCounter_custom_onmozmousepixelscroll
);
463 case eTransitionStart
:
466 case eTransitionCancel
:
467 case eWebkitTransitionEnd
:
468 mMayHaveTransitionEventListener
= true;
469 if (nsPIDOMWindowInner
* window
= GetInnerWindowForTarget()) {
470 window
->SetHasTransitionEventListeners();
473 case eFormCheckboxStateChange
:
474 nsContentUtils::SetMayHaveFormCheckboxStateChangeListeners();
476 case eFormRadioStateChange
:
477 nsContentUtils::SetMayHaveFormRadioStateChangeListeners();
480 // XXX Use NS_ASSERTION here to print resolvedEventMessage since
481 // MOZ_ASSERT can take only string literal, not pointer to
484 resolvedEventMessage
< eLegacyMutationEventFirst
||
485 resolvedEventMessage
> eLegacyMutationEventLast
,
486 nsPrintfCString("You added new mutation event, but it's not "
487 "handled above, resolvedEventMessage=%s",
488 ToChar(resolvedEventMessage
))
490 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onpointerenter
,
491 nsPrintfCString("resolvedEventMessage=%s",
492 ToChar(resolvedEventMessage
))
494 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onpointerleave
,
495 nsPrintfCString("resolvedEventMessage=%s",
496 ToChar(resolvedEventMessage
))
499 resolvedEventMessage
< eGamepadEventFirst
||
500 resolvedEventMessage
> eGamepadEventLast
,
501 nsPrintfCString("You added new gamepad event, but it's not "
502 "handled above, resolvedEventMessage=%s",
503 ToChar(resolvedEventMessage
))
505 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondeviceorientation
,
506 nsPrintfCString("resolvedEventMessage=%s",
507 ToChar(resolvedEventMessage
))
509 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondeviceorientationabsolute
,
510 nsPrintfCString("resolvedEventMessage=%s",
511 ToChar(resolvedEventMessage
))
513 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onuserproximity
,
514 nsPrintfCString("resolvedEventMessage=%s",
515 ToChar(resolvedEventMessage
))
517 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondevicelight
,
518 nsPrintfCString("resolvedEventMessage=%s",
519 ToChar(resolvedEventMessage
))
521 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ondevicemotion
,
522 nsPrintfCString("resolvedEventMessage=%s",
523 ToChar(resolvedEventMessage
))
525 #if defined(MOZ_WIDGET_ANDROID)
526 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onorientationchange
,
527 nsPrintfCString("resolvedEventMessage=%s",
528 ToChar(resolvedEventMessage
))
530 #endif // #if defined(MOZ_WIDGET_ANDROID)
531 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchstart
,
532 nsPrintfCString("resolvedEventMessage=%s",
533 ToChar(resolvedEventMessage
))
535 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchend
,
536 nsPrintfCString("resolvedEventMessage=%s",
537 ToChar(resolvedEventMessage
))
539 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchmove
,
540 nsPrintfCString("resolvedEventMessage=%s",
541 ToChar(resolvedEventMessage
))
543 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::ontouchcancel
,
544 nsPrintfCString("resolvedEventMessage=%s",
545 ToChar(resolvedEventMessage
))
547 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onmouseenter
,
548 nsPrintfCString("resolvedEventMessage=%s",
549 ToChar(resolvedEventMessage
))
551 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onmouseleave
,
552 nsPrintfCString("resolvedEventMessage=%s",
553 ToChar(resolvedEventMessage
))
555 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onkeydown
,
556 nsPrintfCString("resolvedEventMessage=%s",
557 ToChar(resolvedEventMessage
))
559 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onkeypress
,
560 nsPrintfCString("resolvedEventMessage=%s",
561 ToChar(resolvedEventMessage
))
563 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onkeyup
,
564 nsPrintfCString("resolvedEventMessage=%s",
565 ToChar(resolvedEventMessage
))
567 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::oncompositionend
,
568 nsPrintfCString("resolvedEventMessage=%s",
569 ToChar(resolvedEventMessage
))
571 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::oncompositionstart
,
572 nsPrintfCString("resolvedEventMessage=%s",
573 ToChar(resolvedEventMessage
))
575 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::oncompositionupdate
,
576 nsPrintfCString("resolvedEventMessage=%s",
577 ToChar(resolvedEventMessage
))
579 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::oninput
,
580 nsPrintfCString("resolvedEventMessage=%s",
581 ToChar(resolvedEventMessage
))
583 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onbeforeinput
,
584 nsPrintfCString("resolvedEventMessage=%s",
585 ToChar(resolvedEventMessage
))
587 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onselectionchange
,
588 nsPrintfCString("resolvedEventMessage=%s",
589 ToChar(resolvedEventMessage
))
591 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onselect
,
592 nsPrintfCString("resolvedEventMessage=%s",
593 ToChar(resolvedEventMessage
))
595 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onstart
,
596 nsPrintfCString("resolvedEventMessage=%s",
597 ToChar(resolvedEventMessage
))
599 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onbounce
,
600 nsPrintfCString("resolvedEventMessage=%s",
601 ToChar(resolvedEventMessage
))
603 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onfinish
,
604 nsPrintfCString("resolvedEventMessage=%s",
605 ToChar(resolvedEventMessage
))
607 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onoverflow
,
608 nsPrintfCString("resolvedEventMessage=%s",
609 ToChar(resolvedEventMessage
))
611 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onunderflow
,
612 nsPrintfCString("resolvedEventMessage=%s",
613 ToChar(resolvedEventMessage
))
615 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onDOMMouseScroll
,
616 nsPrintfCString("resolvedEventMessage=%s",
617 ToChar(resolvedEventMessage
))
619 NS_ASSERTION(aTypeAtom
!= nsGkAtoms::onMozMousePixelScroll
,
620 nsPrintfCString("resolvedEventMessage=%s",
621 ToChar(resolvedEventMessage
))
627 if (IsApzAwareListener(listener
)) {
628 ProcessApzAwareEventListenerAdd();
632 mTarget
->EventListenerAdded(aTypeAtom
);
635 if (mIsMainThreadELM
&& mTarget
) {
636 EventListenerService::NotifyAboutMainThreadListenerChange(mTarget
,
640 if (!mHasNonPrivilegedClickListeners
|| mUnknownNonPrivilegedClickListeners
) {
641 if (IsNonChromeClickListener(listener
)) {
642 mHasNonPrivilegedClickListeners
= true;
643 mUnknownNonPrivilegedClickListeners
= false;
648 void EventListenerManager::ProcessApzAwareEventListenerAdd() {
649 Document
* doc
= nullptr;
651 // Mark the node as having apz aware listeners
652 if (nsINode
* node
= nsINode::FromEventTargetOrNull(mTarget
)) {
653 node
->SetMayBeApzAware();
654 doc
= node
->OwnerDoc();
657 // Schedule a paint so event regions on the layer tree gets updated
659 if (nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow()) {
660 doc
= window
->GetExtantDoc();
664 if (nsCOMPtr
<DOMEventTargetHelper
> helper
= do_QueryInterface(mTarget
)) {
665 if (nsPIDOMWindowInner
* window
= helper
->GetOwner()) {
666 doc
= window
->GetExtantDoc();
671 if (doc
&& gfxPlatform::AsyncPanZoomEnabled()) {
672 PresShell
* presShell
= doc
->GetPresShell();
674 nsIFrame
* f
= presShell
->GetRootFrame();
682 bool EventListenerManager::IsDeviceType(EventMessage aEventMessage
) {
683 switch (aEventMessage
) {
684 case eDeviceOrientation
:
685 case eDeviceOrientationAbsolute
:
689 #if defined(MOZ_WIDGET_ANDROID)
690 case eOrientationChange
:
699 void EventListenerManager::EnableDevice(EventMessage aEventMessage
) {
700 nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow();
705 switch (aEventMessage
) {
706 case eDeviceOrientation
:
707 #ifdef MOZ_WIDGET_ANDROID
708 // Falls back to SENSOR_ROTATION_VECTOR and SENSOR_ORIENTATION if
709 // unavailable on device.
710 window
->EnableDeviceSensor(SENSOR_GAME_ROTATION_VECTOR
);
711 window
->EnableDeviceSensor(SENSOR_ROTATION_VECTOR
);
713 window
->EnableDeviceSensor(SENSOR_ORIENTATION
);
716 case eDeviceOrientationAbsolute
:
717 #ifdef MOZ_WIDGET_ANDROID
718 // Falls back to SENSOR_ORIENTATION if unavailable on device.
719 window
->EnableDeviceSensor(SENSOR_ROTATION_VECTOR
);
721 window
->EnableDeviceSensor(SENSOR_ORIENTATION
);
725 window
->EnableDeviceSensor(SENSOR_PROXIMITY
);
728 window
->EnableDeviceSensor(SENSOR_LIGHT
);
731 window
->EnableDeviceSensor(SENSOR_ACCELERATION
);
732 window
->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION
);
733 window
->EnableDeviceSensor(SENSOR_GYROSCOPE
);
735 #if defined(MOZ_WIDGET_ANDROID)
736 case eOrientationChange
:
737 window
->EnableOrientationChangeListener();
741 NS_WARNING("Enabling an unknown device sensor.");
746 void EventListenerManager::DisableDevice(EventMessage aEventMessage
) {
747 nsCOMPtr
<nsPIDOMWindowInner
> window
= GetTargetAsInnerWindow();
752 switch (aEventMessage
) {
753 case eDeviceOrientation
:
754 #ifdef MOZ_WIDGET_ANDROID
755 // Disable all potential fallback sensors.
756 window
->DisableDeviceSensor(SENSOR_GAME_ROTATION_VECTOR
);
757 window
->DisableDeviceSensor(SENSOR_ROTATION_VECTOR
);
759 window
->DisableDeviceSensor(SENSOR_ORIENTATION
);
761 case eDeviceOrientationAbsolute
:
762 #ifdef MOZ_WIDGET_ANDROID
763 window
->DisableDeviceSensor(SENSOR_ROTATION_VECTOR
);
765 window
->DisableDeviceSensor(SENSOR_ORIENTATION
);
768 window
->DisableDeviceSensor(SENSOR_ACCELERATION
);
769 window
->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION
);
770 window
->DisableDeviceSensor(SENSOR_GYROSCOPE
);
773 window
->DisableDeviceSensor(SENSOR_PROXIMITY
);
776 window
->DisableDeviceSensor(SENSOR_LIGHT
);
778 #if defined(MOZ_WIDGET_ANDROID)
779 case eOrientationChange
:
780 window
->DisableOrientationChangeListener();
784 NS_WARNING("Disabling an unknown device sensor.");
789 void EventListenerManager::NotifyEventListenerRemoved(nsAtom
* aUserType
) {
790 // If the following code is changed, other callsites of EventListenerRemoved
791 // and NotifyAboutMainThreadListenerChange should be changed too.
792 mNoListenerForEvent
= eVoidEvent
;
793 mNoListenerForEventAtom
= nullptr;
795 mTarget
->EventListenerRemoved(aUserType
);
797 if (mIsMainThreadELM
&& mTarget
) {
798 EventListenerService::NotifyAboutMainThreadListenerChange(mTarget
,
803 void EventListenerManager::RemoveEventListenerInternal(
804 EventListenerHolder aListenerHolder
, EventMessage aEventMessage
,
805 nsAtom
* aUserType
, const EventListenerFlags
& aFlags
, bool aAllEvents
) {
806 if (!aListenerHolder
|| !aEventMessage
|| mClearingListeners
) {
812 uint32_t count
= mListeners
.Length();
813 bool deviceType
= IsDeviceType(aEventMessage
);
815 RefPtr
<EventListenerManager
> kungFuDeathGrip(this);
817 for (uint32_t i
= 0; i
< count
; ++i
) {
818 listener
= &mListeners
.ElementAt(i
);
819 if (EVENT_TYPE_EQUALS(listener
, aEventMessage
, aUserType
, aAllEvents
)) {
820 if (listener
->mListener
== aListenerHolder
&&
821 listener
->mFlags
.EqualsForRemoval(aFlags
)) {
822 if (IsNonChromeClickListener(listener
)) {
823 mUnknownNonPrivilegedClickListeners
= true;
825 mListeners
.RemoveElementAt(i
);
826 NotifyEventListenerRemoved(aUserType
);
827 if (!aAllEvents
&& deviceType
) {
828 DisableDevice(aEventMessage
);
836 bool EventListenerManager::HasNonPrivilegedClickListeners() {
837 if (mUnknownNonPrivilegedClickListeners
) {
840 mUnknownNonPrivilegedClickListeners
= false;
841 for (uint32_t i
= 0; i
< mListeners
.Length(); ++i
) {
842 listener
= &mListeners
.ElementAt(i
);
843 if (IsNonChromeClickListener(listener
)) {
844 mHasNonPrivilegedClickListeners
= true;
845 return mHasNonPrivilegedClickListeners
;
848 mHasNonPrivilegedClickListeners
= false;
850 return mHasNonPrivilegedClickListeners
;
853 bool EventListenerManager::ListenerCanHandle(const Listener
* aListener
,
854 const WidgetEvent
* aEvent
,
855 EventMessage aEventMessage
) const
858 MOZ_ASSERT(aEventMessage
== aEvent
->mMessage
||
859 aEventMessage
== GetLegacyEventMessage(aEvent
->mMessage
),
860 "aEvent and aEventMessage should agree, modulo legacyness");
862 // The listener has been removed, it cannot handle anything.
863 if (aListener
->mListenerType
== Listener::eNoListener
) {
867 // The listener has been disabled, for example by devtools.
868 if (!aListener
->mEnabled
) {
872 // This is slightly different from EVENT_TYPE_EQUALS in that it returns
873 // true even when aEvent->mMessage == eUnidentifiedEvent and
874 // aListener=>mEventMessage != eUnidentifiedEvent as long as the atoms are
876 if (MOZ_UNLIKELY(aListener
->mAllEvents
)) {
879 if (aEvent
->mMessage
== eUnidentifiedEvent
) {
880 return aListener
->mTypeAtom
== aEvent
->mSpecifiedEventType
;
882 MOZ_ASSERT(mIsMainThreadELM
);
883 return aListener
->mEventMessage
== aEventMessage
;
886 static bool IsDefaultPassiveWhenOnRoot(EventMessage aMessage
) {
887 if (aMessage
== eTouchStart
|| aMessage
== eTouchMove
) {
888 return StaticPrefs::dom_event_default_to_passive_touch_listeners();
890 if (aMessage
== eWheel
|| aMessage
== eLegacyMouseLineOrPageScroll
||
891 aMessage
== eLegacyMousePixelScroll
) {
892 return StaticPrefs::dom_event_default_to_passive_wheel_listeners();
897 static bool IsRootEventTarget(EventTarget
* aTarget
) {
901 if (aTarget
->IsInnerWindow()) {
904 const nsINode
* node
= nsINode::FromEventTarget(aTarget
);
908 Document
* doc
= node
->OwnerDoc();
909 return node
== doc
|| node
== doc
->GetRootElement() || node
== doc
->GetBody();
912 void EventListenerManager::MaybeMarkPassive(EventMessage aMessage
,
913 EventListenerFlags
& aFlags
) {
914 if (!mIsMainThreadELM
) {
917 if (!IsDefaultPassiveWhenOnRoot(aMessage
)) {
920 if (!IsRootEventTarget(mTarget
)) {
923 aFlags
.mPassive
= true;
926 void EventListenerManager::AddEventListenerByType(
927 EventListenerHolder aListenerHolder
, const nsAString
& aType
,
928 const EventListenerFlags
& aFlags
, const Optional
<bool>& aPassive
,
929 AbortSignal
* aSignal
) {
931 EventMessage message
=
932 GetEventMessageAndAtomForListener(aType
, getter_AddRefs(atom
));
934 EventListenerFlags flags
= aFlags
;
935 if (aPassive
.WasPassed()) {
936 flags
.mPassive
= aPassive
.Value();
938 MaybeMarkPassive(message
, flags
);
941 AddEventListenerInternal(std::move(aListenerHolder
), message
, atom
, flags
,
942 false, false, aSignal
);
945 void EventListenerManager::RemoveEventListenerByType(
946 EventListenerHolder aListenerHolder
, const nsAString
& aType
,
947 const EventListenerFlags
& aFlags
) {
949 EventMessage message
=
950 GetEventMessageAndAtomForListener(aType
, getter_AddRefs(atom
));
951 RemoveEventListenerInternal(std::move(aListenerHolder
), message
, atom
,
955 EventListenerManager::Listener
* EventListenerManager::FindEventHandler(
956 EventMessage aEventMessage
, nsAtom
* aTypeAtom
) {
957 // Run through the listeners for this type and see if a script
958 // listener is registered
960 uint32_t count
= mListeners
.Length();
961 for (uint32_t i
= 0; i
< count
; ++i
) {
962 listener
= &mListeners
.ElementAt(i
);
963 if (listener
->mListenerIsHandler
&&
964 EVENT_TYPE_EQUALS(listener
, aEventMessage
, aTypeAtom
, false)) {
971 EventListenerManager::Listener
* EventListenerManager::SetEventHandlerInternal(
972 nsAtom
* aName
, const TypedEventHandler
& aTypedHandler
,
973 bool aPermitUntrustedEvents
) {
976 EventMessage eventMessage
= GetEventMessage(aName
);
977 Listener
* listener
= FindEventHandler(eventMessage
, aName
);
980 // If we didn't find a script listener or no listeners existed
981 // create and add a new one.
982 EventListenerFlags flags
;
983 flags
.mListenerIsJSListener
= true;
984 MaybeMarkPassive(eventMessage
, flags
);
986 nsCOMPtr
<JSEventHandler
> jsEventHandler
;
987 NS_NewJSEventHandler(mTarget
, aName
, aTypedHandler
,
988 getter_AddRefs(jsEventHandler
));
989 AddEventListenerInternal(EventListenerHolder(jsEventHandler
), eventMessage
,
992 listener
= FindEventHandler(eventMessage
, aName
);
994 JSEventHandler
* jsEventHandler
= listener
->GetJSEventHandler();
995 MOZ_ASSERT(jsEventHandler
,
996 "How can we have an event handler with no JSEventHandler?");
998 bool same
= jsEventHandler
->GetTypedEventHandler() == aTypedHandler
;
999 // Possibly the same listener, but update still the context and scope.
1000 jsEventHandler
->SetHandler(aTypedHandler
);
1001 if (mTarget
&& !same
) {
1002 mTarget
->EventListenerRemoved(aName
);
1003 mTarget
->EventListenerAdded(aName
);
1005 if (mIsMainThreadELM
&& mTarget
) {
1006 EventListenerService::NotifyAboutMainThreadListenerChange(mTarget
, aName
);
1010 // Set flag to indicate possible need for compilation later
1011 listener
->mHandlerIsString
= !aTypedHandler
.HasEventHandler();
1012 if (aPermitUntrustedEvents
) {
1013 listener
->mFlags
.mAllowUntrustedEvents
= true;
1019 nsresult
EventListenerManager::SetEventHandler(nsAtom
* aName
,
1020 const nsAString
& aBody
,
1021 bool aDeferCompilation
,
1022 bool aPermitUntrustedEvents
,
1023 Element
* aElement
) {
1024 auto removeEventHandler
= MakeScopeExit([&] { RemoveEventHandler(aName
); });
1026 nsCOMPtr
<Document
> doc
;
1027 nsCOMPtr
<nsIScriptGlobalObject
> global
=
1028 GetScriptGlobalAndDocument(getter_AddRefs(doc
));
1031 // This can happen; for example this document might have been
1036 nsresult rv
= NS_OK
;
1037 // return early preventing the event listener from being added
1038 // 'doc' is fetched above
1040 // Don't allow adding an event listener if the document is sandboxed
1041 // without 'allow-scripts'.
1042 if (doc
->HasScriptsBlockedBySandbox()) {
1043 return NS_ERROR_DOM_SECURITY_ERR
;
1046 // Perform CSP check
1047 nsCOMPtr
<nsIContentSecurityPolicy
> csp
= doc
->GetCsp();
1048 unsigned lineNum
= 0;
1049 unsigned columnNum
= 0;
1051 JSContext
* cx
= nsContentUtils::GetCurrentJSContext();
1052 if (cx
&& !JS::DescribeScriptedCaller(cx
, nullptr, &lineNum
, &columnNum
)) {
1053 JS_ClearPendingException(cx
);
1057 bool allowsInlineScript
= true;
1058 rv
= csp
->GetAllowsInline(
1059 nsIContentSecurityPolicy::SCRIPT_SRC_ATTR_DIRECTIVE
,
1060 true, // aHasUnsafeHash
1062 true, // aParserCreated (true because attribute event handler)
1064 nullptr, // nsICSPEventListener
1065 aBody
, lineNum
, columnNum
, &allowsInlineScript
);
1066 NS_ENSURE_SUCCESS(rv
, rv
);
1068 // return early if CSP wants us to block inline scripts
1069 if (!allowsInlineScript
) {
1075 // This might be the first reference to this language in the global
1076 // We must init the language before we attempt to fetch its context.
1077 if (NS_FAILED(global
->EnsureScriptEnvironment())) {
1078 NS_WARNING("Failed to setup script environment for this language");
1079 // but fall through and let the inevitable failure below handle it.
1082 nsIScriptContext
* context
= global
->GetScriptContext();
1083 NS_ENSURE_TRUE(context
, NS_ERROR_FAILURE
);
1084 NS_ENSURE_STATE(global
->HasJSGlobal());
1086 removeEventHandler
.release();
1088 Listener
* listener
= SetEventHandlerInternal(aName
, TypedEventHandler(),
1089 aPermitUntrustedEvents
);
1091 if (!aDeferCompilation
) {
1092 return CompileEventHandlerInternal(listener
, &aBody
, aElement
);
1098 void EventListenerManager::RemoveEventHandler(nsAtom
* aName
) {
1099 if (mClearingListeners
) {
1103 EventMessage eventMessage
= GetEventMessage(aName
);
1104 Listener
* listener
= FindEventHandler(eventMessage
, aName
);
1107 if (IsNonChromeClickListener(listener
)) {
1108 mUnknownNonPrivilegedClickListeners
= true;
1110 mListeners
.RemoveElementAt(uint32_t(listener
- &mListeners
.ElementAt(0)));
1111 NotifyEventListenerRemoved(aName
);
1112 if (IsDeviceType(eventMessage
)) {
1113 DisableDevice(eventMessage
);
1118 bool EventListenerManager::IsNonChromeClickListener(Listener
* aListener
) {
1119 return !aListener
->mFlags
.mInSystemGroup
&& !aListener
->mIsChrome
&&
1120 aListener
->mEventMessage
== eMouseClick
&&
1121 (aListener
->GetJSEventHandler() ||
1122 aListener
->mListener
.HasWebIDLCallback());
1125 nsresult
EventListenerManager::CompileEventHandlerInternal(
1126 Listener
* aListener
, const nsAString
* aBody
, Element
* aElement
) {
1127 MOZ_ASSERT(aListener
->GetJSEventHandler());
1128 MOZ_ASSERT(aListener
->mHandlerIsString
,
1129 "Why are we compiling a non-string JS listener?");
1130 JSEventHandler
* jsEventHandler
= aListener
->GetJSEventHandler();
1131 MOZ_ASSERT(!jsEventHandler
->GetTypedEventHandler().HasEventHandler(),
1132 "What is there to compile?");
1134 nsresult result
= NS_OK
;
1135 nsCOMPtr
<Document
> doc
;
1136 nsCOMPtr
<nsIScriptGlobalObject
> global
=
1137 GetScriptGlobalAndDocument(getter_AddRefs(doc
));
1138 NS_ENSURE_STATE(global
);
1140 // Activate JSAPI, and make sure that exceptions are reported on the right
1143 if (NS_WARN_IF(!jsapi
.Init(global
))) {
1144 return NS_ERROR_UNEXPECTED
;
1146 JSContext
* cx
= jsapi
.cx();
1148 RefPtr
<nsAtom
> typeAtom
= aListener
->mTypeAtom
;
1149 nsAtom
* attrName
= typeAtom
;
1151 // Flag us as not a string so we don't keep trying to compile strings which
1152 // can't be compiled.
1153 aListener
->mHandlerIsString
= false;
1155 // mTarget may not be an Element if it's a window and we're
1156 // getting an inline event listener forwarded from <html:body> or
1157 // <html:frameset> or <xul:window> or the like.
1158 // XXX I don't like that we have to reference content from
1159 // here. The alternative is to store the event handler string on
1160 // the JSEventHandler itself, and that still doesn't address
1161 // the arg names issue.
1162 RefPtr
<Element
> element
= Element::FromEventTargetOrNull(mTarget
);
1163 MOZ_ASSERT(element
|| aBody
, "Where will we get our body?");
1164 nsAutoString handlerBody
;
1165 const nsAString
* body
= aBody
;
1167 if (aListener
->mTypeAtom
== nsGkAtoms::onSVGLoad
) {
1168 attrName
= nsGkAtoms::onload
;
1169 } else if (aListener
->mTypeAtom
== nsGkAtoms::onSVGScroll
) {
1170 attrName
= nsGkAtoms::onscroll
;
1171 } else if (aListener
->mTypeAtom
== nsGkAtoms::onbeginEvent
) {
1172 attrName
= nsGkAtoms::onbegin
;
1173 } else if (aListener
->mTypeAtom
== nsGkAtoms::onrepeatEvent
) {
1174 attrName
= nsGkAtoms::onrepeat
;
1175 } else if (aListener
->mTypeAtom
== nsGkAtoms::onendEvent
) {
1176 attrName
= nsGkAtoms::onend
;
1177 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitAnimationEnd
) {
1178 attrName
= nsGkAtoms::onwebkitanimationend
;
1179 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitAnimationIteration
) {
1180 attrName
= nsGkAtoms::onwebkitanimationiteration
;
1181 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitAnimationStart
) {
1182 attrName
= nsGkAtoms::onwebkitanimationstart
;
1183 } else if (aListener
->mTypeAtom
== nsGkAtoms::onwebkitTransitionEnd
) {
1184 attrName
= nsGkAtoms::onwebkittransitionend
;
1187 element
->GetAttr(kNameSpaceID_None
, attrName
, handlerBody
);
1188 body
= &handlerBody
;
1191 aListener
= nullptr;
1193 nsAutoCString
url("-moz-evil:lying-event-listener"_ns
);
1195 MOZ_ASSERT(aElement
);
1196 nsIURI
* uri
= aElement
->OwnerDoc()->GetDocumentURI();
1201 nsCOMPtr
<nsPIDOMWindowInner
> win
=
1202 nsPIDOMWindowInner::FromEventTargetOrNull(mTarget
);
1204 const char** argNames
;
1205 nsContentUtils::GetEventArgNames(aElement
->GetNameSpaceID(), typeAtom
, win
,
1206 &argCount
, &argNames
);
1208 // Wrap the event target, so that we can use it as the scope for the event
1209 // handler. Note that mTarget is different from aElement in the <body> case,
1210 // where mTarget is a Window.
1212 // The wrapScope doesn't really matter here, because the target will create
1213 // its reflector in the proper scope, and then we'll enter that realm.
1214 JS::Rooted
<JSObject
*> wrapScope(cx
, global
->GetGlobalJSObject());
1215 JS::Rooted
<JS::Value
> v(cx
);
1217 JSAutoRealm
ar(cx
, wrapScope
);
1218 nsresult rv
= nsContentUtils::WrapNative(cx
, mTarget
, &v
,
1219 /* aAllowWrapping = */ false);
1220 if (NS_WARN_IF(NS_FAILED(rv
))) {
1225 JS::Rooted
<JSObject
*> target(cx
, &v
.toObject());
1226 JSAutoRealm
ar(cx
, target
);
1228 // Now that we've entered the realm we actually care about, create our
1229 // scope chain. Note that we start with |element|, not aElement, because
1230 // mTarget is different from aElement in the <body> case, where mTarget is a
1231 // Window, and in that case we do not want the scope chain to include the body
1233 JS::RootedVector
<JSObject
*> scopeChain(cx
);
1234 if (!nsJSUtils::GetScopeChainForElement(cx
, element
, &scopeChain
)) {
1235 return NS_ERROR_OUT_OF_MEMORY
;
1238 nsDependentAtomString
str(attrName
);
1239 // Most of our names are short enough that we don't even have to malloc
1240 // the JS string stuff, so don't worry about playing games with
1241 // refcounting XPCOM stringbuffers.
1242 JS::Rooted
<JSString
*> jsStr(
1243 cx
, JS_NewUCStringCopyN(cx
, str
.BeginReading(), str
.Length()));
1244 NS_ENSURE_TRUE(jsStr
, NS_ERROR_OUT_OF_MEMORY
);
1246 // Get the reflector for |aElement|, so that we can pass to setElement.
1247 if (NS_WARN_IF(!GetOrCreateDOMReflector(cx
, aElement
, &v
))) {
1248 return NS_ERROR_FAILURE
;
1251 RefPtr
<JS::loader::ScriptFetchOptions
> fetchOptions
=
1252 new JS::loader::ScriptFetchOptions(
1253 CORS_NONE
, aElement
->OwnerDoc()->GetReferrerPolicy(),
1254 aElement
->OwnerDoc()->NodePrincipal());
1256 RefPtr
<JS::loader::EventScript
> eventScript
=
1257 new JS::loader::EventScript(fetchOptions
, uri
);
1259 JS::CompileOptions
options(cx
);
1260 // Use line 0 to make the function body starts from line 1.
1261 options
.setIntroductionType("eventHandler")
1262 .setFileAndLine(url
.get(), 0)
1263 .setDeferDebugMetadata(true);
1265 JS::Rooted
<JSObject
*> handler(cx
);
1266 result
= nsJSUtils::CompileFunction(jsapi
, scopeChain
, options
,
1267 nsAtomCString(typeAtom
), argCount
,
1268 argNames
, *body
, handler
.address());
1269 NS_ENSURE_SUCCESS(result
, result
);
1270 NS_ENSURE_TRUE(handler
, NS_ERROR_FAILURE
);
1272 JS::Rooted
<JS::Value
> privateValue(cx
, JS::PrivateValue(eventScript
));
1273 result
= nsJSUtils::UpdateFunctionDebugMetadata(jsapi
, handler
, options
,
1274 jsStr
, privateValue
);
1275 NS_ENSURE_SUCCESS(result
, result
);
1277 MOZ_ASSERT(js::IsObjectInContextCompartment(handler
, cx
));
1278 JS::Rooted
<JSObject
*> handlerGlobal(cx
, JS::CurrentGlobalOrNull(cx
));
1280 if (jsEventHandler
->EventName() == nsGkAtoms::onerror
&& win
) {
1281 RefPtr
<OnErrorEventHandlerNonNull
> handlerCallback
=
1282 new OnErrorEventHandlerNonNull(static_cast<JSContext
*>(nullptr),
1283 handler
, handlerGlobal
,
1284 /* aIncumbentGlobal = */ nullptr);
1285 jsEventHandler
->SetHandler(handlerCallback
);
1286 } else if (jsEventHandler
->EventName() == nsGkAtoms::onbeforeunload
&& win
) {
1287 RefPtr
<OnBeforeUnloadEventHandlerNonNull
> handlerCallback
=
1288 new OnBeforeUnloadEventHandlerNonNull(static_cast<JSContext
*>(nullptr),
1289 handler
, handlerGlobal
,
1290 /* aIncumbentGlobal = */ nullptr);
1291 jsEventHandler
->SetHandler(handlerCallback
);
1293 RefPtr
<EventHandlerNonNull
> handlerCallback
= new EventHandlerNonNull(
1294 static_cast<JSContext
*>(nullptr), handler
, handlerGlobal
,
1295 /* aIncumbentGlobal = */ nullptr);
1296 jsEventHandler
->SetHandler(handlerCallback
);
1302 nsresult
EventListenerManager::HandleEventSubType(Listener
* aListener
,
1304 EventTarget
* aCurrentTarget
) {
1305 nsresult result
= NS_OK
;
1307 EventListenerHolder
listenerHolder(aListener
->mListener
.Clone());
1309 // If this is a script handler and we haven't yet
1310 // compiled the event handler itself
1311 if ((aListener
->mListenerType
== Listener::eJSEventListener
) &&
1312 aListener
->mHandlerIsString
) {
1313 result
= CompileEventHandlerInternal(aListener
, nullptr, nullptr);
1314 aListener
= nullptr;
1317 if (NS_SUCCEEDED(result
)) {
1318 Maybe
<EventCallbackDebuggerNotificationGuard
> dbgGuard
;
1319 if (dom::ChromeUtils::IsDevToolsOpened()) {
1320 dbgGuard
.emplace(aCurrentTarget
, aDOMEvent
);
1324 // Event::currentTarget is set in EventDispatcher.
1325 if (listenerHolder
.HasWebIDLCallback()) {
1327 listenerHolder
.GetWebIDLCallback()->HandleEvent(aCurrentTarget
,
1329 result
= rv
.StealNSResult();
1331 // listenerHolder is holding a stack ref here.
1332 result
= MOZ_KnownLive(listenerHolder
.GetXPCOMCallback())
1333 ->HandleEvent(aDOMEvent
);
1340 EventMessage
EventListenerManager::GetLegacyEventMessage(
1341 EventMessage aEventMessage
) const {
1342 // webkit-prefixed legacy events:
1343 if (aEventMessage
== eTransitionEnd
) {
1344 return eWebkitTransitionEnd
;
1346 if (aEventMessage
== eAnimationStart
) {
1347 return eWebkitAnimationStart
;
1349 if (aEventMessage
== eAnimationEnd
) {
1350 return eWebkitAnimationEnd
;
1352 if (aEventMessage
== eAnimationIteration
) {
1353 return eWebkitAnimationIteration
;
1356 switch (aEventMessage
) {
1357 case eFullscreenChange
:
1358 return eMozFullscreenChange
;
1359 case eFullscreenError
:
1360 return eMozFullscreenError
;
1362 return aEventMessage
;
1366 EventMessage
EventListenerManager::GetEventMessage(nsAtom
* aEventName
) const {
1367 if (mIsMainThreadELM
) {
1368 return nsContentUtils::GetEventMessage(aEventName
);
1371 // The nsContentUtils event message hashtables aren't threadsafe, so just fall
1372 // back to eUnidentifiedEvent.
1373 return eUnidentifiedEvent
;
1376 EventMessage
EventListenerManager::GetEventMessageAndAtomForListener(
1377 const nsAString
& aType
, nsAtom
** aAtom
) {
1378 if (mIsMainThreadELM
) {
1379 return nsContentUtils::GetEventMessageAndAtomForListener(aType
, aAtom
);
1382 *aAtom
= NS_Atomize(u
"on"_ns
+ aType
).take();
1383 return eUnidentifiedEvent
;
1386 already_AddRefed
<nsPIDOMWindowInner
> EventListenerManager::WindowFromListener(
1387 Listener
* aListener
, bool aItemInShadowTree
) {
1388 nsCOMPtr
<nsPIDOMWindowInner
> innerWindow
;
1389 if (!aItemInShadowTree
) {
1390 if (aListener
->mListener
.HasWebIDLCallback()) {
1391 CallbackObject
* callback
= aListener
->mListener
.GetWebIDLCallback();
1392 nsIGlobalObject
* global
= nullptr;
1394 global
= callback
->IncumbentGlobalOrNull();
1397 innerWindow
= global
->AsInnerWindow(); // Can be nullptr
1400 // Can't get the global from
1401 // listener->mListener.GetXPCOMCallback().
1402 // In most cases, it would be the same as for
1403 // the target, so let's do that.
1404 innerWindow
= GetInnerWindowForTarget(); // Can be nullptr
1407 return innerWindow
.forget();
1411 * Causes a check for event listeners and processing by them if they exist.
1412 * @param an event listener
1415 void EventListenerManager::HandleEventInternal(nsPresContext
* aPresContext
,
1416 WidgetEvent
* aEvent
,
1418 EventTarget
* aCurrentTarget
,
1419 nsEventStatus
* aEventStatus
,
1420 bool aItemInShadowTree
) {
1421 // Set the value of the internal PreventDefault flag properly based on
1423 if (!aEvent
->DefaultPrevented() &&
1424 *aEventStatus
== nsEventStatus_eConsumeNoDefault
) {
1425 // Assume that if only aEventStatus claims that the event has already been
1426 // consumed, the consumer is default event handler.
1427 aEvent
->PreventDefault();
1430 Maybe
<AutoHandlingUserInputStatePusher
> userInputStatePusher
;
1431 Maybe
<AutoPopupStatePusher
> popupStatePusher
;
1432 if (mIsMainThreadELM
) {
1433 userInputStatePusher
.emplace(UserActivation::IsUserInteractionEvent(aEvent
),
1435 popupStatePusher
.emplace(
1436 PopupBlocker::GetEventPopupControlState(aEvent
, *aDOMEvent
));
1439 bool hasListener
= false;
1440 bool hasListenerForCurrentGroup
= false;
1441 bool usingLegacyMessage
= false;
1442 bool hasRemovedListener
= false;
1443 EventMessage eventMessage
= aEvent
->mMessage
;
1446 Maybe
<EventMessageAutoOverride
> legacyAutoOverride
;
1447 for (Listener
& listenerRef
: mListeners
.EndLimitedRange()) {
1448 if (aEvent
->mFlags
.mImmediatePropagationStopped
) {
1451 Listener
* listener
= &listenerRef
;
1452 // Check that the phase is same in event and event listener.
1453 // Handle only trusted events, except when listener permits untrusted
1455 if (ListenerCanHandle(listener
, aEvent
, eventMessage
)) {
1457 hasListenerForCurrentGroup
=
1458 hasListenerForCurrentGroup
||
1459 listener
->mFlags
.mInSystemGroup
== aEvent
->mFlags
.mInSystemGroup
;
1460 if (listener
->IsListening(aEvent
) &&
1461 (aEvent
->IsTrusted() || listener
->mFlags
.mAllowUntrustedEvents
)) {
1463 // This is tiny bit slow, but happens only once per event.
1464 // Similar code also in EventDispatcher.
1465 nsCOMPtr
<EventTarget
> et
= aEvent
->mOriginalTarget
;
1466 RefPtr
<Event
> event
=
1467 EventDispatcher::CreateEvent(et
, aPresContext
, aEvent
, u
""_ns
);
1468 event
.forget(aDOMEvent
);
1471 if (!aEvent
->mCurrentTarget
) {
1472 aEvent
->mCurrentTarget
= aCurrentTarget
->GetTargetForDOMEvent();
1473 if (!aEvent
->mCurrentTarget
) {
1477 if (usingLegacyMessage
&& !legacyAutoOverride
) {
1478 // Override the aDOMEvent's event-message (its .type) until we
1479 // finish traversing listeners (when legacyAutoOverride destructs)
1480 legacyAutoOverride
.emplace(*aDOMEvent
, eventMessage
);
1483 aEvent
->mFlags
.mInPassiveListener
= listener
->mFlags
.mPassive
;
1484 Maybe
<Listener
> listenerHolder
;
1485 if (listener
->mFlags
.mOnce
) {
1486 // Move the listener to the stack before handling the event.
1487 // The order is important, otherwise the listener could be
1488 // called again inside the listener.
1489 listenerHolder
.emplace(std::move(*listener
));
1490 listener
= listenerHolder
.ptr();
1491 hasRemovedListener
= true;
1494 nsCOMPtr
<nsPIDOMWindowInner
> innerWindow
=
1495 WindowFromListener(listener
, aItemInShadowTree
);
1496 mozilla::dom::Event
* oldWindowEvent
= nullptr;
1498 oldWindowEvent
= innerWindow
->SetEvent(*aDOMEvent
);
1502 HandleEventSubType(listener
, *aDOMEvent
, aCurrentTarget
);
1505 Unused
<< innerWindow
->SetEvent(oldWindowEvent
);
1508 if (NS_FAILED(rv
)) {
1509 aEvent
->mFlags
.mExceptionWasRaised
= true;
1511 aEvent
->mFlags
.mInPassiveListener
= false;
1517 // If we didn't find any matching listeners, and our event has a legacy
1518 // version, we'll now switch to looking for that legacy version and we'll
1519 // recheck our listeners.
1520 if (hasListenerForCurrentGroup
|| usingLegacyMessage
||
1521 !aEvent
->IsTrusted()) {
1522 // No need to recheck listeners, because we already found a match, we
1523 // already rechecked them, or it is not a trusted event.
1526 EventMessage legacyEventMessage
= GetLegacyEventMessage(eventMessage
);
1527 if (legacyEventMessage
== eventMessage
) {
1528 break; // There's no legacy version of our event; no need to recheck.
1531 GetLegacyEventMessage(legacyEventMessage
) == legacyEventMessage
,
1532 "Legacy event messages should not themselves have legacy versions");
1534 // Recheck our listeners, using the legacy event message we just looked up:
1535 eventMessage
= legacyEventMessage
;
1536 usingLegacyMessage
= true;
1539 aEvent
->mCurrentTarget
= nullptr;
1541 if (hasRemovedListener
) {
1542 // If there are any once listeners replaced with a placeholder in
1543 // the loop above, we need to clean up them here. Note that, this
1544 // could clear once listeners handled in some outer level as well,
1545 // but that should not affect the result.
1546 mListeners
.NonObservingRemoveElementsBy([](const Listener
& aListener
) {
1547 return aListener
.mListenerType
== Listener::eNoListener
;
1549 NotifyEventListenerRemoved(aEvent
->mSpecifiedEventType
);
1550 if (IsDeviceType(aEvent
->mMessage
)) {
1551 // This is a device-type event, we need to check whether we can
1552 // disable device after removing the once listeners.
1553 const auto [begin
, end
] = mListeners
.NonObservingRange();
1554 const bool hasAnyListener
=
1555 std::any_of(begin
, end
, [aEvent
](const Listener
& listenerRef
) {
1556 const Listener
* listener
= &listenerRef
;
1557 return EVENT_TYPE_EQUALS(listener
, aEvent
->mMessage
,
1558 aEvent
->mSpecifiedEventType
,
1559 /* all events */ false);
1562 if (!hasAnyListener
) {
1563 DisableDevice(aEvent
->mMessage
);
1568 if (mIsMainThreadELM
&& !hasListener
) {
1569 mNoListenerForEvent
= aEvent
->mMessage
;
1570 mNoListenerForEventAtom
= aEvent
->mSpecifiedEventType
;
1573 if (aEvent
->DefaultPrevented()) {
1574 *aEventStatus
= nsEventStatus_eConsumeNoDefault
;
1578 void EventListenerManager::Disconnect() {
1580 RemoveAllListenersSilently();
1583 void EventListenerManager::AddEventListener(const nsAString
& aType
,
1584 EventListenerHolder aListenerHolder
,
1586 bool aWantsUntrusted
) {
1587 EventListenerFlags flags
;
1588 flags
.mCapture
= aUseCapture
;
1589 flags
.mAllowUntrustedEvents
= aWantsUntrusted
;
1590 return AddEventListenerByType(std::move(aListenerHolder
), aType
, flags
);
1593 void EventListenerManager::AddEventListener(
1594 const nsAString
& aType
, EventListenerHolder aListenerHolder
,
1595 const dom::AddEventListenerOptionsOrBoolean
& aOptions
,
1596 bool aWantsUntrusted
) {
1597 EventListenerFlags flags
;
1598 Optional
<bool> passive
;
1599 AbortSignal
* signal
= nullptr;
1600 if (aOptions
.IsBoolean()) {
1601 flags
.mCapture
= aOptions
.GetAsBoolean();
1603 const auto& options
= aOptions
.GetAsAddEventListenerOptions();
1604 flags
.mCapture
= options
.mCapture
;
1605 flags
.mInSystemGroup
= options
.mMozSystemGroup
;
1606 flags
.mOnce
= options
.mOnce
;
1607 if (options
.mPassive
.WasPassed()) {
1608 passive
.Construct(options
.mPassive
.Value());
1611 if (options
.mSignal
.WasPassed()) {
1612 signal
= &options
.mSignal
.Value();
1616 flags
.mAllowUntrustedEvents
= aWantsUntrusted
;
1617 return AddEventListenerByType(std::move(aListenerHolder
), aType
, flags
,
1621 void EventListenerManager::RemoveEventListener(
1622 const nsAString
& aType
, EventListenerHolder aListenerHolder
,
1624 EventListenerFlags flags
;
1625 flags
.mCapture
= aUseCapture
;
1626 RemoveEventListenerByType(std::move(aListenerHolder
), aType
, flags
);
1629 void EventListenerManager::RemoveEventListener(
1630 const nsAString
& aType
, EventListenerHolder aListenerHolder
,
1631 const dom::EventListenerOptionsOrBoolean
& aOptions
) {
1632 EventListenerFlags flags
;
1633 if (aOptions
.IsBoolean()) {
1634 flags
.mCapture
= aOptions
.GetAsBoolean();
1636 const auto& options
= aOptions
.GetAsEventListenerOptions();
1637 flags
.mCapture
= options
.mCapture
;
1638 flags
.mInSystemGroup
= options
.mMozSystemGroup
;
1640 RemoveEventListenerByType(std::move(aListenerHolder
), aType
, flags
);
1643 void EventListenerManager::AddListenerForAllEvents(EventListener
* aDOMListener
,
1645 bool aWantsUntrusted
,
1646 bool aSystemEventGroup
) {
1647 EventListenerFlags flags
;
1648 flags
.mCapture
= aUseCapture
;
1649 flags
.mAllowUntrustedEvents
= aWantsUntrusted
;
1650 flags
.mInSystemGroup
= aSystemEventGroup
;
1651 AddEventListenerInternal(EventListenerHolder(aDOMListener
), eAllEvents
,
1652 nullptr, flags
, false, true);
1655 void EventListenerManager::RemoveListenerForAllEvents(
1656 EventListener
* aDOMListener
, bool aUseCapture
, bool aSystemEventGroup
) {
1657 EventListenerFlags flags
;
1658 flags
.mCapture
= aUseCapture
;
1659 flags
.mInSystemGroup
= aSystemEventGroup
;
1660 RemoveEventListenerInternal(EventListenerHolder(aDOMListener
), eAllEvents
,
1661 nullptr, flags
, true);
1664 bool EventListenerManager::HasMutationListeners() {
1665 if (mMayHaveMutationListeners
) {
1666 uint32_t count
= mListeners
.Length();
1667 for (uint32_t i
= 0; i
< count
; ++i
) {
1668 Listener
* listener
= &mListeners
.ElementAt(i
);
1669 if (listener
->mEventMessage
>= eLegacyMutationEventFirst
&&
1670 listener
->mEventMessage
<= eLegacyMutationEventLast
) {
1679 uint32_t EventListenerManager::MutationListenerBits() {
1681 if (mMayHaveMutationListeners
) {
1682 uint32_t count
= mListeners
.Length();
1683 for (uint32_t i
= 0; i
< count
; ++i
) {
1684 Listener
* listener
= &mListeners
.ElementAt(i
);
1685 if (listener
->mEventMessage
>= eLegacyMutationEventFirst
&&
1686 listener
->mEventMessage
<= eLegacyMutationEventLast
) {
1687 if (listener
->mEventMessage
== eLegacySubtreeModified
) {
1688 return kAllMutationBits
;
1690 bits
|= MutationBitForEventType(listener
->mEventMessage
);
1697 bool EventListenerManager::HasListenersFor(const nsAString
& aEventName
) const {
1698 RefPtr
<nsAtom
> atom
= NS_Atomize(u
"on"_ns
+ aEventName
);
1699 return HasListenersFor(atom
);
1702 bool EventListenerManager::HasListenersFor(nsAtom
* aEventNameWithOn
) const {
1703 return HasListenersForInternal(aEventNameWithOn
, false);
1706 bool EventListenerManager::HasNonSystemGroupListenersFor(
1707 nsAtom
* aEventNameWithOn
) const {
1708 return HasListenersForInternal(aEventNameWithOn
, true);
1711 bool EventListenerManager::HasListenersForInternal(
1712 nsAtom
* aEventNameWithOn
, bool aIgnoreSystemGroup
) const {
1715 aEventNameWithOn
->ToString(name
);
1717 NS_ASSERTION(StringBeginsWith(name
, u
"on"_ns
),
1718 "Event name does not start with 'on'");
1719 uint32_t count
= mListeners
.Length();
1720 for (uint32_t i
= 0; i
< count
; ++i
) {
1721 const Listener
* listener
= &mListeners
.ElementAt(i
);
1722 if (listener
->mTypeAtom
== aEventNameWithOn
) {
1723 if (aIgnoreSystemGroup
&& listener
->mFlags
.mInSystemGroup
) {
1732 bool EventListenerManager::HasListeners() const {
1733 return !mListeners
.IsEmpty();
1736 nsresult
EventListenerManager::GetListenerInfo(
1737 nsTArray
<RefPtr
<nsIEventListenerInfo
>>& aList
) {
1738 nsCOMPtr
<EventTarget
> target
= mTarget
;
1739 NS_ENSURE_STATE(target
);
1741 for (const Listener
& listener
: mListeners
.ForwardRange()) {
1742 // If this is a script handler and we haven't yet
1743 // compiled the event handler itself go ahead and compile it
1744 if (listener
.mListenerType
== Listener::eJSEventListener
&&
1745 listener
.mHandlerIsString
) {
1746 CompileEventHandlerInternal(const_cast<Listener
*>(&listener
), nullptr,
1749 nsAutoString eventType
;
1750 if (listener
.mAllEvents
) {
1751 eventType
.SetIsVoid(true);
1752 } else if (listener
.mListenerType
== Listener::eNoListener
) {
1755 eventType
.Assign(Substring(nsDependentAtomString(listener
.mTypeAtom
), 2));
1758 JS::Rooted
<JSObject
*> callback(RootingCx());
1759 JS::Rooted
<JSObject
*> callbackGlobal(RootingCx());
1760 if (JSEventHandler
* handler
= listener
.GetJSEventHandler()) {
1761 if (handler
->GetTypedEventHandler().HasEventHandler()) {
1762 CallbackFunction
* callbackFun
= handler
->GetTypedEventHandler().Ptr();
1763 callback
= callbackFun
->CallableOrNull();
1764 callbackGlobal
= callbackFun
->CallbackGlobalOrNull();
1766 // This will be null for cross-compartment event listeners
1767 // which have been destroyed.
1771 } else if (listener
.mListenerType
== Listener::eWebIDLListener
) {
1772 EventListener
* listenerCallback
= listener
.mListener
.GetWebIDLCallback();
1773 callback
= listenerCallback
->CallbackOrNull();
1774 callbackGlobal
= listenerCallback
->CallbackGlobalOrNull();
1776 // This will be null for cross-compartment event listeners
1777 // which have been destroyed.
1782 RefPtr
<EventListenerInfo
> info
= new EventListenerInfo(
1783 this, eventType
, callback
, callbackGlobal
, listener
.mFlags
.mCapture
,
1784 listener
.mFlags
.mAllowUntrustedEvents
, listener
.mFlags
.mInSystemGroup
,
1785 listener
.mListenerIsHandler
);
1786 aList
.AppendElement(info
.forget());
1791 EventListenerManager::Listener
* EventListenerManager::GetListenerFor(
1792 nsAString
& aType
, JSObject
* aListener
, bool aCapturing
,
1793 bool aAllowsUntrusted
, bool aInSystemEventGroup
, bool aIsHandler
) {
1794 NS_ENSURE_TRUE(aListener
, nullptr);
1796 for (Listener
& listener
: mListeners
.ForwardRange()) {
1797 if ((aType
.IsVoid() && !listener
.mAllEvents
) ||
1798 !Substring(nsDependentAtomString(listener
.mTypeAtom
), 2)
1800 listener
.mListenerType
== Listener::eNoListener
) {
1804 if (listener
.mFlags
.mCapture
!= aCapturing
||
1805 listener
.mFlags
.mAllowUntrustedEvents
!= aAllowsUntrusted
||
1806 listener
.mFlags
.mInSystemGroup
!= aInSystemEventGroup
) {
1811 if (JSEventHandler
* handler
= listener
.GetJSEventHandler()) {
1812 if (handler
->GetTypedEventHandler().HasEventHandler()) {
1813 if (handler
->GetTypedEventHandler().Ptr()->CallableOrNull() ==
1819 } else if (listener
.mListenerType
== Listener::eWebIDLListener
&&
1820 listener
.mListener
.GetWebIDLCallback()->CallbackOrNull() ==
1828 nsresult
EventListenerManager::IsListenerEnabled(
1829 nsAString
& aType
, JSObject
* aListener
, bool aCapturing
,
1830 bool aAllowsUntrusted
, bool aInSystemEventGroup
, bool aIsHandler
,
1832 Listener
* listener
=
1833 GetListenerFor(aType
, aListener
, aCapturing
, aAllowsUntrusted
,
1834 aInSystemEventGroup
, aIsHandler
);
1835 NS_ENSURE_TRUE(listener
, NS_ERROR_NOT_AVAILABLE
);
1836 *aEnabled
= listener
->mEnabled
;
1840 nsresult
EventListenerManager::SetListenerEnabled(
1841 nsAString
& aType
, JSObject
* aListener
, bool aCapturing
,
1842 bool aAllowsUntrusted
, bool aInSystemEventGroup
, bool aIsHandler
,
1844 Listener
* listener
=
1845 GetListenerFor(aType
, aListener
, aCapturing
, aAllowsUntrusted
,
1846 aInSystemEventGroup
, aIsHandler
);
1847 NS_ENSURE_TRUE(listener
, NS_ERROR_NOT_AVAILABLE
);
1848 listener
->mEnabled
= aEnabled
;
1850 // We may have enabled some listener, clear the cache for which events
1851 // we don't have listeners.
1852 mNoListenerForEvent
= eVoidEvent
;
1853 mNoListenerForEventAtom
= nullptr;
1858 bool EventListenerManager::HasUnloadListeners() {
1859 uint32_t count
= mListeners
.Length();
1860 for (uint32_t i
= 0; i
< count
; ++i
) {
1861 Listener
* listener
= &mListeners
.ElementAt(i
);
1862 if (listener
->mEventMessage
== eUnload
) {
1869 bool EventListenerManager::HasBeforeUnloadListeners() {
1870 uint32_t count
= mListeners
.Length();
1871 for (uint32_t i
= 0; i
< count
; ++i
) {
1872 Listener
* listener
= &mListeners
.ElementAt(i
);
1873 if (listener
->mEventMessage
== eBeforeUnload
) {
1880 void EventListenerManager::SetEventHandler(nsAtom
* aEventName
,
1881 EventHandlerNonNull
* aHandler
) {
1883 RemoveEventHandler(aEventName
);
1887 // Untrusted events are always permitted for non-chrome script
1889 SetEventHandlerInternal(
1890 aEventName
, TypedEventHandler(aHandler
),
1891 !mIsMainThreadELM
|| !nsContentUtils::IsCallerChrome());
1894 void EventListenerManager::SetEventHandler(
1895 OnErrorEventHandlerNonNull
* aHandler
) {
1897 RemoveEventHandler(nsGkAtoms::onerror
);
1901 // Untrusted events are always permitted on workers and for non-chrome script
1902 // on the main thread.
1903 bool allowUntrusted
= !mIsMainThreadELM
|| !nsContentUtils::IsCallerChrome();
1905 SetEventHandlerInternal(nsGkAtoms::onerror
, TypedEventHandler(aHandler
),
1909 void EventListenerManager::SetEventHandler(
1910 OnBeforeUnloadEventHandlerNonNull
* aHandler
) {
1912 RemoveEventHandler(nsGkAtoms::onbeforeunload
);
1916 // Untrusted events are always permitted for non-chrome script
1918 SetEventHandlerInternal(
1919 nsGkAtoms::onbeforeunload
, TypedEventHandler(aHandler
),
1920 !mIsMainThreadELM
|| !nsContentUtils::IsCallerChrome());
1923 const TypedEventHandler
* EventListenerManager::GetTypedEventHandler(
1924 nsAtom
* aEventName
) {
1925 EventMessage eventMessage
= GetEventMessage(aEventName
);
1926 Listener
* listener
= FindEventHandler(eventMessage
, aEventName
);
1932 JSEventHandler
* jsEventHandler
= listener
->GetJSEventHandler();
1934 if (listener
->mHandlerIsString
) {
1935 CompileEventHandlerInternal(listener
, nullptr, nullptr);
1938 const TypedEventHandler
& typedHandler
=
1939 jsEventHandler
->GetTypedEventHandler();
1940 return typedHandler
.HasEventHandler() ? &typedHandler
: nullptr;
1943 size_t EventListenerManager::SizeOfIncludingThis(
1944 MallocSizeOf aMallocSizeOf
) const {
1945 size_t n
= aMallocSizeOf(this);
1946 n
+= mListeners
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
1947 uint32_t count
= mListeners
.Length();
1948 for (uint32_t i
= 0; i
< count
; ++i
) {
1949 JSEventHandler
* jsEventHandler
=
1950 mListeners
.ElementAt(i
).GetJSEventHandler();
1951 if (jsEventHandler
) {
1952 n
+= jsEventHandler
->SizeOfIncludingThis(aMallocSizeOf
);
1958 void EventListenerManager::MarkForCC() {
1959 uint32_t count
= mListeners
.Length();
1960 for (uint32_t i
= 0; i
< count
; ++i
) {
1961 const Listener
& listener
= mListeners
.ElementAt(i
);
1962 JSEventHandler
* jsEventHandler
= listener
.GetJSEventHandler();
1963 if (jsEventHandler
) {
1964 const TypedEventHandler
& typedHandler
=
1965 jsEventHandler
->GetTypedEventHandler();
1966 if (typedHandler
.HasEventHandler()) {
1967 typedHandler
.Ptr()->MarkForCC();
1969 } else if (listener
.mListenerType
== Listener::eWebIDLListener
) {
1970 listener
.mListener
.GetWebIDLCallback()->MarkForCC();
1973 if (mRefCnt
.IsPurple()) {
1974 mRefCnt
.RemovePurple();
1978 void EventListenerManager::TraceListeners(JSTracer
* aTrc
) {
1979 uint32_t count
= mListeners
.Length();
1980 for (uint32_t i
= 0; i
< count
; ++i
) {
1981 const Listener
& listener
= mListeners
.ElementAt(i
);
1982 JSEventHandler
* jsEventHandler
= listener
.GetJSEventHandler();
1983 if (jsEventHandler
) {
1984 const TypedEventHandler
& typedHandler
=
1985 jsEventHandler
->GetTypedEventHandler();
1986 if (typedHandler
.HasEventHandler()) {
1987 mozilla::TraceScriptHolder(typedHandler
.Ptr(), aTrc
);
1989 } else if (listener
.mListenerType
== Listener::eWebIDLListener
) {
1990 mozilla::TraceScriptHolder(listener
.mListener
.GetWebIDLCallback(), aTrc
);
1992 // We might have eWrappedJSListener, but that is the legacy type for
1993 // JS implemented event listeners, and trickier to handle here.
1997 bool EventListenerManager::HasNonSystemGroupListenersForUntrustedKeyEvents() {
1998 uint32_t count
= mListeners
.Length();
1999 for (uint32_t i
= 0; i
< count
; ++i
) {
2000 Listener
* listener
= &mListeners
.ElementAt(i
);
2001 if (!listener
->mFlags
.mInSystemGroup
&&
2002 listener
->mFlags
.mAllowUntrustedEvents
&&
2003 (listener
->mTypeAtom
== nsGkAtoms::onkeydown
||
2004 listener
->mTypeAtom
== nsGkAtoms::onkeypress
||
2005 listener
->mTypeAtom
== nsGkAtoms::onkeyup
)) {
2012 bool EventListenerManager::
2013 HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents() {
2014 uint32_t count
= mListeners
.Length();
2015 for (uint32_t i
= 0; i
< count
; ++i
) {
2016 Listener
* listener
= &mListeners
.ElementAt(i
);
2017 if (!listener
->mFlags
.mPassive
&& !listener
->mFlags
.mInSystemGroup
&&
2018 listener
->mFlags
.mAllowUntrustedEvents
&&
2019 (listener
->mTypeAtom
== nsGkAtoms::onkeydown
||
2020 listener
->mTypeAtom
== nsGkAtoms::onkeypress
||
2021 listener
->mTypeAtom
== nsGkAtoms::onkeyup
)) {
2028 bool EventListenerManager::HasApzAwareListeners() {
2029 uint32_t count
= mListeners
.Length();
2030 for (uint32_t i
= 0; i
< count
; ++i
) {
2031 Listener
* listener
= &mListeners
.ElementAt(i
);
2032 if (IsApzAwareListener(listener
)) {
2039 bool EventListenerManager::IsApzAwareListener(Listener
* aListener
) {
2040 return !aListener
->mFlags
.mPassive
&& mIsMainThreadELM
&&
2041 IsApzAwareEvent(aListener
->mTypeAtom
);
2044 static bool IsWheelEventType(nsAtom
* aEvent
) {
2045 if (aEvent
== nsGkAtoms::onwheel
|| aEvent
== nsGkAtoms::onDOMMouseScroll
||
2046 aEvent
== nsGkAtoms::onmousewheel
||
2047 aEvent
== nsGkAtoms::onMozMousePixelScroll
) {
2053 bool EventListenerManager::IsApzAwareEvent(nsAtom
* aEvent
) {
2054 if (IsWheelEventType(aEvent
)) {
2057 // In theory we should schedule a repaint if the touch event pref changes,
2058 // because the event regions might be out of date. In practice that seems like
2059 // overkill because users generally shouldn't be flipping this pref, much
2060 // less expecting touch listeners on the page to immediately start preventing
2061 // scrolling without so much as a repaint. Tests that we write can work
2062 // around this constraint easily enough.
2063 if (aEvent
== nsGkAtoms::ontouchstart
|| aEvent
== nsGkAtoms::ontouchmove
) {
2064 return TouchEvent::PrefEnabled(
2065 nsContentUtils::GetDocShellForEventTarget(mTarget
));
2070 bool EventListenerManager::HasNonPassiveWheelListener() {
2071 MOZ_ASSERT(NS_IsMainThread());
2072 uint32_t count
= mListeners
.Length();
2073 for (uint32_t i
= 0; i
< count
; ++i
) {
2074 Listener
* listener
= &mListeners
.ElementAt(i
);
2075 if (!listener
->mFlags
.mPassive
&& IsWheelEventType(listener
->mTypeAtom
)) {
2082 void EventListenerManager::RemoveAllListeners() {
2083 while (!mListeners
.IsEmpty()) {
2084 size_t idx
= mListeners
.Length() - 1;
2085 RefPtr
<nsAtom
> type
= mListeners
.ElementAt(idx
).mTypeAtom
;
2086 EventMessage message
= mListeners
.ElementAt(idx
).mEventMessage
;
2087 mListeners
.RemoveElementAt(idx
);
2088 NotifyEventListenerRemoved(type
);
2089 if (IsDeviceType(message
)) {
2090 DisableDevice(message
);
2095 already_AddRefed
<nsIScriptGlobalObject
>
2096 EventListenerManager::GetScriptGlobalAndDocument(Document
** aDoc
) {
2097 nsCOMPtr
<Document
> doc
;
2098 nsCOMPtr
<nsPIDOMWindowInner
> win
;
2099 if (nsINode
* node
= nsINode::FromEventTargetOrNull(mTarget
)) {
2100 // Try to get context from doc
2101 doc
= node
->OwnerDoc();
2102 if (doc
->IsLoadedAsData()) {
2106 win
= do_QueryInterface(doc
->GetScopeObject());
2107 } else if ((win
= GetTargetAsInnerWindow())) {
2108 doc
= win
->GetExtantDoc();
2111 if (!win
|| !win
->IsCurrentInnerWindow()) {
2116 nsCOMPtr
<nsIScriptGlobalObject
> global
= do_QueryInterface(win
);
2117 return global
.forget();
2120 EventListenerManager::ListenerSignalFollower::ListenerSignalFollower(
2121 EventListenerManager
* aListenerManager
,
2122 EventListenerManager::Listener
* aListener
)
2123 : dom::AbortFollower(),
2124 mListenerManager(aListenerManager
),
2125 mListener(aListener
->mListener
.Clone()),
2126 mTypeAtom(aListener
->mTypeAtom
),
2127 mEventMessage(aListener
->mEventMessage
),
2128 mAllEvents(aListener
->mAllEvents
),
2129 mFlags(aListener
->mFlags
){};
2131 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager::ListenerSignalFollower
)
2133 NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerManager::ListenerSignalFollower
)
2134 NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerManager::ListenerSignalFollower
)
2136 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
2137 EventListenerManager::ListenerSignalFollower
)
2138 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener
)
2139 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2141 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(
2142 EventListenerManager::ListenerSignalFollower
)
2143 NS_IMPL_CYCLE_COLLECTION_UNLINK(mListener
)
2144 tmp
->mListenerManager
= nullptr;
2145 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2147 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
2148 EventListenerManager::ListenerSignalFollower
)
2149 NS_INTERFACE_MAP_ENTRY(nsISupports
)
2150 NS_INTERFACE_MAP_END
2152 void EventListenerManager::ListenerSignalFollower::RunAbortAlgorithm() {
2153 if (mListenerManager
) {
2154 RefPtr
<EventListenerManager
> elm
= mListenerManager
;
2155 mListenerManager
= nullptr;
2156 elm
->RemoveEventListenerInternal(std::move(mListener
), mEventMessage
,
2157 mTypeAtom
, mFlags
, mAllEvents
);
2161 } // namespace mozilla