tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

EventListenerManager.h (27636B)


      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 #ifndef mozilla_EventListenerManager_h_
      8 #define mozilla_EventListenerManager_h_
      9 
     10 #include "mozilla/BasicEvents.h"
     11 #include "mozilla/JSEventHandler.h"
     12 #include "mozilla/MemoryReporting.h"
     13 #include "mozilla/dom/AbortFollower.h"
     14 #include "mozilla/dom/EventListenerBinding.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsCycleCollectionParticipant.h"
     17 #include "nsGkAtoms.h"
     18 #include "nsIDOMEventListener.h"
     19 #include "nsTArray.h"
     20 #include "nsTObserverArray.h"
     21 
     22 class nsIEventListenerInfo;
     23 class nsPIDOMWindowInner;
     24 class JSTracer;
     25 
     26 struct EventTypeData;
     27 
     28 namespace mozilla {
     29 
     30 class ELMCreationDetector;
     31 class EventListenerManager;
     32 class ListenerSignalFollower;
     33 
     34 namespace dom {
     35 class Event;
     36 class EventTarget;
     37 class Element;
     38 }  // namespace dom
     39 
     40 using EventListenerHolder =
     41    dom::CallbackObjectHolder<dom::EventListener, nsIDOMEventListener>;
     42 
     43 struct EventListenerFlags {
     44  friend class EventListenerManager;
     45 
     46 private:
     47  // If mListenerIsJSListener is true, the listener is implemented by JS.
     48  // Otherwise, it's implemented by native code or JS but it's wrapped.
     49  bool mListenerIsJSListener : 1;
     50 
     51 public:
     52  // If mCapture is true, it means the listener captures the event.  Otherwise,
     53  // it's listening at bubbling phase.
     54  bool mCapture : 1;
     55  // If mInSystemGroup is true, the listener is listening to the events in the
     56  // system group.
     57  bool mInSystemGroup : 1;
     58  // If mAllowUntrustedEvents is true, the listener is listening to the
     59  // untrusted events too.
     60  bool mAllowUntrustedEvents : 1;
     61  // If mPassive is true, the listener will not be calling preventDefault on the
     62  // event. (If it does call preventDefault, we should ignore it).
     63  bool mPassive : 1;
     64  // If mOnce is true, the listener will be removed from the manager before it
     65  // is invoked, so that it would only be invoked once.
     66  bool mOnce : 1;
     67 
     68  EventListenerFlags()
     69      : mListenerIsJSListener(false),
     70        mCapture(false),
     71        mInSystemGroup(false),
     72        mAllowUntrustedEvents(false),
     73        mPassive(false),
     74        mOnce(false) {}
     75 
     76  bool EqualsForAddition(const EventListenerFlags& aOther) const {
     77    return (mCapture == aOther.mCapture &&
     78            mInSystemGroup == aOther.mInSystemGroup &&
     79            mListenerIsJSListener == aOther.mListenerIsJSListener &&
     80            mAllowUntrustedEvents == aOther.mAllowUntrustedEvents);
     81    // Don't compare mPassive or mOnce
     82  }
     83 
     84  bool EqualsForRemoval(const EventListenerFlags& aOther) const {
     85    return (mCapture == aOther.mCapture &&
     86            mInSystemGroup == aOther.mInSystemGroup &&
     87            mListenerIsJSListener == aOther.mListenerIsJSListener);
     88    // Don't compare mAllowUntrustedEvents, mPassive, or mOnce
     89  }
     90 };
     91 
     92 inline EventListenerFlags TrustedEventsAtBubble() {
     93  EventListenerFlags flags;
     94  return flags;
     95 }
     96 
     97 inline EventListenerFlags TrustedEventsAtCapture() {
     98  EventListenerFlags flags;
     99  flags.mCapture = true;
    100  return flags;
    101 }
    102 
    103 inline EventListenerFlags AllEventsAtBubble() {
    104  EventListenerFlags flags;
    105  flags.mAllowUntrustedEvents = true;
    106  return flags;
    107 }
    108 
    109 inline EventListenerFlags AllEventsAtCapture() {
    110  EventListenerFlags flags;
    111  flags.mCapture = true;
    112  flags.mAllowUntrustedEvents = true;
    113  return flags;
    114 }
    115 
    116 inline EventListenerFlags TrustedEventsAtSystemGroupBubble() {
    117  EventListenerFlags flags;
    118  flags.mInSystemGroup = true;
    119  return flags;
    120 }
    121 
    122 inline EventListenerFlags TrustedEventsAtSystemGroupCapture() {
    123  EventListenerFlags flags;
    124  flags.mCapture = true;
    125  flags.mInSystemGroup = true;
    126  return flags;
    127 }
    128 
    129 inline EventListenerFlags AllEventsAtSystemGroupBubble() {
    130  EventListenerFlags flags;
    131  flags.mInSystemGroup = true;
    132  flags.mAllowUntrustedEvents = true;
    133  return flags;
    134 }
    135 
    136 inline EventListenerFlags AllEventsAtSystemGroupCapture() {
    137  EventListenerFlags flags;
    138  flags.mCapture = true;
    139  flags.mInSystemGroup = true;
    140  flags.mAllowUntrustedEvents = true;
    141  return flags;
    142 }
    143 
    144 class EventListenerManagerBase {
    145 protected:
    146  EventListenerManagerBase();
    147 
    148  void ClearNoListenersForEvents() {
    149    mNoListenerForEvents[0] = eVoidEvent;
    150    mNoListenerForEvents[1] = eVoidEvent;
    151    mNoListenerForEvents[2] = eVoidEvent;
    152  }
    153 
    154  EventMessage mNoListenerForEvents[3];
    155  uint16_t mMayHaveDOMActivateEventListener : 1;
    156  uint16_t mMayHaveCapturingListeners : 1;
    157  uint16_t mMayHaveSystemGroupListeners : 1;
    158  uint16_t mMayHaveTouchEventListener : 1;
    159  uint16_t mMayHaveMouseEnterLeaveEventListener : 1;
    160  uint16_t mMayHavePointerEnterLeaveEventListener : 1;
    161  uint16_t mMayHavePointerRawUpdateEventListener : 1;
    162  uint16_t mMayHaveSelectionChangeEventListener : 1;
    163  uint16_t mMayHaveFormSelectEventListener : 1;
    164  uint16_t mMayHaveTransitionEventListener : 1;
    165  uint16_t mMayHaveSMILTimeEventListener : 1;
    166  uint16_t mClearingListeners : 1;
    167  uint16_t mIsMainThreadELM : 1;
    168  uint16_t mMayHaveListenersForUntrustedEvents : 1;
    169  // 2 unused flag.
    170 };
    171 
    172 /*
    173 * Event listener manager
    174 */
    175 
    176 class EventListenerManager final : public EventListenerManagerBase {
    177  ~EventListenerManager();
    178 
    179 public:
    180  struct Listener;
    181  class ListenerSignalFollower : public dom::AbortFollower {
    182   public:
    183    explicit ListenerSignalFollower(EventListenerManager* aListenerManager,
    184                                    Listener* aListener, nsAtom* aTypeAtom);
    185 
    186    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    187    NS_DECL_CYCLE_COLLECTION_CLASS(ListenerSignalFollower)
    188 
    189    void RunAbortAlgorithm() override;
    190 
    191    void Disconnect() {
    192      mListenerManager = nullptr;
    193      mListener.Reset();
    194      Unfollow();
    195    }
    196 
    197   protected:
    198    ~ListenerSignalFollower() = default;
    199 
    200    EventListenerManager* mListenerManager;
    201    EventListenerHolder mListener;
    202    RefPtr<nsAtom> mTypeAtom;
    203    bool mAllEvents;
    204    EventListenerFlags mFlags;
    205  };
    206 
    207  struct Listener {
    208    RefPtr<ListenerSignalFollower> mSignalFollower;
    209    EventListenerHolder mListener;
    210 
    211    enum ListenerType : uint8_t {
    212      // No listener.
    213      eNoListener,
    214      // A generic C++ implementation of nsIDOMEventListener.
    215      eNativeListener,
    216      // An event handler attribute using JSEventHandler.
    217      eJSEventListener,
    218      // A scripted EventListener.
    219      eWebIDLListener,
    220    };
    221    ListenerType mListenerType;
    222 
    223    bool mListenerIsHandler : 1;
    224    bool mHandlerIsString : 1;
    225    bool mAllEvents : 1;
    226    bool mEnabled : 1;
    227 
    228    EventListenerFlags mFlags;
    229 
    230    JSEventHandler* GetJSEventHandler() const {
    231      return (mListenerType == eJSEventListener)
    232                 ? static_cast<JSEventHandler*>(mListener.GetXPCOMCallback())
    233                 : nullptr;
    234    }
    235 
    236    Listener()
    237        : mListenerType(eNoListener),
    238          mListenerIsHandler(false),
    239          mHandlerIsString(false),
    240          mAllEvents(false),
    241          mEnabled(true) {}
    242 
    243    Listener(Listener&& aOther)
    244        : mSignalFollower(std::move(aOther.mSignalFollower)),
    245          mListener(std::move(aOther.mListener)),
    246          mListenerType(aOther.mListenerType),
    247          mListenerIsHandler(aOther.mListenerIsHandler),
    248          mHandlerIsString(aOther.mHandlerIsString),
    249          mAllEvents(aOther.mAllEvents),
    250          mEnabled(aOther.mEnabled),
    251          mFlags(aOther.mFlags) {
    252      aOther.mListenerType = eNoListener;
    253      aOther.mListenerIsHandler = false;
    254      aOther.mHandlerIsString = false;
    255      aOther.mAllEvents = false;
    256      aOther.mEnabled = true;
    257    }
    258 
    259    ~Listener() {
    260      if ((mListenerType == eJSEventListener) && mListener) {
    261        static_cast<JSEventHandler*>(mListener.GetXPCOMCallback())
    262            ->Disconnect();
    263      }
    264      if (mSignalFollower) {
    265        mSignalFollower->Disconnect();
    266      }
    267    }
    268 
    269    MOZ_ALWAYS_INLINE bool MatchesEventGroup(const WidgetEvent* aEvent) const {
    270      return mFlags.mInSystemGroup == aEvent->mFlags.mInSystemGroup;
    271    }
    272 
    273    MOZ_ALWAYS_INLINE bool MatchesEventPhase(const WidgetEvent* aEvent) const {
    274      return ((mFlags.mCapture && aEvent->mFlags.mInCapturePhase) ||
    275              (!mFlags.mCapture && aEvent->mFlags.mInBubblingPhase));
    276    }
    277 
    278    // Allow only trusted events, except when listener permits untrusted
    279    // events.
    280    MOZ_ALWAYS_INLINE bool AllowsEventTrustedness(
    281        const WidgetEvent* aEvent) const {
    282      return aEvent->IsTrusted() || mFlags.mAllowUntrustedEvents;
    283    }
    284  };
    285 
    286  /**
    287   * A reference counted subclass of a listener observer array.
    288   */
    289  struct ListenerArray final : public nsAutoTObserverArray<Listener, 1> {
    290    NS_INLINE_DECL_REFCOUNTING(EventListenerManager::ListenerArray);
    291    size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
    292 
    293   protected:
    294    ~ListenerArray() = default;
    295  };
    296 
    297  /**
    298   * An entry in the event listener map for a certain event type, carrying the
    299   * array of listeners for that type.
    300   */
    301  struct EventListenerMapEntry {
    302    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
    303 
    304    // The event type. Null if this entry is for "all events" listeners.
    305    RefPtr<nsAtom> mTypeAtom;
    306    // The array of listeners. New listeners are always added at the end.
    307    // Always non-null.
    308    // This is a RefPtr rather than an inline member for two reasons:
    309    //  - It needs to be a separate heap allocation so that, if the array of
    310    //    entries is mutated during iteration, the ListenerArray remains in a
    311    //    stable place.
    312    //  - It's a RefPtr rather than a UniquePtr so that iteration can share
    313    //    ownership of it and make sure that the listener array remains alive
    314    //    even if the entry is removed during iteration.
    315    RefPtr<ListenerArray> mListeners;
    316  };
    317 
    318  /**
    319   * The map of event listeners, keyed by event type atom.
    320   */
    321  struct EventListenerMap {
    322    bool IsEmpty() const { return mEntries.IsEmpty(); }
    323    void Clear() { mEntries.Clear(); }
    324 
    325    Maybe<size_t> EntryIndexForType(nsAtom* aTypeAtom) const;
    326    Maybe<size_t> EntryIndexForAllEvents() const;
    327 
    328    // Returns null if no entry is present for the given type.
    329    RefPtr<ListenerArray> GetListenersForType(nsAtom* aTypeAtom) const;
    330    RefPtr<ListenerArray> GetListenersForAllEvents() const;
    331 
    332    // Never returns null, creates a new empty entry if needed.
    333    RefPtr<ListenerArray> GetOrCreateListenersForType(nsAtom* aTypeAtom);
    334    RefPtr<ListenerArray> GetOrCreateListenersForAllEvents();
    335 
    336    size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
    337 
    338    // The array of entries, ordered by event type atom (specifically by the
    339    // nsAtom* address). If mEntries contains an entry for "all events"
    340    // listeners, that entry will be the first entry, because its atom will be
    341    // null so it will be ordered to the front.
    342    // All entries have non-empty listener arrays. If a non-empty listener
    343    // entry becomes empty, it is removed immediately.
    344    AutoTArray<EventListenerMapEntry, 2> mEntries;
    345  };
    346 
    347  explicit EventListenerManager(dom::EventTarget* aTarget);
    348 
    349  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EventListenerManager)
    350 
    351  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager)
    352 
    353  void AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener,
    354                        bool aUseCapture, bool aWantsUntrusted) {
    355    AddEventListener(aType, EventListenerHolder(aListener), aUseCapture,
    356                     aWantsUntrusted);
    357  }
    358  void AddEventListener(const nsAString& aType, dom::EventListener* aListener,
    359                        const dom::AddEventListenerOptionsOrBoolean& aOptions,
    360                        bool aWantsUntrusted) {
    361    AddEventListener(aType, EventListenerHolder(aListener), aOptions,
    362                     aWantsUntrusted);
    363  }
    364  void RemoveEventListener(const nsAString& aType,
    365                           nsIDOMEventListener* aListener, bool aUseCapture) {
    366    RemoveEventListener(aType, EventListenerHolder(aListener), aUseCapture);
    367  }
    368  void RemoveEventListener(const nsAString& aType,
    369                           dom::EventListener* aListener,
    370                           const dom::EventListenerOptionsOrBoolean& aOptions) {
    371    RemoveEventListener(aType, EventListenerHolder(aListener), aOptions);
    372  }
    373 
    374  void AddListenerForAllEvents(dom::EventListener* aListener, bool aUseCapture,
    375                               bool aWantsUntrusted, bool aSystemEventGroup);
    376  void RemoveListenerForAllEvents(dom::EventListener* aListener,
    377                                  bool aUseCapture, bool aSystemEventGroup);
    378 
    379  /**
    380   * Sets events listeners of all types.
    381   * @param an event listener
    382   */
    383  void AddEventListenerByType(nsIDOMEventListener* aListener,
    384                              const nsAString& type,
    385                              const EventListenerFlags& aFlags) {
    386    AddEventListenerByType(EventListenerHolder(aListener), type, aFlags);
    387  }
    388  void AddEventListenerByType(dom::EventListener* aListener,
    389                              const nsAString& type,
    390                              const EventListenerFlags& aFlags) {
    391    AddEventListenerByType(EventListenerHolder(aListener), type, aFlags);
    392  }
    393  void AddEventListenerByType(
    394      EventListenerHolder aListener, const nsAString& type,
    395      const EventListenerFlags& aFlags,
    396      const dom::Optional<bool>& aPassive = dom::Optional<bool>(),
    397      dom::AbortSignal* aSignal = nullptr);
    398  void RemoveEventListenerByType(nsIDOMEventListener* aListener,
    399                                 const nsAString& type,
    400                                 const EventListenerFlags& aFlags) {
    401    RemoveEventListenerByType(EventListenerHolder(aListener), type, aFlags);
    402  }
    403  void RemoveEventListenerByType(dom::EventListener* aListener,
    404                                 const nsAString& type,
    405                                 const EventListenerFlags& aFlags) {
    406    RemoveEventListenerByType(EventListenerHolder(aListener), type, aFlags);
    407  }
    408  void RemoveEventListenerByType(EventListenerHolder aListener,
    409                                 const nsAString& type,
    410                                 const EventListenerFlags& aFlags);
    411 
    412  /**
    413   * Sets the current "inline" event listener for aName to be a
    414   * function compiled from aFunc if !aDeferCompilation.  If
    415   * aDeferCompilation, then we assume that we can get the string from
    416   * mTarget later and compile lazily.
    417   *
    418   * aElement, if not null, is the element the string is associated with.
    419   */
    420  // XXXbz does that play correctly with nodes being adopted across
    421  // documents?  Need to double-check the spec here.
    422  nsresult SetEventHandler(nsAtom* aName, const nsAString& aFunc,
    423                           bool aDeferCompilation, bool aPermitUntrustedEvents,
    424                           dom::Element* aElement);
    425  /**
    426   * Remove the current "inline" event listener for aName.
    427   */
    428  void RemoveEventHandler(nsAtom* aName);
    429 
    430  // We only get called from the event dispatch code, which knows to be careful
    431  // with what it's doing.  We could annotate ourselves as MOZ_CAN_RUN_SCRIPT,
    432  // but then the event dispatch code would need a ton of MOZ_KnownLive for
    433  // things that come from slightly complicated stack-lifetime data structures.
    434  MOZ_CAN_RUN_SCRIPT_BOUNDARY
    435  void HandleEvent(nsPresContext* aPresContext, WidgetEvent* aEvent,
    436                   dom::Event** aDOMEvent, dom::EventTarget* aCurrentTarget,
    437                   nsEventStatus* aEventStatus, bool aItemInShadowTree) {
    438    if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) {
    439      return;
    440    }
    441 
    442    if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
    443      return;
    444    }
    445 
    446    if (!aEvent->IsTrusted() && !mMayHaveListenersForUntrustedEvents) {
    447      return;
    448    }
    449 
    450    // Check if we already know that there is no event listener for the event.
    451    if (aEvent->mMessage == eUnidentifiedEvent) {
    452      if (mNoListenerForEventAtom == aEvent->mSpecifiedEventType) {
    453        return;
    454      }
    455    } else if (mNoListenerForEvents[0] == aEvent->mMessage ||
    456               mNoListenerForEvents[1] == aEvent->mMessage ||
    457               mNoListenerForEvents[2] == aEvent->mMessage) {
    458      return;
    459    }
    460 
    461    if (mListenerMap.IsEmpty() || aEvent->PropagationStopped()) {
    462      return;
    463    }
    464 
    465    HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
    466                        aEventStatus, aItemInShadowTree);
    467  }
    468 
    469  /**
    470   * Tells the event listener manager that its target (which owns it) is
    471   * no longer using it (and could go away).
    472   */
    473  void Disconnect();
    474 
    475  /**
    476   * Allows us to quickly determine whether we have unload listeners registered.
    477   */
    478  bool HasUnloadListeners();
    479 
    480  /**
    481   * Allows us to quickly determine whether we have beforeunload listeners
    482   * registered.
    483   */
    484  bool HasBeforeUnloadListeners();
    485 
    486  /**
    487   * Returns true if there is at least one event listener for aEventName.
    488   */
    489  bool HasListenersFor(const nsAString& aEventName) const;
    490 
    491  /**
    492   * Returns true if there is at least one event listener for aEventNameWithOn.
    493   * Note that aEventNameWithOn must start with "on"!
    494   */
    495  bool HasListenersFor(nsAtom* aEventNameWithOn) const;
    496 
    497  bool HasNonPassiveListenersFor(const WidgetEvent* aEvent) const;
    498 
    499  /**
    500   * Similar to HasListenersFor, but ignores system group listeners.
    501   */
    502  bool HasNonSystemGroupListenersFor(nsAtom* aEventNameWithOn) const;
    503 
    504  /**
    505   * Returns true if there is at least one event listener.
    506   */
    507  bool HasListeners() const;
    508 
    509  /**
    510   * Sets aList to the list of nsIEventListenerInfo objects representing the
    511   * listeners managed by this listener manager.
    512   */
    513  nsresult GetListenerInfo(nsTArray<RefPtr<nsIEventListenerInfo>>& aList);
    514 
    515  nsresult IsListenerEnabled(nsAString& aType, JSObject* aListener,
    516                             bool aCapturing, bool aAllowsUntrusted,
    517                             bool aInSystemEventGroup, bool aIsHandler,
    518                             bool* aEnabled);
    519 
    520  nsresult SetListenerEnabled(nsAString& aType, JSObject* aListener,
    521                              bool aCapturing, bool aAllowsUntrusted,
    522                              bool aInSystemEventGroup, bool aIsHandler,
    523                              bool aEnabled);
    524 
    525  uint32_t GetIdentifierForEvent(nsAtom* aEvent);
    526 
    527  bool MayHaveDOMActivateListeners() const {
    528    return mMayHaveDOMActivateEventListener;
    529  }
    530 
    531  /**
    532   * Returns true if there may be a touch event listener registered,
    533   * false if there definitely isn't.
    534   */
    535  bool MayHaveTouchEventListener() const { return mMayHaveTouchEventListener; }
    536 
    537  bool MayHaveMouseEnterLeaveEventListener() const {
    538    return mMayHaveMouseEnterLeaveEventListener;
    539  }
    540  bool MayHavePointerEnterLeaveEventListener() const {
    541    return mMayHavePointerEnterLeaveEventListener;
    542  }
    543  bool MayHavePointerRawUpdateEventListener() const {
    544    return mMayHavePointerRawUpdateEventListener;
    545  }
    546  bool MayHaveSelectionChangeEventListener() const {
    547    return mMayHaveSelectionChangeEventListener;
    548  }
    549  bool MayHaveFormSelectEventListener() const {
    550    return mMayHaveFormSelectEventListener;
    551  }
    552  bool MayHaveTransitionEventListener() {
    553    return mMayHaveTransitionEventListener;
    554  }
    555  bool MayHaveSMILTimeEventListener() const {
    556    return mMayHaveSMILTimeEventListener;
    557  }
    558 
    559  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
    560 
    561  uint32_t ListenerCount() const;
    562 
    563  void MarkForCC();
    564 
    565  void TraceListeners(JSTracer* aTrc);
    566 
    567  dom::EventTarget* GetTarget() { return mTarget; }
    568 
    569  bool HasNonSystemGroupListenersForUntrustedKeyEvents();
    570  bool HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents();
    571 
    572  bool HasApzAwareListeners();
    573  bool IsApzAwareEvent(nsAtom* aEvent);
    574 
    575  bool HasNonPassiveWheelListener();
    576 
    577  /**
    578   * Remove all event listeners from the event target this EventListenerManager
    579   * is for.
    580   */
    581  void RemoveAllListeners();
    582 
    583 protected:
    584  MOZ_CAN_RUN_SCRIPT
    585  void HandleEventInternal(nsPresContext* aPresContext, WidgetEvent* aEvent,
    586                           dom::Event** aDOMEvent,
    587                           dom::EventTarget* aCurrentTarget,
    588                           nsEventStatus* aEventStatus, bool aItemInShadowTree);
    589 
    590  /**
    591   * Iterate the listener array and calls the matching listeners.
    592   *
    593   * Returns true if any listener matching the event group was found.
    594   */
    595  MOZ_CAN_RUN_SCRIPT
    596  bool HandleEventWithListenerArray(
    597      ListenerArray* aListeners, nsAtom* aTypeAtom, EventMessage aEventMessage,
    598      nsPresContext* aPresContext, WidgetEvent* aEvent, dom::Event** aDOMEvent,
    599      dom::EventTarget* aCurrentTarget, bool aItemInShadowTree);
    600 
    601  /**
    602   * Call the listener.
    603   *
    604   * Returns true if we should proceed iterating over the remaining listeners,
    605   * or false if iteration should be stopped.
    606   */
    607  MOZ_CAN_RUN_SCRIPT
    608  bool HandleEventSingleListener(Listener* aListener, nsAtom* aTypeAtom,
    609                                 WidgetEvent* aEvent, dom::Event* aDOMEvent,
    610                                 dom::EventTarget* aCurrentTarget,
    611                                 bool aItemInShadowTree);
    612 
    613  /**
    614   * If the given EventMessage has a legacy version that we support, then this
    615   * function returns that legacy version. Otherwise, this function simply
    616   * returns the passed-in EventMessage.
    617   */
    618  static EventMessage GetLegacyEventMessage(EventMessage aEventMessage);
    619 
    620  /**
    621   * Get the event message for the given event name.
    622   */
    623  EventMessage GetEventMessage(nsAtom* aEventName) const;
    624 
    625  /**
    626   * Get the event message and atom for the given event type.
    627   */
    628  EventMessage GetEventMessageAndAtomForListener(const nsAString& aType,
    629                                                 nsAtom** aAtom);
    630 
    631  void ProcessApzAwareEventListenerAdd();
    632 
    633  /**
    634   * Compile the "inline" event listener for aListener.  The
    635   * body of the listener can be provided in aBody; if this is null we
    636   * will look for it on mTarget.  If aBody is provided, aElement should be
    637   * as well; otherwise it will also be inferred from mTarget.
    638   */
    639  nsresult CompileEventHandlerInternal(Listener* aListener, nsAtom* aTypeAtom,
    640                                       const nsAString* aBody,
    641                                       dom::Element* aElement);
    642 
    643  /**
    644   * Find the Listener for the "inline" event listener for aTypeAtom.
    645   */
    646  Listener* FindEventHandler(nsAtom* aTypeAtom);
    647 
    648  /**
    649   * Set the "inline" event listener for aName to aHandler.  aHandler may be
    650   * have no actual handler set to indicate that we should lazily get and
    651   * compile the string for this listener, but in that case aContext and
    652   * aScopeGlobal must be non-null.  Otherwise, aContext and aScopeGlobal are
    653   * allowed to be null.
    654   */
    655  Listener* SetEventHandlerInternal(nsAtom* aName,
    656                                    const TypedEventHandler& aHandler,
    657                                    bool aPermitUntrustedEvents);
    658 
    659  bool IsDeviceType(nsAtom* aTypeAtom);
    660  void EnableDevice(nsAtom* aTypeAtom);
    661  void DisableDevice(nsAtom* aTypeAtom);
    662 
    663  bool HasListenersForInternal(nsAtom* aEventNameWithOn,
    664                               bool aIgnoreSystemGroup) const;
    665 
    666  Listener* GetListenerFor(nsAString& aType, JSObject* aListener,
    667                           bool aCapturing, bool aAllowsUntrusted,
    668                           bool aInSystemEventGroup, bool aIsHandler);
    669 
    670 public:
    671  /**
    672   * Set the "inline" event listener for aEventName to aHandler.  If
    673   * aHandler is null, this will actually remove the event listener
    674   */
    675  void SetEventHandler(nsAtom* aEventName, dom::EventHandlerNonNull* aHandler);
    676  void SetEventHandler(dom::OnErrorEventHandlerNonNull* aHandler);
    677  void SetEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler);
    678 
    679  /**
    680   * Get the value of the "inline" event listener for aEventName.
    681   * This may cause lazy compilation if the listener is uncompiled.
    682   *
    683   * Note: It's the caller's responsibility to make sure to call the right one
    684   * of these methods.  In particular, "onerror" events use
    685   * OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
    686   * for others.
    687   */
    688  dom::EventHandlerNonNull* GetEventHandler(nsAtom* aEventName) {
    689    const TypedEventHandler* typedHandler = GetTypedEventHandler(aEventName);
    690    return typedHandler ? typedHandler->NormalEventHandler() : nullptr;
    691  }
    692 
    693  dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler() {
    694    const TypedEventHandler* typedHandler =
    695        GetTypedEventHandler(nsGkAtoms::onerror);
    696    return typedHandler ? typedHandler->OnErrorEventHandler() : nullptr;
    697  }
    698 
    699  dom::OnBeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler() {
    700    const TypedEventHandler* typedHandler =
    701        GetTypedEventHandler(nsGkAtoms::onbeforeunload);
    702    return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr;
    703  }
    704 
    705 private:
    706  already_AddRefed<nsPIDOMWindowInner> WindowFromListener(
    707      Listener* aListener, nsAtom* aTypeAtom, bool aItemInShadowTree);
    708 
    709 protected:
    710  /**
    711   * Helper method for implementing the various Get*EventHandler above.  Will
    712   * return null if we don't have an event handler for this event name.
    713   */
    714  const TypedEventHandler* GetTypedEventHandler(nsAtom* aEventName);
    715 
    716  void AddEventListener(const nsAString& aType, EventListenerHolder aListener,
    717                        const dom::AddEventListenerOptionsOrBoolean& aOptions,
    718                        bool aWantsUntrusted);
    719  void AddEventListener(const nsAString& aType, EventListenerHolder aListener,
    720                        bool aUseCapture, bool aWantsUntrusted);
    721  void RemoveEventListener(const nsAString& aType,
    722                           EventListenerHolder aListener,
    723                           const dom::EventListenerOptionsOrBoolean& aOptions);
    724  void RemoveEventListener(const nsAString& aType,
    725                           EventListenerHolder aListener, bool aUseCapture);
    726 
    727  void AddEventListenerInternal(EventListenerHolder aListener,
    728                                EventMessage aEventMessage, nsAtom* aTypeAtom,
    729                                const EventListenerFlags& aFlags,
    730                                bool aHandler = false, bool aAllEvents = false,
    731                                dom::AbortSignal* aSignal = nullptr);
    732  void RemoveEventListenerInternal(EventListenerHolder aListener,
    733                                   nsAtom* aUserType,
    734                                   const EventListenerFlags& aFlags,
    735                                   bool aAllEvents = false);
    736  void RemoveAllListenersSilently();
    737  void NotifyEventListenerRemoved(nsAtom* aUserType);
    738  const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
    739  const EventTypeData* GetTypeDataForEventName(nsAtom* aName);
    740  nsPIDOMWindowInner* GetInnerWindowForTarget();
    741  already_AddRefed<nsPIDOMWindowInner> GetTargetAsInnerWindow() const;
    742 
    743  bool ListenerCanHandle(const Listener* aListener,
    744                         const WidgetEvent* aEvent) const;
    745 
    746  // BE AWARE, a lot of instances of EventListenerManager will be created.
    747  // Therefor, we need to keep this class compact.  When you add integer
    748  // members, please add them to EventListenerManagerBase and check the size
    749  // at build time.
    750 
    751  already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalAndDocument(
    752      mozilla::dom::Document** aDoc);
    753 
    754  void MaybeMarkPassive(EventMessage aMessage, EventListenerFlags& aFlags);
    755 
    756  EventListenerMap mListenerMap;
    757  dom::EventTarget* MOZ_NON_OWNING_REF mTarget;
    758  RefPtr<nsAtom> mNoListenerForEventAtom;
    759 
    760  friend class ELMCreationDetector;
    761  static uint32_t sMainThreadCreatedCount;
    762 };
    763 
    764 }  // namespace mozilla
    765 
    766 #endif  // mozilla_EventListenerManager_h_