TEST_F(APZCGestureDetectorTester, TapFollowedByMultipleTouches) { MakeApzcZoomable(); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(100)); int inputId = 0; MultiTouchInput mti; mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0)); apzc->ReceiveInputEvent(mti, nullptr); mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_START, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0)); mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0)); apzc->ReceiveInputEvent(mti, nullptr); mti = CreateMultiTouchInput(MultiTouchInput::MULTITOUCH_END, mcc->Time()); mti.mTouches.AppendElement(SingleTouchData(inputId, ParentLayerPoint(20, 20), ScreenSize(0, 0), 0, 0)); mti.mTouches.AppendElement(SingleTouchData(inputId + 1, ParentLayerPoint(10, 10), ScreenSize(0, 0), 0, 0)); apzc->ReceiveInputEvent(mti, nullptr); apzc->AssertStateIsReset(); }
TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) { MakeApzcWaitForMainThread(); MakeApzcZoomable(); EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0); EXPECT_CALL(*mcc, HandleDoubleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(0); uint64_t blockIds[2]; DoubleTapAndCheckStatus(apzc, ScreenIntPoint(10, 10), &blockIds); // responses to the two touchstarts apzc->ContentReceivedInputBlock(blockIds[0], true); apzc->ContentReceivedInputBlock(blockIds[1], true); apzc->AssertStateIsReset(); }
TEST_F(APZCGestureDetectorTester, TapTimeoutInterruptedByWheel) { // In this test, even though the wheel block comes right after the tap, the // tap should still be dispatched because it completes fully before the wheel // block arrived. EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1); // We make the APZC zoomable so the gesture detector needs to wait to // distinguish between tap and double-tap. During that timeout is when we // insert the wheel event. MakeApzcZoomable(); uint64_t touchBlockId = 0; uint64_t wheelBlockId = 0; Tap(apzc, ScreenIntPoint(10, 10), TimeDuration::FromMilliseconds(100), nullptr, &touchBlockId); mcc->AdvanceByMillis(10); Wheel(apzc, ScreenIntPoint(10, 10), ScreenPoint(0, -10), mcc->Time(), &wheelBlockId); EXPECT_NE(touchBlockId, wheelBlockId); while (mcc->RunThroughDelayedTasks()); }
TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault) { FrameMetrics originalMetrics = GetPinchableFrameMetrics(); apzc->SetFrameMetrics(originalMetrics); MakeApzcWaitForMainThread(); MakeApzcZoomable(); int touchInputId = 0; uint64_t blockId = 0; PinchWithTouchInput(apzc, 250, 300, 1.25, touchInputId, nullptr, nullptr, &blockId); // Send the prevent-default notification for the touch block apzc->ContentReceivedInputBlock(blockId, true); // verify the metrics didn't change (i.e. the pinch was ignored) FrameMetrics fm = apzc->GetFrameMetrics(); EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom()); EXPECT_EQ(originalMetrics.GetScrollOffset().x, fm.GetScrollOffset().x); EXPECT_EQ(originalMetrics.GetScrollOffset().y, fm.GetScrollOffset().y); apzc->AssertStateIsReset(); }
TEST_F(APZCBasicTester, Overzoom) { // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100 FrameMetrics fm; fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); fm.SetScrollableRect(CSSRect(0, 0, 125, 150)); fm.SetScrollOffset(CSSPoint(10, 0)); fm.SetZoom(CSSToParentLayerScale2D(1.0, 1.0)); fm.SetIsRootContent(true); apzc->SetFrameMetrics(fm); MakeApzcZoomable(); EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(50, 50), 0.5, true); fm = apzc->GetFrameMetrics(); EXPECT_EQ(0.8f, fm.GetZoom().ToScaleFactor().scale); // bug 936721 - PGO builds introduce rounding error so // use a fuzzy match instead EXPECT_LT(std::abs(fm.GetScrollOffset().x), 1e-5); EXPECT_LT(std::abs(fm.GetScrollOffset().y), 1e-5); }
void DoPinchTest(bool aShouldTriggerPinch, nsTArray<uint32_t> *aAllowedTouchBehaviors = nullptr) { apzc->SetFrameMetrics(GetPinchableFrameMetrics()); MakeApzcZoomable(); if (aShouldTriggerPinch) { // One repaint request for each gesture. EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2); } else { EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0); } int touchInputId = 0; if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) { PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 1.25, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors); } else { PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 1.25, aShouldTriggerPinch); } FrameMetrics fm = apzc->GetFrameMetrics(); if (aShouldTriggerPinch) { // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80 EXPECT_EQ(2.5f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(305, fm.GetScrollOffset().x); EXPECT_EQ(310, fm.GetScrollOffset().y); } else { // The frame metrics should stay the same since touch-action:none makes // apzc ignore pinch gestures. EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(300, fm.GetScrollOffset().x); EXPECT_EQ(300, fm.GetScrollOffset().y); } // part 2 of the test, move to the top-right corner of the page and pinch and // make sure we stay in the correct spot fm.SetZoom(CSSToParentLayerScale2D(2.0, 2.0)); fm.SetScrollOffset(CSSPoint(930, 5)); apzc->SetFrameMetrics(fm); // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100 if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) { PinchWithTouchInputAndCheckStatus(apzc, 250, 300, 0.5, touchInputId, aShouldTriggerPinch, aAllowedTouchBehaviors); } else { PinchWithPinchInputAndCheckStatus(apzc, 250, 300, 0.5, aShouldTriggerPinch); } fm = apzc->GetFrameMetrics(); if (aShouldTriggerPinch) { // the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200 EXPECT_EQ(1.0f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(880, fm.GetScrollOffset().x); EXPECT_EQ(0, fm.GetScrollOffset().y); } else { EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale); EXPECT_EQ(930, fm.GetScrollOffset().x); EXPECT_EQ(5, fm.GetScrollOffset().y); } }
TEST_F(APZCGestureDetectorTester, Pan_After_Pinch) { SCOPED_GFX_PREF(TouchActionEnabled, bool, false); FrameMetrics originalMetrics = GetPinchableFrameMetrics(); apzc->SetFrameMetrics(originalMetrics); MakeApzcZoomable(); // Test parameters float zoomAmount = 1.25; float pinchLength = 100.0; float pinchLengthScaled = pinchLength * zoomAmount; int focusX = 250; int focusY = 300; int panDistance = 20; int firstFingerId = 0; int secondFingerId = firstFingerId + 1; // Put fingers down MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, focusX, focusY)); mti.mTouches.AppendElement(CreateSingleTouchData(secondFingerId, focusX, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // Spread fingers out to enter the pinch state mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, focusX - pinchLength, focusY)); mti.mTouches.AppendElement(CreateSingleTouchData(secondFingerId, focusX + pinchLength, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // Do the actual pinch of 1.25x mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY)); mti.mTouches.AppendElement(CreateSingleTouchData(secondFingerId, focusX + pinchLengthScaled, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // Verify that the zoom changed, just to make sure our code above did what it // was supposed to. FrameMetrics zoomedMetrics = apzc->GetFrameMetrics(); float newZoom = zoomedMetrics.GetZoom().ToScaleFactor().scale; EXPECT_EQ(originalMetrics.GetZoom().ToScaleFactor().scale * zoomAmount, newZoom); // Now we lift one finger... mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(secondFingerId, focusX + pinchLengthScaled, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // ... and pan with the remaining finger. This pan just breaks through the // distance threshold. focusY += 40; mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // This one does an actual pan of 20 pixels focusY += panDistance; mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // Lift the remaining finger mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, focusX - pinchLengthScaled, focusY)); apzc->ReceiveInputEvent(mti, nullptr); // Verify that we scrolled FrameMetrics finalMetrics = apzc->GetFrameMetrics(); EXPECT_EQ(zoomedMetrics.GetScrollOffset().y - (panDistance / newZoom), finalMetrics.GetScrollOffset().y); // Clear out any remaining fling animation and pending tasks apzc->AdvanceAnimationsUntilEnd(); while (mcc->RunThroughDelayedTasks()); apzc->AssertStateIsReset(); }
TEST_F(APZCGestureDetectorTester, Pan_With_Tap) { SCOPED_GFX_PREF(TouchActionEnabled, bool, false); FrameMetrics originalMetrics = GetPinchableFrameMetrics(); apzc->SetFrameMetrics(originalMetrics); // Making the APZC zoomable isn't really needed for the correct operation of // this test, but it could help catch regressions where we accidentally enter // a pinch state. MakeApzcZoomable(); // Test parameters int touchX = 250; int touchY = 300; int panDistance = 20; int firstFingerId = 0; int secondFingerId = firstFingerId + 1; // Put finger down MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Start a pan, break through the threshold touchY += 40; mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Do an actual pan for a bit touchY += panDistance; mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Put a second finger down mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); mti.mTouches.AppendElement(CreateSingleTouchData(secondFingerId, touchX + 10, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Lift the second finger mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(secondFingerId, touchX + 10, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Bust through the threshold again touchY += 40; mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Do some more actual panning touchY += panDistance; mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Lift the first finger mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, TimeStamp(), 0); mti.mTouches.AppendElement(CreateSingleTouchData(firstFingerId, touchX, touchY)); apzc->ReceiveInputEvent(mti, nullptr); // Verify that we scrolled FrameMetrics finalMetrics = apzc->GetFrameMetrics(); float zoom = finalMetrics.GetZoom().ToScaleFactor().scale; EXPECT_EQ(originalMetrics.GetScrollOffset().y - (panDistance * 2 / zoom), finalMetrics.GetScrollOffset().y); // Clear out any remaining fling animation and pending tasks apzc->AdvanceAnimationsUntilEnd(); while (mcc->RunThroughDelayedTasks()); apzc->AssertStateIsReset(); }