Bug 907098 - Don't send input events to apz if touchstart or the first touchmove get cancelled. Also filter touchmoves that don't change position. r=tabraldes
authorJim Mathies <jmathies@mozilla.com>
Mon, 09 Sep 2013 13:57:25 -0500
changeset 146215 14eb0d5731d64b657282f9e94107f6e65aa5a529
parent 146214 f583bcbb5e82affa7895b0b65d2a0794c47b6cfa
child 146216 a468b2e34b043362715ea032ca204d35bd99fc9f
push id25245
push userryanvm@gmail.com
push dateMon, 09 Sep 2013 20:57:55 +0000
treeherdermozilla-central@a468b2e34b04 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstabraldes
bugs907098
milestone26.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 907098 - Don't send input events to apz if touchstart or the first touchmove get cancelled. Also filter touchmoves that don't change position. r=tabraldes
widget/windows/winrt/MetroInput.cpp
--- a/widget/windows/winrt/MetroInput.cpp
+++ b/widget/windows/winrt/MetroInput.cpp
@@ -94,16 +94,48 @@ namespace {
                      // consistent with what Windows provides us here.
                      // XXX: Windows defaults to 0.5, but the current W3C
                      // draft says that the value should be 0.0 if no value
                      // known.
                      pressure);
   }
 
   /**
+   * Test if a touchpoint position has moved. See Touch.Equals for
+   * criteria.
+   *
+   * @param aTouch previous touch point
+   * @param aPoint new winrt touch point
+   * @return true if the point has moved
+   */
+  bool
+  HasPointMoved(Touch* aTouch, UI::Input::IPointerPoint* aPoint) {
+    WRL::ComPtr<UI::Input::IPointerPointProperties> props;
+    Foundation::Point position;
+    Foundation::Rect contactRect;
+    float pressure;
+
+    aPoint->get_Properties(props.GetAddressOf());
+    aPoint->get_Position(&position);
+    props->get_ContactRect(&contactRect);
+    props->get_Pressure(&pressure);
+    nsIntPoint touchPoint = MetroUtils::LogToPhys(position);
+    nsIntPoint touchRadius;
+    touchRadius.x = MetroUtils::LogToPhys(contactRect.Width) / 2;
+    touchRadius.y = MetroUtils::LogToPhys(contactRect.Height) / 2;
+
+    // from Touch.Equals
+    return touchPoint != aTouch->mRefPoint ||
+           pressure != aTouch->Force() ||
+           /* mRotationAngle == aTouch->RotationAngle() || */
+           touchRadius.x != aTouch->RadiusX() ||
+           touchRadius.y != aTouch->RadiusY();
+  }
+
+  /**
    * Converts from the Devices::Input::PointerDeviceType enumeration
    * to a nsIDOMMouseEvent::MOZ_SOURCE_* value.
    *
    * @param aDeviceType the value to convert
    * @param aMozInputSource the converted value
    */
   void
   MozInputSourceFromDeviceType(
@@ -463,19 +495,26 @@ MetroInput::OnPointerMoved(UI::Core::ICo
   // Some old drivers cause us to receive a PointerMoved event for a touchId
   // after we've already received a PointerReleased event for that touchId.
   // To work around those busted drivers, we simply ignore TouchMoved events
   // for touchIds that we are not currently tracking.  See bug 819223.
   if (!touch) {
     return S_OK;
   }
 
+  // If the point hasn't moved, filter it out per the spec. Pres shell does
+  // this as well, but we need to know when our first touchmove is going to
+  // get delivered so we can check the result.
+  if (!HasPointMoved(touch, currentPoint.Get())) {
+    return S_OK;
+  }
+
   // If we've accumulated a batch of pointer moves and we're now on a new batch
   // at a new position send the previous batch. (perf opt)
-  if (touch->mChanged) {
+  if (!mIsFirstTouchMove && touch->mChanged) {
     nsTouchEvent* touchEvent =
       new nsTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
     InitTouchEventTouchList(touchEvent);
     DispatchAsyncTouchEventIgnoreStatus(touchEvent);
   }
 
   touch = CreateDOMTouch(currentPoint.Get());
   touch->mChanged = true;
@@ -1056,17 +1095,18 @@ MetroInput::DispatchAsyncTouchEventIgnor
 
 nsEventStatus
 MetroInput::DeliverNextQueuedTouchEvent()
 {
   nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
   MOZ_ASSERT(event);
   nsEventStatus status;
   mWidget->DispatchEvent(event, status);
-  if (status != nsEventStatus_eConsumeNoDefault && MetroWidget::sAPZC) {
+  // Deliver to the apz if content has *not* cancelled touchstart or the first touchmove.
+  if (!mTouchStartDefaultPrevented && !mTouchMoveDefaultPrevented && MetroWidget::sAPZC) {
     MultiTouchInput inputData(*event);
     MetroWidget::sAPZC->ReceiveInputEvent(inputData);
   }
   delete event;
   return status;
 }
 
 void