diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 148cb11998f..61a571139f4 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -1612,6 +1612,55 @@ protected: } }; +// A version of ApzcPan() that routes the pan through the tree manager, +// so that the tree manager has the appropriate state for testing. +static void +ApzctmPan(APZCTreeManager* aTreeManager, + int& aTime, + int aTouchStartY, + int aTouchEndY, + bool aKeepFingerDown = false) +{ + // TODO: Reuse some code between this and ApzcPan(). + + // Reduce the touch start tolerance to a tiny value. + // We can't do what ApzcPan() does to overcome the tolerance (send the + // touch-start at (aTouchStartY + some_large_value)) because the tree manager + // does hit testing based on the touch-start coordinates, and a different + // APZC than the one we intend might be hit. + SCOPED_GFX_PREF(APZTouchStartTolerance, float, 1.0f / 1000.0f); + const int OVERCOME_TOUCH_TOLERANCE = 1; + + const int TIME_BETWEEN_TOUCH_EVENT = 100; + + // Make sure the move is large enough to not be handled as a tap + MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, TimeStamp(), 0); + mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY), ScreenSize(0, 0), 0, 0)); + aTreeManager->ReceiveInputEvent(mti, nullptr); + + aTime += TIME_BETWEEN_TOUCH_EVENT; + + mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, TimeStamp(), 0); + mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY + OVERCOME_TOUCH_TOLERANCE), ScreenSize(0, 0), 0, 0)); + aTreeManager->ReceiveInputEvent(mti, nullptr); + + aTime += TIME_BETWEEN_TOUCH_EVENT; + + mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, TimeStamp(), 0); + mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0)); + aTreeManager->ReceiveInputEvent(mti, nullptr); + + aTime += TIME_BETWEEN_TOUCH_EVENT; + + if (!aKeepFingerDown) { + mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, TimeStamp(), 0); + mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0)); + aTreeManager->ReceiveInputEvent(mti, nullptr); + } + + aTime += TIME_BETWEEN_TOUCH_EVENT; +} + class APZHitTestingTester : public APZCTreeManagerTester { protected: Matrix4x4 transformToApzc; @@ -2189,6 +2238,43 @@ TEST_F(APZOverscrollHandoffTester, LayerStructureChangesWhileEventsArePending) { EXPECT_EQ(-10, middleApzc->GetFrameMetrics().GetScrollOffset().y); } +// Test that putting a second finger down on an APZC while a down-chain APZC +// is overscrolled doesn't result in being stuck in overscroll. +TEST_F(APZOverscrollHandoffTester, StuckInOverscroll_Bug1073250) { + // Enable overscrolling. + SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); + + CreateOverscrollHandoffLayerTree1(); + + TestAsyncPanZoomController* child = ApzcOf(layers[1]); + + // Pan, causing the parent APZC to overscroll. + int time = 0; + ApzctmPan(manager, time, 10, 40, true /* keep finger down */); + EXPECT_FALSE(child->IsOverscrolled()); + EXPECT_TRUE(rootApzc->IsOverscrolled()); + + // Put a second finger down. + MultiTouchInput secondFingerDown(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0); + // Use the same touch identifier for the first touch (0) as ApzctmPan(). (A bit hacky.) + secondFingerDown.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, 40), ScreenSize(0, 0), 0, 0)); + secondFingerDown.mTouches.AppendElement(SingleTouchData(1, ScreenIntPoint(30, 20), ScreenSize(0, 0), 0, 0)); + manager->ReceiveInputEvent(secondFingerDown, nullptr); + + // Release the fingers. + MultiTouchInput fingersUp = secondFingerDown; + fingersUp.mType = MultiTouchInput::MULTITOUCH_END; + manager->ReceiveInputEvent(fingersUp, nullptr); + + // Allow any animations to run their course. + child->AdvanceAnimationsUntilEnd(testStartTime); + rootApzc->AdvanceAnimationsUntilEnd(testStartTime); + + // Make sure nothing is overscrolled. + EXPECT_FALSE(child->IsOverscrolled()); + EXPECT_FALSE(rootApzc->IsOverscrolled()); +} + // Here we test that if two flings are happening simultaneously, overscroll // is handed off correctly for each. TEST_F(APZOverscrollHandoffTester, SimultaneousFlings) {