Bug 947892. Add dispatching of the tap event when the tap is followed by multiple touches. r=botond
authorNick Lebedev <nicklebedev37@gmail.com>
Fri, 03 Oct 2014 09:24:56 -0400
changeset 231908 e5b574a8db51e1e1d3be5e39494bd4955f32bc1e
parent 231907 e36bdb0150b920a4c23249abcdb955dca7efd3d0
child 231909 e4165ab15b4e70f99afd4e429f3f429eb0e61463
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs947892
milestone35.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 947892. Add dispatching of the tap event when the tap is followed by multiple touches. r=botond
gfx/layers/apz/src/GestureEventListener.cpp
gfx/layers/apz/src/GestureEventListener.h
gfx/tests/gtest/TestAsyncPanZoomController.cpp
--- a/gfx/layers/apz/src/GestureEventListener.cpp
+++ b/gfx/layers/apz/src/GestureEventListener.cpp
@@ -50,16 +50,17 @@ float GetCurrentSpan(const MultiTouchInp
 }
 
 GestureEventListener::GestureEventListener(AsyncPanZoomController* aAsyncPanZoomController)
   : mAsyncPanZoomController(aAsyncPanZoomController),
     mState(GESTURE_NONE),
     mSpanChange(0.0f),
     mPreviousSpan(0.0f),
     mLastTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0),
+    mLastTapInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0),
     mLongTapTimeoutTask(nullptr),
     mMaxTapTimeoutTask(nullptr)
 {
 }
 
 GestureEventListener::~GestureEventListener()
 {
 }
@@ -163,23 +164,25 @@ nsEventStatus GestureEventListener::Hand
     SetState(GESTURE_MULTI_TOUCH_DOWN);
     // Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event
     rv = nsEventStatus_eConsumeNoDefault;
     break;
   case GESTURE_FIRST_SINGLE_TOUCH_UP:
     // Cancel wait for double tap
     CancelMaxTapTimeoutTask();
     SetState(GESTURE_MULTI_TOUCH_DOWN);
+    TriggerSingleTapConfirmedEvent();
     // Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event
     rv = nsEventStatus_eConsumeNoDefault;
     break;
   case GESTURE_SECOND_SINGLE_TOUCH_DOWN:
     // Cancel wait for single tap
     CancelMaxTapTimeoutTask();
     SetState(GESTURE_MULTI_TOUCH_DOWN);
+    TriggerSingleTapConfirmedEvent();
     // Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event
     rv = nsEventStatus_eConsumeNoDefault;
     break;
   case GESTURE_LONG_TOUCH_DOWN:
     SetState(GESTURE_MULTI_TOUCH_DOWN);
     break;
   case GESTURE_MULTI_TOUCH_DOWN:
   case GESTURE_PINCH:
@@ -436,20 +439,20 @@ void GestureEventListener::HandleInputTi
     NS_WARNING("Unhandled state upon MAX_TAP timeout");
     SetState(GESTURE_NONE);
   }
 }
 
 void GestureEventListener::TriggerSingleTapConfirmedEvent()
 {
   TapGestureInput tapEvent(TapGestureInput::TAPGESTURE_CONFIRMED,
-                           mLastTouchInput.mTime,
-                           mLastTouchInput.mTimeStamp,
-                           mLastTouchInput.mTouches[0].mScreenPoint,
-                           mLastTouchInput.modifiers);
+                           mLastTapInput.mTime,
+                           mLastTapInput.mTimeStamp,
+                           mLastTapInput.mTouches[0].mScreenPoint,
+                           mLastTapInput.modifiers);
   mAsyncPanZoomController->HandleGestureEvent(tapEvent);
 }
 
 void GestureEventListener::SetState(GestureState aState)
 {
   mState = aState;
 
   if (mState == GESTURE_NONE) {
@@ -493,16 +496,18 @@ void GestureEventListener::CancelMaxTapT
   if (mMaxTapTimeoutTask) {
     mMaxTapTimeoutTask->Cancel();
     mMaxTapTimeoutTask = nullptr;
   }
 }
 
 void GestureEventListener::CreateMaxTapTimeoutTask()
 {
+  mLastTapInput = mLastTouchInput;
+
   mMaxTapTimeoutTask =
     NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap);
 
   mAsyncPanZoomController->PostDelayedTask(
     mMaxTapTimeoutTask,
     MAX_TAP_TIME);
 }
 
--- a/gfx/layers/apz/src/GestureEventListener.h
+++ b/gfx/layers/apz/src/GestureEventListener.h
@@ -171,16 +171,25 @@ private:
   float mPreviousSpan;
 
   /**
    * Cached copy of the last touch input.
    */
   MultiTouchInput mLastTouchInput;
 
   /**
+   * Cached copy of the last tap gesture input.
+   * In the situation when we have a tap followed by a pinch we lose info
+   * about tap since we keep only last input and to dispatch it correctly
+   * we save last tap copy into this variable.
+   * For more info see bug 947892.
+   */
+  MultiTouchInput mLastTapInput;
+
+  /**
    * Position of the last touch starting. This is only valid during an attempt
    * to determine if a touch is a tap. If a touch point moves away from
    * mTouchStartPosition to the distance greater than
    * AsyncPanZoomController::GetTouchStartTolerance() while in
    * GESTURE_FIRST_SINGLE_TOUCH_DOWN, GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN
    * or GESTURE_SECOND_SINGLE_TOUCH_DOWN then we're certain the gesture is
    * not tap.
    */
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -1473,16 +1473,72 @@ TEST_F(APZCGestureDetectorTester, Double
   apzc->ContentReceivedTouch(true);
   apzc->ContentReceivedTouch(true);
 
   while (mcc->RunThroughDelayedTasks());
 
   apzc->AssertStateIsReset();
 }
 
+// Test for bug 947892
+// We test whether we dispatch tap event when the tap is followed by pinch.
+TEST_F(APZCGestureDetectorTester, TapFollowedByPinch) {
+  MakeApzcZoomable();
+
+  EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+
+  int time = 0;
+  ApzcTap(apzc, 10, 10, time, 100);
+
+  int inputId = 0;
+  MultiTouchInput mti;
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
+  mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
+  apzc->ReceiveInputEvent(mti);
+
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, time, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
+  mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
+  apzc->ReceiveInputEvent(mti);
+
+  while (mcc->RunThroughDelayedTasks());
+
+  apzc->AssertStateIsReset();
+}
+
+TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) {
+  MakeApzcZoomable();
+
+  EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
+
+  int time = 0;
+  ApzcTap(apzc, 10, 10, time, 100);
+
+  int inputId = 0;
+  MultiTouchInput mti;
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
+  apzc->ReceiveInputEvent(mti);
+
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, time, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
+  mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
+  apzc->ReceiveInputEvent(mti);
+
+  mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, time, TimeStamp(), 0);
+  mti.mTouches.AppendElement(SingleTouchData(inputId, ScreenIntPoint(20, 20), ScreenSize(0, 0), 0, 0));
+  mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ScreenIntPoint(10, 10), ScreenSize(0, 0), 0, 0));
+  apzc->ReceiveInputEvent(mti);
+
+  while (mcc->RunThroughDelayedTasks());
+
+  apzc->AssertStateIsReset();
+}
+
 class APZCTreeManagerTester : public ::testing::Test {
 protected:
   virtual void SetUp() {
     gfxPrefs::GetSingleton();
     AsyncPanZoomController::SetThreadAssertionsEnabled(false);
 
     testStartTime = TimeStamp::Now();
     AsyncPanZoomController::SetFrameTime(testStartTime);