/* -*- 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());
}