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/dom/EventListenerBinding.h"
12 #include "mozilla/JSEventHandler.h"
13 #include "mozilla/MemoryReporting.h"
14 #include "nsCOMPtr.h"
15 #include "nsCycleCollectionParticipant.h"
16 #include "nsGkAtoms.h"
17 #include "nsIDOMEventListener.h"
18 #include "nsTObserverArray.h"
19 
20 class nsIDocShell;
21 class nsIDOMEvent;
22 class nsIEventListenerInfo;
23 class nsPIDOMWindowInner;
24 class JSTracer;
25 
26 struct EventTypeData;
27 
28 template <class T>
29 class nsCOMArray;
30 
31 namespace mozilla {
32 
33 class ELMCreationDetector;
34 class EventListenerManager;
35 
36 namespace dom {
37 class EventTarget;
38 class Element;
39 }  // namespace dom
40 
41 typedef dom::CallbackObjectHolder<dom::EventListener, nsIDOMEventListener>
42     EventListenerHolder;
43 
44 struct EventListenerFlags {
45   friend class EventListenerManager;
46 
47  private:
48   // If mListenerIsJSListener is true, the listener is implemented by JS.
49   // Otherwise, it's implemented by native code or JS but it's wrapped.
50   bool mListenerIsJSListener : 1;
51 
52  public:
53   // If mCapture is true, it means the listener captures the event.  Otherwise,
54   // it's listening at bubbling phase.
55   bool mCapture : 1;
56   // If mInSystemGroup is true, the listener is listening to the events in the
57   // system group.
58   bool mInSystemGroup : 1;
59   // If mAllowUntrustedEvents is true, the listener is listening to the
60   // untrusted events too.
61   bool mAllowUntrustedEvents : 1;
62   // If mPassive is true, the listener will not be calling preventDefault on the
63   // event. (If it does call preventDefault, we should ignore it).
64   bool mPassive : 1;
65   // If mOnce is true, the listener will be removed from the manager before it
66   // is invoked, so that it would only be invoked once.
67   bool mOnce : 1;
68 
EventListenerFlagsEventListenerFlags69   EventListenerFlags()
70       : mListenerIsJSListener(false),
71         mCapture(false),
72         mInSystemGroup(false),
73         mAllowUntrustedEvents(false),
74         mPassive(false),
75         mOnce(false) {}
76 
EqualsForAdditionEventListenerFlags77   bool EqualsForAddition(const EventListenerFlags& aOther) const {
78     return (mCapture == aOther.mCapture &&
79             mInSystemGroup == aOther.mInSystemGroup &&
80             mListenerIsJSListener == aOther.mListenerIsJSListener &&
81             mAllowUntrustedEvents == aOther.mAllowUntrustedEvents);
82     // Don't compare mPassive or mOnce
83   }
84 
EqualsForRemovalEventListenerFlags85   bool EqualsForRemoval(const EventListenerFlags& aOther) const {
86     return (mCapture == aOther.mCapture &&
87             mInSystemGroup == aOther.mInSystemGroup &&
88             mListenerIsJSListener == aOther.mListenerIsJSListener);
89     // Don't compare mAllowUntrustedEvents, mPassive, or mOnce
90   }
91 };
92 
TrustedEventsAtBubble()93 inline EventListenerFlags TrustedEventsAtBubble() {
94   EventListenerFlags flags;
95   return flags;
96 }
97 
TrustedEventsAtCapture()98 inline EventListenerFlags TrustedEventsAtCapture() {
99   EventListenerFlags flags;
100   flags.mCapture = true;
101   return flags;
102 }
103 
AllEventsAtBubble()104 inline EventListenerFlags AllEventsAtBubble() {
105   EventListenerFlags flags;
106   flags.mAllowUntrustedEvents = true;
107   return flags;
108 }
109 
AllEventsAtCapture()110 inline EventListenerFlags AllEventsAtCapture() {
111   EventListenerFlags flags;
112   flags.mCapture = true;
113   flags.mAllowUntrustedEvents = true;
114   return flags;
115 }
116 
TrustedEventsAtSystemGroupBubble()117 inline EventListenerFlags TrustedEventsAtSystemGroupBubble() {
118   EventListenerFlags flags;
119   flags.mInSystemGroup = true;
120   return flags;
121 }
122 
TrustedEventsAtSystemGroupCapture()123 inline EventListenerFlags TrustedEventsAtSystemGroupCapture() {
124   EventListenerFlags flags;
125   flags.mCapture = true;
126   flags.mInSystemGroup = true;
127   return flags;
128 }
129 
AllEventsAtSystemGroupBubble()130 inline EventListenerFlags AllEventsAtSystemGroupBubble() {
131   EventListenerFlags flags;
132   flags.mInSystemGroup = true;
133   flags.mAllowUntrustedEvents = true;
134   return flags;
135 }
136 
AllEventsAtSystemGroupCapture()137 inline EventListenerFlags AllEventsAtSystemGroupCapture() {
138   EventListenerFlags flags;
139   flags.mCapture = true;
140   flags.mInSystemGroup = true;
141   flags.mAllowUntrustedEvents = true;
142   return flags;
143 }
144 
145 class EventListenerManagerBase {
146  protected:
147   EventListenerManagerBase();
148 
149   EventMessage mNoListenerForEvent;
150   uint16_t mMayHavePaintEventListener : 1;
151   uint16_t mMayHaveMutationListeners : 1;
152   uint16_t mMayHaveCapturingListeners : 1;
153   uint16_t mMayHaveSystemGroupListeners : 1;
154   uint16_t mMayHaveTouchEventListener : 1;
155   uint16_t mMayHaveMouseEnterLeaveEventListener : 1;
156   uint16_t mMayHavePointerEnterLeaveEventListener : 1;
157   uint16_t mMayHaveKeyEventListener : 1;
158   uint16_t mMayHaveInputOrCompositionEventListener : 1;
159   uint16_t mMayHaveSelectionChangeEventListener : 1;
160   uint16_t mClearingListeners : 1;
161   uint16_t mIsMainThreadELM : 1;
162   // uint16_t mUnused : 4;
163 };
164 
165 /*
166  * Event listener manager
167  */
168 
169 class EventListenerManager final : public EventListenerManagerBase {
170   ~EventListenerManager();
171 
172  public:
173   struct Listener {
174     EventListenerHolder mListener;
175     RefPtr<nsAtom> mTypeAtom;  // for the main thread
176     nsString mTypeString;      // for non-main-threads
177     EventMessage mEventMessage;
178 
179     enum ListenerType : uint8_t {
180       eNoListener,
181       eNativeListener,
182       eJSEventListener,
183       eWrappedJSListener,
184       eWebIDLListener,
185     };
186     ListenerType mListenerType;
187 
188     bool mListenerIsHandler : 1;
189     bool mHandlerIsString : 1;
190     bool mAllEvents : 1;
191     bool mIsChrome : 1;
192 
193     EventListenerFlags mFlags;
194 
GetJSEventHandlerListener195     JSEventHandler* GetJSEventHandler() const {
196       return (mListenerType == eJSEventListener)
197                  ? static_cast<JSEventHandler*>(mListener.GetXPCOMCallback())
198                  : nullptr;
199     }
200 
ListenerListener201     Listener()
202         : mEventMessage(eVoidEvent),
203           mListenerType(eNoListener),
204           mListenerIsHandler(false),
205           mHandlerIsString(false),
206           mAllEvents(false),
207           mIsChrome(false) {}
208 
ListenerListener209     Listener(Listener&& aOther)
210         : mListener(Move(aOther.mListener)),
211           mTypeAtom(aOther.mTypeAtom.forget()),
212           mTypeString(aOther.mTypeString),
213           mEventMessage(aOther.mEventMessage),
214           mListenerType(aOther.mListenerType),
215           mListenerIsHandler(aOther.mListenerIsHandler),
216           mHandlerIsString(aOther.mHandlerIsString),
217           mAllEvents(aOther.mAllEvents),
218           mIsChrome(aOther.mIsChrome) {
219       aOther.mTypeString.Truncate();
220       aOther.mEventMessage = eVoidEvent;
221       aOther.mListenerType = eNoListener;
222       aOther.mListenerIsHandler = false;
223       aOther.mHandlerIsString = false;
224       aOther.mAllEvents = false;
225       aOther.mIsChrome = false;
226     }
227 
~ListenerListener228     ~Listener() {
229       if ((mListenerType == eJSEventListener) && mListener) {
230         static_cast<JSEventHandler*>(mListener.GetXPCOMCallback())
231             ->Disconnect();
232       }
233     }
234 
IsListeningListener235     MOZ_ALWAYS_INLINE bool IsListening(const WidgetEvent* aEvent) const {
236       if (mFlags.mInSystemGroup != aEvent->mFlags.mInSystemGroup) {
237         return false;
238       }
239       // FIXME Should check !mFlags.mCapture when the event is in target
240       //       phase because capture phase event listeners should not be fired.
241       //       But it breaks at least <xul:dialog>'s buttons. Bug 235441.
242       return ((mFlags.mCapture && aEvent->mFlags.mInCapturePhase) ||
243               (!mFlags.mCapture && aEvent->mFlags.mInBubblingPhase));
244     }
245   };
246 
247   explicit EventListenerManager(dom::EventTarget* aTarget);
248 
249   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EventListenerManager)
250 
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager)251   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager)
252 
253   void AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener,
254                         bool aUseCapture, bool aWantsUntrusted) {
255     AddEventListener(aType, EventListenerHolder(aListener), aUseCapture,
256                      aWantsUntrusted);
257   }
AddEventListener(const nsAString & aType,dom::EventListener * aListener,const dom::AddEventListenerOptionsOrBoolean & aOptions,bool aWantsUntrusted)258   void AddEventListener(const nsAString& aType, dom::EventListener* aListener,
259                         const dom::AddEventListenerOptionsOrBoolean& aOptions,
260                         bool aWantsUntrusted) {
261     AddEventListener(aType, EventListenerHolder(aListener), aOptions,
262                      aWantsUntrusted);
263   }
RemoveEventListener(const nsAString & aType,nsIDOMEventListener * aListener,bool aUseCapture)264   void RemoveEventListener(const nsAString& aType,
265                            nsIDOMEventListener* aListener, bool aUseCapture) {
266     RemoveEventListener(aType, EventListenerHolder(aListener), aUseCapture);
267   }
RemoveEventListener(const nsAString & aType,dom::EventListener * aListener,const dom::EventListenerOptionsOrBoolean & aOptions)268   void RemoveEventListener(const nsAString& aType,
269                            dom::EventListener* aListener,
270                            const dom::EventListenerOptionsOrBoolean& aOptions) {
271     RemoveEventListener(aType, EventListenerHolder(aListener), aOptions);
272   }
273 
274   void AddListenerForAllEvents(nsIDOMEventListener* aListener, bool aUseCapture,
275                                bool aWantsUntrusted, bool aSystemEventGroup);
276   void RemoveListenerForAllEvents(nsIDOMEventListener* aListener,
277                                   bool aUseCapture, bool aSystemEventGroup);
278 
279   /**
280    * Sets events listeners of all types.
281    * @param an event listener
282    */
AddEventListenerByType(nsIDOMEventListener * aListener,const nsAString & type,const EventListenerFlags & aFlags)283   void AddEventListenerByType(nsIDOMEventListener* aListener,
284                               const nsAString& type,
285                               const EventListenerFlags& aFlags) {
286     AddEventListenerByType(EventListenerHolder(aListener), type, aFlags);
287   }
288   void AddEventListenerByType(EventListenerHolder aListener,
289                               const nsAString& type,
290                               const EventListenerFlags& aFlags);
RemoveEventListenerByType(nsIDOMEventListener * aListener,const nsAString & type,const EventListenerFlags & aFlags)291   void RemoveEventListenerByType(nsIDOMEventListener* aListener,
292                                  const nsAString& type,
293                                  const EventListenerFlags& aFlags) {
294     RemoveEventListenerByType(EventListenerHolder(aListener), type, aFlags);
295   }
296   void RemoveEventListenerByType(EventListenerHolder aListener,
297                                  const nsAString& type,
298                                  const EventListenerFlags& aFlags);
299 
300   /**
301    * Sets the current "inline" event listener for aName to be a
302    * function compiled from aFunc if !aDeferCompilation.  If
303    * aDeferCompilation, then we assume that we can get the string from
304    * mTarget later and compile lazily.
305    *
306    * aElement, if not null, is the element the string is associated with.
307    */
308   // XXXbz does that play correctly with nodes being adopted across
309   // documents?  Need to double-check the spec here.
310   nsresult SetEventHandler(nsAtom* aName, const nsAString& aFunc,
311                            bool aDeferCompilation, bool aPermitUntrustedEvents,
312                            dom::Element* aElement);
313   /**
314    * Remove the current "inline" event listener for aName.
315    */
316   void RemoveEventHandler(nsAtom* aName, const nsAString& aTypeString);
317 
HandleEvent(nsPresContext * aPresContext,WidgetEvent * aEvent,nsIDOMEvent ** aDOMEvent,dom::EventTarget * aCurrentTarget,nsEventStatus * aEventStatus)318   void HandleEvent(nsPresContext* aPresContext, WidgetEvent* aEvent,
319                    nsIDOMEvent** aDOMEvent, dom::EventTarget* aCurrentTarget,
320                    nsEventStatus* aEventStatus) {
321     if (mListeners.IsEmpty() || aEvent->PropagationStopped()) {
322       return;
323     }
324 
325     if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) {
326       return;
327     }
328 
329     if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
330       return;
331     }
332 
333     // Check if we already know that there is no event listener for the event.
334     if (mNoListenerForEvent == aEvent->mMessage &&
335         (mNoListenerForEvent != eUnidentifiedEvent ||
336          mNoListenerForEventAtom == aEvent->mSpecifiedEventType)) {
337       return;
338     }
339     HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
340                         aEventStatus);
341   }
342 
343   /**
344    * Tells the event listener manager that its target (which owns it) is
345    * no longer using it (and could go away).
346    */
347   void Disconnect();
348 
349   /**
350    * Allows us to quickly determine if we have mutation listeners registered.
351    */
352   bool HasMutationListeners();
353 
354   /**
355    * Allows us to quickly determine whether we have unload or beforeunload
356    * listeners registered.
357    */
358   bool HasUnloadListeners();
359 
360   /**
361    * Returns the mutation bits depending on which mutation listeners are
362    * registered to this listener manager.
363    * @note If a listener is an nsIDOMMutationListener, all possible mutation
364    *       event bits are returned. All bits are also returned if one of the
365    *       event listeners is registered to handle DOMSubtreeModified events.
366    */
367   uint32_t MutationListenerBits();
368 
369   /**
370    * Returns true if there is at least one event listener for aEventName.
371    */
372   bool HasListenersFor(const nsAString& aEventName);
373 
374   /**
375    * Returns true if there is at least one event listener for aEventNameWithOn.
376    * Note that aEventNameWithOn must start with "on"!
377    */
378   bool HasListenersFor(nsAtom* aEventNameWithOn);
379 
380   /**
381    * Returns true if there is at least one event listener.
382    */
383   bool HasListeners();
384 
385   /**
386    * Sets aList to the list of nsIEventListenerInfo objects representing the
387    * listeners managed by this listener manager.
388    */
389   nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
390 
391   uint32_t GetIdentifierForEvent(nsAtom* aEvent);
392 
393   static void Shutdown();
394 
395   /**
396    * Returns true if there may be a paint event listener registered,
397    * false if there definitely isn't.
398    */
MayHavePaintEventListener()399   bool MayHavePaintEventListener() { return mMayHavePaintEventListener; }
400 
401   /**
402    * Returns true if there may be a touch event listener registered,
403    * false if there definitely isn't.
404    */
MayHaveTouchEventListener()405   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
406 
MayHaveMouseEnterLeaveEventListener()407   bool MayHaveMouseEnterLeaveEventListener() {
408     return mMayHaveMouseEnterLeaveEventListener;
409   }
MayHavePointerEnterLeaveEventListener()410   bool MayHavePointerEnterLeaveEventListener() {
411     return mMayHavePointerEnterLeaveEventListener;
412   }
MayHaveSelectionChangeEventListener()413   bool MayHaveSelectionChangeEventListener() {
414     return mMayHaveSelectionChangeEventListener;
415   }
416 
417   /**
418    * Returns true if there may be a key event listener (keydown, keypress,
419    * or keyup) registered, or false if there definitely isn't.
420    */
MayHaveKeyEventListener()421   bool MayHaveKeyEventListener() { return mMayHaveKeyEventListener; }
422 
423   /**
424    * Returns true if there may be an advanced input event listener (input,
425    * compositionstart, compositionupdate, or compositionend) registered,
426    * or false if there definitely isn't.
427    */
MayHaveInputOrCompositionEventListener()428   bool MayHaveInputOrCompositionEventListener() {
429     return mMayHaveInputOrCompositionEventListener;
430   }
431 
432   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
433 
ListenerCount()434   uint32_t ListenerCount() const { return mListeners.Length(); }
435 
436   void MarkForCC();
437 
438   void TraceListeners(JSTracer* aTrc);
439 
GetTarget()440   dom::EventTarget* GetTarget() { return mTarget; }
441 
442   bool HasNonSystemGroupListenersForUntrustedKeyEvents();
443   bool HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents();
444 
445   bool HasApzAwareListeners();
446   bool IsApzAwareListener(Listener* aListener);
447   bool IsApzAwareEvent(nsAtom* aEvent);
448 
449  protected:
450   void HandleEventInternal(nsPresContext* aPresContext, WidgetEvent* aEvent,
451                            nsIDOMEvent** aDOMEvent,
452                            dom::EventTarget* aCurrentTarget,
453                            nsEventStatus* aEventStatus);
454 
455   nsresult HandleEventSubType(Listener* aListener, nsIDOMEvent* aDOMEvent,
456                               dom::EventTarget* aCurrentTarget);
457 
458   /**
459    * If the given EventMessage has a legacy version that we support, then this
460    * function returns that legacy version. Otherwise, this function simply
461    * returns the passed-in EventMessage.
462    */
463   EventMessage GetLegacyEventMessage(EventMessage aEventMessage) const;
464 
465   void ProcessApzAwareEventListenerAdd();
466 
467   /**
468    * Compile the "inline" event listener for aListener.  The
469    * body of the listener can be provided in aBody; if this is null we
470    * will look for it on mTarget.  If aBody is provided, aElement should be
471    * as well; otherwise it will also be inferred from mTarget.
472    */
473   nsresult CompileEventHandlerInternal(Listener* aListener,
474                                        const nsAString* aBody,
475                                        dom::Element* aElement);
476 
477   /**
478    * Find the Listener for the "inline" event listener for aTypeAtom.
479    */
480   Listener* FindEventHandler(EventMessage aEventMessage, nsAtom* aTypeAtom,
481                              const nsAString& aTypeString);
482 
483   /**
484    * Set the "inline" event listener for aName to aHandler.  aHandler may be
485    * have no actual handler set to indicate that we should lazily get and
486    * compile the string for this listener, but in that case aContext and
487    * aScopeGlobal must be non-null.  Otherwise, aContext and aScopeGlobal are
488    * allowed to be null.
489    */
490   Listener* SetEventHandlerInternal(nsAtom* aName, const nsAString& aTypeString,
491                                     const TypedEventHandler& aHandler,
492                                     bool aPermitUntrustedEvents);
493 
494   bool IsDeviceType(EventMessage aEventMessage);
495   void EnableDevice(EventMessage aEventMessage);
496   void DisableDevice(EventMessage aEventMessage);
497 
498  public:
499   /**
500    * Set the "inline" event listener for aEventName to aHandler.  If
501    * aHandler is null, this will actually remove the event listener
502    */
503   void SetEventHandler(nsAtom* aEventName, const nsAString& aTypeString,
504                        dom::EventHandlerNonNull* aHandler);
505   void SetEventHandler(dom::OnErrorEventHandlerNonNull* aHandler);
506   void SetEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler);
507 
508   /**
509    * Get the value of the "inline" event listener for aEventName.
510    * This may cause lazy compilation if the listener is uncompiled.
511    *
512    * Note: It's the caller's responsibility to make sure to call the right one
513    * of these methods.  In particular, "onerror" events use
514    * OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
515    * for others.
516    */
GetEventHandler(nsAtom * aEventName,const nsAString & aTypeString)517   dom::EventHandlerNonNull* GetEventHandler(nsAtom* aEventName,
518                                             const nsAString& aTypeString) {
519     const TypedEventHandler* typedHandler =
520         GetTypedEventHandler(aEventName, aTypeString);
521     return typedHandler ? typedHandler->NormalEventHandler() : nullptr;
522   }
523 
GetOnErrorEventHandler()524   dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler() {
525     const TypedEventHandler* typedHandler =
526         mIsMainThreadELM
527             ? GetTypedEventHandler(nsGkAtoms::onerror, EmptyString())
528             : GetTypedEventHandler(nullptr, NS_LITERAL_STRING("error"));
529     return typedHandler ? typedHandler->OnErrorEventHandler() : nullptr;
530   }
531 
GetOnBeforeUnloadEventHandler()532   dom::OnBeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler() {
533     const TypedEventHandler* typedHandler =
534         GetTypedEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
535     return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr;
536   }
537 
538  protected:
539   /**
540    * Helper method for implementing the various Get*EventHandler above.  Will
541    * return null if we don't have an event handler for this event name.
542    */
543   const TypedEventHandler* GetTypedEventHandler(nsAtom* aEventName,
544                                                 const nsAString& aTypeString);
545 
546   void AddEventListener(const nsAString& aType, EventListenerHolder aListener,
547                         const dom::AddEventListenerOptionsOrBoolean& aOptions,
548                         bool aWantsUntrusted);
549   void AddEventListener(const nsAString& aType, EventListenerHolder aListener,
550                         bool aUseCapture, bool aWantsUntrusted);
551   void RemoveEventListener(const nsAString& aType,
552                            EventListenerHolder aListener,
553                            const dom::EventListenerOptionsOrBoolean& aOptions);
554   void RemoveEventListener(const nsAString& aType,
555                            EventListenerHolder aListener, bool aUseCapture);
556 
557   void AddEventListenerInternal(EventListenerHolder aListener,
558                                 EventMessage aEventMessage, nsAtom* aTypeAtom,
559                                 const nsAString& aTypeString,
560                                 const EventListenerFlags& aFlags,
561                                 bool aHandler = false, bool aAllEvents = false);
562   void RemoveEventListenerInternal(EventListenerHolder aListener,
563                                    EventMessage aEventMessage,
564                                    nsAtom* aUserType,
565                                    const nsAString& aTypeString,
566                                    const EventListenerFlags& aFlags,
567                                    bool aAllEvents = false);
568   void RemoveAllListeners();
569   void NotifyEventListenerRemoved(nsAtom* aUserType,
570                                   const nsAString& aTypeString);
571   const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
572   const EventTypeData* GetTypeDataForEventName(nsAtom* aName);
573   nsPIDOMWindowInner* GetInnerWindowForTarget();
574   already_AddRefed<nsPIDOMWindowInner> GetTargetAsInnerWindow() const;
575 
576   bool ListenerCanHandle(const Listener* aListener, const WidgetEvent* aEvent,
577                          EventMessage aEventMessage) const;
578 
579   // BE AWARE, a lot of instances of EventListenerManager will be created.
580   // Therefor, we need to keep this class compact.  When you add integer
581   // members, please add them to EventListemerManagerBase and check the size
582   // at build time.
583 
584   already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalAndDocument(
585       nsIDocument** aDoc);
586 
587   nsAutoTObserverArray<Listener, 2> mListeners;
588   dom::EventTarget* MOZ_NON_OWNING_REF mTarget;
589   RefPtr<nsAtom> mNoListenerForEventAtom;
590 
591   friend class ELMCreationDetector;
592   static uint32_t sMainThreadCreatedCount;
593 };
594 
595 }  // namespace mozilla
596 
597 /**
598  * NS_AddSystemEventListener() is a helper function for implementing
599  * EventTarget::AddSystemEventListener().
600  */
NS_AddSystemEventListener(mozilla::dom::EventTarget * aTarget,const nsAString & aType,nsIDOMEventListener * aListener,bool aUseCapture,bool aWantsUntrusted)601 inline nsresult NS_AddSystemEventListener(mozilla::dom::EventTarget* aTarget,
602                                           const nsAString& aType,
603                                           nsIDOMEventListener* aListener,
604                                           bool aUseCapture,
605                                           bool aWantsUntrusted) {
606   mozilla::EventListenerManager* listenerManager =
607       aTarget->GetOrCreateListenerManager();
608   NS_ENSURE_STATE(listenerManager);
609   mozilla::EventListenerFlags flags;
610   flags.mInSystemGroup = true;
611   flags.mCapture = aUseCapture;
612   flags.mAllowUntrustedEvents = aWantsUntrusted;
613   listenerManager->AddEventListenerByType(aListener, aType, flags);
614   return NS_OK;
615 }
616 
617 #endif  // mozilla_EventListenerManager_h_
618