dom/events/EventListenerManager.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef mozilla_EventListenerManager_h_
     7 #define mozilla_EventListenerManager_h_
     9 #include "mozilla/BasicEvents.h"
    10 #include "mozilla/dom/EventListenerBinding.h"
    11 #include "mozilla/JSEventHandler.h"
    12 #include "mozilla/MemoryReporting.h"
    13 #include "nsCOMPtr.h"
    14 #include "nsCycleCollectionParticipant.h"
    15 #include "nsGkAtoms.h"
    16 #include "nsIDOMEventListener.h"
    17 #include "nsTObserverArray.h"
    19 class nsIDOMEvent;
    20 class nsIEventListenerInfo;
    21 class nsIScriptContext;
    22 class nsPIDOMWindow;
    24 struct EventTypeData;
    26 template<class T> class nsCOMArray;
    28 namespace mozilla {
    30 class ELMCreationDetector;
    31 class EventListenerManager;
    33 namespace dom {
    34 class EventTarget;
    35 class Element;
    36 } // namespace dom
    38 typedef dom::CallbackObjectHolder<dom::EventListener,
    39                                   nsIDOMEventListener> EventListenerHolder;
    41 struct EventListenerFlags
    42 {
    43   friend class EventListenerManager;
    44 private:
    45   // If mListenerIsJSListener is true, the listener is implemented by JS.
    46   // Otherwise, it's implemented by native code or JS but it's wrapped.
    47   bool mListenerIsJSListener : 1;
    49 public:
    50   // If mCapture is true, it means the listener captures the event.  Otherwise,
    51   // it's listening at bubbling phase.
    52   bool mCapture : 1;
    53   // If mInSystemGroup is true, the listener is listening to the events in the
    54   // system group.
    55   bool mInSystemGroup : 1;
    56   // If mAllowUntrustedEvents is true, the listener is listening to the
    57   // untrusted events too.
    58   bool mAllowUntrustedEvents : 1;
    60   EventListenerFlags() :
    61     mListenerIsJSListener(false),
    62     mCapture(false), mInSystemGroup(false), mAllowUntrustedEvents(false)
    63   {
    64   }
    66   bool Equals(const EventListenerFlags& aOther) const
    67   {
    68     return (mCapture == aOther.mCapture &&
    69             mInSystemGroup == aOther.mInSystemGroup &&
    70             mListenerIsJSListener == aOther.mListenerIsJSListener &&
    71             mAllowUntrustedEvents == aOther.mAllowUntrustedEvents);
    72   }
    74   bool EqualsIgnoringTrustness(const EventListenerFlags& aOther) const
    75   {
    76     return (mCapture == aOther.mCapture &&
    77             mInSystemGroup == aOther.mInSystemGroup &&
    78             mListenerIsJSListener == aOther.mListenerIsJSListener);
    79   }
    81   bool operator==(const EventListenerFlags& aOther) const
    82   {
    83     return Equals(aOther);
    84   }
    85 };
    87 inline EventListenerFlags TrustedEventsAtBubble()
    88 {
    89   EventListenerFlags flags;
    90   return flags;
    91 }
    93 inline EventListenerFlags TrustedEventsAtCapture()
    94 {
    95   EventListenerFlags flags;
    96   flags.mCapture = true;
    97   return flags;
    98 }
   100 inline EventListenerFlags AllEventsAtBubbe()
   101 {
   102   EventListenerFlags flags;
   103   flags.mAllowUntrustedEvents = true;
   104   return flags;
   105 }
   107 inline EventListenerFlags AllEventsAtCapture()
   108 {
   109   EventListenerFlags flags;
   110   flags.mCapture = true;
   111   flags.mAllowUntrustedEvents = true;
   112   return flags;
   113 }
   115 inline EventListenerFlags TrustedEventsAtSystemGroupBubble()
   116 {
   117   EventListenerFlags flags;
   118   flags.mInSystemGroup = true;
   119   return flags;
   120 }
   122 inline EventListenerFlags TrustedEventsAtSystemGroupCapture()
   123 {
   124   EventListenerFlags flags;
   125   flags.mCapture = true;
   126   flags.mInSystemGroup = true;
   127   return flags;
   128 }
   130 inline EventListenerFlags AllEventsAtSystemGroupBubble()
   131 {
   132   EventListenerFlags flags;
   133   flags.mInSystemGroup = true;
   134   flags.mAllowUntrustedEvents = true;
   135   return flags;
   136 }
   138 inline EventListenerFlags AllEventsAtSystemGroupCapture()
   139 {
   140   EventListenerFlags flags;
   141   flags.mCapture = true;
   142   flags.mInSystemGroup = true;
   143   flags.mAllowUntrustedEvents = true;
   144   return flags;
   145 }
   147 /*
   148  * Event listener manager
   149  */
   151 class EventListenerManager MOZ_FINAL
   152 {
   153 public:
   154   struct Listener
   155   {
   156     EventListenerHolder mListener;
   157     nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
   158     nsString mTypeString; // for non-main-threads
   159     uint16_t mEventType;
   161     enum ListenerType MOZ_ENUM_TYPE(uint8_t)
   162     {
   163       eNativeListener = 0,
   164       eJSEventListener,
   165       eWrappedJSListener,
   166       eWebIDLListener,
   167       eListenerTypeCount
   168     };
   169     uint8_t mListenerType;
   171     bool mListenerIsHandler : 1;
   172     bool mHandlerIsString : 1;
   173     bool mAllEvents : 1;
   175     EventListenerFlags mFlags;
   177     JSEventHandler* GetJSEventHandler() const
   178     {
   179       return (mListenerType == eJSEventListener) ?
   180         static_cast<JSEventHandler*>(mListener.GetXPCOMCallback()) :
   181         nullptr;
   182     }
   184     Listener()
   185     {
   186       MOZ_ASSERT(sizeof(mListenerType) == 1);
   187       MOZ_ASSERT(eListenerTypeCount < 255);
   188     }
   190     ~Listener()
   191     {
   192       if ((mListenerType == eJSEventListener) && mListener) {
   193         static_cast<JSEventHandler*>(
   194           mListener.GetXPCOMCallback())->Disconnect();
   195       }
   196     }
   198     MOZ_ALWAYS_INLINE bool IsListening(const WidgetEvent* aEvent) const
   199     {
   200       if (mFlags.mInSystemGroup != aEvent->mFlags.mInSystemGroup) {
   201         return false;
   202       }
   203       // FIXME Should check !mFlags.mCapture when the event is in target
   204       //       phase because capture phase event listeners should not be fired.
   205       //       But it breaks at least <xul:dialog>'s buttons. Bug 235441.
   206       return ((mFlags.mCapture && aEvent->mFlags.mInCapturePhase) ||
   207               (!mFlags.mCapture && aEvent->mFlags.mInBubblingPhase));
   208     }
   209   };
   211   EventListenerManager(dom::EventTarget* aTarget);
   212   virtual ~EventListenerManager();
   214   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(EventListenerManager)
   216   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(EventListenerManager)
   218   void AddEventListener(const nsAString& aType,
   219                         nsIDOMEventListener* aListener,
   220                         bool aUseCapture,
   221                         bool aWantsUntrusted)
   222   {
   223     EventListenerHolder holder(aListener);
   224     AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
   225   }
   226   void AddEventListener(const nsAString& aType,
   227                         dom::EventListener* aListener,
   228                         bool aUseCapture,
   229                         bool aWantsUntrusted)
   230   {
   231     EventListenerHolder holder(aListener);
   232     AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
   233   }
   234   void RemoveEventListener(const nsAString& aType,
   235                            nsIDOMEventListener* aListener,
   236                            bool aUseCapture)
   237   {
   238     EventListenerHolder holder(aListener);
   239     RemoveEventListener(aType, holder, aUseCapture);
   240   }
   241   void RemoveEventListener(const nsAString& aType,
   242                            dom::EventListener* aListener,
   243                            bool aUseCapture)
   244   {
   245     EventListenerHolder holder(aListener);
   246     RemoveEventListener(aType, holder, aUseCapture);
   247   }
   249   void AddListenerForAllEvents(nsIDOMEventListener* aListener,
   250                                bool aUseCapture,
   251                                bool aWantsUntrusted,
   252                                bool aSystemEventGroup);
   253   void RemoveListenerForAllEvents(nsIDOMEventListener* aListener,
   254                                   bool aUseCapture,
   255                                   bool aSystemEventGroup);
   257   /**
   258   * Sets events listeners of all types. 
   259   * @param an event listener
   260   */
   261   void AddEventListenerByType(nsIDOMEventListener *aListener,
   262                               const nsAString& type,
   263                               const EventListenerFlags& aFlags)
   264   {
   265     EventListenerHolder holder(aListener);
   266     AddEventListenerByType(holder, type, aFlags);
   267   }
   268   void AddEventListenerByType(const EventListenerHolder& aListener,
   269                               const nsAString& type,
   270                               const EventListenerFlags& aFlags);
   271   void RemoveEventListenerByType(nsIDOMEventListener *aListener,
   272                                  const nsAString& type,
   273                                  const EventListenerFlags& aFlags)
   274   {
   275     EventListenerHolder holder(aListener);
   276     RemoveEventListenerByType(holder, type, aFlags);
   277   }
   278   void RemoveEventListenerByType(const EventListenerHolder& aListener,
   279                                  const nsAString& type,
   280                                  const EventListenerFlags& aFlags);
   282   /**
   283    * Sets the current "inline" event listener for aName to be a
   284    * function compiled from aFunc if !aDeferCompilation.  If
   285    * aDeferCompilation, then we assume that we can get the string from
   286    * mTarget later and compile lazily.
   287    *
   288    * aElement, if not null, is the element the string is associated with.
   289    */
   290   // XXXbz does that play correctly with nodes being adopted across
   291   // documents?  Need to double-check the spec here.
   292   nsresult SetEventHandler(nsIAtom *aName,
   293                            const nsAString& aFunc,
   294                            uint32_t aLanguage,
   295                            bool aDeferCompilation,
   296                            bool aPermitUntrustedEvents,
   297                            dom::Element* aElement);
   298   /**
   299    * Remove the current "inline" event listener for aName.
   300    */
   301   void RemoveEventHandler(nsIAtom *aName, const nsAString& aTypeString);
   303   void HandleEvent(nsPresContext* aPresContext,
   304                    WidgetEvent* aEvent, 
   305                    nsIDOMEvent** aDOMEvent,
   306                    dom::EventTarget* aCurrentTarget,
   307                    nsEventStatus* aEventStatus)
   308   {
   309     if (mListeners.IsEmpty() || aEvent->mFlags.mPropagationStopped) {
   310       return;
   311     }
   313     if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) {
   314       return;
   315     }
   317     if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
   318       return;
   319     }
   321     // Check if we already know that there is no event listener for the event.
   322     if (mNoListenerForEvent == aEvent->message &&
   323         (mNoListenerForEvent != NS_USER_DEFINED_EVENT ||
   324          mNoListenerForEventAtom == aEvent->userType)) {
   325       return;
   326     }
   327     HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
   328                         aEventStatus);
   329   }
   331   /**
   332    * Tells the event listener manager that its target (which owns it) is
   333    * no longer using it (and could go away).
   334    */
   335   void Disconnect();
   337   /**
   338    * Allows us to quickly determine if we have mutation listeners registered.
   339    */
   340   bool HasMutationListeners();
   342   /**
   343    * Allows us to quickly determine whether we have unload or beforeunload
   344    * listeners registered.
   345    */
   346   bool HasUnloadListeners();
   348   /**
   349    * Returns the mutation bits depending on which mutation listeners are
   350    * registered to this listener manager.
   351    * @note If a listener is an nsIDOMMutationListener, all possible mutation
   352    *       event bits are returned. All bits are also returned if one of the
   353    *       event listeners is registered to handle DOMSubtreeModified events.
   354    */
   355   uint32_t MutationListenerBits();
   357   /**
   358    * Returns true if there is at least one event listener for aEventName.
   359    */
   360   bool HasListenersFor(const nsAString& aEventName);
   362   /**
   363    * Returns true if there is at least one event listener for aEventNameWithOn.
   364    * Note that aEventNameWithOn must start with "on"!
   365    */
   366   bool HasListenersFor(nsIAtom* aEventNameWithOn);
   368   /**
   369    * Returns true if there is at least one event listener.
   370    */
   371   bool HasListeners();
   373   /**
   374    * Sets aList to the list of nsIEventListenerInfo objects representing the
   375    * listeners managed by this listener manager.
   376    */
   377   nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
   379   uint32_t GetIdentifierForEvent(nsIAtom* aEvent);
   381   static void Shutdown();
   383   /**
   384    * Returns true if there may be a paint event listener registered,
   385    * false if there definitely isn't.
   386    */
   387   bool MayHavePaintEventListener() { return mMayHavePaintEventListener; }
   389   /**
   390    * Returns true if there may be a touch event listener registered,
   391    * false if there definitely isn't.
   392    */
   393   bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
   395   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
   396   bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
   398   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   400   uint32_t ListenerCount() const
   401   {
   402     return mListeners.Length();
   403   }
   405   void MarkForCC();
   407   dom::EventTarget* GetTarget() { return mTarget; }
   409 protected:
   410   void HandleEventInternal(nsPresContext* aPresContext,
   411                            WidgetEvent* aEvent,
   412                            nsIDOMEvent** aDOMEvent,
   413                            dom::EventTarget* aCurrentTarget,
   414                            nsEventStatus* aEventStatus);
   416   nsresult HandleEventSubType(Listener* aListener,
   417                               nsIDOMEvent* aDOMEvent,
   418                               dom::EventTarget* aCurrentTarget);
   420   /**
   421    * Compile the "inline" event listener for aListener.  The
   422    * body of the listener can be provided in aBody; if this is null we
   423    * will look for it on mTarget.  If aBody is provided, aElement should be
   424    * as well; otherwise it will also be inferred from mTarget.
   425    */
   426   nsresult CompileEventHandlerInternal(Listener* aListener,
   427                                        const nsAString* aBody,
   428                                        dom::Element* aElement);
   430   /**
   431    * Find the Listener for the "inline" event listener for aTypeAtom.
   432    */
   433   Listener* FindEventHandler(uint32_t aEventType,
   434                              nsIAtom* aTypeAtom,
   435                              const nsAString& aTypeString);
   437   /**
   438    * Set the "inline" event listener for aName to aHandler.  aHandler may be
   439    * have no actual handler set to indicate that we should lazily get and
   440    * compile the string for this listener, but in that case aContext and
   441    * aScopeGlobal must be non-null.  Otherwise, aContext and aScopeGlobal are
   442    * allowed to be null.
   443    */
   444   Listener* SetEventHandlerInternal(nsIAtom* aName,
   445                                     const nsAString& aTypeString,
   446                                     const TypedEventHandler& aHandler,
   447                                     bool aPermitUntrustedEvents);
   449   bool IsDeviceType(uint32_t aType);
   450   void EnableDevice(uint32_t aType);
   451   void DisableDevice(uint32_t aType);
   453 public:
   454   /**
   455    * Set the "inline" event listener for aEventName to aHandler.  If
   456    * aHandler is null, this will actually remove the event listener
   457    */
   458   void SetEventHandler(nsIAtom* aEventName,
   459                        const nsAString& aTypeString,
   460                        dom::EventHandlerNonNull* aHandler);
   461   void SetEventHandler(dom::OnErrorEventHandlerNonNull* aHandler);
   462   void SetEventHandler(dom::OnBeforeUnloadEventHandlerNonNull* aHandler);
   464   /**
   465    * Get the value of the "inline" event listener for aEventName.
   466    * This may cause lazy compilation if the listener is uncompiled.
   467    *
   468    * Note: It's the caller's responsibility to make sure to call the right one
   469    * of these methods.  In particular, "onerror" events use
   470    * OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
   471    * for others.
   472    */
   473   dom::EventHandlerNonNull* GetEventHandler(nsIAtom* aEventName,
   474                                             const nsAString& aTypeString)
   475   {
   476     const TypedEventHandler* typedHandler =
   477       GetTypedEventHandler(aEventName, aTypeString);
   478     return typedHandler ? typedHandler->NormalEventHandler() : nullptr;
   479   }
   481   dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler()
   482   {
   483     const TypedEventHandler* typedHandler = mIsMainThreadELM ?
   484       GetTypedEventHandler(nsGkAtoms::onerror, EmptyString()) :
   485       GetTypedEventHandler(nullptr, NS_LITERAL_STRING("error"));
   486     return typedHandler ? typedHandler->OnErrorEventHandler() : nullptr;
   487   }
   489   dom::OnBeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler()
   490   {
   491     const TypedEventHandler* typedHandler =
   492       GetTypedEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
   493     return typedHandler ? typedHandler->OnBeforeUnloadEventHandler() : nullptr;
   494   }
   496 protected:
   497   /**
   498    * Helper method for implementing the various Get*EventHandler above.  Will
   499    * return null if we don't have an event handler for this event name.
   500    */
   501   const TypedEventHandler* GetTypedEventHandler(nsIAtom* aEventName,
   502                                                 const nsAString& aTypeString);
   504   void AddEventListener(const nsAString& aType,
   505                         const EventListenerHolder& aListener,
   506                         bool aUseCapture,
   507                         bool aWantsUntrusted);
   508   void RemoveEventListener(const nsAString& aType,
   509                            const EventListenerHolder& aListener,
   510                            bool aUseCapture);
   512   void AddEventListenerInternal(const EventListenerHolder& aListener,
   513                                 uint32_t aType,
   514                                 nsIAtom* aTypeAtom,
   515                                 const nsAString& aTypeString,
   516                                 const EventListenerFlags& aFlags,
   517                                 bool aHandler = false,
   518                                 bool aAllEvents = false);
   519   void RemoveEventListenerInternal(const EventListenerHolder& aListener,
   520                                    uint32_t aType,
   521                                    nsIAtom* aUserType,
   522                                    const nsAString& aTypeString,
   523                                    const EventListenerFlags& aFlags,
   524                                    bool aAllEvents = false);
   525   void RemoveAllListeners();
   526   const EventTypeData* GetTypeDataForIID(const nsIID& aIID);
   527   const EventTypeData* GetTypeDataForEventName(nsIAtom* aName);
   528   nsPIDOMWindow* GetInnerWindowForTarget();
   529   already_AddRefed<nsPIDOMWindow> GetTargetAsInnerWindow() const;
   531   bool ListenerCanHandle(Listener* aListener, WidgetEvent* aEvent);
   533   already_AddRefed<nsIScriptGlobalObject>
   534   GetScriptGlobalAndDocument(nsIDocument** aDoc);
   536   uint32_t mMayHavePaintEventListener : 1;
   537   uint32_t mMayHaveMutationListeners : 1;
   538   uint32_t mMayHaveCapturingListeners : 1;
   539   uint32_t mMayHaveSystemGroupListeners : 1;
   540   uint32_t mMayHaveTouchEventListener : 1;
   541   uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
   542   uint32_t mMayHavePointerEnterLeaveEventListener : 1;
   543   uint32_t mClearingListeners : 1;
   544   uint32_t mIsMainThreadELM : 1;
   545   uint32_t mNoListenerForEvent : 23;
   547   nsAutoTObserverArray<Listener, 2> mListeners;
   548   dom::EventTarget* mTarget;  // WEAK
   549   nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
   551   friend class ELMCreationDetector;
   552   static uint32_t sMainThreadCreatedCount;
   553 };
   555 } // namespace mozilla
   557 /**
   558  * NS_AddSystemEventListener() is a helper function for implementing
   559  * EventTarget::AddSystemEventListener().
   560  */
   561 inline nsresult
   562 NS_AddSystemEventListener(mozilla::dom::EventTarget* aTarget,
   563                           const nsAString& aType,
   564                           nsIDOMEventListener *aListener,
   565                           bool aUseCapture,
   566                           bool aWantsUntrusted)
   567 {
   568   mozilla::EventListenerManager* listenerManager =
   569     aTarget->GetOrCreateListenerManager();
   570   NS_ENSURE_STATE(listenerManager);
   571   mozilla::EventListenerFlags flags;
   572   flags.mInSystemGroup = true;
   573   flags.mCapture = aUseCapture;
   574   flags.mAllowUntrustedEvents = aWantsUntrusted;
   575   listenerManager->AddEventListenerByType(aListener, aType, flags);
   576   return NS_OK;
   577 }
   579 #endif // mozilla_EventListenerManager_h_

mercurial