diff --git a/gfx/layers/apz/src/GestureEventListener.cpp b/gfx/layers/apz/src/GestureEventListener.cpp index 3bde1fe51597..bdd6e4622ef5 100644 --- a/gfx/layers/apz/src/GestureEventListener.cpp +++ b/gfx/layers/apz/src/GestureEventListener.cpp @@ -55,6 +55,7 @@ GestureEventListener::GestureEventListener(AsyncPanZoomController* aAsyncPanZoom mSpanChange(0.0f), mPreviousSpan(0.0f), mLastTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0), + mLastTapInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0), mLongTapTimeoutTask(nullptr), mMaxTapTimeoutTask(nullptr) { @@ -168,6 +169,7 @@ nsEventStatus GestureEventListener::HandleInputTouchMultiStart() // Cancel wait for double tap CancelMaxTapTimeoutTask(); SetState(GESTURE_MULTI_TOUCH_DOWN); + TriggerSingleTapConfirmedEvent(); // Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event rv = nsEventStatus_eConsumeNoDefault; break; @@ -175,6 +177,7 @@ nsEventStatus GestureEventListener::HandleInputTouchMultiStart() // Cancel wait for single tap CancelMaxTapTimeoutTask(); SetState(GESTURE_MULTI_TOUCH_DOWN); + TriggerSingleTapConfirmedEvent(); // Prevent APZC::OnTouchStart() from handling MULTITOUCH_START event rv = nsEventStatus_eConsumeNoDefault; break; @@ -441,10 +444,10 @@ void GestureEventListener::HandleInputTimeoutMaxTap() 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); } @@ -498,6 +501,8 @@ void GestureEventListener::CancelMaxTapTimeoutTask() void GestureEventListener::CreateMaxTapTimeoutTask() { + mLastTapInput = mLastTouchInput; + mMaxTapTimeoutTask = NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap); diff --git a/gfx/layers/apz/src/GestureEventListener.h b/gfx/layers/apz/src/GestureEventListener.h index fc5e31049994..c38ea07d2fe2 100644 --- a/gfx/layers/apz/src/GestureEventListener.h +++ b/gfx/layers/apz/src/GestureEventListener.h @@ -175,6 +175,15 @@ private: */ 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 diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 480f81210e35..148cb11998f3 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -1478,6 +1478,62 @@ TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) { 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() {