author | jlogandavison <jlogandavison@gmail.com> |
Wed, 30 May 2018 19:43:28 +0000 | |
changeset 421592 | 21861ee0ddb89d1d3b575ccfeaa1c5043374eeab |
parent 421591 | fac57eb7e7aaaa0c5396d39dc67eae2451754b9f |
child 421593 | 011f238cc9ab82efbaba621046514cd689bd1f86 |
push id | 34098 |
push user | nbeleuzu@mozilla.com |
push date | Wed, 06 Jun 2018 17:00:32 +0000 |
treeherder | mozilla-central@04cc917f68c5 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | botond |
bugs | 1355656 |
milestone | 62.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
|
--- a/gfx/layers/apz/test/gtest/APZTestCommon.h +++ b/gfx/layers/apz/test/gtest/APZTestCommon.h @@ -38,16 +38,35 @@ using namespace mozilla::layers; using ::testing::_; using ::testing::NiceMock; using ::testing::AtLeast; using ::testing::AtMost; using ::testing::MockFunction; using ::testing::InSequence; typedef mozilla::layers::GeckoContentController::TapType TapType; +// Some helper functions for constructing input event objects suitable to be +// passed either to an APZC (which expects an transformed point), or to an APZTM +// (which expects an untransformed point). We handle both cases by setting both +// the transformed and untransformed fields to the same value. +SingleTouchData +CreateSingleTouchData(int32_t aIdentifier, const ScreenIntPoint& aPoint) +{ + SingleTouchData touch(aIdentifier, aPoint, ScreenSize(0, 0), 0, 0); + touch.mLocalScreenPoint = ParentLayerPoint(aPoint.x, aPoint.y); + return touch; +} + +// Convenience wrapper for CreateSingleTouchData() that takes loose coordinates. +SingleTouchData +CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY) +{ + return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY)); +} + template<class T> class ScopedGfxPref { public: ScopedGfxPref(T (*aGetPrefFunc)(void), void (*aSetPrefFunc)(T), T aVal) : mSetPrefFunc(aSetPrefFunc) { mOldVal = aGetPrefFunc(); aSetPrefFunc(aVal); @@ -327,16 +346,29 @@ public: * Do not adjust the touch-start coordinates to overcome the touch-start * tolerance threshold. If this option is passed, it's up to the caller * to pass in coordinates that are sufficient to overcome the touch-start * tolerance *and* cause the desired amount of scrolling. */ ExactCoordinates = 0x2 }; + enum class PinchOptions { + None = 0, + LiftFinger1 = 0x1, + LiftFinger2 = 0x2, + /* + * The bitwise OR result of (LiftFinger1 | LiftFinger2). + * Defined explicitly here because it is used as the default + * argument for PinchWithTouchInput which is defined BEFORE the + * definition of operator| for this class. + */ + LiftBothFingers = 0x3 + }; + template<class InputReceiver> void Tap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint, TimeDuration aTapLength, nsEventStatus (*aOutEventStatuses)[2] = nullptr, uint64_t* aOutInputBlockId = nullptr); template<class InputReceiver> void TapAndCheckStatus(const RefPtr<InputReceiver>& aTarget, @@ -385,21 +417,48 @@ public: nsEventStatus (*aOutEventStatuses)[4] = nullptr, uint64_t (*aOutInputBlockIds)[2] = nullptr); template<class InputReceiver> void DoubleTapAndCheckStatus(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint, uint64_t (*aOutInputBlockIds)[2] = nullptr); + template<class InputReceiver> + void PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget, + const ScreenIntPoint& aFocus, const ScreenIntPoint& aSecondFocus, + float aScale, + int& inputId, + nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr, + nsEventStatus (*aOutEventStatuses)[4] = nullptr, + uint64_t* aOutInputBlockId = nullptr, + PinchOptions aOptions = PinchOptions::LiftBothFingers); + + // Pinch with one focus point. Zooms in place with no panning + template<class InputReceiver> + void PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget, + const ScreenIntPoint& aFocus, float aScale, + int& inputId, + nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr, + nsEventStatus (*aOutEventStatuses)[4] = nullptr, + uint64_t* aOutInputBlockId = nullptr, + PinchOptions aOptions = PinchOptions::LiftBothFingers); + + template<class InputReceiver> + void PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget, + const ScreenIntPoint& aFocus, float aScale, + int& inputId, bool aShouldTriggerPinch, + nsTArray<uint32_t>* aAllowedTouchBehaviors); + protected: RefPtr<MockContentControllerDelayed> mcc; }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(APZCTesterBase::PanOptions) +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(APZCTesterBase::PinchOptions) template<class InputReceiver> void APZCTesterBase::Tap(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint, TimeDuration aTapLength, nsEventStatus (*aOutEventStatuses)[2], uint64_t* aOutInputBlockId) { @@ -629,16 +688,129 @@ APZCTesterBase::DoubleTapAndCheckStatus( nsEventStatus statuses[4]; DoubleTap(aTarget, aPoint, &statuses, aOutInputBlockIds); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[1]); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[2]); EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[3]); } +template<class InputReceiver> +void +APZCTesterBase::PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget, + const ScreenIntPoint& aFocus, float aScale, + int& inputId, + nsTArray<uint32_t>* aAllowedTouchBehaviors, + nsEventStatus (*aOutEventStatuses)[4], + uint64_t* aOutInputBlockId, + PinchOptions aOptions) +{ + //Perform a pinch gesture with the same start & end focus point + PinchWithTouchInput(aTarget, aFocus, aFocus, aScale, inputId, + aAllowedTouchBehaviors, aOutEventStatuses, + aOutInputBlockId, aOptions); +} + +template<class InputReceiver> +void +APZCTesterBase::PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget, + const ScreenIntPoint& aFocus, const ScreenIntPoint& aSecondFocus, + float aScale, + int& inputId, + nsTArray<uint32_t>* aAllowedTouchBehaviors, + nsEventStatus (*aOutEventStatuses)[4], + uint64_t* aOutInputBlockId, + PinchOptions aOptions) +{ + // Having pinch coordinates in float type may cause problems with high-precision scale values + // since SingleTouchData accepts integer value. But for trivial tests it should be ok. + float pinchLength = 100.0; + float pinchLengthScaled = pinchLength * aScale; + + // Even if the caller doesn't care about the block id, we need it to set the + // allowed touch behaviour below, so make sure aOutInputBlockId is non-null. + uint64_t blockId; + if (!aOutInputBlockId) { + aOutInputBlockId = &blockId; + } + + const TimeDuration TIME_BETWEEN_TOUCH_EVENT = TimeDuration::FromMilliseconds(50); + + MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0); + mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus)); + mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus)); + nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId); + if (aOutEventStatuses) { + (*aOutEventStatuses)[0] = status; + } + + mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT); + + if (aAllowedTouchBehaviors) { + EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length()); + aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors); + } else if (gfxPrefs::TouchActionEnabled()) { + SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2); + } + + MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0); + mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLength, aFocus.y)); + mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLength, aFocus.y)); + status = aTarget->ReceiveInputEvent(mtiMove1, nullptr); + if (aOutEventStatuses) { + (*aOutEventStatuses)[1] = status; + } + + mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT); + + MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0); + mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aSecondFocus.x - pinchLengthScaled, aSecondFocus.y)); + mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aSecondFocus.x + pinchLengthScaled, aSecondFocus.y)); + status = aTarget->ReceiveInputEvent(mtiMove2, nullptr); + if (aOutEventStatuses) { + (*aOutEventStatuses)[2] = status; + } + + if (aOptions & (PinchOptions::LiftFinger1 | PinchOptions::LiftFinger2)) { + mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT); + + MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0); + if (aOptions & PinchOptions::LiftFinger1) { + mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aSecondFocus.x - pinchLengthScaled, aSecondFocus.y)); + } + if (aOptions & PinchOptions::LiftFinger2) { + mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aSecondFocus.x + pinchLengthScaled, aSecondFocus.y)); + } + status = aTarget->ReceiveInputEvent(mtiEnd, nullptr); + if (aOutEventStatuses) { + (*aOutEventStatuses)[3] = status; + } + } + + inputId += 2; +} + +template<class InputReceiver> +void +APZCTesterBase::PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget, + const ScreenIntPoint& aFocus, float aScale, + int& inputId, bool aShouldTriggerPinch, + nsTArray<uint32_t>* aAllowedTouchBehaviors) +{ + nsEventStatus statuses[4]; // down, move, move, up + PinchWithTouchInput(aTarget, aFocus, aScale, inputId, aAllowedTouchBehaviors, &statuses); + + nsEventStatus expectedMoveStatus = aShouldTriggerPinch + ? nsEventStatus_eConsumeDoDefault + : nsEventStatus_eIgnore; + EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]); + EXPECT_EQ(expectedMoveStatus, statuses[1]); + EXPECT_EQ(expectedMoveStatus, statuses[2]); +} + AsyncPanZoomController* TestAPZCTreeManager::NewAPZCInstance(LayersId aLayersId, GeckoContentController* aController) { MockContentControllerDelayed* mcc = static_cast<MockContentControllerDelayed*>(aController); return new TestAsyncPanZoomController(aLayersId, mcc, this, AsyncPanZoomController::USE_GESTURE_DETECTOR); }
--- a/gfx/layers/apz/test/gtest/InputUtils.h +++ b/gfx/layers/apz/test/gtest/InputUtils.h @@ -23,35 +23,16 @@ * void SetAllowedTouchBehavior(uint64_t aInputBlockId, * const nsTArray<uint32_t>& aBehaviours); * The classes that currently implement these are APZCTreeManager and * TestAsyncPanZoomController. Using this template allows us to test individual * APZC instances in isolation and also an entire APZ tree, while using the same * code to dispatch input events. */ -// Some helper functions for constructing input event objects suitable to be -// passed either to an APZC (which expects an transformed point), or to an APZTM -// (which expects an untransformed point). We handle both cases by setting both -// the transformed and untransformed fields to the same value. -SingleTouchData -CreateSingleTouchData(int32_t aIdentifier, const ScreenIntPoint& aPoint) -{ - SingleTouchData touch(aIdentifier, aPoint, ScreenSize(0, 0), 0, 0); - touch.mLocalScreenPoint = ParentLayerPoint(aPoint.x, aPoint.y); - return touch; -} - -// Convenience wrapper for CreateSingleTouchData() that takes loose coordinates. -SingleTouchData -CreateSingleTouchData(int32_t aIdentifier, ScreenIntCoord aX, ScreenIntCoord aY) -{ - return CreateSingleTouchData(aIdentifier, ScreenIntPoint(aX, aY)); -} - PinchGestureInput CreatePinchGestureInput(PinchGestureInput::PinchGestureType aType, const ScreenPoint& aFocus, float aCurrentSpan, float aPreviousSpan) { ParentLayerPoint localFocus(aFocus.x, aFocus.y); PinchGestureInput result(aType, 0, TimeStamp(), localFocus, aCurrentSpan, aPreviousSpan, 0); @@ -156,97 +137,16 @@ PinchWithPinchInputAndCheckStatus(const nsEventStatus expectedStatus = aShouldTriggerPinch ? nsEventStatus_eConsumeNoDefault : nsEventStatus_eIgnore; EXPECT_EQ(expectedStatus, statuses[0]); EXPECT_EQ(expectedStatus, statuses[1]); } template<class InputReceiver> -void -PinchWithTouchInput(const RefPtr<InputReceiver>& aTarget, - const ScreenIntPoint& aFocus, float aScale, - int& inputId, - nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr, - nsEventStatus (*aOutEventStatuses)[4] = nullptr, - uint64_t* aOutInputBlockId = nullptr) -{ - // Having pinch coordinates in float type may cause problems with high-precision scale values - // since SingleTouchData accepts integer value. But for trivial tests it should be ok. - float pinchLength = 100.0; - float pinchLengthScaled = pinchLength * aScale; - - // Even if the caller doesn't care about the block id, we need it to set the - // allowed touch behaviour below, so make sure aOutInputBlockId is non-null. - uint64_t blockId; - if (!aOutInputBlockId) { - aOutInputBlockId = &blockId; - } - - MultiTouchInput mtiStart = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0); - mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus)); - mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus)); - nsEventStatus status = aTarget->ReceiveInputEvent(mtiStart, aOutInputBlockId); - if (aOutEventStatuses) { - (*aOutEventStatuses)[0] = status; - } - - if (aAllowedTouchBehaviors) { - EXPECT_EQ(2UL, aAllowedTouchBehaviors->Length()); - aTarget->SetAllowedTouchBehavior(*aOutInputBlockId, *aAllowedTouchBehaviors); - } else if (gfxPrefs::TouchActionEnabled()) { - SetDefaultAllowedTouchBehavior(aTarget, *aOutInputBlockId, 2); - } - - MultiTouchInput mtiMove1 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); - mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLength, aFocus.y)); - mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLength, aFocus.y)); - status = aTarget->ReceiveInputEvent(mtiMove1, nullptr); - if (aOutEventStatuses) { - (*aOutEventStatuses)[1] = status; - } - - MultiTouchInput mtiMove2 = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); - mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLengthScaled, aFocus.y)); - mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLengthScaled, aFocus.y)); - status = aTarget->ReceiveInputEvent(mtiMove2, nullptr); - if (aOutEventStatuses) { - (*aOutEventStatuses)[2] = status; - } - - MultiTouchInput mtiEnd = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0); - mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, aFocus.x - pinchLengthScaled, aFocus.y)); - mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, aFocus.x + pinchLengthScaled, aFocus.y)); - status = aTarget->ReceiveInputEvent(mtiEnd, nullptr); - if (aOutEventStatuses) { - (*aOutEventStatuses)[3] = status; - } - - inputId += 2; -} - -template<class InputReceiver> -void -PinchWithTouchInputAndCheckStatus(const RefPtr<InputReceiver>& aTarget, - const ScreenIntPoint& aFocus, float aScale, - int& inputId, bool aShouldTriggerPinch, - nsTArray<uint32_t>* aAllowedTouchBehaviors) -{ - nsEventStatus statuses[4]; // down, move, move, up - PinchWithTouchInput(aTarget, aFocus, aScale, inputId, aAllowedTouchBehaviors, &statuses); - - nsEventStatus expectedMoveStatus = aShouldTriggerPinch - ? nsEventStatus_eConsumeDoDefault - : nsEventStatus_eIgnore; - EXPECT_EQ(nsEventStatus_eConsumeDoDefault, statuses[0]); - EXPECT_EQ(expectedMoveStatus, statuses[1]); - EXPECT_EQ(expectedMoveStatus, statuses[2]); -} - -template<class InputReceiver> nsEventStatus Wheel(const RefPtr<InputReceiver>& aTarget, const ScreenIntPoint& aPoint, const ScreenPoint& aDelta, TimeStamp aTime, uint64_t* aOutInputBlockId = nullptr) { ScrollWheelInput input(MillisecondsSinceStartup(aTime), aTime, 0, ScrollWheelInput::SCROLLMODE_INSTANT, ScrollWheelInput::SCROLLDELTA_PIXEL, aPoint, aDelta.x, aDelta.y, false, WheelDeltaAdjustmentStrategy::eNone); return aTarget->ReceiveInputEvent(input, nullptr, aOutInputBlockId);
--- a/gfx/layers/apz/test/gtest/TestPinching.cpp +++ b/gfx/layers/apz/test/gtest/TestPinching.cpp @@ -265,16 +265,68 @@ TEST_F(APZCPinchGestureDetectorTester, P // Since we are preventing the pinch action we should not be sending the pinch // gesture notifications that would normally be sent when APZAllowZooming is // false. EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _)).Times(0); DoPinchWithPreventDefaultTest(); } +TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomDisabled) { + SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f); + + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + MakeApzcUnzoomable(); + + // Perform a two finger pan + int touchInputId = 0; + uint64_t blockId = 0; + PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), ScreenIntPoint(100, 100), + 1, touchInputId, nullptr, nullptr, &blockId); + + // Expect to be in a flinging state + apzc->AssertStateIsFling(); +} + +TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomEnabled) { + SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f); + + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + MakeApzcZoomable(); + + // Perform a two finger pan + int touchInputId = 0; + uint64_t blockId = 0; + PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), ScreenIntPoint(100, 100), + 1, touchInputId, nullptr, nullptr, &blockId); + + // Expect to NOT be in flinging state + apzc->AssertStateIsReset(); +} + +TEST_F(APZCPinchGestureDetectorTester, Panning_TwoThenOneFingerFling_ZoomEnabled) { + SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f); + + apzc->SetFrameMetrics(GetPinchableFrameMetrics()); + MakeApzcZoomable(); + + // Perform a two finger pan lifting only the first finger + int touchInputId = 0; + uint64_t blockId = 0; + PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), ScreenIntPoint(100, 100), + 1, touchInputId, nullptr, nullptr, &blockId, PinchOptions::LiftFinger2); + + // Lift second finger after a pause + mcc->AdvanceBy(TimeDuration::FromMilliseconds(50)); + TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time()); + + // Expect to NOT be in flinging state + apzc->AssertStateIsReset(); +} + TEST_F(APZCPinchTester, Panning_TwoFinger_ZoomDisabled) { // set up APZ apzc->SetFrameMetrics(GetPinchableFrameMetrics()); MakeApzcUnzoomable(); nsEventStatus statuses[3]; // scalebegin, scale, scaleend PinchWithPinchInput(apzc, ScreenIntPoint(250, 350), ScreenIntPoint(200, 300), 10, &statuses);