Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 "mozilla/StaticPrefs_apz.h"
class APZCPinchTester : public APZCBasicTester {
private:
// This (multiplied by apz.touch_start_tolerance) needs to be the hypotenuse
// in a Pythagorean triple, along with overcomeTouchToleranceX and
// overcomeTouchToleranceY from APZCTesterBase::Pan().
// This is because APZCTesterBase::Pan(), when run without the
// PanOptions::ExactCoordinates option, will need to first overcome the
// touch start tolerance by performing a move of exactly
// (apz.touch_start_tolerance * DPI) length.
// When moving on both axes at once, we need to use integers for both legs
// (overcomeTouchToleranceX and overcomeTouchToleranceY) while making sure
// that the hypotenuse is also a round integer number (hence Pythagorean
// triples). (The hypotenuse is the length of the movement in this case.)
static const int mDPI = 100;
public:
explicit APZCPinchTester(
AsyncPanZoomController::GestureBehavior aGestureBehavior =
AsyncPanZoomController::DEFAULT_GESTURES)
: APZCBasicTester(aGestureBehavior) {}
void SetUp() override {
APZCBasicTester::SetUp();
tm->SetDPI(mDPI);
}
protected:
FrameMetrics GetPinchableFrameMetrics() {
FrameMetrics fm;
fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 200));
fm.SetScrollableRect(CSSRect(0, 0, 980, 1000));
fm.SetVisualScrollOffset(CSSPoint(300, 300));
fm.SetLayoutViewport(CSSRect(300, 300, 100, 200));
fm.SetZoom(CSSToParentLayerScale(2.0));
// APZC only allows zooming on the root scrollable frame.
fm.SetIsRootContent(true);
// the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
return fm;
}
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, ScreenIntPoint(250, 300), 1.25,
touchInputId, aShouldTriggerPinch,
aAllowedTouchBehaviors);
} else {
PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 1.25,
aShouldTriggerPinch);
}
apzc->AssertStateIsReset();
FrameMetrics fm = apzc->GetFrameMetrics();
if (aShouldTriggerPinch) {
// the visible area of the document in CSS pixels is now x=325 y=330 w=40
// h=80
EXPECT_EQ(2.5f, fm.GetZoom().scale);
EXPECT_EQ(325, fm.GetVisualScrollOffset().x);
EXPECT_EQ(330, fm.GetVisualScrollOffset().y);
} else {
// The frame metrics should stay the same since touch-action:none makes
// apzc ignore pinch gestures.
EXPECT_EQ(2.0f, fm.GetZoom().scale);
EXPECT_EQ(300, fm.GetVisualScrollOffset().x);
EXPECT_EQ(300, fm.GetVisualScrollOffset().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(CSSToParentLayerScale(2.0));
fm.SetVisualScrollOffset(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, ScreenIntPoint(250, 300), 0.5,
touchInputId, aShouldTriggerPinch,
aAllowedTouchBehaviors);
} else {
PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 0.5,
aShouldTriggerPinch);
}
apzc->AssertStateIsReset();
fm = apzc->GetFrameMetrics();
if (aShouldTriggerPinch) {
// the visible area of the document in CSS pixels is now x=805 y=0 w=100
// h=200
EXPECT_EQ(1.0f, fm.GetZoom().scale);
EXPECT_EQ(805, fm.GetVisualScrollOffset().x);
EXPECT_EQ(0, fm.GetVisualScrollOffset().y);
} else {
EXPECT_EQ(2.0f, fm.GetZoom().scale);
EXPECT_EQ(930, fm.GetVisualScrollOffset().x);
EXPECT_EQ(5, fm.GetVisualScrollOffset().y);
}
}
};
class APZCPinchGestureDetectorTester : public APZCPinchTester {
public:
APZCPinchGestureDetectorTester()
: APZCPinchTester(AsyncPanZoomController::USE_GESTURE_DETECTOR) {}
void DoPinchWithPreventDefaultTest() {
FrameMetrics originalMetrics = GetPinchableFrameMetrics();
apzc->SetFrameMetrics(originalMetrics);
MakeApzcWaitForMainThread();
MakeApzcZoomable();
uint64_t blockId = 0;
PinchWithTouchInput(apzc, ScreenIntPoint(250, 300), 1.25,
PinchOptions().OutInputBlockId(&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.GetVisualScrollOffset().x,
fm.GetVisualScrollOffset().x);
EXPECT_EQ(originalMetrics.GetVisualScrollOffset().y,
fm.GetVisualScrollOffset().y);
apzc->AssertStateIsReset();
}
};
class APZCPinchLockingTester : public APZCPinchTester {
private:
ScreenIntPoint mFocus;
float mSpan;
int mPinchLockBufferMaxAge;
public:
APZCPinchLockingTester()
: APZCPinchTester(AsyncPanZoomController::USE_GESTURE_DETECTOR),
mFocus(ScreenIntPoint(200, 300)),
mSpan(10.0) {}
virtual void SetUp() {
mPinchLockBufferMaxAge =
StaticPrefs::apz_pinch_lock_buffer_max_age_AtStartup();
APZCPinchTester::SetUp();
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcZoomable();
auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
mFocus, mSpan, mSpan, mcc->Time());
apzc->ReceiveInputEvent(event);
mcc->AdvanceBy(TimeDuration::FromMilliseconds(mPinchLockBufferMaxAge + 1));
}
void twoFingerPan() {
ScreenCoord panDistance =
StaticPrefs::apz_pinch_lock_scroll_lock_threshold() * 1.2 *
tm->GetDPI();
mFocus = ScreenIntPoint((int)(mFocus.x.value + panDistance),
(int)(mFocus.y.value));
auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
mFocus, mSpan, mSpan, mcc->Time());
apzc->ReceiveInputEvent(event);
mcc->AdvanceBy(TimeDuration::FromMilliseconds(mPinchLockBufferMaxAge + 1));
}
void twoFingerZoom() {
float pinchDistance =
StaticPrefs::apz_pinch_lock_span_breakout_threshold() * 1.2 *
tm->GetDPI();
float newSpan = mSpan + pinchDistance;
auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
mFocus, newSpan, mSpan, mcc->Time());
apzc->ReceiveInputEvent(event);
mcc->AdvanceBy(TimeDuration::FromMilliseconds(mPinchLockBufferMaxAge + 1));
mSpan = newSpan;
}
bool isPinchLockActive() {
FrameMetrics originalMetrics = apzc->GetFrameMetrics();
// Send a small scale input to the APZC
float pinchDistance =
StaticPrefs::apz_pinch_lock_span_breakout_threshold() * 0.8 *
tm->GetDPI();
auto event =
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus,
mSpan + pinchDistance, mSpan, mcc->Time());
apzc->ReceiveInputEvent(event);
FrameMetrics result = apzc->GetFrameMetrics();
bool lockActive = originalMetrics.GetZoom() == result.GetZoom() &&
originalMetrics.GetVisualScrollOffset().x ==
result.GetVisualScrollOffset().x &&
originalMetrics.GetVisualScrollOffset().y ==
result.GetVisualScrollOffset().y;
// Avoid side effects, reset to original frame metrics
apzc->SetFrameMetrics(originalMetrics);
return lockActive;
}
};
TEST_F(APZCPinchGestureDetectorTester,
Pinch_UseGestureDetector_TouchActionNone) {
nsTArray<uint32_t> behaviors = {mozilla::layers::AllowedTouchBehavior::NONE,
mozilla::layers::AllowedTouchBehavior::NONE};
DoPinchTest(false, &behaviors);
}
TEST_F(APZCPinchGestureDetectorTester,
Pinch_UseGestureDetector_TouchActionZoom) {
nsTArray<uint32_t> behaviors;
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
DoPinchTest(true, &behaviors);
}
TEST_F(APZCPinchGestureDetectorTester,
Pinch_UseGestureDetector_TouchActionNotAllowZoom) {
nsTArray<uint32_t> behaviors;
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE);
behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM);
DoPinchTest(false, &behaviors);
}
TEST_F(APZCPinchGestureDetectorTester,
Pinch_UseGestureDetector_TouchActionNone_NoAPZZoom) {
SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false);
// Since we are preventing the pinch action via touch-action we should not be
// sending the pinch gesture notifications that would normally be sent when
// apz_allow_zooming is false.
EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _, _)).Times(0);
nsTArray<uint32_t> behaviors = {mozilla::layers::AllowedTouchBehavior::NONE,
mozilla::layers::AllowedTouchBehavior::NONE};
DoPinchTest(false, &behaviors);
}
TEST_F(
APZCPinchGestureDetectorTester,
Pinch_UseGestureDetector_TouchActionPanY_APZZoom_When_ForceUserScalable) {
SCOPED_GFX_PREF_BOOL("browser.ui.zoom.force-user-scalable", true);
nsTArray<uint32_t> behaviors = {
mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN,
mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN};
DoPinchTest(true, &behaviors);
}
TEST_F(
APZCPinchGestureDetectorTester,
Pinch_UseGestureDetector_TouchActionNone_NoAPZZoom_When_ForceUserScalable) {
SCOPED_GFX_PREF_BOOL("browser.ui.zoom.force-user-scalable", true);
EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _, _)).Times(0);
nsTArray<uint32_t> behaviors = {
{mozilla::layers::AllowedTouchBehavior::NONE,
mozilla::layers::AllowedTouchBehavior::NONE},
};
DoPinchTest(false, &behaviors);
}
TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault) {
DoPinchWithPreventDefaultTest();
}
TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault_NoAPZZoom) {
SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false);
// Since we are preventing the pinch action we should not be sending the pinch
// gesture notifications that would normally be sent when apz_allow_zooming is
// false.
EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _, _)).Times(0);
DoPinchWithPreventDefaultTest();
}
TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomDisabled) {
SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcUnzoomable();
// Perform a two finger pan
PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1,
PinchOptions().SecondFocus(ScreenIntPoint(100, 100)));
// Expect to be in a flinging state
apzc->AssertStateIsFling();
}
TEST_F(APZCPinchGestureDetectorTester, Pinch_DoesntFling_ZoomDisabled) {
SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcUnzoomable();
// Perform a pinch
PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 2,
PinchOptions()
.Flags(PinchFlags::LiftFinger2)
.Vertical(true)
.SecondFocus(ScreenIntPoint(100, 100)));
// Lift second finger after a pause
mcc->AdvanceBy(TimeDuration::FromMilliseconds(50));
TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time());
// Pinch should not trigger a fling
EXPECT_EQ(apzc->GetVelocityVector().y, 0);
}
TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomEnabled) {
SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcZoomable();
// Perform a two finger pan
PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1,
PinchOptions().SecondFocus(ScreenIntPoint(100, 100)));
// Expect to NOT be in flinging state
apzc->AssertStateIsReset();
}
TEST_F(APZCPinchGestureDetectorTester,
Panning_TwoThenOneFingerFling_ZoomEnabled) {
SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcZoomable();
// Perform a two finger pan lifting only the first finger
PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1,
PinchOptions()
.Flags(PinchFlags::LiftFinger2)
.SecondFocus(ScreenIntPoint(100, 100)));
// Lift second finger after a pause
mcc->AdvanceBy(TimeDuration::FromMilliseconds(50));
TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time());
// This gesture should activate the pinch lock, and result
// in a fling even if the page is zoomable.
apzc->AssertStateIsFling();
}
TEST_F(APZCPinchGestureDetectorTester,
Panning_TwoThenOneFingerFling_ZoomDisabled) {
SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcUnzoomable();
// Perform a two finger pan lifting only the first finger
PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1,
PinchOptions()
.Flags(PinchFlags::LiftFinger2)
.SecondFocus(ScreenIntPoint(100, 100)));
// Lift second finger after a pause
mcc->AdvanceBy(TimeDuration::FromMilliseconds(50));
TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time());
// This gesture should activate the pinch lock and result in a fling
apzc->AssertStateIsFling();
}
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);
FrameMetrics fm = apzc->GetFrameMetrics();
// It starts from (300, 300), then moves the focus point from (250, 350) to
// (200, 300) pans by (50, 50) screen pixels, but there is a 2x zoom, which
// causes the scroll offset to change by half of that (25, 25) pixels.
EXPECT_EQ(325, fm.GetVisualScrollOffset().x);
EXPECT_EQ(325, fm.GetVisualScrollOffset().y);
EXPECT_EQ(2.0, fm.GetZoom().scale);
}
TEST_F(APZCPinchTester, Panning_Beyond_LayoutViewport) {
SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 0);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcZoomable();
// Case 1 - visual viewport is still inside layout viewport.
Pan(apzc, 350, 300, PanOptions::NoFling);
FrameMetrics fm = apzc->GetFrameMetrics();
// It starts from (300, 300) pans by (0, 50) screen pixels, but there is a
// 2x zoom, which causes the scroll offset to change by half of that (0, 25).
// But the visual viewport is still inside the layout viewport.
EXPECT_EQ(300, fm.GetVisualScrollOffset().x);
EXPECT_EQ(325, fm.GetVisualScrollOffset().y);
EXPECT_EQ(300, fm.GetLayoutViewport().X());
EXPECT_EQ(300, fm.GetLayoutViewport().Y());
// Case 2 - visual viewport crosses the bottom boundary of the layout
// viewport.
Pan(apzc, 525, 325, PanOptions::NoFling);
fm = apzc->GetFrameMetrics();
// It starts from (300, 325) pans by (0, 200) screen pixels, but there is a
// 2x zoom, which causes the scroll offset to change by half of that
// (0, 100). The visual viewport crossed the bottom boundary of the layout
// viewport by 25px.
EXPECT_EQ(300, fm.GetVisualScrollOffset().x);
EXPECT_EQ(425, fm.GetVisualScrollOffset().y);
EXPECT_EQ(300, fm.GetLayoutViewport().X());
EXPECT_EQ(325, fm.GetLayoutViewport().Y());
// Case 3 - visual viewport crosses the top boundary of the layout viewport.
Pan(apzc, 425, 775, PanOptions::NoFling);
fm = apzc->GetFrameMetrics();
// It starts from (300, 425) pans by (0, -350) screen pixels, but there is a
// 2x zoom, which causes the scroll offset to change by half of that
// (0, -175). The visual viewport crossed the top of the layout viewport by
// 75px.
EXPECT_EQ(300, fm.GetVisualScrollOffset().x);
EXPECT_EQ(250, fm.GetVisualScrollOffset().y);
EXPECT_EQ(300, fm.GetLayoutViewport().X());
EXPECT_EQ(250, fm.GetLayoutViewport().Y());
// Case 4 - visual viewport crosses the left boundary of the layout viewport.
Pan(apzc, ScreenIntPoint(150, 10), ScreenIntPoint(350, 10),
PanOptions::NoFling);
fm = apzc->GetFrameMetrics();
// It starts from (300, 250) pans by (-200, 0) screen pixels, but there is a
// 2x zoom, which causes the scroll offset to change by half of that
// (-100, 0). The visual viewport crossed the left boundary of the layout
// viewport by 100px.
EXPECT_EQ(200, fm.GetVisualScrollOffset().x);
EXPECT_EQ(250, fm.GetVisualScrollOffset().y);
EXPECT_EQ(200, fm.GetLayoutViewport().X());
EXPECT_EQ(250, fm.GetLayoutViewport().Y());
// Case 5 - visual viewport crosses the right boundary of the layout viewport.
Pan(apzc, ScreenIntPoint(350, 10), ScreenIntPoint(150, 10),
PanOptions::NoFling);
fm = apzc->GetFrameMetrics();
// It starts from (200, 250) pans by (200, 0) screen pixels, but there is a
// 2x zoom, which causes the scroll offset to change by half of that
// (100, 0). The visual viewport crossed the right boundary of the layout
// viewport by 50px.
EXPECT_EQ(300, fm.GetVisualScrollOffset().x);
EXPECT_EQ(250, fm.GetVisualScrollOffset().y);
EXPECT_EQ(250, fm.GetLayoutViewport().X());
EXPECT_EQ(250, fm.GetLayoutViewport().Y());
// Case 6 - visual viewport crosses both the vertical and horizontal
// boundaries of the layout viewport by moving diagonally towards the
// top-right corner.
Pan(apzc, ScreenIntPoint(350, 200), ScreenIntPoint(150, 400),
PanOptions::NoFling);
fm = apzc->GetFrameMetrics();
// It starts from (300, 250) pans by (200, -200) screen pixels, but there is
// a 2x zoom, which causes the scroll offset to change by half of that
// (100, -100). The visual viewport moved by (100, -100) outside the
// boundary of the layout viewport.
EXPECT_EQ(400, fm.GetVisualScrollOffset().x);
EXPECT_EQ(150, fm.GetVisualScrollOffset().y);
EXPECT_EQ(350, fm.GetLayoutViewport().X());
EXPECT_EQ(150, fm.GetLayoutViewport().Y());
}
TEST_F(APZCPinchGestureDetectorTester, Pinch_APZZoom_Disabled) {
SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false);
FrameMetrics originalMetrics = GetPinchableFrameMetrics();
apzc->SetFrameMetrics(originalMetrics);
// When apz_allow_zooming is false, the ZoomConstraintsClient produces
// ZoomConstraints with mAllowZoom set to false.
MakeApzcUnzoomable();
// With apz_allow_zooming false, we expect the NotifyPinchGesture function to
// get called as the pinch progresses, but the metrics shouldn't change.
EXPECT_CALL(*mcc,
NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_START,
apzc->GetGuid(), _, LayoutDeviceCoord(0), _))
.Times(1);
EXPECT_CALL(*mcc, NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_SCALE,
apzc->GetGuid(), _, _, _))
.Times(AtLeast(1));
EXPECT_CALL(*mcc,
NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_END,
apzc->GetGuid(), _, LayoutDeviceCoord(0), _))
.Times(1);
PinchWithTouchInput(apzc, ScreenIntPoint(250, 300), 1.25);
// verify the metrics didn't change (i.e. the pinch was ignored inside APZ)
FrameMetrics fm = apzc->GetFrameMetrics();
EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom());
EXPECT_EQ(originalMetrics.GetVisualScrollOffset().x,
fm.GetVisualScrollOffset().x);
EXPECT_EQ(originalMetrics.GetVisualScrollOffset().y,
fm.GetVisualScrollOffset().y);
apzc->AssertStateIsReset();
}
TEST_F(APZCPinchGestureDetectorTester, Pinch_NoSpan) {
SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false);
FrameMetrics originalMetrics = GetPinchableFrameMetrics();
apzc->SetFrameMetrics(originalMetrics);
// When apz_allow_zooming is false, the ZoomConstraintsClient produces
// ZoomConstraints with mAllowZoom set to false.
MakeApzcUnzoomable();
// With apz_allow_zooming false, we expect the NotifyPinchGesture function to
// get called as the pinch progresses, but the metrics shouldn't change.
EXPECT_CALL(*mcc,
NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_START,
apzc->GetGuid(), _, LayoutDeviceCoord(0), _))
.Times(1);
EXPECT_CALL(*mcc, NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_SCALE,
apzc->GetGuid(), _, _, _))
.Times(AtLeast(1));
EXPECT_CALL(*mcc,
NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_END,
apzc->GetGuid(), _, LayoutDeviceCoord(0), _))
.Times(1);
int inputId = 0;
ScreenIntPoint focus(250, 300);
// Do a pinch holding a zero span and moving the focus by y=100
const TimeDuration TIME_BETWEEN_TOUCH_EVENT =
TimeDuration::FromMilliseconds(50);
const auto touchBehaviors = Some(nsTArray<uint32_t>{kDefaultTouchBehavior});
MultiTouchInput mtiStart =
MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0);
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
apzc->ReceiveInputEvent(mtiStart, touchBehaviors);
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
focus.y -= 35 + 1; // this is to get over the PINCH_START_THRESHOLD in
// GestureEventListener.cpp
MultiTouchInput mtiMove1 =
MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
apzc->ReceiveInputEvent(mtiMove1);
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
focus.y -= 100; // do a two-finger scroll of 100 screen pixels
MultiTouchInput mtiMove2 =
MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0);
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
apzc->ReceiveInputEvent(mtiMove2);
mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT);
MultiTouchInput mtiEnd =
MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0);
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, focus));
mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus));
apzc->ReceiveInputEvent(mtiEnd);
// Done, check the metrics to make sure we scrolled by 100 screen pixels,
// which is 50 CSS pixels for the pinchable frame metrics.
FrameMetrics fm = apzc->GetFrameMetrics();
EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom());
EXPECT_EQ(originalMetrics.GetVisualScrollOffset().x,
fm.GetVisualScrollOffset().x);
EXPECT_EQ(originalMetrics.GetVisualScrollOffset().y + 50,
fm.GetVisualScrollOffset().y);
apzc->AssertStateIsReset();
}
TEST_F(APZCPinchTester, Pinch_TwoFinger_APZZoom_Disabled_Bug1354185) {
// Set up APZ such that mZoomConstraints.mAllowZoom is false.
SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false);
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
MakeApzcUnzoomable();
// We expect a repaint request for scrolling.
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
// Send only the PINCHGESTURE_START and PINCHGESTURE_SCALE events,
// in order to trigger a call to AsyncPanZoomController::OnScale
// but not to AsyncPanZoomController::OnScaleEnd.
ScreenIntPoint aFocus(250, 350);
ScreenIntPoint aSecondFocus(200, 300);
float aScale = 10;
auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
aFocus, 10.0, 10.0, mcc->Time());
apzc->ReceiveInputEvent(event);
event =
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
aSecondFocus, 10.0f * aScale, 10.0, mcc->Time());
apzc->ReceiveInputEvent(event);
}
TEST_F(APZCPinchLockingTester, Pinch_Locking_Free) {
SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 0); // PINCH_FREE
twoFingerPan();
EXPECT_FALSE(isPinchLockActive());
}
TEST_F(APZCPinchLockingTester, Pinch_Locking_Normal_Lock) {
SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 1); // PINCH_NORMAL
twoFingerPan();
EXPECT_TRUE(isPinchLockActive());
}
TEST_F(APZCPinchLockingTester, Pinch_Locking_Normal_Lock_Break) {
SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 1); // PINCH_NORMAL
twoFingerPan();
twoFingerZoom();
EXPECT_TRUE(isPinchLockActive());
}
TEST_F(APZCPinchLockingTester, Pinch_Locking_Sticky_Lock) {
SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 2); // PINCH_STICKY
twoFingerPan();
EXPECT_TRUE(isPinchLockActive());
}
TEST_F(APZCPinchLockingTester, Pinch_Locking_Sticky_Lock_Break) {
SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 2); // PINCH_STICKY
twoFingerPan();
twoFingerZoom();
EXPECT_FALSE(isPinchLockActive());
}
TEST_F(APZCPinchLockingTester, Pinch_Locking_Sticky_Lock_Break_Lock) {
SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 2); // PINCH_STICKY
twoFingerPan();
twoFingerZoom();
twoFingerPan();
EXPECT_TRUE(isPinchLockActive());
}