Bug 1323158 - Part 1: Fire pointer and mouse boundary events when capturing the pointer. r=smaug
authorStone Shih <sshih@mozilla.com>
Wed, 18 Jan 2017 15:25:44 +0800
changeset 347238 4311e8a7e14fc2bcfdfebc63ab472673056dd02a
parent 347237 11ce882384cc268ad2be6c6a2c2083b3c0bc81bf
child 347239 feadd76c7f3c08d52aec63c78df32206f4b5f6bf
push id31491
push usercbook@mozilla.com
push dateMon, 13 Mar 2017 14:24:00 +0000
treeherdermozilla-central@8d9fd089cabd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1323158
milestone55.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 1323158 - Part 1: Fire pointer and mouse boundary events when capturing the pointer. r=smaug
dom/events/EventStateManager.cpp
dom/events/test/pointerevents/mochitest.ini
dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
layout/base/PresShell.cpp
widget/MouseEvents.h
widget/nsGUIEventIPC.h
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -3869,20 +3869,17 @@ CreateMouseOrPointerWidgetEvent(WidgetMo
     nsAutoPtr<WidgetPointerEvent> newPointerEvent;
     newPointerEvent =
       new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
                              aMouseEvent->mWidget);
     newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
     newPointerEvent->mWidth = sourcePointer->mWidth;
     newPointerEvent->mHeight = sourcePointer->mHeight;
     newPointerEvent->inputSource = sourcePointer->inputSource;
-    newPointerEvent->relatedTarget =
-      nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
-        ? nullptr
-        : aRelatedContent;
+    newPointerEvent->relatedTarget = aRelatedContent;
     aNewEvent = newPointerEvent.forget();
   } else {
     aNewEvent =
       new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
                            aMouseEvent->mWidget, WidgetMouseEvent::eReal);
     aNewEvent->relatedTarget = aRelatedContent;
   }
   aNewEvent->mRefPoint = aMouseEvent->mRefPoint;
@@ -4082,24 +4079,18 @@ EventStateManager::NotifyMouseOut(Widget
   // two nearby elements both deep in the DOM tree that would be defeated by
   // switching the hover state to null here.
   bool isPointer = aMouseEvent->mClass == ePointerEventClass;
   if (!aMovingInto && !isPointer) {
     // Unset :hover
     SetContentState(nullptr, NS_EVENT_STATE_HOVER);
   }
 
-  // In case we go out from capturing element (retargetedByPointerCapture is true)
-  // we should dispatch ePointerLeave event and only for capturing element.
-  RefPtr<nsIContent> movingInto = aMouseEvent->retargetedByPointerCapture
-                                    ? wrapper->mLastOverElement->GetParent()
-                                    : aMovingInto;
-
   EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
-                                       movingInto, aMouseEvent,
+                                       aMovingInto, aMouseEvent,
                                        isPointer ? ePointerLeave : eMouseLeave);
 
   // Fire mouseout
   DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? ePointerOut : eMouseOut,
                               wrapper->mLastOverElement, aMovingInto);
   leaveDispatcher.Dispatch();
 
   wrapper->mLastOverFrame = nullptr;
@@ -4110,23 +4101,19 @@ EventStateManager::NotifyMouseOut(Widget
 }
 
 void
 EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
                                    nsIContent* aContent)
 {
   NS_ASSERTION(aContent, "Mouse must be over something");
 
-  // If pointer capture is set, we should suppress pointerover/pointerenter events
-  // for all elements except element which have pointer capture.
-  bool dispatch = !aMouseEvent->retargetedByPointerCapture;
-
   OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
 
-  if (wrapper->mLastOverElement == aContent && dispatch)
+  if (wrapper->mLastOverElement == aContent)
     return;
 
   // Before firing mouseover, check for recursion
   if (aContent == wrapper->mFirstOverEventElement)
     return;
 
   // Check to see if we're a subdocument and if so update the parent
   // document's ESM state to indicate that the mouse is over the
@@ -4138,53 +4125,46 @@ EventStateManager::NotifyMouseOver(Widge
         EventStateManager* parentESM =
           parentShell->GetPresContext()->EventStateManager();
         parentESM->NotifyMouseOver(aMouseEvent, docContent);
       }
     }
   }
   // Firing the DOM event in the parent document could cause all kinds
   // of havoc.  Reverify and take care.
-  if (wrapper->mLastOverElement == aContent && dispatch)
+  if (wrapper->mLastOverElement == aContent)
     return;
 
   // Remember mLastOverElement as the related content for the
   // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
   nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
 
   bool isPointer = aMouseEvent->mClass == ePointerEventClass;
   
-  Maybe<EnterLeaveDispatcher> enterDispatcher;
-  if (dispatch) {
-    enterDispatcher.emplace(this, aContent, lastOverElement, aMouseEvent,
-                            isPointer ? ePointerEnter : eMouseEnter);
-  }
+  EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
+                                       aMouseEvent,
+                                       isPointer ? ePointerEnter : eMouseEnter);
 
   NotifyMouseOut(aMouseEvent, aContent);
 
   // Store the first mouseOver event we fire and don't refire mouseOver
   // to that element while the first mouseOver is still ongoing.
   wrapper->mFirstOverEventElement = aContent;
 
   if (!isPointer) {
     SetContentState(aContent, NS_EVENT_STATE_HOVER);
   }
 
-  if (dispatch) {
-    // Fire mouseover
-    wrapper->mLastOverFrame = 
-      DispatchMouseOrPointerEvent(aMouseEvent,
-                                  isPointer ? ePointerOver : eMouseOver,
-                                  aContent, lastOverElement);
-    enterDispatcher->Dispatch();
-    wrapper->mLastOverElement = aContent;
-  } else {
-    wrapper->mLastOverFrame = nullptr;
-    wrapper->mLastOverElement = nullptr;
-  }
+  // Fire mouseover
+  wrapper->mLastOverFrame =
+    DispatchMouseOrPointerEvent(aMouseEvent,
+                                isPointer ? ePointerOver : eMouseOver,
+                                aContent, lastOverElement);
+  enterDispatcher.Dispatch();
+  wrapper->mLastOverElement = aContent;
 
   // Turn recursion protection back off
   wrapper->mFirstOverEventElement = nullptr;
 }
 
 // Returns the center point of the window's client area. This is
 // in widget coordinates, i.e. relative to the widget's top-left
 // corner, not in screen coordinates, the same units that UIEvent::
--- a/dom/events/test/pointerevents/mochitest.ini
+++ b/dom/events/test/pointerevents/mochitest.ini
@@ -13,17 +13,16 @@ support-files =
 [test_pointerevent_attributes_nohover_pointers-manual.html]
   support-files =
     pointerevent_attributes_nohover_pointers-manual.html
     ./resources/pointerevent_attributes_hoverable_pointers-iframe.html
 [test_pointerevent_capture_mouse-manual.html]
   support-files = pointerevent_capture_mouse-manual.html
 [test_pointerevent_capture_suppressing_mouse-manual.html]
   support-files = pointerevent_capture_suppressing_mouse-manual.html
-  disabled = should be investigated
 [test_pointerevent_change-touch-action-onpointerdown_touch-manual.html]
   support-files = pointerevent_change-touch-action-onpointerdown_touch-manual.html
   disabled = disabled
 [test_pointerevent_constructor.html]
   support-files = pointerevent_constructor.html
 [test_pointerevent_element_haspointercapture-manual.html]
   support-files = pointerevent_element_haspointercapture-manual.html
 [test_pointerevent_element_haspointercapture_release_pending_capture-manual.html]
--- a/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
+++ b/dom/events/test/pointerevents/test_pointerevent_capture_suppressing_mouse-manual.html
@@ -14,16 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     <script type="text/javascript">
       SimpleTest.waitForExplicitFinish();
       function startTest() {
         runTestInNewWindow("pointerevent_capture_suppressing_mouse-manual.html");
       }
       function executeTest(int_win) {
         sendMouseEvent(int_win, "target0",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mousemove");
+        sendMouseEvent(int_win, "btnCapture", "mousemove");
         sendMouseEvent(int_win, "btnCapture", "mousedown");
         sendMouseEvent(int_win, "target1",    "mousemove");
         sendMouseEvent(int_win, "target0",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mousemove");
         sendMouseEvent(int_win, "target1",    "mouseup");
         sendMouseEvent(int_win, "target1",    "mousemove");
       }
     </script>
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -7603,40 +7603,38 @@ PresShell::HandleEvent(nsIFrame* aFrame,
           }
           if (targetContent) {
             SetPointerCapturingContent(pointerEvent->pointerId, targetContent);
           }
         }
       }
     }
 
-    if (aEvent->mClass == ePointerEventClass &&
-        aEvent->mMessage != ePointerDown) {
-      if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
-        uint32_t pointerId = pointerEvent->pointerId;
+    // Mouse events should be fired to the same target as their mapped pointer
+    // events
+    if ((aEvent->mClass == ePointerEventClass ||
+         aEvent->mClass == eMouseEventClass) &&
+        aEvent->mMessage != ePointerDown && aEvent->mMessage != eMouseDown) {
+      if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
+        uint32_t pointerId = mouseEvent->pointerId;
         nsIContent* pointerCapturingContent =
           GetPointerCapturingContent(pointerId);
 
         if (pointerCapturingContent) {
           if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) {
-            // If pointer capture is set, we should suppress
-            // pointerover/pointerenter events for all elements except element
-            // which have pointer capture. (Code in EventStateManager)
-            pointerEvent->retargetedByPointerCapture =
-              frame && frame->GetContent() &&
-              !nsContentUtils::ContentIsDescendantOf(frame->GetContent(),
-                                                     pointerCapturingContent);
             frame = capturingFrame;
           }
 
-          if (pointerEvent->mMessage == ePointerUp ||
-              pointerEvent->mMessage == ePointerCancel) {
+          if (aEvent->mMessage == ePointerUp ||
+              aEvent->mMessage == ePointerCancel) {
             // Implicitly releasing capture for given pointer.
             // ePointerLostCapture should be send after ePointerUp or
             // ePointerCancel.
+            WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
+            MOZ_ASSERT(pointerEvent);
             releasePointerCaptureCaller.SetTarget(pointerId,
                                                   pointerEvent->inputSource,
                                                   pointerEvent->mIsPrimary);
           }
         }
       }
     }
 
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -44,50 +44,46 @@ class WidgetPointerHelper
 {
 public:
   uint32_t pointerId;
   uint32_t tiltX;
   uint32_t tiltY;
   uint32_t twist;
   float tangentialPressure;
   bool convertToPointer;
-  bool retargetedByPointerCapture;
 
   WidgetPointerHelper()
     : pointerId(0)
     , tiltX(0)
     , tiltY(0)
     , twist(0)
     , tangentialPressure(0)
     , convertToPointer(true)
-    , retargetedByPointerCapture(false)
   {
   }
 
   WidgetPointerHelper(uint32_t aPointerId, uint32_t aTiltX, uint32_t aTiltY,
                       uint32_t aTwist = 0, float aTangentialPressure = 0)
     : pointerId(aPointerId)
     , tiltX(aTiltX)
     , tiltY(aTiltY)
     , twist(aTwist)
     , tangentialPressure(aTangentialPressure)
     , convertToPointer(true)
-    , retargetedByPointerCapture(false)
   {
   }
 
   void AssignPointerHelperData(const WidgetPointerHelper& aEvent)
   {
     pointerId = aEvent.pointerId;
     tiltX = aEvent.tiltX;
     tiltY = aEvent.tiltY;
     twist = aEvent.twist;
     tangentialPressure = aEvent.tangentialPressure;
     convertToPointer = aEvent.convertToPointer;
-    retargetedByPointerCapture = aEvent.retargetedByPointerCapture;
   }
 };
 
 /******************************************************************************
  * mozilla::WidgetMouseEventBase
  ******************************************************************************/
 
 class WidgetMouseEventBase : public WidgetInputEvent
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -225,18 +225,18 @@ struct ParamTraits<mozilla::WidgetPointe
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.pointerId);
     WriteParam(aMsg, aParam.tiltX);
     WriteParam(aMsg, aParam.tiltY);
     WriteParam(aMsg, aParam.twist);
     WriteParam(aMsg, aParam.tangentialPressure);
-    // We don't serialize convertToPointer and retargetedByPointerCapture since
-    // they are temporarily variable and should be reset to default.
+    // We don't serialize convertToPointer since it's temporarily variable and
+    // should be reset to default.
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool rv;
     rv = ReadParam(aMsg, aIter, &aResult->pointerId) &&
          ReadParam(aMsg, aIter, &aResult->tiltX) &&
          ReadParam(aMsg, aIter, &aResult->tiltY) &&