Bug 813445 part.13 nsEventDispatcher shouldn't use the flags defined in nsGUIEvent.h r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Sun, 16 Dec 2012 10:26:05 +0900
changeset 125285 f3a4323d12803d3afbd95806de5225b986fdf077
parent 125284 4c517352ac35c44bfe1010169f1461a20ea947fc
child 125286 583b6c704134f5f3ec30e13d1530ff3f25ee1e02
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs813445
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 813445 part.13 nsEventDispatcher shouldn't use the flags defined in nsGUIEvent.h r=smaug
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventListenerManager.cpp
content/events/src/nsEventListenerManager.h
widget/nsGUIEvent.h
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -137,32 +137,31 @@ public:
 
   /**
    * Dispatches event through the event target chain.
    * Handles capture, target and bubble phases both in default
    * and system event group and calls also PostHandleEvent for each
    * item in the chain.
    */
   nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor,
-                                  uint32_t aFlags,
                                   nsDispatchingCallback* aCallback,
                                   bool aMayHaveNewListenerManagers,
                                   nsCxPusher* aPusher);
 
   /**
    * Resets aVisitor object and calls PreHandleEvent.
    * Copies mItemFlags and mItemData to the current nsEventTargetChainItem.
    */
   nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   /**
    * If the current item in the event target chain has an event listener
    * manager, this method calls nsEventListenerManager::HandleEvent().
    */
-  nsresult HandleEvent(nsEventChainPostVisitor& aVisitor, uint32_t aFlags,
+  nsresult HandleEvent(nsEventChainPostVisitor& aVisitor,
                        bool aMayHaveNewListenerManagers,
                        nsCxPusher* aPusher)
   {
     if (WantsWillHandleEvent()) {
       mTarget->WillHandleEvent(aVisitor);
     }
     if (aVisitor.mEvent->mFlags.mPropagationStopped) {
       return NS_OK;
@@ -174,17 +173,17 @@ public:
       mManager =
         static_cast<nsEventListenerManager*>(mTarget->GetListenerManager(false));
     }
     if (mManager) {
       NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
                    "CurrentTarget should be null!");
       mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
                             &aVisitor.mDOMEvent,
-                            CurrentTarget(), aFlags,
+                            CurrentTarget(),
                             &aVisitor.mEventStatus,
                             aPusher);
       NS_ASSERTION(aVisitor.mEvent->currentTarget == nullptr,
                    "CurrentTarget should be null!");
     }
     return NS_OK;
   }
 
@@ -258,34 +257,35 @@ nsEventTargetChainItem::PostHandleEvent(
   aPusher->Pop();
   aVisitor.mItemFlags = mItemFlags;
   aVisitor.mItemData = mItemData;
   mTarget->PostHandleEvent(aVisitor);
   return NS_OK;
 }
 
 nsresult
-nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, uint32_t aFlags,
-                                               nsDispatchingCallback* aCallback,
-                                               bool aMayHaveNewListenerManagers,
-                                               nsCxPusher* aPusher)
+nsEventTargetChainItem::HandleEventTargetChain(
+                          nsEventChainPostVisitor& aVisitor,
+                          nsDispatchingCallback* aCallback,
+                          bool aMayHaveNewListenerManagers,
+                          nsCxPusher* aPusher)
 {
   uint32_t createdELMs = nsEventListenerManager::sCreatedCount;
   // Save the target so that it can be restored later.
   nsCOMPtr<nsIDOMEventTarget> firstTarget = aVisitor.mEvent->target;
 
   // Capture
   nsEventTargetChainItem* item = this;
   aVisitor.mEvent->mFlags.mInCapturePhase = true;
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
   while (item->mChild) {
     if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
          item->ForceContentDispatch()) &&
         !aVisitor.mEvent->mFlags.mPropagationStopped) {
-      item->HandleEvent(aVisitor, aFlags & NS_EVENT_CAPTURE_MASK,
+      item->HandleEvent(aVisitor,
                         aMayHaveNewListenerManagers ||
                         createdELMs != nsEventListenerManager::sCreatedCount,
                         aPusher);
     }
 
     if (item->GetNewTarget()) {
       // item is at anonymous boundary. Need to retarget for the child items.
       nsEventTargetChainItem* nextTarget = item->mChild;
@@ -302,25 +302,22 @@ nsEventTargetChainItem::HandleEventTarge
     item = item->mChild;
   }
 
   // Target
   aVisitor.mEvent->mFlags.mInBubblingPhase = true;
   if (!aVisitor.mEvent->mFlags.mPropagationStopped &&
       (!aVisitor.mEvent->mFlags.mNoContentDispatch ||
        item->ForceContentDispatch())) {
-    // FIXME Should use aFlags & NS_EVENT_BUBBLE_MASK because capture phase
-    //       event listeners should not be fired. But it breaks at least
-    //       <xul:dialog>'s buttons. Bug 235441.
-    item->HandleEvent(aVisitor, aFlags,
+    item->HandleEvent(aVisitor,
                       aMayHaveNewListenerManagers ||
                       createdELMs != nsEventListenerManager::sCreatedCount,
                       aPusher);
   }
-  if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
+  if (aVisitor.mEvent->mFlags.mInSystemGroup) {
     item->PostHandleEvent(aVisitor, aPusher);
   }
 
   // Bubble
   aVisitor.mEvent->mFlags.mInCapturePhase = false;
   item = item->mParent;
   while (item) {
     nsIDOMEventTarget* newTarget = item->GetNewTarget();
@@ -329,29 +326,29 @@ nsEventTargetChainItem::HandleEventTarge
       // and for parent items.
       aVisitor.mEvent->target = newTarget;
     }
 
     if (aVisitor.mEvent->mFlags.mBubbles || newTarget) {
       if ((!aVisitor.mEvent->mFlags.mNoContentDispatch ||
            item->ForceContentDispatch()) &&
           !aVisitor.mEvent->mFlags.mPropagationStopped) {
-        item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK,
+        item->HandleEvent(aVisitor,
                           createdELMs != nsEventListenerManager::sCreatedCount,
                           aPusher);
       }
-      if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
+      if (aVisitor.mEvent->mFlags.mInSystemGroup) {
         item->PostHandleEvent(aVisitor, aPusher);
       }
     }
     item = item->mParent;
   }
   aVisitor.mEvent->mFlags.mInBubblingPhase = false;
 
-  if (!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
+  if (!aVisitor.mEvent->mFlags.mInSystemGroup) {
     // Dispatch to the system event group.  Make sure to clear the
     // STOP_DISPATCH flag since this resets for each event group.
     aVisitor.mEvent->mFlags.mPropagationStopped = false;
     aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
 
     // Setting back the original target of the event.
     aVisitor.mEvent->target = aVisitor.mEvent->originalTarget;
 
@@ -360,20 +357,22 @@ nsEventTargetChainItem::HandleEventTarge
     if (aCallback) {
       aPusher->Pop();
       aCallback->HandleEvent(aVisitor);
     }
 
     // Retarget for system event group (which does the default handling too).
     // Setting back the target which was used also for default event group.
     aVisitor.mEvent->target = firstTarget;
-    HandleEventTargetChain(aVisitor, aFlags | NS_EVENT_FLAG_SYSTEM_EVENT,
+    aVisitor.mEvent->mFlags.mInSystemGroup = true;
+    HandleEventTargetChain(aVisitor,
                            aCallback,
                            createdELMs != nsEventListenerManager::sCreatedCount,
                            aPusher);
+    aVisitor.mEvent->mFlags.mInSystemGroup = false;
 
     // After dispatch, clear all the propagation flags so that
     // system group listeners don't affect to the event.
     aVisitor.mEvent->mFlags.mPropagationStopped = false;
     aVisitor.mEvent->mFlags.mImmediatePropagationStopped = false;
   }
 
   return NS_OK;
@@ -622,18 +621,16 @@ nsEventDispatcher::Dispatch(nsISupports*
           aTargets->AppendObject(item->CurrentTarget()->GetTargetForDOMEvent());
           item = item->mParent;
         }
       } else {
         // Event target chain is created. Handle the chain.
         nsEventChainPostVisitor postVisitor(preVisitor);
         nsCxPusher pusher;
         rv = topEtci->HandleEventTargetChain(postVisitor,
-                                             NS_EVENT_FLAG_BUBBLE |
-                                             NS_EVENT_FLAG_CAPTURE,
                                              aCallback,
                                              false,
                                              &pusher);
   
         preVisitor.mEventStatus = postVisitor.mEventStatus;
         // If the DOM event was created during event flow.
         if (!preVisitor.mDOMEvent && postVisitor.mDOMEvent) {
           preVisitor.mDOMEvent = postVisitor.mDOMEvent;
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -892,17 +892,16 @@ nsEventListenerManager::CompileEventHand
   return result;
 }
 
 nsresult
 nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
                                            nsIDOMEventListener* aListener,
                                            nsIDOMEvent* aDOMEvent,
                                            nsIDOMEventTarget* aCurrentTarget,
-                                           uint32_t aPhaseFlags,
                                            nsCxPusher* aPusher)
 {
   nsresult result = NS_OK;
 
   // If this is a script handler and we haven't yet
   // compiled the event handler itself
   if ((aListenerStruct->mListenerType == eJSEventListener) &&
       aListenerStruct->mHandlerIsString) {
@@ -927,17 +926,16 @@ nsEventListenerManager::HandleEventSubTy
 * @param an event listener
 */
 
 void
 nsEventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
                                             nsEvent* aEvent,
                                             nsIDOMEvent** aDOMEvent,
                                             nsIDOMEventTarget* aCurrentTarget,
-                                            uint32_t aFlags,
                                             nsEventStatus* aEventStatus,
                                             nsCxPusher* aPusher)
 {
   //Set the value of the internal PreventDefault flag properly based on aEventStatus
   if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
     aEvent->mFlags.mDefaultPrevented = true;
   }
 
@@ -950,19 +948,17 @@ nsEventListenerManager::HandleEventInter
     }
     nsListenerStruct* ls = &iter.GetNext();
     // Check that the phase is same in event and event listener.
     // Handle only trusted events, except when listener permits untrusted events.
     if (ListenerCanHandle(ls, aEvent)) {
       hasListener = true;
       // XXX The (mFlags & aFlags) test here seems fragile. Shouldn't we
       // specifically only test the capture/bubble flags.
-      if ((ls->mFlags & aFlags & ~NS_EVENT_FLAG_SYSTEM_EVENT) &&
-          (ls->mFlags & NS_EVENT_FLAG_SYSTEM_EVENT) ==
-          (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) &&
+      if (ls->IsListening(aEvent) &&
           (aEvent->mFlags.mIsTrusted ||
            ls->mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED)) {
         if (!*aDOMEvent) {
           nsEventDispatcher::CreateEvent(aPresContext, aEvent,
                                          EmptyString(), aDOMEvent);
         }
         if (*aDOMEvent) {
           if (!aEvent->currentTarget) {
@@ -985,18 +981,17 @@ nsEventListenerManager::HandleEventInter
           if (ls->mListenerType == eNativeListener) {
             aPusher->Pop();
           } else if (!aPusher->RePush(aCurrentTarget)) {
             continue;
           }
 
           nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener;
           if (NS_FAILED(HandleEventSubType(ls, ls->mListener, *aDOMEvent,
-                                           aCurrentTarget, aFlags,
-                                           aPusher))) {
+                                           aCurrentTarget, aPusher))) {
             aEvent->mFlags.mExceptionHasBeenRisen = true;
           }
         }
       }
     }
   }
 
   aEvent->currentTarget = nullptr;
--- a/content/events/src/nsEventListenerManager.h
+++ b/content/events/src/nsEventListenerManager.h
@@ -54,16 +54,31 @@ struct nsListenerStruct
   }
 
   ~nsListenerStruct()
   {
     if ((mListenerType == eJSEventListener) && mListener) {
       static_cast<nsIJSEventListener*>(mListener.get())->Disconnect();
     }
   }
+
+  MOZ_ALWAYS_INLINE bool IsListening(const nsEvent* aEvent) const
+  {
+    if (((mFlags & NS_EVENT_FLAG_SYSTEM_EVENT) != 0) !=
+          aEvent->mFlags.mInSystemGroup) {
+      return false;
+    }
+    // FIXME Should check NS_EVENT_FLAG_CAPTURE when the event is in target
+    //       phase because capture phase event listeners should not be fired.
+    //       But it breaks at least <xul:dialog>'s buttons. Bug 235441.
+    return ((mFlags & NS_EVENT_FLAG_CAPTURE) &&
+            aEvent->mFlags.mInCapturePhase) ||
+           ((mFlags & NS_EVENT_FLAG_BUBBLE) &&
+            aEvent->mFlags.mInBubblingPhase);
+  }
 };
 
 /*
  * Event listener manager
  */
 
 class nsEventListenerManager
 {
@@ -120,51 +135,41 @@ public:
    * Remove the current "inline" event listener for aName.
    */
   void RemoveEventHandler(nsIAtom *aName);
 
   void HandleEvent(nsPresContext* aPresContext,
                    nsEvent* aEvent, 
                    nsIDOMEvent** aDOMEvent,
                    nsIDOMEventTarget* aCurrentTarget,
-                   uint32_t aFlags,
                    nsEventStatus* aEventStatus,
                    nsCxPusher* aPusher)
   {
     if (mListeners.IsEmpty() || aEvent->mFlags.mPropagationStopped) {
       return;
     }
 
     if (!mMayHaveCapturingListeners && !aEvent->mFlags.mInBubblingPhase) {
       return;
     }
 
-    if (!mMayHaveSystemGroupListeners &&
-        aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
+    if (!mMayHaveSystemGroupListeners && aEvent->mFlags.mInSystemGroup) {
       return;
     }
 
     // Check if we already know that there is no event listener for the event.
     if (mNoListenerForEvent == aEvent->message &&
         (mNoListenerForEvent != NS_USER_DEFINED_EVENT ||
          mNoListenerForEventAtom == aEvent->userType)) {
       return;
     }
     HandleEventInternal(aPresContext, aEvent, aDOMEvent, aCurrentTarget,
-                        aFlags, aEventStatus, aPusher);
+                        aEventStatus, aPusher);
   }
 
-  void HandleEventInternal(nsPresContext* aPresContext,
-                           nsEvent* aEvent, 
-                           nsIDOMEvent** aDOMEvent,
-                           nsIDOMEventTarget* aCurrentTarget,
-                           uint32_t aFlags,
-                           nsEventStatus* aEventStatus,
-                           nsCxPusher* aPusher);
-
   /**
    * Tells the event listener manager that its target (which owns it) is
    * no longer using it (and could go away).
    */
   void Disconnect();
 
   /**
    * Allows us to quickly determine if we have mutation listeners registered.
@@ -233,21 +238,27 @@ public:
   bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
 
   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
   void MarkForCC();
 
   nsISupports* GetTarget() { return mTarget; }
 protected:
+  void HandleEventInternal(nsPresContext* aPresContext,
+                           nsEvent* aEvent, 
+                           nsIDOMEvent** aDOMEvent,
+                           nsIDOMEventTarget* aCurrentTarget,
+                           nsEventStatus* aEventStatus,
+                           nsCxPusher* aPusher);
+
   nsresult HandleEventSubType(nsListenerStruct* aListenerStruct,
                               nsIDOMEventListener* aListener,
                               nsIDOMEvent* aDOMEvent,
                               nsIDOMEventTarget* aCurrentTarget,
-                              uint32_t aPhaseFlags,
                               nsCxPusher* aPusher);
 
   /**
    * Compile the "inline" event listener for aListenerStruct.  The
    * body of the listener can be provided in aBody; if this is null we
    * will look for it on mTarget.
    */
   nsresult CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -107,23 +107,19 @@ enum nsEventStructType {
 
 // These flags are sort of a mess. They're sort of shared between event
 // listener flags and event flags, but only some of them. You've been
 // warned!
 #define NS_EVENT_FLAG_NONE                0x0000
 #define NS_EVENT_FLAG_BUBBLE              0x0002
 #define NS_EVENT_FLAG_CAPTURE             0x0004
 #define NS_PRIV_EVENT_FLAG_SCRIPT         0x0080
-#define NS_EVENT_FLAG_NO_CONTENT_DISPATCH 0x0100
 #define NS_EVENT_FLAG_SYSTEM_EVENT        0x0200
 #define NS_PRIV_EVENT_UNTRUSTED_PERMITTED 0x8000
 
-#define NS_EVENT_CAPTURE_MASK             (~(NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH))
-#define NS_EVENT_BUBBLE_MASK              (~(NS_EVENT_FLAG_CAPTURE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH))
-
 #define NS_EVENT_TYPE_NULL                   0
 #define NS_EVENT_TYPE_ALL                  1 // Not a real event type
 
 /**
  * GUI MESSAGES
  */
  //@{
 #define NS_EVENT_NULL                   0
@@ -488,16 +484,18 @@ public:
   // If mIsTrusted is true, the event is a trusted event.  Otherwise, it's
   // an untrusted event.
   bool    mIsTrusted : 1;
   // If mInBubblingPhase is true, the event is in bubbling phase or target
   // phase.
   bool    mInBubblingPhase : 1;
   // If mInCapturePhase is true, the event is in capture phase or target phase.
   bool    mInCapturePhase : 1;
+  // If mInSystemGroup is true, the event is being dispatched in system group.
+  bool    mInSystemGroup: 1;
   // If mCancelable is true, the event can be consumed.  I.e., calling
   // nsDOMEvent::PreventDefault() can prevent the default action.
   bool    mCancelable : 1;
   // If mBubbles is true, the event can bubble.  Otherwise, cannot be handled
   // in bubbling phase.
   bool    mBubbles : 1;
   // If mPropagationStopped is true, nsDOMEvent::StopPropagation() or
   // nsDOMEvent::StopImmediatePropagation() has been called.