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/. */
6 
7 // Microsoft's API Name hackery sucks
8 #undef CreateEvent
9 
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/TimelineConsumers.h"
37 #include "mozilla/EventTimelineMarker.h"
38 #include "mozilla/TimeStamp.h"
39 
40 #include "EventListenerService.h"
41 #include "nsCOMPtr.h"
42 #include "nsContentUtils.h"
43 #include "nsDOMCID.h"
44 #include "nsError.h"
45 #include "nsGenericHTMLElement.h"
46 #include "nsGkAtoms.h"
47 #include "nsIContent.h"
48 #include "nsIContentSecurityPolicy.h"
49 #include "mozilla/dom/Document.h"
50 #include "nsIScriptGlobalObject.h"
51 #include "nsISupports.h"
52 #include "nsJSUtils.h"
53 #include "nsNameSpaceManager.h"
54 #include "nsPIDOMWindow.h"
55 #include "nsPrintfCString.h"
56 #include "nsSandboxFlags.h"
57 #include "xpcpublic.h"
58 #include "nsIFrame.h"
59 #include "nsDisplayList.h"
60 
61 namespace mozilla {
62 
63 using namespace dom;
64 using namespace hal;
65 
66 #define EVENT_TYPE_EQUALS(ls, message, userType, allEvents)                    \
67   ((ls->mEventMessage == message &&                                            \
68     (ls->mEventMessage != eUnidentifiedEvent || ls->mTypeAtom == userType)) || \
69    (allEvents && ls->mAllEvents))
70 
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;
78 
MutationBitForEventType(EventMessage aEventType)79 static uint32_t MutationBitForEventType(EventMessage aEventType) {
80   switch (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;
95     default:
96       break;
97   }
98   return 0;
99 }
100 
101 uint32_t EventListenerManager::sMainThreadCreatedCount = 0;
102 
EventListenerManagerBase()103 EventListenerManagerBase::EventListenerManagerBase()
104     : mNoListenerForEvent(eVoidEvent),
105       mMayHavePaintEventListener(false),
106       mMayHaveMutationListeners(false),
107       mMayHaveCapturingListeners(false),
108       mMayHaveSystemGroupListeners(false),
109       mMayHaveTouchEventListener(false),
110       mMayHaveMouseEnterLeaveEventListener(false),
111       mMayHavePointerEnterLeaveEventListener(false),
112       mMayHaveKeyEventListener(false),
113       mMayHaveInputOrCompositionEventListener(false),
114       mMayHaveSelectionChangeEventListener(false),
115       mMayHaveFormSelectEventListener(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!");
122 }
123 
EventListenerManager(EventTarget * aTarget)124 EventListenerManager::EventListenerManager(EventTarget* aTarget)
125     : EventListenerManagerBase(), mTarget(aTarget) {
126   NS_ASSERTION(aTarget, "unexpected null pointer");
127 
128   if (mIsMainThreadELM) {
129     ++sMainThreadCreatedCount;
130   }
131 }
132 
~EventListenerManager()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();
145 }
146 
RemoveAllListenersSilently()147 void EventListenerManager::RemoveAllListenersSilently() {
148   if (mClearingListeners) {
149     return;
150   }
151   mClearingListeners = true;
152   mListeners.Clear();
153   mClearingListeners = false;
154 }
155 
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(EventListenerManager,AddRef)156 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(EventListenerManager, AddRef)
157 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(EventListenerManager, Release)
158 
159 inline void ImplCycleCollectionTraverse(
160     nsCycleCollectionTraversalCallback& aCallback,
161     EventListenerManager::Listener& aField, const char* aName,
162     unsigned aFlags) {
163   if (MOZ_UNLIKELY(aCallback.WantDebugInfo())) {
164     nsAutoCString name;
165     name.AppendASCII(aName);
166     if (aField.mTypeAtom) {
167       name.AppendLiteral(" event=");
168       name.Append(nsAtomCString(aField.mTypeAtom));
169       name.AppendLiteral(" listenerType=");
170       name.AppendInt(aField.mListenerType);
171       name.AppendLiteral(" ");
172     }
173     CycleCollectionNoteChild(aCallback, aField.mListener.GetISupports(),
174                              name.get(), aFlags);
175   } else {
176     CycleCollectionNoteChild(aCallback, aField.mListener.GetISupports(), aName,
177                              aFlags);
178   }
179 
180   CycleCollectionNoteChild(aCallback, aField.mSignalFollower.get(),
181                            "mSignalFollower", aFlags);
182 }
183 
184 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager)
185 
186 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(EventListenerManager)
187   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListeners)
188 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
189 
190 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(EventListenerManager)
191   tmp->Disconnect();
192 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
193 
GetInnerWindowForTarget()194 nsPIDOMWindowInner* EventListenerManager::GetInnerWindowForTarget() {
195   if (nsINode* node = nsINode::FromEventTargetOrNull(mTarget)) {
196     // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
197     // if that's the XBL document?
198     return node->OwnerDoc()->GetInnerWindow();
199   }
200 
201   nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow();
202   return window;
203 }
204 
205 already_AddRefed<nsPIDOMWindowInner>
GetTargetAsInnerWindow() const206 EventListenerManager::GetTargetAsInnerWindow() const {
207   nsCOMPtr<nsPIDOMWindowInner> window =
208       nsPIDOMWindowInner::FromEventTargetOrNull(mTarget);
209   return window.forget();
210 }
211 
AddEventListenerInternal(EventListenerHolder aListenerHolder,EventMessage aEventMessage,nsAtom * aTypeAtom,const EventListenerFlags & aFlags,bool aHandler,bool aAllEvents,AbortSignal * aSignal)212 void EventListenerManager::AddEventListenerInternal(
213     EventListenerHolder aListenerHolder, EventMessage aEventMessage,
214     nsAtom* aTypeAtom, const EventListenerFlags& aFlags, bool aHandler,
215     bool aAllEvents, AbortSignal* aSignal) {
216   MOZ_ASSERT((aEventMessage && aTypeAtom) || aAllEvents,  // all-events listener
217              "Missing type");
218 
219   if (!aListenerHolder || mClearingListeners) {
220     return;
221   }
222 
223   if (aSignal && aSignal->Aborted()) {
224     return;
225   }
226 
227   // Since there is no public API to call us with an EventListenerHolder, we
228   // know that there's an EventListenerHolder on the stack holding a strong ref
229   // to the listener.
230 
231   Listener* listener;
232   uint32_t count = mListeners.Length();
233   for (uint32_t i = 0; i < count; i++) {
234     listener = &mListeners.ElementAt(i);
235     // mListener == aListenerHolder is the last one, since it can be a bit slow.
236     if (listener->mListenerIsHandler == aHandler &&
237         listener->mFlags.EqualsForAddition(aFlags) &&
238         EVENT_TYPE_EQUALS(listener, aEventMessage, aTypeAtom, aAllEvents) &&
239         listener->mListener == aListenerHolder) {
240       return;
241     }
242   }
243 
244   mNoListenerForEvent = eVoidEvent;
245   mNoListenerForEventAtom = nullptr;
246 
247   listener =
248       aAllEvents ? mListeners.InsertElementAt(0) : mListeners.AppendElement();
249   listener->mEventMessage = aEventMessage;
250   listener->mTypeAtom = aTypeAtom;
251   listener->mFlags = aFlags;
252   listener->mListenerIsHandler = aHandler;
253   listener->mHandlerIsString = false;
254   listener->mAllEvents = aAllEvents;
255   listener->mIsChrome =
256       mIsMainThreadELM && nsContentUtils::LegacyIsCallerChromeOrNativeCode();
257 
258   // Detect the type of event listener.
259   if (aFlags.mListenerIsJSListener) {
260     MOZ_ASSERT(!aListenerHolder.HasWebIDLCallback());
261     listener->mListenerType = Listener::eJSEventListener;
262   } else if (aListenerHolder.HasWebIDLCallback()) {
263     listener->mListenerType = Listener::eWebIDLListener;
264   } else {
265     listener->mListenerType = Listener::eNativeListener;
266   }
267   listener->mListener = std::move(aListenerHolder);
268 
269   if (aSignal) {
270     listener->mSignalFollower = new ListenerSignalFollower(this, listener);
271     listener->mSignalFollower->Follow(aSignal);
272   }
273 
274   if (aFlags.mInSystemGroup) {
275     mMayHaveSystemGroupListeners = true;
276   }
277   if (aFlags.mCapture) {
278     mMayHaveCapturingListeners = true;
279   }
280 
281   // Events which are not supported in the running environment is mapped to
282   // eUnidentifiedEvent.  Then, we need to consider the proper event message
283   // with comparing the atom.
284   {
285     EventMessage resolvedEventMessage = aEventMessage;
286     if (resolvedEventMessage == eUnidentifiedEvent && aTypeAtom->IsStatic()) {
287       // TouchEvents are registered only when
288       // nsContentUtils::InitializeTouchEventTable() is called.
289       if (aTypeAtom == nsGkAtoms::ontouchstart) {
290         resolvedEventMessage = eTouchStart;
291       } else if (aTypeAtom == nsGkAtoms::ontouchend) {
292         resolvedEventMessage = eTouchEnd;
293       } else if (aTypeAtom == nsGkAtoms::ontouchmove) {
294         resolvedEventMessage = eTouchMove;
295       } else if (aTypeAtom == nsGkAtoms::ontouchcancel) {
296         resolvedEventMessage = eTouchCancel;
297       }
298     }
299 
300     switch (resolvedEventMessage) {
301       case eAfterPaint:
302         mMayHavePaintEventListener = true;
303         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
304           window->SetHasPaintEventListeners();
305         }
306         break;
307       case eLegacySubtreeModified:
308       case eLegacyNodeInserted:
309       case eLegacyNodeRemoved:
310       case eLegacyNodeRemovedFromDocument:
311       case eLegacyNodeInsertedIntoDocument:
312       case eLegacyAttrModified:
313       case eLegacyCharacterDataModified:
314         // For mutation listeners, we need to update the global bit on the DOM
315         // window. Otherwise we won't actually fire the mutation event.
316         mMayHaveMutationListeners = true;
317         // Go from our target to the nearest enclosing DOM window.
318         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
319           if (Document* doc = window->GetExtantDoc()) {
320             doc->WarnOnceAbout(DeprecatedOperations::eMutationEvent);
321           }
322           // If resolvedEventMessage is eLegacySubtreeModified, we need to
323           // listen all mutations. nsContentUtils::HasMutationListeners relies
324           // on this.
325           window->SetMutationListeners(
326               (resolvedEventMessage == eLegacySubtreeModified)
327                   ? kAllMutationBits
328                   : MutationBitForEventType(resolvedEventMessage));
329         }
330         break;
331       case ePointerEnter:
332       case ePointerLeave:
333         mMayHavePointerEnterLeaveEventListener = true;
334         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
335           NS_WARNING_ASSERTION(
336               !nsContentUtils::IsChromeDoc(window->GetExtantDoc()),
337               "Please do not use pointerenter/leave events in chrome. "
338               "They are slower than pointerover/out!");
339           window->SetHasPointerEnterLeaveEventListeners();
340         }
341         break;
342       case eGamepadButtonDown:
343       case eGamepadButtonUp:
344       case eGamepadAxisMove:
345       case eGamepadConnected:
346       case eGamepadDisconnected:
347         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
348           window->SetHasGamepadEventListener();
349         }
350         break;
351       case eDeviceOrientation:
352       case eAbsoluteDeviceOrientation:
353       case eUserProximity:
354       case eDeviceLight:
355       case eDeviceMotion:
356 #if defined(MOZ_WIDGET_ANDROID)
357       case eOrientationChange:
358 #endif  // #if defined(MOZ_WIDGET_ANDROID)
359         EnableDevice(resolvedEventMessage);
360         break;
361       case eTouchStart:
362       case eTouchEnd:
363       case eTouchMove:
364       case eTouchCancel:
365         mMayHaveTouchEventListener = true;
366         // we don't want touchevent listeners added by scrollbars to flip this
367         // flag so we ignore listeners created with system event flag
368         if (!aFlags.mInSystemGroup) {
369           if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
370             window->SetHasTouchEventListeners();
371           }
372         }
373         break;
374       case eMouseEnter:
375       case eMouseLeave:
376         mMayHaveMouseEnterLeaveEventListener = true;
377         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
378           NS_WARNING_ASSERTION(
379               !nsContentUtils::IsChromeDoc(window->GetExtantDoc()),
380               "Please do not use mouseenter/leave events in chrome. "
381               "They are slower than mouseover/out!");
382           window->SetHasMouseEnterLeaveEventListeners();
383         }
384         break;
385       case eKeyDown:
386       case eKeyPress:
387       case eKeyUp:
388         if (!aFlags.mInSystemGroup) {
389           mMayHaveKeyEventListener = true;
390         }
391         break;
392       case eCompositionEnd:
393       case eCompositionStart:
394       case eCompositionUpdate:
395       case eEditorInput:
396         if (!aFlags.mInSystemGroup) {
397           mMayHaveInputOrCompositionEventListener = true;
398         }
399         break;
400       case eEditorBeforeInput:
401         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
402           window->SetHasBeforeInputEventListenersForTelemetry();
403         }
404         break;
405       case eSelectionChange:
406         mMayHaveSelectionChangeEventListener = true;
407         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
408           window->SetHasSelectionChangeEventListeners();
409         }
410         break;
411       case eFormSelect:
412         mMayHaveFormSelectEventListener = true;
413         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
414           window->SetHasFormSelectEventListeners();
415         }
416         break;
417       case eMarqueeStart:
418         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
419           if (Document* doc = window->GetExtantDoc()) {
420             doc->SetUseCounter(eUseCounter_custom_onstart);
421           }
422         }
423         break;
424       case eMarqueeBounce:
425         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
426           if (Document* doc = window->GetExtantDoc()) {
427             doc->SetUseCounter(eUseCounter_custom_onbounce);
428           }
429         }
430         break;
431       case eMarqueeFinish:
432         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
433           if (Document* doc = window->GetExtantDoc()) {
434             doc->SetUseCounter(eUseCounter_custom_onfinish);
435           }
436         }
437         break;
438       case eScrollPortOverflow:
439         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
440           if (Document* doc = window->GetExtantDoc()) {
441             doc->SetUseCounter(eUseCounter_custom_onoverflow);
442           }
443         }
444         break;
445       case eScrollPortUnderflow:
446         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
447           if (Document* doc = window->GetExtantDoc()) {
448             doc->SetUseCounter(eUseCounter_custom_onunderflow);
449           }
450         }
451         break;
452       case eLegacyMouseLineOrPageScroll:
453         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
454           if (Document* doc = window->GetExtantDoc()) {
455             doc->SetUseCounter(eUseCounter_custom_ondommousescroll);
456           }
457         }
458         break;
459       case eLegacyMousePixelScroll:
460         if (nsPIDOMWindowInner* window = GetInnerWindowForTarget()) {
461           if (Document* doc = window->GetExtantDoc()) {
462             doc->SetUseCounter(eUseCounter_custom_onmozmousepixelscroll);
463           }
464         }
465         break;
466       default:
467         // XXX Use NS_ASSERTION here to print resolvedEventMessage since
468         //     MOZ_ASSERT can take only string literal, not pointer to
469         //     characters.
470         NS_ASSERTION(
471             resolvedEventMessage < eLegacyMutationEventFirst ||
472                 resolvedEventMessage > eLegacyMutationEventLast,
473             nsPrintfCString("You added new mutation event, but it's not "
474                             "handled above, resolvedEventMessage=%s",
475                             ToChar(resolvedEventMessage))
476                 .get());
477         NS_ASSERTION(aTypeAtom != nsGkAtoms::onpointerenter,
478                      nsPrintfCString("resolvedEventMessage=%s",
479                                      ToChar(resolvedEventMessage))
480                          .get());
481         NS_ASSERTION(aTypeAtom != nsGkAtoms::onpointerleave,
482                      nsPrintfCString("resolvedEventMessage=%s",
483                                      ToChar(resolvedEventMessage))
484                          .get());
485         NS_ASSERTION(
486             resolvedEventMessage < eGamepadEventFirst ||
487                 resolvedEventMessage > eGamepadEventLast,
488             nsPrintfCString("You added new gamepad event, but it's not "
489                             "handled above, resolvedEventMessage=%s",
490                             ToChar(resolvedEventMessage))
491                 .get());
492         NS_ASSERTION(aTypeAtom != nsGkAtoms::ondeviceorientation,
493                      nsPrintfCString("resolvedEventMessage=%s",
494                                      ToChar(resolvedEventMessage))
495                          .get());
496         NS_ASSERTION(aTypeAtom != nsGkAtoms::onabsolutedeviceorientation,
497                      nsPrintfCString("resolvedEventMessage=%s",
498                                      ToChar(resolvedEventMessage))
499                          .get());
500         NS_ASSERTION(aTypeAtom != nsGkAtoms::onuserproximity,
501                      nsPrintfCString("resolvedEventMessage=%s",
502                                      ToChar(resolvedEventMessage))
503                          .get());
504         NS_ASSERTION(aTypeAtom != nsGkAtoms::ondevicelight,
505                      nsPrintfCString("resolvedEventMessage=%s",
506                                      ToChar(resolvedEventMessage))
507                          .get());
508         NS_ASSERTION(aTypeAtom != nsGkAtoms::ondevicemotion,
509                      nsPrintfCString("resolvedEventMessage=%s",
510                                      ToChar(resolvedEventMessage))
511                          .get());
512 #if defined(MOZ_WIDGET_ANDROID)
513         NS_ASSERTION(aTypeAtom != nsGkAtoms::onorientationchange,
514                      nsPrintfCString("resolvedEventMessage=%s",
515                                      ToChar(resolvedEventMessage))
516                          .get());
517 #endif  // #if defined(MOZ_WIDGET_ANDROID)
518         NS_ASSERTION(aTypeAtom != nsGkAtoms::ontouchstart,
519                      nsPrintfCString("resolvedEventMessage=%s",
520                                      ToChar(resolvedEventMessage))
521                          .get());
522         NS_ASSERTION(aTypeAtom != nsGkAtoms::ontouchend,
523                      nsPrintfCString("resolvedEventMessage=%s",
524                                      ToChar(resolvedEventMessage))
525                          .get());
526         NS_ASSERTION(aTypeAtom != nsGkAtoms::ontouchmove,
527                      nsPrintfCString("resolvedEventMessage=%s",
528                                      ToChar(resolvedEventMessage))
529                          .get());
530         NS_ASSERTION(aTypeAtom != nsGkAtoms::ontouchcancel,
531                      nsPrintfCString("resolvedEventMessage=%s",
532                                      ToChar(resolvedEventMessage))
533                          .get());
534         NS_ASSERTION(aTypeAtom != nsGkAtoms::onmouseenter,
535                      nsPrintfCString("resolvedEventMessage=%s",
536                                      ToChar(resolvedEventMessage))
537                          .get());
538         NS_ASSERTION(aTypeAtom != nsGkAtoms::onmouseleave,
539                      nsPrintfCString("resolvedEventMessage=%s",
540                                      ToChar(resolvedEventMessage))
541                          .get());
542         NS_ASSERTION(aTypeAtom != nsGkAtoms::onkeydown,
543                      nsPrintfCString("resolvedEventMessage=%s",
544                                      ToChar(resolvedEventMessage))
545                          .get());
546         NS_ASSERTION(aTypeAtom != nsGkAtoms::onkeypress,
547                      nsPrintfCString("resolvedEventMessage=%s",
548                                      ToChar(resolvedEventMessage))
549                          .get());
550         NS_ASSERTION(aTypeAtom != nsGkAtoms::onkeyup,
551                      nsPrintfCString("resolvedEventMessage=%s",
552                                      ToChar(resolvedEventMessage))
553                          .get());
554         NS_ASSERTION(aTypeAtom != nsGkAtoms::oncompositionend,
555                      nsPrintfCString("resolvedEventMessage=%s",
556                                      ToChar(resolvedEventMessage))
557                          .get());
558         NS_ASSERTION(aTypeAtom != nsGkAtoms::oncompositionstart,
559                      nsPrintfCString("resolvedEventMessage=%s",
560                                      ToChar(resolvedEventMessage))
561                          .get());
562         NS_ASSERTION(aTypeAtom != nsGkAtoms::oncompositionupdate,
563                      nsPrintfCString("resolvedEventMessage=%s",
564                                      ToChar(resolvedEventMessage))
565                          .get());
566         NS_ASSERTION(aTypeAtom != nsGkAtoms::oninput,
567                      nsPrintfCString("resolvedEventMessage=%s",
568                                      ToChar(resolvedEventMessage))
569                          .get());
570         NS_ASSERTION(aTypeAtom != nsGkAtoms::onbeforeinput,
571                      nsPrintfCString("resolvedEventMessage=%s",
572                                      ToChar(resolvedEventMessage))
573                          .get());
574         NS_ASSERTION(aTypeAtom != nsGkAtoms::onselectionchange,
575                      nsPrintfCString("resolvedEventMessage=%s",
576                                      ToChar(resolvedEventMessage))
577                          .get());
578         NS_ASSERTION(aTypeAtom != nsGkAtoms::onselect,
579                      nsPrintfCString("resolvedEventMessage=%s",
580                                      ToChar(resolvedEventMessage))
581                          .get());
582         NS_ASSERTION(aTypeAtom != nsGkAtoms::onstart,
583                      nsPrintfCString("resolvedEventMessage=%s",
584                                      ToChar(resolvedEventMessage))
585                          .get());
586         NS_ASSERTION(aTypeAtom != nsGkAtoms::onbounce,
587                      nsPrintfCString("resolvedEventMessage=%s",
588                                      ToChar(resolvedEventMessage))
589                          .get());
590         NS_ASSERTION(aTypeAtom != nsGkAtoms::onfinish,
591                      nsPrintfCString("resolvedEventMessage=%s",
592                                      ToChar(resolvedEventMessage))
593                          .get());
594         NS_ASSERTION(aTypeAtom != nsGkAtoms::onoverflow,
595                      nsPrintfCString("resolvedEventMessage=%s",
596                                      ToChar(resolvedEventMessage))
597                          .get());
598         NS_ASSERTION(aTypeAtom != nsGkAtoms::onunderflow,
599                      nsPrintfCString("resolvedEventMessage=%s",
600                                      ToChar(resolvedEventMessage))
601                          .get());
602         NS_ASSERTION(aTypeAtom != nsGkAtoms::onDOMMouseScroll,
603                      nsPrintfCString("resolvedEventMessage=%s",
604                                      ToChar(resolvedEventMessage))
605                          .get());
606         NS_ASSERTION(aTypeAtom != nsGkAtoms::onMozMousePixelScroll,
607                      nsPrintfCString("resolvedEventMessage=%s",
608                                      ToChar(resolvedEventMessage))
609                          .get());
610         break;
611     }
612   }
613 
614   if (IsApzAwareListener(listener)) {
615     ProcessApzAwareEventListenerAdd();
616   }
617 
618   if (mTarget) {
619     mTarget->EventListenerAdded(aTypeAtom);
620   }
621 
622   if (mIsMainThreadELM && mTarget) {
623     EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
624                                                               aTypeAtom);
625   }
626 
627   if (!mHasNonPrivilegedClickListeners || mUnknownNonPrivilegedClickListeners) {
628     if (IsNonChromeClickListener(listener)) {
629       mHasNonPrivilegedClickListeners = true;
630       mUnknownNonPrivilegedClickListeners = false;
631     }
632   }
633 }
634 
ProcessApzAwareEventListenerAdd()635 void EventListenerManager::ProcessApzAwareEventListenerAdd() {
636   Document* doc = nullptr;
637 
638   // Mark the node as having apz aware listeners
639   if (nsINode* node = nsINode::FromEventTargetOrNull(mTarget)) {
640     node->SetMayBeApzAware();
641     doc = node->OwnerDoc();
642   }
643 
644   // Schedule a paint so event regions on the layer tree gets updated
645   if (!doc) {
646     if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
647       doc = window->GetExtantDoc();
648     }
649   }
650   if (!doc) {
651     if (nsCOMPtr<DOMEventTargetHelper> helper = do_QueryInterface(mTarget)) {
652       if (nsPIDOMWindowInner* window = helper->GetOwner()) {
653         doc = window->GetExtantDoc();
654       }
655     }
656   }
657 
658   if (doc && gfxPlatform::AsyncPanZoomEnabled()) {
659     PresShell* presShell = doc->GetPresShell();
660     if (presShell) {
661       nsIFrame* f = presShell->GetRootFrame();
662       if (f) {
663         f->SchedulePaint();
664       }
665     }
666   }
667 }
668 
IsDeviceType(EventMessage aEventMessage)669 bool EventListenerManager::IsDeviceType(EventMessage aEventMessage) {
670   switch (aEventMessage) {
671     case eDeviceOrientation:
672     case eAbsoluteDeviceOrientation:
673     case eDeviceMotion:
674     case eDeviceLight:
675     case eUserProximity:
676 #if defined(MOZ_WIDGET_ANDROID)
677     case eOrientationChange:
678 #endif
679       return true;
680     default:
681       break;
682   }
683   return false;
684 }
685 
EnableDevice(EventMessage aEventMessage)686 void EventListenerManager::EnableDevice(EventMessage aEventMessage) {
687   nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow();
688   if (!window) {
689     return;
690   }
691 
692   switch (aEventMessage) {
693     case eDeviceOrientation:
694 #ifdef MOZ_WIDGET_ANDROID
695       // Falls back to SENSOR_ROTATION_VECTOR and SENSOR_ORIENTATION if
696       // unavailable on device.
697       window->EnableDeviceSensor(SENSOR_GAME_ROTATION_VECTOR);
698       window->EnableDeviceSensor(SENSOR_ROTATION_VECTOR);
699 #else
700       window->EnableDeviceSensor(SENSOR_ORIENTATION);
701 #endif
702       break;
703     case eAbsoluteDeviceOrientation:
704 #ifdef MOZ_WIDGET_ANDROID
705       // Falls back to SENSOR_ORIENTATION if unavailable on device.
706       window->EnableDeviceSensor(SENSOR_ROTATION_VECTOR);
707 #else
708       window->EnableDeviceSensor(SENSOR_ORIENTATION);
709 #endif
710       break;
711     case eUserProximity:
712       window->EnableDeviceSensor(SENSOR_PROXIMITY);
713       break;
714     case eDeviceLight:
715       window->EnableDeviceSensor(SENSOR_LIGHT);
716       break;
717     case eDeviceMotion:
718       window->EnableDeviceSensor(SENSOR_ACCELERATION);
719       window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
720       window->EnableDeviceSensor(SENSOR_GYROSCOPE);
721       break;
722 #if defined(MOZ_WIDGET_ANDROID)
723     case eOrientationChange:
724       window->EnableOrientationChangeListener();
725       break;
726 #endif
727     default:
728       NS_WARNING("Enabling an unknown device sensor.");
729       break;
730   }
731 }
732 
DisableDevice(EventMessage aEventMessage)733 void EventListenerManager::DisableDevice(EventMessage aEventMessage) {
734   nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow();
735   if (!window) {
736     return;
737   }
738 
739   switch (aEventMessage) {
740     case eDeviceOrientation:
741 #ifdef MOZ_WIDGET_ANDROID
742       // Disable all potential fallback sensors.
743       window->DisableDeviceSensor(SENSOR_GAME_ROTATION_VECTOR);
744       window->DisableDeviceSensor(SENSOR_ROTATION_VECTOR);
745 #endif
746       window->DisableDeviceSensor(SENSOR_ORIENTATION);
747       break;
748     case eAbsoluteDeviceOrientation:
749 #ifdef MOZ_WIDGET_ANDROID
750       window->DisableDeviceSensor(SENSOR_ROTATION_VECTOR);
751 #endif
752       window->DisableDeviceSensor(SENSOR_ORIENTATION);
753       break;
754     case eDeviceMotion:
755       window->DisableDeviceSensor(SENSOR_ACCELERATION);
756       window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
757       window->DisableDeviceSensor(SENSOR_GYROSCOPE);
758       break;
759     case eUserProximity:
760       window->DisableDeviceSensor(SENSOR_PROXIMITY);
761       break;
762     case eDeviceLight:
763       window->DisableDeviceSensor(SENSOR_LIGHT);
764       break;
765 #if defined(MOZ_WIDGET_ANDROID)
766     case eOrientationChange:
767       window->DisableOrientationChangeListener();
768       break;
769 #endif
770     default:
771       NS_WARNING("Disabling an unknown device sensor.");
772       break;
773   }
774 }
775 
NotifyEventListenerRemoved(nsAtom * aUserType)776 void EventListenerManager::NotifyEventListenerRemoved(nsAtom* aUserType) {
777   // If the following code is changed, other callsites of EventListenerRemoved
778   // and NotifyAboutMainThreadListenerChange should be changed too.
779   mNoListenerForEvent = eVoidEvent;
780   mNoListenerForEventAtom = nullptr;
781   if (mTarget) {
782     mTarget->EventListenerRemoved(aUserType);
783   }
784   if (mIsMainThreadELM && mTarget) {
785     EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
786                                                               aUserType);
787   }
788 }
789 
RemoveEventListenerInternal(EventListenerHolder aListenerHolder,EventMessage aEventMessage,nsAtom * aUserType,const EventListenerFlags & aFlags,bool aAllEvents)790 void EventListenerManager::RemoveEventListenerInternal(
791     EventListenerHolder aListenerHolder, EventMessage aEventMessage,
792     nsAtom* aUserType, const EventListenerFlags& aFlags, bool aAllEvents) {
793   if (!aListenerHolder || !aEventMessage || mClearingListeners) {
794     return;
795   }
796 
797   Listener* listener;
798 
799   uint32_t count = mListeners.Length();
800   bool deviceType = IsDeviceType(aEventMessage);
801 
802   RefPtr<EventListenerManager> kungFuDeathGrip(this);
803 
804   for (uint32_t i = 0; i < count; ++i) {
805     listener = &mListeners.ElementAt(i);
806     if (EVENT_TYPE_EQUALS(listener, aEventMessage, aUserType, aAllEvents)) {
807       if (listener->mListener == aListenerHolder &&
808           listener->mFlags.EqualsForRemoval(aFlags)) {
809         if (IsNonChromeClickListener(listener)) {
810           mUnknownNonPrivilegedClickListeners = true;
811         }
812         mListeners.RemoveElementAt(i);
813         NotifyEventListenerRemoved(aUserType);
814         if (!aAllEvents && deviceType) {
815           DisableDevice(aEventMessage);
816         }
817         return;
818       }
819     }
820   }
821 }
822 
HasNonPrivilegedClickListeners()823 bool EventListenerManager::HasNonPrivilegedClickListeners() {
824   if (mUnknownNonPrivilegedClickListeners) {
825     Listener* listener;
826 
827     mUnknownNonPrivilegedClickListeners = false;
828     for (uint32_t i = 0; i < mListeners.Length(); ++i) {
829       listener = &mListeners.ElementAt(i);
830       if (IsNonChromeClickListener(listener)) {
831         mHasNonPrivilegedClickListeners = true;
832         return mHasNonPrivilegedClickListeners;
833       }
834     }
835     mHasNonPrivilegedClickListeners = false;
836   }
837   return mHasNonPrivilegedClickListeners;
838 }
839 
ListenerCanHandle(const Listener * aListener,const WidgetEvent * aEvent,EventMessage aEventMessage) const840 bool EventListenerManager::ListenerCanHandle(const Listener* aListener,
841                                              const WidgetEvent* aEvent,
842                                              EventMessage aEventMessage) const
843 
844 {
845   MOZ_ASSERT(aEventMessage == aEvent->mMessage ||
846                  aEventMessage == GetLegacyEventMessage(aEvent->mMessage),
847              "aEvent and aEventMessage should agree, modulo legacyness");
848 
849   // The listener has been removed, it cannot handle anything.
850   if (aListener->mListenerType == Listener::eNoListener) {
851     return false;
852   }
853 
854   // The listener has been disabled, for example by devtools.
855   if (!aListener->mEnabled) {
856     return false;
857   }
858 
859   // This is slightly different from EVENT_TYPE_EQUALS in that it returns
860   // true even when aEvent->mMessage == eUnidentifiedEvent and
861   // aListener=>mEventMessage != eUnidentifiedEvent as long as the atoms are
862   // the same
863   if (MOZ_UNLIKELY(aListener->mAllEvents)) {
864     return true;
865   }
866   if (aEvent->mMessage == eUnidentifiedEvent) {
867     return aListener->mTypeAtom == aEvent->mSpecifiedEventType;
868   }
869   MOZ_ASSERT(mIsMainThreadELM);
870   return aListener->mEventMessage == aEventMessage;
871 }
872 
IsDefaultPassiveWhenOnRoot(EventMessage aMessage)873 static bool IsDefaultPassiveWhenOnRoot(EventMessage aMessage) {
874   if (aMessage == eTouchStart || aMessage == eTouchMove) {
875     return StaticPrefs::dom_event_default_to_passive_touch_listeners();
876   }
877   if (aMessage == eWheel || aMessage == eLegacyMouseLineOrPageScroll ||
878       aMessage == eLegacyMousePixelScroll) {
879     return StaticPrefs::dom_event_default_to_passive_wheel_listeners();
880   }
881   return false;
882 }
883 
IsRootEventTarget(EventTarget * aTarget)884 static bool IsRootEventTarget(EventTarget* aTarget) {
885   if (!aTarget) {
886     return false;
887   }
888   if (aTarget->IsInnerWindow()) {
889     return true;
890   }
891   const nsINode* node = nsINode::FromEventTarget(aTarget);
892   if (!node) {
893     return false;
894   }
895   Document* doc = node->OwnerDoc();
896   return node == doc || node == doc->GetRootElement() || node == doc->GetBody();
897 }
898 
MaybeMarkPassive(EventMessage aMessage,EventListenerFlags & aFlags)899 void EventListenerManager::MaybeMarkPassive(EventMessage aMessage,
900                                             EventListenerFlags& aFlags) {
901   if (!mIsMainThreadELM) {
902     return;
903   }
904   if (!IsDefaultPassiveWhenOnRoot(aMessage)) {
905     return;
906   }
907   if (!IsRootEventTarget(mTarget)) {
908     return;
909   }
910   aFlags.mPassive = true;
911 }
912 
AddEventListenerByType(EventListenerHolder aListenerHolder,const nsAString & aType,const EventListenerFlags & aFlags,const Optional<bool> & aPassive,AbortSignal * aSignal)913 void EventListenerManager::AddEventListenerByType(
914     EventListenerHolder aListenerHolder, const nsAString& aType,
915     const EventListenerFlags& aFlags, const Optional<bool>& aPassive,
916     AbortSignal* aSignal) {
917   RefPtr<nsAtom> atom;
918   EventMessage message =
919       GetEventMessageAndAtomForListener(aType, getter_AddRefs(atom));
920 
921   EventListenerFlags flags = aFlags;
922   if (aPassive.WasPassed()) {
923     flags.mPassive = aPassive.Value();
924   } else {
925     MaybeMarkPassive(message, flags);
926   }
927 
928   AddEventListenerInternal(std::move(aListenerHolder), message, atom, flags,
929                            false, false, aSignal);
930 }
931 
RemoveEventListenerByType(EventListenerHolder aListenerHolder,const nsAString & aType,const EventListenerFlags & aFlags)932 void EventListenerManager::RemoveEventListenerByType(
933     EventListenerHolder aListenerHolder, const nsAString& aType,
934     const EventListenerFlags& aFlags) {
935   RefPtr<nsAtom> atom;
936   EventMessage message =
937       GetEventMessageAndAtomForListener(aType, getter_AddRefs(atom));
938   RemoveEventListenerInternal(std::move(aListenerHolder), message, atom,
939                               aFlags);
940 }
941 
FindEventHandler(EventMessage aEventMessage,nsAtom * aTypeAtom)942 EventListenerManager::Listener* EventListenerManager::FindEventHandler(
943     EventMessage aEventMessage, nsAtom* aTypeAtom) {
944   // Run through the listeners for this type and see if a script
945   // listener is registered
946   Listener* listener;
947   uint32_t count = mListeners.Length();
948   for (uint32_t i = 0; i < count; ++i) {
949     listener = &mListeners.ElementAt(i);
950     if (listener->mListenerIsHandler &&
951         EVENT_TYPE_EQUALS(listener, aEventMessage, aTypeAtom, false)) {
952       return listener;
953     }
954   }
955   return nullptr;
956 }
957 
SetEventHandlerInternal(nsAtom * aName,const TypedEventHandler & aTypedHandler,bool aPermitUntrustedEvents)958 EventListenerManager::Listener* EventListenerManager::SetEventHandlerInternal(
959     nsAtom* aName, const TypedEventHandler& aTypedHandler,
960     bool aPermitUntrustedEvents) {
961   MOZ_ASSERT(aName);
962 
963   EventMessage eventMessage = GetEventMessage(aName);
964   Listener* listener = FindEventHandler(eventMessage, aName);
965 
966   if (!listener) {
967     // If we didn't find a script listener or no listeners existed
968     // create and add a new one.
969     EventListenerFlags flags;
970     flags.mListenerIsJSListener = true;
971     MaybeMarkPassive(eventMessage, flags);
972 
973     nsCOMPtr<JSEventHandler> jsEventHandler;
974     NS_NewJSEventHandler(mTarget, aName, aTypedHandler,
975                          getter_AddRefs(jsEventHandler));
976     AddEventListenerInternal(EventListenerHolder(jsEventHandler), eventMessage,
977                              aName, flags, true);
978 
979     listener = FindEventHandler(eventMessage, aName);
980   } else {
981     JSEventHandler* jsEventHandler = listener->GetJSEventHandler();
982     MOZ_ASSERT(jsEventHandler,
983                "How can we have an event handler with no JSEventHandler?");
984 
985     bool same = jsEventHandler->GetTypedEventHandler() == aTypedHandler;
986     // Possibly the same listener, but update still the context and scope.
987     jsEventHandler->SetHandler(aTypedHandler);
988     if (mTarget && !same) {
989       mTarget->EventListenerRemoved(aName);
990       mTarget->EventListenerAdded(aName);
991     }
992     if (mIsMainThreadELM && mTarget) {
993       EventListenerService::NotifyAboutMainThreadListenerChange(mTarget, aName);
994     }
995   }
996 
997   // Set flag to indicate possible need for compilation later
998   listener->mHandlerIsString = !aTypedHandler.HasEventHandler();
999   if (aPermitUntrustedEvents) {
1000     listener->mFlags.mAllowUntrustedEvents = true;
1001   }
1002 
1003   return listener;
1004 }
1005 
SetEventHandler(nsAtom * aName,const nsAString & aBody,bool aDeferCompilation,bool aPermitUntrustedEvents,Element * aElement)1006 nsresult EventListenerManager::SetEventHandler(nsAtom* aName,
1007                                                const nsAString& aBody,
1008                                                bool aDeferCompilation,
1009                                                bool aPermitUntrustedEvents,
1010                                                Element* aElement) {
1011   auto removeEventHandler = MakeScopeExit([&] { RemoveEventHandler(aName); });
1012 
1013   nsCOMPtr<Document> doc;
1014   nsCOMPtr<nsIScriptGlobalObject> global =
1015       GetScriptGlobalAndDocument(getter_AddRefs(doc));
1016 
1017   if (!global) {
1018     // This can happen; for example this document might have been
1019     // loaded as data.
1020     return NS_OK;
1021   }
1022 
1023   nsresult rv = NS_OK;
1024   // return early preventing the event listener from being added
1025   // 'doc' is fetched above
1026   if (doc) {
1027     // Don't allow adding an event listener if the document is sandboxed
1028     // without 'allow-scripts'.
1029     if (doc->HasScriptsBlockedBySandbox()) {
1030       return NS_ERROR_DOM_SECURITY_ERR;
1031     }
1032 
1033     // Perform CSP check
1034     nsCOMPtr<nsIContentSecurityPolicy> csp = doc->GetCsp();
1035     unsigned lineNum = 0;
1036     unsigned columnNum = 0;
1037 
1038     JSContext* cx = nsContentUtils::GetCurrentJSContext();
1039     if (cx && !JS::DescribeScriptedCaller(cx, nullptr, &lineNum, &columnNum)) {
1040       JS_ClearPendingException(cx);
1041     }
1042 
1043     if (csp) {
1044       bool allowsInlineScript = true;
1045       rv = csp->GetAllowsInline(
1046           nsIContentSecurityPolicy::SCRIPT_SRC_DIRECTIVE,
1047           u""_ns,  // aNonce
1048           true,    // aParserCreated (true because attribute event handler)
1049           aElement,
1050           nullptr,  // nsICSPEventListener
1051           aBody, lineNum, columnNum, &allowsInlineScript);
1052       NS_ENSURE_SUCCESS(rv, rv);
1053 
1054       // return early if CSP wants us to block inline scripts
1055       if (!allowsInlineScript) {
1056         return NS_OK;
1057       }
1058     }
1059   }
1060 
1061   // This might be the first reference to this language in the global
1062   // We must init the language before we attempt to fetch its context.
1063   if (NS_FAILED(global->EnsureScriptEnvironment())) {
1064     NS_WARNING("Failed to setup script environment for this language");
1065     // but fall through and let the inevitable failure below handle it.
1066   }
1067 
1068   nsIScriptContext* context = global->GetScriptContext();
1069   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
1070   NS_ENSURE_STATE(global->HasJSGlobal());
1071 
1072   removeEventHandler.release();
1073 
1074   Listener* listener = SetEventHandlerInternal(aName, TypedEventHandler(),
1075                                                aPermitUntrustedEvents);
1076 
1077   if (!aDeferCompilation) {
1078     return CompileEventHandlerInternal(listener, &aBody, aElement);
1079   }
1080 
1081   return NS_OK;
1082 }
1083 
RemoveEventHandler(nsAtom * aName)1084 void EventListenerManager::RemoveEventHandler(nsAtom* aName) {
1085   if (mClearingListeners) {
1086     return;
1087   }
1088 
1089   EventMessage eventMessage = GetEventMessage(aName);
1090   Listener* listener = FindEventHandler(eventMessage, aName);
1091 
1092   if (listener) {
1093     if (IsNonChromeClickListener(listener)) {
1094       mUnknownNonPrivilegedClickListeners = true;
1095     }
1096     mListeners.RemoveElementAt(uint32_t(listener - &mListeners.ElementAt(0)));
1097     NotifyEventListenerRemoved(aName);
1098     if (IsDeviceType(eventMessage)) {
1099       DisableDevice(eventMessage);
1100     }
1101   }
1102 }
1103 
IsNonChromeClickListener(Listener * aListener)1104 bool EventListenerManager::IsNonChromeClickListener(Listener* aListener) {
1105   return !aListener->mFlags.mInSystemGroup && !aListener->mIsChrome &&
1106          aListener->mEventMessage == eMouseClick &&
1107          (aListener->GetJSEventHandler() ||
1108           aListener->mListener.HasWebIDLCallback());
1109 }
1110 
CompileEventHandlerInternal(Listener * aListener,const nsAString * aBody,Element * aElement)1111 nsresult EventListenerManager::CompileEventHandlerInternal(
1112     Listener* aListener, const nsAString* aBody, Element* aElement) {
1113   MOZ_ASSERT(aListener->GetJSEventHandler());
1114   MOZ_ASSERT(aListener->mHandlerIsString,
1115              "Why are we compiling a non-string JS listener?");
1116   JSEventHandler* jsEventHandler = aListener->GetJSEventHandler();
1117   MOZ_ASSERT(!jsEventHandler->GetTypedEventHandler().HasEventHandler(),
1118              "What is there to compile?");
1119 
1120   nsresult result = NS_OK;
1121   nsCOMPtr<Document> doc;
1122   nsCOMPtr<nsIScriptGlobalObject> global =
1123       GetScriptGlobalAndDocument(getter_AddRefs(doc));
1124   NS_ENSURE_STATE(global);
1125 
1126   // Activate JSAPI, and make sure that exceptions are reported on the right
1127   // Window.
1128   AutoJSAPI jsapi;
1129   if (NS_WARN_IF(!jsapi.Init(global))) {
1130     return NS_ERROR_UNEXPECTED;
1131   }
1132   JSContext* cx = jsapi.cx();
1133 
1134   RefPtr<nsAtom> typeAtom = aListener->mTypeAtom;
1135   nsAtom* attrName = typeAtom;
1136 
1137   // Flag us as not a string so we don't keep trying to compile strings which
1138   // can't be compiled.
1139   aListener->mHandlerIsString = false;
1140 
1141   // mTarget may not be an Element if it's a window and we're
1142   // getting an inline event listener forwarded from <html:body> or
1143   // <html:frameset> or <xul:window> or the like.
1144   // XXX I don't like that we have to reference content from
1145   // here. The alternative is to store the event handler string on
1146   // the JSEventHandler itself, and that still doesn't address
1147   // the arg names issue.
1148   RefPtr<Element> element = Element::FromEventTargetOrNull(mTarget);
1149   MOZ_ASSERT(element || aBody, "Where will we get our body?");
1150   nsAutoString handlerBody;
1151   const nsAString* body = aBody;
1152   if (!aBody) {
1153     if (aListener->mTypeAtom == nsGkAtoms::onSVGLoad) {
1154       attrName = nsGkAtoms::onload;
1155     } else if (aListener->mTypeAtom == nsGkAtoms::onSVGScroll) {
1156       attrName = nsGkAtoms::onscroll;
1157     } else if (aListener->mTypeAtom == nsGkAtoms::onbeginEvent) {
1158       attrName = nsGkAtoms::onbegin;
1159     } else if (aListener->mTypeAtom == nsGkAtoms::onrepeatEvent) {
1160       attrName = nsGkAtoms::onrepeat;
1161     } else if (aListener->mTypeAtom == nsGkAtoms::onendEvent) {
1162       attrName = nsGkAtoms::onend;
1163     } else if (aListener->mTypeAtom == nsGkAtoms::onwebkitAnimationEnd) {
1164       attrName = nsGkAtoms::onwebkitanimationend;
1165     } else if (aListener->mTypeAtom == nsGkAtoms::onwebkitAnimationIteration) {
1166       attrName = nsGkAtoms::onwebkitanimationiteration;
1167     } else if (aListener->mTypeAtom == nsGkAtoms::onwebkitAnimationStart) {
1168       attrName = nsGkAtoms::onwebkitanimationstart;
1169     } else if (aListener->mTypeAtom == nsGkAtoms::onwebkitTransitionEnd) {
1170       attrName = nsGkAtoms::onwebkittransitionend;
1171     }
1172 
1173     element->GetAttr(kNameSpaceID_None, attrName, handlerBody);
1174     body = &handlerBody;
1175     aElement = element;
1176   }
1177   aListener = nullptr;
1178 
1179   nsAutoCString url("-moz-evil:lying-event-listener"_ns);
1180   MOZ_ASSERT(body);
1181   MOZ_ASSERT(aElement);
1182   nsIURI* uri = aElement->OwnerDoc()->GetDocumentURI();
1183   if (uri) {
1184     uri->GetSpec(url);
1185   }
1186 
1187   nsCOMPtr<nsPIDOMWindowInner> win =
1188       nsPIDOMWindowInner::FromEventTargetOrNull(mTarget);
1189   uint32_t argCount;
1190   const char** argNames;
1191   nsContentUtils::GetEventArgNames(aElement->GetNameSpaceID(), typeAtom, win,
1192                                    &argCount, &argNames);
1193 
1194   // Wrap the event target, so that we can use it as the scope for the event
1195   // handler. Note that mTarget is different from aElement in the <body> case,
1196   // where mTarget is a Window.
1197   //
1198   // The wrapScope doesn't really matter here, because the target will create
1199   // its reflector in the proper scope, and then we'll enter that realm.
1200   JS::Rooted<JSObject*> wrapScope(cx, global->GetGlobalJSObject());
1201   JS::Rooted<JS::Value> v(cx);
1202   {
1203     JSAutoRealm ar(cx, wrapScope);
1204     nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v,
1205                                              /* aAllowWrapping = */ false);
1206     if (NS_WARN_IF(NS_FAILED(rv))) {
1207       return rv;
1208     }
1209   }
1210 
1211   JS::Rooted<JSObject*> target(cx, &v.toObject());
1212   JSAutoRealm ar(cx, target);
1213 
1214   // Now that we've entered the realm we actually care about, create our
1215   // scope chain.  Note that we start with |element|, not aElement, because
1216   // mTarget is different from aElement in the <body> case, where mTarget is a
1217   // Window, and in that case we do not want the scope chain to include the body
1218   // or the document.
1219   JS::RootedVector<JSObject*> scopeChain(cx);
1220   if (!nsJSUtils::GetScopeChainForElement(cx, element, &scopeChain)) {
1221     return NS_ERROR_OUT_OF_MEMORY;
1222   }
1223 
1224   nsDependentAtomString str(attrName);
1225   // Most of our names are short enough that we don't even have to malloc
1226   // the JS string stuff, so don't worry about playing games with
1227   // refcounting XPCOM stringbuffers.
1228   JS::Rooted<JSString*> jsStr(
1229       cx, JS_NewUCStringCopyN(cx, str.BeginReading(), str.Length()));
1230   NS_ENSURE_TRUE(jsStr, NS_ERROR_OUT_OF_MEMORY);
1231 
1232   // Get the reflector for |aElement|, so that we can pass to setElement.
1233   if (NS_WARN_IF(!GetOrCreateDOMReflector(cx, aElement, &v))) {
1234     return NS_ERROR_FAILURE;
1235   }
1236 
1237   RefPtr<JS::loader::ScriptFetchOptions> fetchOptions =
1238       new JS::loader::ScriptFetchOptions(
1239           CORS_NONE, aElement->OwnerDoc()->GetReferrerPolicy(),
1240           aElement->OwnerDoc()->NodePrincipal());
1241 
1242   RefPtr<JS::loader::EventScript> eventScript =
1243       new JS::loader::EventScript(fetchOptions, uri, aElement);
1244 
1245   JS::CompileOptions options(cx);
1246   // Use line 0 to make the function body starts from line 1.
1247   options.setIntroductionType("eventHandler")
1248       .setFileAndLine(url.get(), 0)
1249       .setDeferDebugMetadata(true);
1250 
1251   JS::Rooted<JSObject*> handler(cx);
1252   result = nsJSUtils::CompileFunction(jsapi, scopeChain, options,
1253                                       nsAtomCString(typeAtom), argCount,
1254                                       argNames, *body, handler.address());
1255   NS_ENSURE_SUCCESS(result, result);
1256   NS_ENSURE_TRUE(handler, NS_ERROR_FAILURE);
1257 
1258   JS::Rooted<JS::Value> privateValue(cx, JS::PrivateValue(eventScript));
1259   result = nsJSUtils::UpdateFunctionDebugMetadata(jsapi, handler, options,
1260                                                   jsStr, privateValue);
1261   NS_ENSURE_SUCCESS(result, result);
1262 
1263   MOZ_ASSERT(js::IsObjectInContextCompartment(handler, cx));
1264   JS::Rooted<JSObject*> handlerGlobal(cx, JS::CurrentGlobalOrNull(cx));
1265 
1266   if (jsEventHandler->EventName() == nsGkAtoms::onerror && win) {
1267     RefPtr<OnErrorEventHandlerNonNull> handlerCallback =
1268         new OnErrorEventHandlerNonNull(static_cast<JSContext*>(nullptr),
1269                                        handler, handlerGlobal,
1270                                        /* aIncumbentGlobal = */ nullptr);
1271     jsEventHandler->SetHandler(handlerCallback);
1272   } else if (jsEventHandler->EventName() == nsGkAtoms::onbeforeunload && win) {
1273     RefPtr<OnBeforeUnloadEventHandlerNonNull> handlerCallback =
1274         new OnBeforeUnloadEventHandlerNonNull(static_cast<JSContext*>(nullptr),
1275                                               handler, handlerGlobal,
1276                                               /* aIncumbentGlobal = */ nullptr);
1277     jsEventHandler->SetHandler(handlerCallback);
1278   } else {
1279     RefPtr<EventHandlerNonNull> handlerCallback = new EventHandlerNonNull(
1280         static_cast<JSContext*>(nullptr), handler, handlerGlobal,
1281         /* aIncumbentGlobal = */ nullptr);
1282     jsEventHandler->SetHandler(handlerCallback);
1283   }
1284 
1285   return result;
1286 }
1287 
HandleEventSubType(Listener * aListener,Event * aDOMEvent,EventTarget * aCurrentTarget)1288 nsresult EventListenerManager::HandleEventSubType(Listener* aListener,
1289                                                   Event* aDOMEvent,
1290                                                   EventTarget* aCurrentTarget) {
1291   nsresult result = NS_OK;
1292   // strong ref
1293   EventListenerHolder listenerHolder(aListener->mListener.Clone());
1294 
1295   // If this is a script handler and we haven't yet
1296   // compiled the event handler itself
1297   if ((aListener->mListenerType == Listener::eJSEventListener) &&
1298       aListener->mHandlerIsString) {
1299     result = CompileEventHandlerInternal(aListener, nullptr, nullptr);
1300     aListener = nullptr;
1301   }
1302 
1303   if (NS_SUCCEEDED(result)) {
1304     EventCallbackDebuggerNotificationGuard dbgGuard(aCurrentTarget, aDOMEvent);
1305     nsAutoMicroTask mt;
1306 
1307     // Event::currentTarget is set in EventDispatcher.
1308     if (listenerHolder.HasWebIDLCallback()) {
1309       ErrorResult rv;
1310       listenerHolder.GetWebIDLCallback()->HandleEvent(aCurrentTarget,
1311                                                       *aDOMEvent, rv);
1312       result = rv.StealNSResult();
1313     } else {
1314       // listenerHolder is holding a stack ref here.
1315       result = MOZ_KnownLive(listenerHolder.GetXPCOMCallback())
1316                    ->HandleEvent(aDOMEvent);
1317     }
1318   }
1319 
1320   return result;
1321 }
1322 
GetLegacyEventMessage(EventMessage aEventMessage) const1323 EventMessage EventListenerManager::GetLegacyEventMessage(
1324     EventMessage aEventMessage) const {
1325   // webkit-prefixed legacy events:
1326   if (aEventMessage == eTransitionEnd) {
1327     return eWebkitTransitionEnd;
1328   }
1329   if (aEventMessage == eAnimationStart) {
1330     return eWebkitAnimationStart;
1331   }
1332   if (aEventMessage == eAnimationEnd) {
1333     return eWebkitAnimationEnd;
1334   }
1335   if (aEventMessage == eAnimationIteration) {
1336     return eWebkitAnimationIteration;
1337   }
1338 
1339   switch (aEventMessage) {
1340     case eFullscreenChange:
1341       return eMozFullscreenChange;
1342     case eFullscreenError:
1343       return eMozFullscreenError;
1344     default:
1345       return aEventMessage;
1346   }
1347 }
1348 
GetEventMessage(nsAtom * aEventName) const1349 EventMessage EventListenerManager::GetEventMessage(nsAtom* aEventName) const {
1350   if (mIsMainThreadELM) {
1351     return nsContentUtils::GetEventMessage(aEventName);
1352   }
1353 
1354   // The nsContentUtils event message hashtables aren't threadsafe, so just fall
1355   // back to eUnidentifiedEvent.
1356   return eUnidentifiedEvent;
1357 }
1358 
GetEventMessageAndAtomForListener(const nsAString & aType,nsAtom ** aAtom)1359 EventMessage EventListenerManager::GetEventMessageAndAtomForListener(
1360     const nsAString& aType, nsAtom** aAtom) {
1361   if (mIsMainThreadELM) {
1362     return nsContentUtils::GetEventMessageAndAtomForListener(aType, aAtom);
1363   }
1364 
1365   *aAtom = NS_Atomize(u"on"_ns + aType).take();
1366   return eUnidentifiedEvent;
1367 }
1368 
WindowFromListener(Listener * aListener,bool aItemInShadowTree)1369 already_AddRefed<nsPIDOMWindowInner> EventListenerManager::WindowFromListener(
1370     Listener* aListener, bool aItemInShadowTree) {
1371   nsCOMPtr<nsPIDOMWindowInner> innerWindow;
1372   if (!aItemInShadowTree) {
1373     if (aListener->mListener.HasWebIDLCallback()) {
1374       CallbackObject* callback = aListener->mListener.GetWebIDLCallback();
1375       nsIGlobalObject* global = nullptr;
1376       if (callback) {
1377         global = callback->IncumbentGlobalOrNull();
1378       }
1379       if (global) {
1380         innerWindow = global->AsInnerWindow();  // Can be nullptr
1381       }
1382     } else {
1383       // Can't get the global from
1384       // listener->mListener.GetXPCOMCallback().
1385       // In most cases, it would be the same as for
1386       // the target, so let's do that.
1387       innerWindow = GetInnerWindowForTarget();  // Can be nullptr
1388     }
1389   }
1390   return innerWindow.forget();
1391 }
1392 
1393 /**
1394  * Causes a check for event listeners and processing by them if they exist.
1395  * @param an event listener
1396  */
1397 
HandleEventInternal(nsPresContext * aPresContext,WidgetEvent * aEvent,Event ** aDOMEvent,EventTarget * aCurrentTarget,nsEventStatus * aEventStatus,bool aItemInShadowTree)1398 void EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
1399                                                WidgetEvent* aEvent,
1400                                                Event** aDOMEvent,
1401                                                EventTarget* aCurrentTarget,
1402                                                nsEventStatus* aEventStatus,
1403                                                bool aItemInShadowTree) {
1404   // Set the value of the internal PreventDefault flag properly based on
1405   // aEventStatus
1406   if (!aEvent->DefaultPrevented() &&
1407       *aEventStatus == nsEventStatus_eConsumeNoDefault) {
1408     // Assume that if only aEventStatus claims that the event has already been
1409     // consumed, the consumer is default event handler.
1410     aEvent->PreventDefault();
1411   }
1412 
1413   Maybe<AutoHandlingUserInputStatePusher> userInputStatePusher;
1414   Maybe<AutoPopupStatePusher> popupStatePusher;
1415   if (mIsMainThreadELM) {
1416     userInputStatePusher.emplace(UserActivation::IsUserInteractionEvent(aEvent),
1417                                  aEvent);
1418     popupStatePusher.emplace(
1419         PopupBlocker::GetEventPopupControlState(aEvent, *aDOMEvent));
1420   }
1421 
1422   bool hasListener = false;
1423   bool hasListenerForCurrentGroup = false;
1424   bool usingLegacyMessage = false;
1425   bool hasRemovedListener = false;
1426   EventMessage eventMessage = aEvent->mMessage;
1427 
1428   while (true) {
1429     Maybe<EventMessageAutoOverride> legacyAutoOverride;
1430     for (Listener& listenerRef : mListeners.EndLimitedRange()) {
1431       if (aEvent->mFlags.mImmediatePropagationStopped) {
1432         break;
1433       }
1434       Listener* listener = &listenerRef;
1435       // Check that the phase is same in event and event listener.
1436       // Handle only trusted events, except when listener permits untrusted
1437       // events.
1438       if (ListenerCanHandle(listener, aEvent, eventMessage)) {
1439         hasListener = true;
1440         hasListenerForCurrentGroup =
1441             hasListenerForCurrentGroup ||
1442             listener->mFlags.mInSystemGroup == aEvent->mFlags.mInSystemGroup;
1443         if (listener->IsListening(aEvent) &&
1444             (aEvent->IsTrusted() || listener->mFlags.mAllowUntrustedEvents)) {
1445           if (!*aDOMEvent) {
1446             // This is tiny bit slow, but happens only once per event.
1447             // Similar code also in EventDispatcher.
1448             nsCOMPtr<EventTarget> et = aEvent->mOriginalTarget;
1449             RefPtr<Event> event =
1450                 EventDispatcher::CreateEvent(et, aPresContext, aEvent, u""_ns);
1451             event.forget(aDOMEvent);
1452           }
1453           if (*aDOMEvent) {
1454             if (!aEvent->mCurrentTarget) {
1455               aEvent->mCurrentTarget = aCurrentTarget->GetTargetForDOMEvent();
1456               if (!aEvent->mCurrentTarget) {
1457                 break;
1458               }
1459             }
1460             if (usingLegacyMessage && !legacyAutoOverride) {
1461               // Override the aDOMEvent's event-message (its .type) until we
1462               // finish traversing listeners (when legacyAutoOverride destructs)
1463               legacyAutoOverride.emplace(*aDOMEvent, eventMessage);
1464             }
1465 
1466             // Maybe add a marker to the docshell's timeline, but only
1467             // bother with all the logic if some docshell is recording.
1468             nsCOMPtr<nsIDocShell> docShell;
1469             RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
1470             bool needsEndEventMarker = false;
1471 
1472             if (mIsMainThreadELM &&
1473                 listener->mListenerType != Listener::eNativeListener) {
1474               docShell = nsContentUtils::GetDocShellForEventTarget(mTarget);
1475               if (docShell) {
1476                 if (timelines && timelines->HasConsumer(docShell)) {
1477                   needsEndEventMarker = true;
1478                   nsAutoString typeStr;
1479                   (*aDOMEvent)->GetType(typeStr);
1480                   uint16_t phase = (*aDOMEvent)->EventPhase();
1481                   timelines->AddMarkerForDocShell(
1482                       docShell, MakeUnique<EventTimelineMarker>(
1483                                     typeStr, phase, MarkerTracingType::START));
1484                 }
1485               }
1486             }
1487 
1488             aEvent->mFlags.mInPassiveListener = listener->mFlags.mPassive;
1489             Maybe<Listener> listenerHolder;
1490             if (listener->mFlags.mOnce) {
1491               // Move the listener to the stack before handling the event.
1492               // The order is important, otherwise the listener could be
1493               // called again inside the listener.
1494               listenerHolder.emplace(std::move(*listener));
1495               listener = listenerHolder.ptr();
1496               hasRemovedListener = true;
1497             }
1498 
1499             nsCOMPtr<nsPIDOMWindowInner> innerWindow =
1500                 WindowFromListener(listener, aItemInShadowTree);
1501             mozilla::dom::Event* oldWindowEvent = nullptr;
1502             if (innerWindow) {
1503               oldWindowEvent = innerWindow->SetEvent(*aDOMEvent);
1504             }
1505 
1506             nsresult rv =
1507                 HandleEventSubType(listener, *aDOMEvent, aCurrentTarget);
1508 
1509             if (innerWindow) {
1510               Unused << innerWindow->SetEvent(oldWindowEvent);
1511             }
1512 
1513             if (NS_FAILED(rv)) {
1514               aEvent->mFlags.mExceptionWasRaised = true;
1515             }
1516             aEvent->mFlags.mInPassiveListener = false;
1517 
1518             if (needsEndEventMarker) {
1519               timelines->AddMarkerForDocShell(docShell, "DOMEvent",
1520                                               MarkerTracingType::END);
1521             }
1522           }
1523         }
1524       }
1525     }
1526 
1527     // If we didn't find any matching listeners, and our event has a legacy
1528     // version, we'll now switch to looking for that legacy version and we'll
1529     // recheck our listeners.
1530     if (hasListenerForCurrentGroup || usingLegacyMessage ||
1531         !aEvent->IsTrusted()) {
1532       // No need to recheck listeners, because we already found a match, we
1533       // already rechecked them, or it is not a trusted event.
1534       break;
1535     }
1536     EventMessage legacyEventMessage = GetLegacyEventMessage(eventMessage);
1537     if (legacyEventMessage == eventMessage) {
1538       break;  // There's no legacy version of our event; no need to recheck.
1539     }
1540     MOZ_ASSERT(
1541         GetLegacyEventMessage(legacyEventMessage) == legacyEventMessage,
1542         "Legacy event messages should not themselves have legacy versions");
1543 
1544     // Recheck our listeners, using the legacy event message we just looked up:
1545     eventMessage = legacyEventMessage;
1546     usingLegacyMessage = true;
1547   }
1548 
1549   aEvent->mCurrentTarget = nullptr;
1550 
1551   if (hasRemovedListener) {
1552     // If there are any once listeners replaced with a placeholder in
1553     // the loop above, we need to clean up them here. Note that, this
1554     // could clear once listeners handled in some outer level as well,
1555     // but that should not affect the result.
1556     mListeners.NonObservingRemoveElementsBy([](const Listener& aListener) {
1557       return aListener.mListenerType == Listener::eNoListener;
1558     });
1559     NotifyEventListenerRemoved(aEvent->mSpecifiedEventType);
1560     if (IsDeviceType(aEvent->mMessage)) {
1561       // This is a device-type event, we need to check whether we can
1562       // disable device after removing the once listeners.
1563       const auto [begin, end] = mListeners.NonObservingRange();
1564       const bool hasAnyListener =
1565           std::any_of(begin, end, [aEvent](const Listener& listenerRef) {
1566             const Listener* listener = &listenerRef;
1567             return EVENT_TYPE_EQUALS(listener, aEvent->mMessage,
1568                                      aEvent->mSpecifiedEventType,
1569                                      /* all events */ false);
1570           });
1571 
1572       if (!hasAnyListener) {
1573         DisableDevice(aEvent->mMessage);
1574       }
1575     }
1576   }
1577 
1578   if (mIsMainThreadELM && !hasListener) {
1579     mNoListenerForEvent = aEvent->mMessage;
1580     mNoListenerForEventAtom = aEvent->mSpecifiedEventType;
1581   }
1582 
1583   if (aEvent->DefaultPrevented()) {
1584     *aEventStatus = nsEventStatus_eConsumeNoDefault;
1585   }
1586 }
1587 
Disconnect()1588 void EventListenerManager::Disconnect() {
1589   mTarget = nullptr;
1590   RemoveAllListenersSilently();
1591 }
1592 
AddEventListener(const nsAString & aType,EventListenerHolder aListenerHolder,bool aUseCapture,bool aWantsUntrusted)1593 void EventListenerManager::AddEventListener(const nsAString& aType,
1594                                             EventListenerHolder aListenerHolder,
1595                                             bool aUseCapture,
1596                                             bool aWantsUntrusted) {
1597   EventListenerFlags flags;
1598   flags.mCapture = aUseCapture;
1599   flags.mAllowUntrustedEvents = aWantsUntrusted;
1600   return AddEventListenerByType(std::move(aListenerHolder), aType, flags);
1601 }
1602 
AddEventListener(const nsAString & aType,EventListenerHolder aListenerHolder,const dom::AddEventListenerOptionsOrBoolean & aOptions,bool aWantsUntrusted)1603 void EventListenerManager::AddEventListener(
1604     const nsAString& aType, EventListenerHolder aListenerHolder,
1605     const dom::AddEventListenerOptionsOrBoolean& aOptions,
1606     bool aWantsUntrusted) {
1607   EventListenerFlags flags;
1608   Optional<bool> passive;
1609   AbortSignal* signal = nullptr;
1610   if (aOptions.IsBoolean()) {
1611     flags.mCapture = aOptions.GetAsBoolean();
1612   } else {
1613     const auto& options = aOptions.GetAsAddEventListenerOptions();
1614     flags.mCapture = options.mCapture;
1615     flags.mInSystemGroup = options.mMozSystemGroup;
1616     flags.mOnce = options.mOnce;
1617     if (options.mPassive.WasPassed()) {
1618       passive.Construct(options.mPassive.Value());
1619     }
1620 
1621     if (options.mSignal.WasPassed()) {
1622       signal = &options.mSignal.Value();
1623     }
1624   }
1625 
1626   flags.mAllowUntrustedEvents = aWantsUntrusted;
1627   return AddEventListenerByType(std::move(aListenerHolder), aType, flags,
1628                                 passive, signal);
1629 }
1630 
RemoveEventListener(const nsAString & aType,EventListenerHolder aListenerHolder,bool aUseCapture)1631 void EventListenerManager::RemoveEventListener(
1632     const nsAString& aType, EventListenerHolder aListenerHolder,
1633     bool aUseCapture) {
1634   EventListenerFlags flags;
1635   flags.mCapture = aUseCapture;
1636   RemoveEventListenerByType(std::move(aListenerHolder), aType, flags);
1637 }
1638 
RemoveEventListener(const nsAString & aType,EventListenerHolder aListenerHolder,const dom::EventListenerOptionsOrBoolean & aOptions)1639 void EventListenerManager::RemoveEventListener(
1640     const nsAString& aType, EventListenerHolder aListenerHolder,
1641     const dom::EventListenerOptionsOrBoolean& aOptions) {
1642   EventListenerFlags flags;
1643   if (aOptions.IsBoolean()) {
1644     flags.mCapture = aOptions.GetAsBoolean();
1645   } else {
1646     const auto& options = aOptions.GetAsEventListenerOptions();
1647     flags.mCapture = options.mCapture;
1648     flags.mInSystemGroup = options.mMozSystemGroup;
1649   }
1650   RemoveEventListenerByType(std::move(aListenerHolder), aType, flags);
1651 }
1652 
AddListenerForAllEvents(EventListener * aDOMListener,bool aUseCapture,bool aWantsUntrusted,bool aSystemEventGroup)1653 void EventListenerManager::AddListenerForAllEvents(EventListener* aDOMListener,
1654                                                    bool aUseCapture,
1655                                                    bool aWantsUntrusted,
1656                                                    bool aSystemEventGroup) {
1657   EventListenerFlags flags;
1658   flags.mCapture = aUseCapture;
1659   flags.mAllowUntrustedEvents = aWantsUntrusted;
1660   flags.mInSystemGroup = aSystemEventGroup;
1661   AddEventListenerInternal(EventListenerHolder(aDOMListener), eAllEvents,
1662                            nullptr, flags, false, true);
1663 }
1664 
RemoveListenerForAllEvents(EventListener * aDOMListener,bool aUseCapture,bool aSystemEventGroup)1665 void EventListenerManager::RemoveListenerForAllEvents(
1666     EventListener* aDOMListener, bool aUseCapture, bool aSystemEventGroup) {
1667   EventListenerFlags flags;
1668   flags.mCapture = aUseCapture;
1669   flags.mInSystemGroup = aSystemEventGroup;
1670   RemoveEventListenerInternal(EventListenerHolder(aDOMListener), eAllEvents,
1671                               nullptr, flags, true);
1672 }
1673 
HasMutationListeners()1674 bool EventListenerManager::HasMutationListeners() {
1675   if (mMayHaveMutationListeners) {
1676     uint32_t count = mListeners.Length();
1677     for (uint32_t i = 0; i < count; ++i) {
1678       Listener* listener = &mListeners.ElementAt(i);
1679       if (listener->mEventMessage >= eLegacyMutationEventFirst &&
1680           listener->mEventMessage <= eLegacyMutationEventLast) {
1681         return true;
1682       }
1683     }
1684   }
1685 
1686   return false;
1687 }
1688 
MutationListenerBits()1689 uint32_t EventListenerManager::MutationListenerBits() {
1690   uint32_t bits = 0;
1691   if (mMayHaveMutationListeners) {
1692     uint32_t count = mListeners.Length();
1693     for (uint32_t i = 0; i < count; ++i) {
1694       Listener* listener = &mListeners.ElementAt(i);
1695       if (listener->mEventMessage >= eLegacyMutationEventFirst &&
1696           listener->mEventMessage <= eLegacyMutationEventLast) {
1697         if (listener->mEventMessage == eLegacySubtreeModified) {
1698           return kAllMutationBits;
1699         }
1700         bits |= MutationBitForEventType(listener->mEventMessage);
1701       }
1702     }
1703   }
1704   return bits;
1705 }
1706 
HasListenersFor(const nsAString & aEventName) const1707 bool EventListenerManager::HasListenersFor(const nsAString& aEventName) const {
1708   RefPtr<nsAtom> atom = NS_Atomize(u"on"_ns + aEventName);
1709   return HasListenersFor(atom);
1710 }
1711 
HasListenersFor(nsAtom * aEventNameWithOn) const1712 bool EventListenerManager::HasListenersFor(nsAtom* aEventNameWithOn) const {
1713   return HasListenersForInternal(aEventNameWithOn, false);
1714 }
1715 
HasNonSystemGroupListenersFor(nsAtom * aEventNameWithOn) const1716 bool EventListenerManager::HasNonSystemGroupListenersFor(
1717     nsAtom* aEventNameWithOn) const {
1718   return HasListenersForInternal(aEventNameWithOn, true);
1719 }
1720 
HasListenersForInternal(nsAtom * aEventNameWithOn,bool aIgnoreSystemGroup) const1721 bool EventListenerManager::HasListenersForInternal(
1722     nsAtom* aEventNameWithOn, bool aIgnoreSystemGroup) const {
1723 #ifdef DEBUG
1724   nsAutoString name;
1725   aEventNameWithOn->ToString(name);
1726 #endif
1727   NS_ASSERTION(StringBeginsWith(name, u"on"_ns),
1728                "Event name does not start with 'on'");
1729   uint32_t count = mListeners.Length();
1730   for (uint32_t i = 0; i < count; ++i) {
1731     const Listener* listener = &mListeners.ElementAt(i);
1732     if (listener->mTypeAtom == aEventNameWithOn) {
1733       if (aIgnoreSystemGroup && listener->mFlags.mInSystemGroup) {
1734         continue;
1735       }
1736       return true;
1737     }
1738   }
1739   return false;
1740 }
1741 
HasListeners() const1742 bool EventListenerManager::HasListeners() const {
1743   return !mListeners.IsEmpty();
1744 }
1745 
GetListenerInfo(nsTArray<RefPtr<nsIEventListenerInfo>> & aList)1746 nsresult EventListenerManager::GetListenerInfo(
1747     nsTArray<RefPtr<nsIEventListenerInfo>>& aList) {
1748   nsCOMPtr<EventTarget> target = mTarget;
1749   NS_ENSURE_STATE(target);
1750   aList.Clear();
1751   for (const Listener& listener : mListeners.ForwardRange()) {
1752     // If this is a script handler and we haven't yet
1753     // compiled the event handler itself go ahead and compile it
1754     if (listener.mListenerType == Listener::eJSEventListener &&
1755         listener.mHandlerIsString) {
1756       CompileEventHandlerInternal(const_cast<Listener*>(&listener), nullptr,
1757                                   nullptr);
1758     }
1759     nsAutoString eventType;
1760     if (listener.mAllEvents) {
1761       eventType.SetIsVoid(true);
1762     } else if (listener.mListenerType == Listener::eNoListener) {
1763       continue;
1764     } else {
1765       eventType.Assign(Substring(nsDependentAtomString(listener.mTypeAtom), 2));
1766     }
1767 
1768     JS::Rooted<JSObject*> callback(RootingCx());
1769     JS::Rooted<JSObject*> callbackGlobal(RootingCx());
1770     if (JSEventHandler* handler = listener.GetJSEventHandler()) {
1771       if (handler->GetTypedEventHandler().HasEventHandler()) {
1772         CallbackFunction* callbackFun = handler->GetTypedEventHandler().Ptr();
1773         callback = callbackFun->CallableOrNull();
1774         callbackGlobal = callbackFun->CallbackGlobalOrNull();
1775         if (!callback) {
1776           // This will be null for cross-compartment event listeners
1777           // which have been destroyed.
1778           continue;
1779         }
1780       }
1781     } else if (listener.mListenerType == Listener::eWebIDLListener) {
1782       EventListener* listenerCallback = listener.mListener.GetWebIDLCallback();
1783       callback = listenerCallback->CallbackOrNull();
1784       callbackGlobal = listenerCallback->CallbackGlobalOrNull();
1785       if (!callback) {
1786         // This will be null for cross-compartment event listeners
1787         // which have been destroyed.
1788         continue;
1789       }
1790     }
1791 
1792     RefPtr<EventListenerInfo> info = new EventListenerInfo(
1793         this, eventType, callback, callbackGlobal, listener.mFlags.mCapture,
1794         listener.mFlags.mAllowUntrustedEvents, listener.mFlags.mInSystemGroup,
1795         listener.mListenerIsHandler);
1796     aList.AppendElement(info.forget());
1797   }
1798   return NS_OK;
1799 }
1800 
GetListenerFor(nsAString & aType,JSObject * aListener,bool aCapturing,bool aAllowsUntrusted,bool aInSystemEventGroup,bool aIsHandler)1801 EventListenerManager::Listener* EventListenerManager::GetListenerFor(
1802     nsAString& aType, JSObject* aListener, bool aCapturing,
1803     bool aAllowsUntrusted, bool aInSystemEventGroup, bool aIsHandler) {
1804   NS_ENSURE_TRUE(aListener, nullptr);
1805 
1806   for (Listener& listener : mListeners.ForwardRange()) {
1807     if ((aType.IsVoid() && !listener.mAllEvents) ||
1808         !Substring(nsDependentAtomString(listener.mTypeAtom), 2)
1809              .Equals(aType) ||
1810         listener.mListenerType == Listener::eNoListener) {
1811       continue;
1812     }
1813 
1814     if (listener.mFlags.mCapture != aCapturing ||
1815         listener.mFlags.mAllowUntrustedEvents != aAllowsUntrusted ||
1816         listener.mFlags.mInSystemGroup != aInSystemEventGroup) {
1817       continue;
1818     }
1819 
1820     if (aIsHandler) {
1821       if (JSEventHandler* handler = listener.GetJSEventHandler()) {
1822         if (handler->GetTypedEventHandler().HasEventHandler()) {
1823           if (handler->GetTypedEventHandler().Ptr()->CallableOrNull() ==
1824               aListener) {
1825             return &listener;
1826           }
1827         }
1828       }
1829     } else if (listener.mListenerType == Listener::eWebIDLListener &&
1830                listener.mListener.GetWebIDLCallback()->CallbackOrNull() ==
1831                    aListener) {
1832       return &listener;
1833     }
1834   }
1835   return nullptr;
1836 }
1837 
IsListenerEnabled(nsAString & aType,JSObject * aListener,bool aCapturing,bool aAllowsUntrusted,bool aInSystemEventGroup,bool aIsHandler,bool * aEnabled)1838 nsresult EventListenerManager::IsListenerEnabled(
1839     nsAString& aType, JSObject* aListener, bool aCapturing,
1840     bool aAllowsUntrusted, bool aInSystemEventGroup, bool aIsHandler,
1841     bool* aEnabled) {
1842   Listener* listener =
1843       GetListenerFor(aType, aListener, aCapturing, aAllowsUntrusted,
1844                      aInSystemEventGroup, aIsHandler);
1845   NS_ENSURE_TRUE(listener, NS_ERROR_NOT_AVAILABLE);
1846   *aEnabled = listener->mEnabled;
1847   return NS_OK;
1848 }
1849 
SetListenerEnabled(nsAString & aType,JSObject * aListener,bool aCapturing,bool aAllowsUntrusted,bool aInSystemEventGroup,bool aIsHandler,bool aEnabled)1850 nsresult EventListenerManager::SetListenerEnabled(
1851     nsAString& aType, JSObject* aListener, bool aCapturing,
1852     bool aAllowsUntrusted, bool aInSystemEventGroup, bool aIsHandler,
1853     bool aEnabled) {
1854   Listener* listener =
1855       GetListenerFor(aType, aListener, aCapturing, aAllowsUntrusted,
1856                      aInSystemEventGroup, aIsHandler);
1857   NS_ENSURE_TRUE(listener, NS_ERROR_NOT_AVAILABLE);
1858   listener->mEnabled = aEnabled;
1859   if (aEnabled) {
1860     // We may have enabled some listener, clear the cache for which events
1861     // we don't have listeners.
1862     mNoListenerForEvent = eVoidEvent;
1863     mNoListenerForEventAtom = nullptr;
1864   }
1865   return NS_OK;
1866 }
1867 
HasUnloadListeners()1868 bool EventListenerManager::HasUnloadListeners() {
1869   uint32_t count = mListeners.Length();
1870   for (uint32_t i = 0; i < count; ++i) {
1871     Listener* listener = &mListeners.ElementAt(i);
1872     if (listener->mEventMessage == eUnload) {
1873       return true;
1874     }
1875   }
1876   return false;
1877 }
1878 
HasBeforeUnloadListeners()1879 bool EventListenerManager::HasBeforeUnloadListeners() {
1880   uint32_t count = mListeners.Length();
1881   for (uint32_t i = 0; i < count; ++i) {
1882     Listener* listener = &mListeners.ElementAt(i);
1883     if (listener->mEventMessage == eBeforeUnload) {
1884       return true;
1885     }
1886   }
1887   return false;
1888 }
1889 
SetEventHandler(nsAtom * aEventName,EventHandlerNonNull * aHandler)1890 void EventListenerManager::SetEventHandler(nsAtom* aEventName,
1891                                            EventHandlerNonNull* aHandler) {
1892   if (!aHandler) {
1893     RemoveEventHandler(aEventName);
1894     return;
1895   }
1896 
1897   // Untrusted events are always permitted for non-chrome script
1898   // handlers.
1899   SetEventHandlerInternal(
1900       aEventName, TypedEventHandler(aHandler),
1901       !mIsMainThreadELM || !nsContentUtils::IsCallerChrome());
1902 }
1903 
SetEventHandler(OnErrorEventHandlerNonNull * aHandler)1904 void EventListenerManager::SetEventHandler(
1905     OnErrorEventHandlerNonNull* aHandler) {
1906   if (!aHandler) {
1907     RemoveEventHandler(nsGkAtoms::onerror);
1908     return;
1909   }
1910 
1911   // Untrusted events are always permitted on workers and for non-chrome script
1912   // on the main thread.
1913   bool allowUntrusted = !mIsMainThreadELM || !nsContentUtils::IsCallerChrome();
1914 
1915   SetEventHandlerInternal(nsGkAtoms::onerror, TypedEventHandler(aHandler),
1916                           allowUntrusted);
1917 }
1918 
SetEventHandler(OnBeforeUnloadEventHandlerNonNull * aHandler)1919 void EventListenerManager::SetEventHandler(
1920     OnBeforeUnloadEventHandlerNonNull* aHandler) {
1921   if (!aHandler) {
1922     RemoveEventHandler(nsGkAtoms::onbeforeunload);
1923     return;
1924   }
1925 
1926   // Untrusted events are always permitted for non-chrome script
1927   // handlers.
1928   SetEventHandlerInternal(
1929       nsGkAtoms::onbeforeunload, TypedEventHandler(aHandler),
1930       !mIsMainThreadELM || !nsContentUtils::IsCallerChrome());
1931 }
1932 
GetTypedEventHandler(nsAtom * aEventName)1933 const TypedEventHandler* EventListenerManager::GetTypedEventHandler(
1934     nsAtom* aEventName) {
1935   EventMessage eventMessage = GetEventMessage(aEventName);
1936   Listener* listener = FindEventHandler(eventMessage, aEventName);
1937 
1938   if (!listener) {
1939     return nullptr;
1940   }
1941 
1942   JSEventHandler* jsEventHandler = listener->GetJSEventHandler();
1943 
1944   if (listener->mHandlerIsString) {
1945     CompileEventHandlerInternal(listener, nullptr, nullptr);
1946   }
1947 
1948   const TypedEventHandler& typedHandler =
1949       jsEventHandler->GetTypedEventHandler();
1950   return typedHandler.HasEventHandler() ? &typedHandler : nullptr;
1951 }
1952 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const1953 size_t EventListenerManager::SizeOfIncludingThis(
1954     MallocSizeOf aMallocSizeOf) const {
1955   size_t n = aMallocSizeOf(this);
1956   n += mListeners.ShallowSizeOfExcludingThis(aMallocSizeOf);
1957   uint32_t count = mListeners.Length();
1958   for (uint32_t i = 0; i < count; ++i) {
1959     JSEventHandler* jsEventHandler =
1960         mListeners.ElementAt(i).GetJSEventHandler();
1961     if (jsEventHandler) {
1962       n += jsEventHandler->SizeOfIncludingThis(aMallocSizeOf);
1963     }
1964   }
1965   return n;
1966 }
1967 
MarkForCC()1968 void EventListenerManager::MarkForCC() {
1969   uint32_t count = mListeners.Length();
1970   for (uint32_t i = 0; i < count; ++i) {
1971     const Listener& listener = mListeners.ElementAt(i);
1972     JSEventHandler* jsEventHandler = listener.GetJSEventHandler();
1973     if (jsEventHandler) {
1974       const TypedEventHandler& typedHandler =
1975           jsEventHandler->GetTypedEventHandler();
1976       if (typedHandler.HasEventHandler()) {
1977         typedHandler.Ptr()->MarkForCC();
1978       }
1979     } else if (listener.mListenerType == Listener::eWebIDLListener) {
1980       listener.mListener.GetWebIDLCallback()->MarkForCC();
1981     }
1982   }
1983   if (mRefCnt.IsPurple()) {
1984     mRefCnt.RemovePurple();
1985   }
1986 }
1987 
TraceListeners(JSTracer * aTrc)1988 void EventListenerManager::TraceListeners(JSTracer* aTrc) {
1989   uint32_t count = mListeners.Length();
1990   for (uint32_t i = 0; i < count; ++i) {
1991     const Listener& listener = mListeners.ElementAt(i);
1992     JSEventHandler* jsEventHandler = listener.GetJSEventHandler();
1993     if (jsEventHandler) {
1994       const TypedEventHandler& typedHandler =
1995           jsEventHandler->GetTypedEventHandler();
1996       if (typedHandler.HasEventHandler()) {
1997         mozilla::TraceScriptHolder(typedHandler.Ptr(), aTrc);
1998       }
1999     } else if (listener.mListenerType == Listener::eWebIDLListener) {
2000       mozilla::TraceScriptHolder(listener.mListener.GetWebIDLCallback(), aTrc);
2001     }
2002     // We might have eWrappedJSListener, but that is the legacy type for
2003     // JS implemented event listeners, and trickier to handle here.
2004   }
2005 }
2006 
HasNonSystemGroupListenersForUntrustedKeyEvents()2007 bool EventListenerManager::HasNonSystemGroupListenersForUntrustedKeyEvents() {
2008   uint32_t count = mListeners.Length();
2009   for (uint32_t i = 0; i < count; ++i) {
2010     Listener* listener = &mListeners.ElementAt(i);
2011     if (!listener->mFlags.mInSystemGroup &&
2012         listener->mFlags.mAllowUntrustedEvents &&
2013         (listener->mTypeAtom == nsGkAtoms::onkeydown ||
2014          listener->mTypeAtom == nsGkAtoms::onkeypress ||
2015          listener->mTypeAtom == nsGkAtoms::onkeyup)) {
2016       return true;
2017     }
2018   }
2019   return false;
2020 }
2021 
2022 bool EventListenerManager::
HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents()2023     HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents() {
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 && !listener->mFlags.mInSystemGroup &&
2028         listener->mFlags.mAllowUntrustedEvents &&
2029         (listener->mTypeAtom == nsGkAtoms::onkeydown ||
2030          listener->mTypeAtom == nsGkAtoms::onkeypress ||
2031          listener->mTypeAtom == nsGkAtoms::onkeyup)) {
2032       return true;
2033     }
2034   }
2035   return false;
2036 }
2037 
HasApzAwareListeners()2038 bool EventListenerManager::HasApzAwareListeners() {
2039   uint32_t count = mListeners.Length();
2040   for (uint32_t i = 0; i < count; ++i) {
2041     Listener* listener = &mListeners.ElementAt(i);
2042     if (IsApzAwareListener(listener)) {
2043       return true;
2044     }
2045   }
2046   return false;
2047 }
2048 
IsApzAwareListener(Listener * aListener)2049 bool EventListenerManager::IsApzAwareListener(Listener* aListener) {
2050   return !aListener->mFlags.mPassive && mIsMainThreadELM &&
2051          IsApzAwareEvent(aListener->mTypeAtom);
2052 }
2053 
IsWheelEventType(nsAtom * aEvent)2054 static bool IsWheelEventType(nsAtom* aEvent) {
2055   if (aEvent == nsGkAtoms::onwheel || aEvent == nsGkAtoms::onDOMMouseScroll ||
2056       aEvent == nsGkAtoms::onmousewheel ||
2057       aEvent == nsGkAtoms::onMozMousePixelScroll) {
2058     return true;
2059   }
2060   return false;
2061 }
2062 
IsApzAwareEvent(nsAtom * aEvent)2063 bool EventListenerManager::IsApzAwareEvent(nsAtom* aEvent) {
2064   if (IsWheelEventType(aEvent)) {
2065     return true;
2066   }
2067   // In theory we should schedule a repaint if the touch event pref changes,
2068   // because the event regions might be out of date. In practice that seems like
2069   // overkill because users generally shouldn't be flipping this pref, much
2070   // less expecting touch listeners on the page to immediately start preventing
2071   // scrolling without so much as a repaint. Tests that we write can work
2072   // around this constraint easily enough.
2073   if (aEvent == nsGkAtoms::ontouchstart || aEvent == nsGkAtoms::ontouchmove) {
2074     return TouchEvent::PrefEnabled(
2075         nsContentUtils::GetDocShellForEventTarget(mTarget));
2076   }
2077   return false;
2078 }
2079 
HasNonPassiveWheelListener()2080 bool EventListenerManager::HasNonPassiveWheelListener() {
2081   MOZ_ASSERT(NS_IsMainThread());
2082   uint32_t count = mListeners.Length();
2083   for (uint32_t i = 0; i < count; ++i) {
2084     Listener* listener = &mListeners.ElementAt(i);
2085     if (!listener->mFlags.mPassive && IsWheelEventType(listener->mTypeAtom)) {
2086       return true;
2087     }
2088   }
2089   return false;
2090 }
2091 
RemoveAllListeners()2092 void EventListenerManager::RemoveAllListeners() {
2093   while (!mListeners.IsEmpty()) {
2094     size_t idx = mListeners.Length() - 1;
2095     RefPtr<nsAtom> type = mListeners.ElementAt(idx).mTypeAtom;
2096     EventMessage message = mListeners.ElementAt(idx).mEventMessage;
2097     mListeners.RemoveElementAt(idx);
2098     NotifyEventListenerRemoved(type);
2099     if (IsDeviceType(message)) {
2100       DisableDevice(message);
2101     }
2102   }
2103 }
2104 
2105 already_AddRefed<nsIScriptGlobalObject>
GetScriptGlobalAndDocument(Document ** aDoc)2106 EventListenerManager::GetScriptGlobalAndDocument(Document** aDoc) {
2107   nsCOMPtr<Document> doc;
2108   nsCOMPtr<nsPIDOMWindowInner> win;
2109   if (nsINode* node = nsINode::FromEventTargetOrNull(mTarget)) {
2110     // Try to get context from doc
2111     doc = node->OwnerDoc();
2112     if (doc->IsLoadedAsData()) {
2113       return nullptr;
2114     }
2115 
2116     win = do_QueryInterface(doc->GetScopeObject());
2117   } else if ((win = GetTargetAsInnerWindow())) {
2118     doc = win->GetExtantDoc();
2119   }
2120 
2121   if (!win || !win->IsCurrentInnerWindow()) {
2122     return nullptr;
2123   }
2124 
2125   doc.forget(aDoc);
2126   nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(win);
2127   return global.forget();
2128 }
2129 
ListenerSignalFollower(EventListenerManager * aListenerManager,EventListenerManager::Listener * aListener)2130 EventListenerManager::ListenerSignalFollower::ListenerSignalFollower(
2131     EventListenerManager* aListenerManager,
2132     EventListenerManager::Listener* aListener)
2133     : dom::AbortFollower(),
2134       mListenerManager(aListenerManager),
2135       mListener(aListener->mListener.Clone()),
2136       mTypeAtom(aListener->mTypeAtom),
2137       mEventMessage(aListener->mEventMessage),
2138       mAllEvents(aListener->mAllEvents),
2139       mFlags(aListener->mFlags){};
2140 
2141 NS_IMPL_CYCLE_COLLECTION_CLASS(EventListenerManager::ListenerSignalFollower)
2142 
2143 NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerManager::ListenerSignalFollower)
2144 NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerManager::ListenerSignalFollower)
2145 
2146 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
2147     EventListenerManager::ListenerSignalFollower)
2148   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListener)
2149 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2150 
2151 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(
2152     EventListenerManager::ListenerSignalFollower)
2153   NS_IMPL_CYCLE_COLLECTION_UNLINK(mListener)
2154   tmp->mListenerManager = nullptr;
2155 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2156 
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerManager::ListenerSignalFollower)2157 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
2158     EventListenerManager::ListenerSignalFollower)
2159   NS_INTERFACE_MAP_ENTRY(nsISupports)
2160 NS_INTERFACE_MAP_END
2161 
2162 void EventListenerManager::ListenerSignalFollower::RunAbortAlgorithm() {
2163   if (mListenerManager) {
2164     RefPtr<EventListenerManager> elm = mListenerManager;
2165     mListenerManager = nullptr;
2166     elm->RemoveEventListenerInternal(std::move(mListener), mEventMessage,
2167                                      mTypeAtom, mFlags, mAllEvents);
2168   }
2169 }
2170 
2171 }  // namespace mozilla
2172