diff options
Diffstat (limited to 'gfx/layers/apz/test/gtest/TestPanning.cpp')
-rw-r--r-- | gfx/layers/apz/test/gtest/TestPanning.cpp | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/gfx/layers/apz/test/gtest/TestPanning.cpp b/gfx/layers/apz/test/gtest/TestPanning.cpp new file mode 100644 index 0000000000..886b0fec99 --- /dev/null +++ b/gfx/layers/apz/test/gtest/TestPanning.cpp @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "APZCBasicTester.h" +#include "APZTestCommon.h" +#include "InputUtils.h" +#include "gtest/gtest.h" + +class APZCPanningTester : public APZCBasicTester { + protected: + void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed, + uint32_t aBehavior) { + if (aShouldTriggerScroll) { + // Three repaint request for each pan. + EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(6); + } else { + EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0); + } + + int touchStart = 50; + int touchEnd = 10; + ParentLayerPoint pointOut; + AsyncTransform viewTransformOut; + + nsTArray<uint32_t> allowedTouchBehaviors; + allowedTouchBehaviors.AppendElement(aBehavior); + + // Pan down + PanAndCheckStatus(apzc, touchStart, touchEnd, aShouldBeConsumed, + &allowedTouchBehaviors); + apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); + + if (aShouldTriggerScroll) { + EXPECT_EQ(ParentLayerPoint(0, -(touchEnd - touchStart)), pointOut); + EXPECT_NE(AsyncTransform(), viewTransformOut); + } else { + EXPECT_EQ(ParentLayerPoint(), pointOut); + EXPECT_EQ(AsyncTransform(), viewTransformOut); + } + + // Clear the fling from the previous pan, or stopping it will + // consume the next touchstart + apzc->CancelAnimation(); + + // Pan back + PanAndCheckStatus(apzc, touchEnd, touchStart, aShouldBeConsumed, + &allowedTouchBehaviors); + apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); + + EXPECT_EQ(ParentLayerPoint(), pointOut); + EXPECT_EQ(AsyncTransform(), viewTransformOut); + } + + void DoPanWithPreventDefaultTest() { + MakeApzcWaitForMainThread(); + + int touchStart = 50; + int touchEnd = 10; + ParentLayerPoint pointOut; + AsyncTransform viewTransformOut; + uint64_t blockId = 0; + + // Pan down + nsTArray<uint32_t> allowedTouchBehaviors; + allowedTouchBehaviors.AppendElement( + mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN); + PanAndCheckStatus(apzc, touchStart, touchEnd, true, &allowedTouchBehaviors, + &blockId); + + // Send the signal that content has handled and preventDefaulted the touch + // events. This flushes the event queue. + apzc->ContentReceivedInputBlock(blockId, true); + + apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); + EXPECT_EQ(ParentLayerPoint(), pointOut); + EXPECT_EQ(AsyncTransform(), viewTransformOut); + + apzc->AssertStateIsReset(); + } +}; + +// In the each of the following 4 pan tests we are performing two pan gestures: +// vertical pan from top to bottom and back - from bottom to top. According to +// the pointer-events/touch-action spec AUTO and PAN_Y touch-action values allow +// vertical scrolling while NONE and PAN_X forbid it. The first parameter of +// DoPanTest method specifies this behavior. However, the events will be marked +// as consumed even if the behavior in PAN_X, because the user could move their +// finger horizontally too - APZ has no way of knowing beforehand and so must +// consume the events. +TEST_F(APZCPanningTester, PanWithTouchActionAuto) { + // Velocity bias can cause extra repaint requests. + SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0); + DoPanTest(true, true, + mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN | + mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN); +} + +TEST_F(APZCPanningTester, PanWithTouchActionNone) { + // Velocity bias can cause extra repaint requests. + SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0); + DoPanTest(false, false, 0); +} + +TEST_F(APZCPanningTester, PanWithTouchActionPanX) { + // Velocity bias can cause extra repaint requests. + SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0); + DoPanTest(false, false, + mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN); +} + +TEST_F(APZCPanningTester, PanWithTouchActionPanY) { + // Velocity bias can cause extra repaint requests. + SCOPED_GFX_PREF_FLOAT("apz.velocity_bias", 0.0); + DoPanTest(true, true, mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN); +} + +TEST_F(APZCPanningTester, PanWithPreventDefault) { + DoPanWithPreventDefaultTest(); +} + +TEST_F(APZCPanningTester, PanWithHistoricalTouchData) { + SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0); + + // Simulate the same pan gesture, in three different ways. + // We start at y=50, with a 50ms resting period at the start of the pan. + // Then we accelerate the finger upwards towards y=10, reaching a 10px/10ms + // velocity towards the end of the panning motion. + // + // The first simulation fires touch move events with 10ms gaps. + // The second simulation skips two of the touch move events, simulating + // "jank". The third simulation also skips those two events, but reports the + // missed positions in the following event's historical coordinates. + // + // Consequently, the first and third simulation should estimate the same + // velocities, whereas the second simulation should estimate a different + // velocity because it is missing data. + + // First simulation: full data + + APZEventResult result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time()); + if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) { + SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); + } + + mcc->AdvanceByMillis(50); + result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time()); + mcc->AdvanceByMillis(10); + result = TouchMove(apzc, ScreenIntPoint(0, 40), mcc->Time()); + mcc->AdvanceByMillis(10); + result = TouchMove(apzc, ScreenIntPoint(0, 30), mcc->Time()); + mcc->AdvanceByMillis(10); + result = TouchMove(apzc, ScreenIntPoint(0, 20), mcc->Time()); + result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time()); + auto velocityFromFullDataAsSeparateEvents = apzc->GetVelocityVector(); + apzc->CancelAnimation(); + + mcc->AdvanceByMillis(100); + + // Second simulation: partial data + + result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time()); + if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) { + SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); + } + + mcc->AdvanceByMillis(50); + result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time()); + mcc->AdvanceByMillis(30); + result = TouchMove(apzc, ScreenIntPoint(0, 20), mcc->Time()); + result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time()); + auto velocityFromPartialData = apzc->GetVelocityVector(); + apzc->CancelAnimation(); + + mcc->AdvanceByMillis(100); + + // Third simulation: full data via historical data + + result = TouchDown(apzc, ScreenIntPoint(0, 50), mcc->Time()); + if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) { + SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); + } + + mcc->AdvanceByMillis(50); + result = TouchMove(apzc, ScreenIntPoint(0, 45), mcc->Time()); + mcc->AdvanceByMillis(30); + + MultiTouchInput mti = + CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, mcc->Time()); + auto singleTouchData = CreateSingleTouchData(0, ScreenIntPoint(0, 20)); + singleTouchData.mHistoricalData.AppendElement( + SingleTouchData::HistoricalTouchData{ + mcc->Time() - TimeDuration::FromMilliseconds(20), + ScreenIntPoint(0, 40), + {}, + {}, + 0.0f, + 0.0f}); + singleTouchData.mHistoricalData.AppendElement( + SingleTouchData::HistoricalTouchData{ + mcc->Time() - TimeDuration::FromMilliseconds(10), + ScreenIntPoint(0, 30), + {}, + {}, + 0.0f, + 0.0f}); + mti.mTouches.AppendElement(singleTouchData); + result = apzc->ReceiveInputEvent(mti); + + result = TouchUp(apzc, ScreenIntPoint(0, 20), mcc->Time()); + auto velocityFromFullDataViaHistory = apzc->GetVelocityVector(); + apzc->CancelAnimation(); + + EXPECT_EQ(velocityFromFullDataAsSeparateEvents, + velocityFromFullDataViaHistory); + EXPECT_NE(velocityFromPartialData, velocityFromFullDataViaHistory); +} + +TEST_F(APZCPanningTester, DuplicatePanEndEvents_Bug1833950) { + // Send a pan gesture that triggers a fling animation at the end. + // Note that we need at least two _PAN events to have enough samples + // in the velocity tracker to compute a fling velocity. + PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), + ScreenPoint(0, 2), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), + ScreenPoint(0, 10), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), + ScreenPoint(0, 10), mcc->Time()); + mcc->AdvanceByMillis(5); + apzc->AdvanceAnimations(mcc->GetSampleTime()); + PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), + ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, + /*aSimulateMomentum=*/true); + + // Give the fling animation a chance to start. + SampleAnimationOnce(); + apzc->AssertStateIsFling(); + + // Send a duplicate pan-end event. + // This test is just intended to check that doing this doesn't + // trigger an assertion failure in debug mode. + PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), + ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, + /*aSimulateMomentum=*/true); +} |