Bug 1400143 - [Pointer Event] Update pointerevent's mLastRefPoint to get correct movementX/movementY values. r=smaug.
☠☠ backed out by f0eb4f3117c3 ☠ ☠
authorStone Shih <sshih@mozilla.com>
Fri, 15 Sep 2017 13:51:10 +0800
changeset 427593 c608c6fd9a9ad37116636980095bdcb6af8e74d6
parent 427592 8f0bb6229e99b494fd746d722938ac8b86c4e37e
child 427594 c68838a2ad091d023ca6e6d38c5b01507f302797
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewerssmaug
bugs1400143
milestone58.0a1
Bug 1400143 - [Pointer Event] Update pointerevent's mLastRefPoint to get correct movementX/movementY values. r=smaug. Add pointermove handling in UpdateLastRefPointOfMouseEvent to update mLastRefPoint of pointermove events. MozReview-Commit-ID: DC7HyKsLE8y
dom/events/EventStateManager.cpp
dom/events/UIEvent.cpp
dom/events/test/pointerevents/pointerlock/mochitest.ini
dom/events/test/pointerevents/pointerlock/pointerevent_movementxy-manual.html
dom/events/test/pointerevents/pointerlock/resources/pointerevent_movementxy-iframe.html
dom/events/test/pointerevents/pointerlock/test_pointerevent_movementxy-manual.html
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -4271,17 +4271,18 @@ EventStateManager::GeneratePointerEnterE
   WidgetPointerEvent pointerEvent(*aEvent);
   pointerEvent.mMessage = aMessage;
   GenerateMouseEnterExit(&pointerEvent);
 }
 
 /* static */ void
 EventStateManager::UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent)
 {
-  if (aMouseEvent->mMessage != eMouseMove) {
+  if (aMouseEvent->mMessage != eMouseMove &&
+      aMouseEvent->mMessage != ePointerMove) {
     return;
   }
 
   // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
   // Movement is calculated in UIEvent::GetMovementPoint() as:
   //   previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
   if (sIsPointerLocked && aMouseEvent->mWidget) {
     // The pointer is locked. If the pointer is not located at the center of
@@ -4304,45 +4305,52 @@ EventStateManager::UpdateLastRefPointOfM
   }
 }
 
 /* static */ void
 EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
                      WidgetMouseEvent* aMouseEvent)
 {
   MOZ_ASSERT(sIsPointerLocked);
-  if (aMouseEvent->mMessage != eMouseMove || !aMouseEvent->mWidget) {
+  if ((aMouseEvent->mMessage != eMouseMove &&
+       aMouseEvent->mMessage != ePointerMove) || !aMouseEvent->mWidget) {
     return;
   }
 
+  // We generate pointermove from mousemove event, so only synthesize native
+  // mouse move and update sSynthCenteringPoint by mousemove event.
+  bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
+
   // The pointer is locked. If the pointer is not located at the center of
   // the window, dispatch a synthetic mousemove to return the pointer there.
   // Doing this between "real" pointer moves gives the impression that the
   // (locked) pointer can continue moving and won't stop at the screen
   // boundary. We cancel the synthetic event so that we don't end up
   // dispatching the centering move event to content.
   LayoutDeviceIntPoint center =
     GetWindowClientRectCenter(aMouseEvent->mWidget);
 
-  if (aMouseEvent->mRefPoint != center) {
+  if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
     // Mouse move doesn't finish at the center of the window. Dispatch a
     // synthetic native mouse event to move the pointer back to the center
     // of the window, to faciliate more movement. But first, record that
     // we've dispatched a synthetic mouse movement, so we can cancel it
     // in the other branch here.
     sSynthCenteringPoint = center;
     aMouseEvent->mWidget->SynthesizeNativeMouseMove(
       center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
   } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
     // This is the "synthetic native" event we dispatched to re-center the
     // pointer. Cancel it so we don't expose the centering move to content.
     aMouseEvent->StopPropagation();
     // Clear sSynthCenteringPoint so we don't cancel other events
     // targeted at the center.
-    sSynthCenteringPoint = kInvalidRefPoint;
+    if (updateSynthCenteringPoint) {
+      sSynthCenteringPoint = kInvalidRefPoint;
+    }
   }
 }
 
 /* static */ void
 EventStateManager::UpdateLastPointerPosition(WidgetMouseEvent* aMouseEvent)
 {
   if (aMouseEvent->mMessage != eMouseMove) {
     return;
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -119,17 +119,17 @@ UIEvent::GetMovementPoint()
     return nsIntPoint(0, 0);
   }
 
   if (mPrivateDataDuplicated || mEventIsInternal) {
     return mMovementPoint;
   }
 
   if (!mEvent || !mEvent->AsGUIEvent()->mWidget ||
-      (mEvent->mMessage != eMouseMove)) {
+      (mEvent->mMessage != eMouseMove && mEvent->mMessage != ePointerMove)) {
     // Pointer Lock spec defines that movementX/Y must be zero for all mouse
     // events except mousemove.
     return nsIntPoint(0, 0);
   }
 
   // Calculate the delta between the last screen point and the current one.
   nsIntPoint current = DevPixelsToCSSPixels(mEvent->mRefPoint, mPresContext);
   nsIntPoint last = DevPixelsToCSSPixels(mEvent->mLastRefPoint, mPresContext);
--- a/dom/events/test/pointerevents/pointerlock/mochitest.ini
+++ b/dom/events/test/pointerevents/pointerlock/mochitest.ini
@@ -1,13 +1,17 @@
 [DEFAULT]
 skip-if = os == 'android' # Bug 1312791
 support-files =
   ../mochitest_support_external.js
   ../mochitest_support_internal.js
   ../pointerevent_styles.css
   ../pointerevent_support.js
 
+[test_pointerevent_movementxy-manual.html]
+  support-files =
+    pointerevent_movementxy-manual.html
+    ./resources/pointerevent_movementxy-iframe.html
 [test_pointerevent_pointerlock_after_pointercapture-manual.html]
   support-files = pointerevent_pointerlock_after_pointercapture-manual.html
   disabled = disabled # We don't allow pointer lock in mousemove handlers.
 [test_pointerevent_pointerlock_supercedes_capture-manual.html]
   support-files = pointerevent_pointerlock_supercedes_capture-manual.html
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerlock/pointerevent_movementxy-manual.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html>
+    <head>
+        <title>Pointer Events properties tests</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <!-- Additional helper script for common checks across event types -->
+        <script type="text/javascript" src="../pointerevent_support.js"></script>
+        <style>
+          #testContainer {
+            touch-action: none;
+            user-select: none;
+            position: relative;
+          }
+          #box1 {
+            top: 30px;
+            left: 50px;
+            background: black;
+          }
+          #box2 {
+            top: 70px;
+            left: 250px;
+            background: red;
+          }
+          #innerFrame {
+            top: 10px;
+            left: 100px;
+          }
+          #square2 {
+            visibility: block;
+          }
+        </style>
+        <script>
+            var expectedPointerId = NaN;
+            var startSummation = false;
+            var lastScreenX = 0;
+            var lastScreenY = 0;
+
+            function resetTestState() {
+                startSummation = false;
+                lastScreenX = 0;
+                lastScreenY = 0;
+            }
+
+            function run() {
+                var test_pointerEvent = setup_pointerevent_test("pointerevent attributes", ['mouse', 'touch']);
+
+                [document, document.getElementById('innerFrame').contentDocument].forEach(function(element) {
+                  on_event(element, 'pointermove', function (event) {
+                    if (startSummation) {
+                      test_pointerEvent.step(function() {
+                        assert_equals(event.movementX, event.screenX - lastScreenX, "movementX should be the delta between current event's and last event's screenX");
+                        assert_equals(event.movementY, event.screenY - lastScreenY, "movementY should be the delta between current event's and last event's screenY");
+                      });
+                      lastScreenX = event.screenX;
+                      lastScreenY = event.screenY;
+                    }
+                  });
+                });
+                on_event(document.querySelector('#box1'), 'pointerdown', function(event) {
+                  event.target.releasePointerCapture(event.pointerId);
+                  test_pointerEvent.step(function() {
+                      assert_equals(event.pointerType, expectedPointerType, "Use the instructed pointer type.");
+                  });
+                  startSummation = true;
+                  lastScreenX = event.screenX;
+                  lastScreenY = event.screenY;
+                });
+                on_event(document.querySelector('#box2'), 'pointerup', function(event) {
+                  startSummation = false;
+                  test_pointerEvent.done();
+                });
+            }
+        </script>
+    </head>
+    <body onload="run()">
+        <h1>Pointer Events movementX/Y attribute test</h1>
+        <h2 id="pointerTypeDescription"></h2>
+        <h4>
+            Test Description: This test checks the properties of pointer events that do not support hover.
+            <ol>
+                 <li>Press down on the black square.</li>
+                 <li>Move your pointer  slowly along a straight line to the red square.</li>
+                 <li>Release the pointer when you are over the red square.</li>
+            </ol>
+
+            Test passes if the proper behavior of the events is observed.
+        </h4>
+        <div id="testContainer">
+            <div id="box1" class="square"></div>
+            <div id="box2" class="square"></div>
+            <iframe id="innerFrame" src="resources/pointerevent_movementxy-iframe.html"></iframe>
+        </div>
+        <div class="spacer"></div>
+    </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerlock/resources/pointerevent_movementxy-iframe.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width">
+    </head>
+    <body>
+    </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/events/test/pointerevents/pointerlock/test_pointerevent_movementxy-manual.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1399740
+-->
+  <head>
+    <meta charset="utf-8">
+    <title>Test for Bug 1399740</title>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+    <script type="text/javascript" src="mochitest_support_external.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+    <script type="text/javascript">
+      SimpleTest.waitForExplicitFinish();
+      function startTest() {
+        runTestInNewWindow("pointerevent_movementxy-manual.html");
+      }
+      function executeTest(int_win) {
+        let box1 = int_win.document.getElementById("box1");
+        let box2 = int_win.document.getElementById("box2");
+        let rect1 = box1.getBoundingClientRect();
+        let rect2 = box2.getBoundingClientRect();
+        let offsetX = rect1.left + rect1.width / 2;
+        let offsetY = rect1.top + rect1.height / 2;
+        let stepX = (rect2.left + rect2.width / 2 - offsetX) / 10;
+        let stepY = (rect2.top + rect2.height / 2 - offsetY) / 10;
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+        for (var i = 0; i < 10; ++i) {
+          offsetX += stepX;
+          offsetY += stepY;
+          sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+        }
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
+
+        offsetX = rect1.left + rect1.width / 2;
+        offsetY = rect1.top + rect1.height / 2;
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+        for (var i = 0; i < 10; ++i) {
+          offsetX += stepX;
+          offsetY += stepY;
+          sendMouseEventAtPoint(int_win, offsetX, offsetY, "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+        }
+        sendMouseEventAtPoint(int_win, offsetX, offsetY, "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_TOUCH});
+      }
+    </script>
+  </head>
+  <body>
+  </body>
+</html>