TestPinching.cpp (26717B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "APZCBasicTester.h" 8 #include "APZTestCommon.h" 9 #include "InputUtils.h" 10 #include "mozilla/StaticPrefs_apz.h" 11 12 class APZCPinchTester : public APZCBasicTester { 13 private: 14 // This (multiplied by apz.touch_start_tolerance) needs to be the hypotenuse 15 // in a Pythagorean triple, along with overcomeTouchToleranceX and 16 // overcomeTouchToleranceY from APZCTesterBase::Pan(). 17 // This is because APZCTesterBase::Pan(), when run without the 18 // PanOptions::ExactCoordinates option, will need to first overcome the 19 // touch start tolerance by performing a move of exactly 20 // (apz.touch_start_tolerance * DPI) length. 21 // When moving on both axes at once, we need to use integers for both legs 22 // (overcomeTouchToleranceX and overcomeTouchToleranceY) while making sure 23 // that the hypotenuse is also a round integer number (hence Pythagorean 24 // triples). (The hypotenuse is the length of the movement in this case.) 25 static const int mDPI = 100; 26 27 public: 28 explicit APZCPinchTester( 29 AsyncPanZoomController::GestureBehavior aGestureBehavior = 30 AsyncPanZoomController::DEFAULT_GESTURES) 31 : APZCBasicTester(aGestureBehavior) {} 32 33 void SetUp() override { 34 APZCBasicTester::SetUp(); 35 tm->SetDPI(mDPI); 36 } 37 38 protected: 39 FrameMetrics GetPinchableFrameMetrics() { 40 FrameMetrics fm; 41 fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 200)); 42 fm.SetScrollableRect(CSSRect(0, 0, 980, 1000)); 43 fm.SetVisualScrollOffset(CSSPoint(300, 300)); 44 fm.SetLayoutViewport(CSSRect(300, 300, 100, 200)); 45 fm.SetZoom(CSSToParentLayerScale(2.0)); 46 // APZC only allows zooming on the root scrollable frame. 47 fm.SetIsRootContent(true); 48 // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100 49 return fm; 50 } 51 52 void DoPinchTest(bool aShouldTriggerPinch, 53 nsTArray<uint32_t>* aAllowedTouchBehaviors = nullptr) { 54 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 55 MakeApzcZoomable(); 56 57 if (aShouldTriggerPinch) { 58 // One repaint request for each gesture. 59 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(2); 60 } else { 61 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0); 62 } 63 64 int touchInputId = 0; 65 if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) { 66 PinchWithTouchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 1.25, 67 touchInputId, aShouldTriggerPinch, 68 aAllowedTouchBehaviors); 69 } else { 70 PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 1.25, 71 aShouldTriggerPinch); 72 } 73 74 apzc->AssertStateIsReset(); 75 76 FrameMetrics fm = apzc->GetFrameMetrics(); 77 78 if (aShouldTriggerPinch) { 79 // the visible area of the document in CSS pixels is now x=325 y=330 w=40 80 // h=80 81 EXPECT_EQ(2.5f, fm.GetZoom().scale); 82 EXPECT_EQ(325, fm.GetVisualScrollOffset().x); 83 EXPECT_EQ(330, fm.GetVisualScrollOffset().y); 84 } else { 85 // The frame metrics should stay the same since touch-action:none makes 86 // apzc ignore pinch gestures. 87 EXPECT_EQ(2.0f, fm.GetZoom().scale); 88 EXPECT_EQ(300, fm.GetVisualScrollOffset().x); 89 EXPECT_EQ(300, fm.GetVisualScrollOffset().y); 90 } 91 92 // part 2 of the test, move to the top-right corner of the page and pinch 93 // and make sure we stay in the correct spot 94 fm.SetZoom(CSSToParentLayerScale(2.0)); 95 fm.SetVisualScrollOffset(CSSPoint(930, 5)); 96 apzc->SetFrameMetrics(fm); 97 // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100 98 99 if (mGestureBehavior == AsyncPanZoomController::USE_GESTURE_DETECTOR) { 100 PinchWithTouchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 0.5, 101 touchInputId, aShouldTriggerPinch, 102 aAllowedTouchBehaviors); 103 } else { 104 PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(250, 300), 0.5, 105 aShouldTriggerPinch); 106 } 107 108 apzc->AssertStateIsReset(); 109 110 fm = apzc->GetFrameMetrics(); 111 112 if (aShouldTriggerPinch) { 113 // the visible area of the document in CSS pixels is now x=805 y=0 w=100 114 // h=200 115 EXPECT_EQ(1.0f, fm.GetZoom().scale); 116 EXPECT_EQ(805, fm.GetVisualScrollOffset().x); 117 EXPECT_EQ(0, fm.GetVisualScrollOffset().y); 118 } else { 119 EXPECT_EQ(2.0f, fm.GetZoom().scale); 120 EXPECT_EQ(930, fm.GetVisualScrollOffset().x); 121 EXPECT_EQ(5, fm.GetVisualScrollOffset().y); 122 } 123 } 124 }; 125 126 class APZCPinchGestureDetectorTester : public APZCPinchTester { 127 public: 128 APZCPinchGestureDetectorTester() 129 : APZCPinchTester(AsyncPanZoomController::USE_GESTURE_DETECTOR) {} 130 131 void DoPinchWithPreventDefaultTest() { 132 FrameMetrics originalMetrics = GetPinchableFrameMetrics(); 133 apzc->SetFrameMetrics(originalMetrics); 134 135 MakeApzcWaitForMainThread(); 136 MakeApzcZoomable(); 137 138 uint64_t blockId = 0; 139 PinchWithTouchInput(apzc, ScreenIntPoint(250, 300), 1.25, 140 PinchOptions().OutInputBlockId(&blockId)); 141 142 // Send the prevent-default notification for the touch block 143 apzc->ContentReceivedInputBlock(blockId, true); 144 145 // verify the metrics didn't change (i.e. the pinch was ignored) 146 FrameMetrics fm = apzc->GetFrameMetrics(); 147 EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom()); 148 EXPECT_EQ(originalMetrics.GetVisualScrollOffset().x, 149 fm.GetVisualScrollOffset().x); 150 EXPECT_EQ(originalMetrics.GetVisualScrollOffset().y, 151 fm.GetVisualScrollOffset().y); 152 153 apzc->AssertStateIsReset(); 154 } 155 }; 156 157 class APZCPinchLockingTester : public APZCPinchTester { 158 private: 159 ScreenIntPoint mFocus; 160 float mSpan; 161 int mPinchLockBufferMaxAge; 162 163 public: 164 APZCPinchLockingTester() 165 : APZCPinchTester(AsyncPanZoomController::USE_GESTURE_DETECTOR), 166 mFocus(ScreenIntPoint(200, 300)), 167 mSpan(10.0) {} 168 169 virtual void SetUp() { 170 mPinchLockBufferMaxAge = 171 StaticPrefs::apz_pinch_lock_buffer_max_age_AtStartup(); 172 173 APZCPinchTester::SetUp(); 174 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 175 MakeApzcZoomable(); 176 177 auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, 178 mFocus, mSpan, mSpan, mcc->Time()); 179 apzc->ReceiveInputEvent(event); 180 mcc->AdvanceBy(TimeDuration::FromMilliseconds(mPinchLockBufferMaxAge + 1)); 181 } 182 183 void twoFingerPan() { 184 ScreenCoord panDistance = 185 StaticPrefs::apz_pinch_lock_scroll_lock_threshold() * 1.2 * 186 tm->GetDPI(); 187 188 mFocus = ScreenIntPoint((int)(mFocus.x.value + panDistance), 189 (int)(mFocus.y.value)); 190 191 auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, 192 mFocus, mSpan, mSpan, mcc->Time()); 193 apzc->ReceiveInputEvent(event); 194 mcc->AdvanceBy(TimeDuration::FromMilliseconds(mPinchLockBufferMaxAge + 1)); 195 } 196 197 void twoFingerZoom() { 198 float pinchDistance = 199 StaticPrefs::apz_pinch_lock_span_breakout_threshold() * 1.2 * 200 tm->GetDPI(); 201 202 float newSpan = mSpan + pinchDistance; 203 204 auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, 205 mFocus, newSpan, mSpan, mcc->Time()); 206 apzc->ReceiveInputEvent(event); 207 mcc->AdvanceBy(TimeDuration::FromMilliseconds(mPinchLockBufferMaxAge + 1)); 208 mSpan = newSpan; 209 } 210 211 bool isPinchLockActive() { 212 FrameMetrics originalMetrics = apzc->GetFrameMetrics(); 213 214 // Send a small scale input to the APZC 215 float pinchDistance = 216 StaticPrefs::apz_pinch_lock_span_breakout_threshold() * 0.8 * 217 tm->GetDPI(); 218 auto event = 219 CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, mFocus, 220 mSpan + pinchDistance, mSpan, mcc->Time()); 221 apzc->ReceiveInputEvent(event); 222 223 FrameMetrics result = apzc->GetFrameMetrics(); 224 bool lockActive = originalMetrics.GetZoom() == result.GetZoom() && 225 originalMetrics.GetVisualScrollOffset().x == 226 result.GetVisualScrollOffset().x && 227 originalMetrics.GetVisualScrollOffset().y == 228 result.GetVisualScrollOffset().y; 229 230 // Avoid side effects, reset to original frame metrics 231 apzc->SetFrameMetrics(originalMetrics); 232 return lockActive; 233 } 234 }; 235 236 TEST_F(APZCPinchGestureDetectorTester, 237 Pinch_UseGestureDetector_TouchActionNone) { 238 nsTArray<uint32_t> behaviors = {mozilla::layers::AllowedTouchBehavior::NONE, 239 mozilla::layers::AllowedTouchBehavior::NONE}; 240 DoPinchTest(false, &behaviors); 241 } 242 243 TEST_F(APZCPinchGestureDetectorTester, 244 Pinch_UseGestureDetector_TouchActionZoom) { 245 nsTArray<uint32_t> behaviors; 246 behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); 247 behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); 248 DoPinchTest(true, &behaviors); 249 } 250 251 TEST_F(APZCPinchGestureDetectorTester, 252 Pinch_UseGestureDetector_TouchActionNotAllowZoom) { 253 nsTArray<uint32_t> behaviors; 254 behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::NONE); 255 behaviors.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); 256 DoPinchTest(false, &behaviors); 257 } 258 259 TEST_F(APZCPinchGestureDetectorTester, 260 Pinch_UseGestureDetector_TouchActionNone_NoAPZZoom) { 261 SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false); 262 263 // Since we are preventing the pinch action via touch-action we should not be 264 // sending the pinch gesture notifications that would normally be sent when 265 // apz_allow_zooming is false. 266 EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _, _)).Times(0); 267 nsTArray<uint32_t> behaviors = {mozilla::layers::AllowedTouchBehavior::NONE, 268 mozilla::layers::AllowedTouchBehavior::NONE}; 269 DoPinchTest(false, &behaviors); 270 } 271 272 TEST_F( 273 APZCPinchGestureDetectorTester, 274 Pinch_UseGestureDetector_TouchActionPanY_APZZoom_When_ForceUserScalable) { 275 SCOPED_GFX_PREF_BOOL("browser.ui.zoom.force-user-scalable", true); 276 277 nsTArray<uint32_t> behaviors = { 278 mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN, 279 mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN}; 280 DoPinchTest(true, &behaviors); 281 } 282 283 TEST_F( 284 APZCPinchGestureDetectorTester, 285 Pinch_UseGestureDetector_TouchActionNone_NoAPZZoom_When_ForceUserScalable) { 286 SCOPED_GFX_PREF_BOOL("browser.ui.zoom.force-user-scalable", true); 287 288 EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _, _)).Times(0); 289 nsTArray<uint32_t> behaviors = { 290 {mozilla::layers::AllowedTouchBehavior::NONE, 291 mozilla::layers::AllowedTouchBehavior::NONE}, 292 }; 293 DoPinchTest(false, &behaviors); 294 } 295 296 TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault) { 297 DoPinchWithPreventDefaultTest(); 298 } 299 300 TEST_F(APZCPinchGestureDetectorTester, Pinch_PreventDefault_NoAPZZoom) { 301 SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false); 302 303 // Since we are preventing the pinch action we should not be sending the pinch 304 // gesture notifications that would normally be sent when apz_allow_zooming is 305 // false. 306 EXPECT_CALL(*mcc, NotifyPinchGesture(_, _, _, _, _)).Times(0); 307 308 DoPinchWithPreventDefaultTest(); 309 } 310 311 TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomDisabled) { 312 SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f); 313 314 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 315 MakeApzcUnzoomable(); 316 317 // Perform a two finger pan 318 PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1, 319 PinchOptions().SecondFocus(ScreenIntPoint(100, 100))); 320 321 // Expect to be in a flinging state 322 apzc->AssertStateIsFling(); 323 } 324 325 TEST_F(APZCPinchGestureDetectorTester, Pinch_DoesntFling_ZoomDisabled) { 326 SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f); 327 328 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 329 MakeApzcUnzoomable(); 330 331 // Perform a pinch 332 PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 2, 333 PinchOptions() 334 .Flags(PinchFlags::LiftFinger2) 335 .Vertical(true) 336 .SecondFocus(ScreenIntPoint(100, 100))); 337 338 // Lift second finger after a pause 339 mcc->AdvanceBy(TimeDuration::FromMilliseconds(50)); 340 TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time()); 341 342 // Pinch should not trigger a fling 343 EXPECT_EQ(apzc->GetVelocityVector().y, 0); 344 } 345 346 TEST_F(APZCPinchGestureDetectorTester, Panning_TwoFingerFling_ZoomEnabled) { 347 SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f); 348 349 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 350 MakeApzcZoomable(); 351 352 // Perform a two finger pan 353 PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1, 354 PinchOptions().SecondFocus(ScreenIntPoint(100, 100))); 355 356 // Expect to NOT be in flinging state 357 apzc->AssertStateIsReset(); 358 } 359 360 TEST_F(APZCPinchGestureDetectorTester, 361 Panning_TwoThenOneFingerFling_ZoomEnabled) { 362 SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f); 363 364 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 365 MakeApzcZoomable(); 366 367 // Perform a two finger pan lifting only the first finger 368 PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1, 369 PinchOptions() 370 .Flags(PinchFlags::LiftFinger2) 371 .SecondFocus(ScreenIntPoint(100, 100))); 372 373 // Lift second finger after a pause 374 mcc->AdvanceBy(TimeDuration::FromMilliseconds(50)); 375 TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time()); 376 377 // This gesture should activate the pinch lock, and result 378 // in a fling even if the page is zoomable. 379 apzc->AssertStateIsFling(); 380 } 381 382 TEST_F(APZCPinchGestureDetectorTester, 383 Panning_TwoThenOneFingerFling_ZoomDisabled) { 384 SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f); 385 386 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 387 MakeApzcUnzoomable(); 388 389 // Perform a two finger pan lifting only the first finger 390 PinchWithTouchInput(apzc, ScreenIntPoint(100, 200), 1, 391 PinchOptions() 392 .Flags(PinchFlags::LiftFinger2) 393 .SecondFocus(ScreenIntPoint(100, 100))); 394 395 // Lift second finger after a pause 396 mcc->AdvanceBy(TimeDuration::FromMilliseconds(50)); 397 TouchUp(apzc, ScreenIntPoint(100, 100), mcc->Time()); 398 399 // This gesture should activate the pinch lock and result in a fling 400 apzc->AssertStateIsFling(); 401 } 402 403 TEST_F(APZCPinchTester, Panning_TwoFinger_ZoomDisabled) { 404 // set up APZ 405 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 406 MakeApzcUnzoomable(); 407 408 nsEventStatus statuses[3]; // scalebegin, scale, scaleend 409 PinchWithPinchInput(apzc, ScreenIntPoint(250, 350), ScreenIntPoint(200, 300), 410 10, &statuses); 411 412 FrameMetrics fm = apzc->GetFrameMetrics(); 413 414 // It starts from (300, 300), then moves the focus point from (250, 350) to 415 // (200, 300) pans by (50, 50) screen pixels, but there is a 2x zoom, which 416 // causes the scroll offset to change by half of that (25, 25) pixels. 417 EXPECT_EQ(325, fm.GetVisualScrollOffset().x); 418 EXPECT_EQ(325, fm.GetVisualScrollOffset().y); 419 EXPECT_EQ(2.0, fm.GetZoom().scale); 420 } 421 422 TEST_F(APZCPinchTester, Panning_Beyond_LayoutViewport) { 423 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 0); 424 425 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 426 MakeApzcZoomable(); 427 428 // Case 1 - visual viewport is still inside layout viewport. 429 Pan(apzc, 350, 300, PanOptions::NoFling); 430 FrameMetrics fm = apzc->GetFrameMetrics(); 431 // It starts from (300, 300) pans by (0, 50) screen pixels, but there is a 432 // 2x zoom, which causes the scroll offset to change by half of that (0, 25). 433 // But the visual viewport is still inside the layout viewport. 434 EXPECT_EQ(300, fm.GetVisualScrollOffset().x); 435 EXPECT_EQ(325, fm.GetVisualScrollOffset().y); 436 EXPECT_EQ(300, fm.GetLayoutViewport().X()); 437 EXPECT_EQ(300, fm.GetLayoutViewport().Y()); 438 439 // Case 2 - visual viewport crosses the bottom boundary of the layout 440 // viewport. 441 Pan(apzc, 525, 325, PanOptions::NoFling); 442 fm = apzc->GetFrameMetrics(); 443 // It starts from (300, 325) pans by (0, 200) screen pixels, but there is a 444 // 2x zoom, which causes the scroll offset to change by half of that 445 // (0, 100). The visual viewport crossed the bottom boundary of the layout 446 // viewport by 25px. 447 EXPECT_EQ(300, fm.GetVisualScrollOffset().x); 448 EXPECT_EQ(425, fm.GetVisualScrollOffset().y); 449 EXPECT_EQ(300, fm.GetLayoutViewport().X()); 450 EXPECT_EQ(325, fm.GetLayoutViewport().Y()); 451 452 // Case 3 - visual viewport crosses the top boundary of the layout viewport. 453 Pan(apzc, 425, 775, PanOptions::NoFling); 454 fm = apzc->GetFrameMetrics(); 455 // It starts from (300, 425) pans by (0, -350) screen pixels, but there is a 456 // 2x zoom, which causes the scroll offset to change by half of that 457 // (0, -175). The visual viewport crossed the top of the layout viewport by 458 // 75px. 459 EXPECT_EQ(300, fm.GetVisualScrollOffset().x); 460 EXPECT_EQ(250, fm.GetVisualScrollOffset().y); 461 EXPECT_EQ(300, fm.GetLayoutViewport().X()); 462 EXPECT_EQ(250, fm.GetLayoutViewport().Y()); 463 464 // Case 4 - visual viewport crosses the left boundary of the layout viewport. 465 Pan(apzc, ScreenIntPoint(150, 10), ScreenIntPoint(350, 10), 466 PanOptions::NoFling); 467 fm = apzc->GetFrameMetrics(); 468 // It starts from (300, 250) pans by (-200, 0) screen pixels, but there is a 469 // 2x zoom, which causes the scroll offset to change by half of that 470 // (-100, 0). The visual viewport crossed the left boundary of the layout 471 // viewport by 100px. 472 EXPECT_EQ(200, fm.GetVisualScrollOffset().x); 473 EXPECT_EQ(250, fm.GetVisualScrollOffset().y); 474 EXPECT_EQ(200, fm.GetLayoutViewport().X()); 475 EXPECT_EQ(250, fm.GetLayoutViewport().Y()); 476 477 // Case 5 - visual viewport crosses the right boundary of the layout viewport. 478 Pan(apzc, ScreenIntPoint(350, 10), ScreenIntPoint(150, 10), 479 PanOptions::NoFling); 480 fm = apzc->GetFrameMetrics(); 481 // It starts from (200, 250) pans by (200, 0) screen pixels, but there is a 482 // 2x zoom, which causes the scroll offset to change by half of that 483 // (100, 0). The visual viewport crossed the right boundary of the layout 484 // viewport by 50px. 485 EXPECT_EQ(300, fm.GetVisualScrollOffset().x); 486 EXPECT_EQ(250, fm.GetVisualScrollOffset().y); 487 EXPECT_EQ(250, fm.GetLayoutViewport().X()); 488 EXPECT_EQ(250, fm.GetLayoutViewport().Y()); 489 490 // Case 6 - visual viewport crosses both the vertical and horizontal 491 // boundaries of the layout viewport by moving diagonally towards the 492 // top-right corner. 493 Pan(apzc, ScreenIntPoint(350, 200), ScreenIntPoint(150, 400), 494 PanOptions::NoFling); 495 fm = apzc->GetFrameMetrics(); 496 // It starts from (300, 250) pans by (200, -200) screen pixels, but there is 497 // a 2x zoom, which causes the scroll offset to change by half of that 498 // (100, -100). The visual viewport moved by (100, -100) outside the 499 // boundary of the layout viewport. 500 EXPECT_EQ(400, fm.GetVisualScrollOffset().x); 501 EXPECT_EQ(150, fm.GetVisualScrollOffset().y); 502 EXPECT_EQ(350, fm.GetLayoutViewport().X()); 503 EXPECT_EQ(150, fm.GetLayoutViewport().Y()); 504 } 505 506 TEST_F(APZCPinchGestureDetectorTester, Pinch_APZZoom_Disabled) { 507 SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false); 508 509 FrameMetrics originalMetrics = GetPinchableFrameMetrics(); 510 apzc->SetFrameMetrics(originalMetrics); 511 512 // When apz_allow_zooming is false, the ZoomConstraintsClient produces 513 // ZoomConstraints with mAllowZoom set to false. 514 MakeApzcUnzoomable(); 515 516 // With apz_allow_zooming false, we expect the NotifyPinchGesture function to 517 // get called as the pinch progresses, but the metrics shouldn't change. 518 EXPECT_CALL(*mcc, 519 NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_START, 520 apzc->GetGuid(), _, LayoutDeviceCoord(0), _)) 521 .Times(1); 522 EXPECT_CALL(*mcc, NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_SCALE, 523 apzc->GetGuid(), _, _, _)) 524 .Times(AtLeast(1)); 525 EXPECT_CALL(*mcc, 526 NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_END, 527 apzc->GetGuid(), _, LayoutDeviceCoord(0), _)) 528 .Times(1); 529 530 PinchWithTouchInput(apzc, ScreenIntPoint(250, 300), 1.25); 531 532 // verify the metrics didn't change (i.e. the pinch was ignored inside APZ) 533 FrameMetrics fm = apzc->GetFrameMetrics(); 534 EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom()); 535 EXPECT_EQ(originalMetrics.GetVisualScrollOffset().x, 536 fm.GetVisualScrollOffset().x); 537 EXPECT_EQ(originalMetrics.GetVisualScrollOffset().y, 538 fm.GetVisualScrollOffset().y); 539 540 apzc->AssertStateIsReset(); 541 } 542 543 TEST_F(APZCPinchGestureDetectorTester, Pinch_NoSpan) { 544 SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false); 545 546 FrameMetrics originalMetrics = GetPinchableFrameMetrics(); 547 apzc->SetFrameMetrics(originalMetrics); 548 549 // When apz_allow_zooming is false, the ZoomConstraintsClient produces 550 // ZoomConstraints with mAllowZoom set to false. 551 MakeApzcUnzoomable(); 552 553 // With apz_allow_zooming false, we expect the NotifyPinchGesture function to 554 // get called as the pinch progresses, but the metrics shouldn't change. 555 EXPECT_CALL(*mcc, 556 NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_START, 557 apzc->GetGuid(), _, LayoutDeviceCoord(0), _)) 558 .Times(1); 559 EXPECT_CALL(*mcc, NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_SCALE, 560 apzc->GetGuid(), _, _, _)) 561 .Times(AtLeast(1)); 562 EXPECT_CALL(*mcc, 563 NotifyPinchGesture(PinchGestureInput::PINCHGESTURE_END, 564 apzc->GetGuid(), _, LayoutDeviceCoord(0), _)) 565 .Times(1); 566 567 int inputId = 0; 568 ScreenIntPoint focus(250, 300); 569 570 // Do a pinch holding a zero span and moving the focus by y=100 571 572 const TimeDuration TIME_BETWEEN_TOUCH_EVENT = 573 TimeDuration::FromMilliseconds(50); 574 const auto touchBehaviors = Some(nsTArray<uint32_t>{kDefaultTouchBehavior}); 575 576 MultiTouchInput mtiStart = 577 MultiTouchInput(MultiTouchInput::MULTITOUCH_START, 0, mcc->Time(), 0); 578 mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId, focus)); 579 mtiStart.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus)); 580 apzc->ReceiveInputEvent(mtiStart, touchBehaviors); 581 mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT); 582 583 focus.y -= 35 + 1; // this is to get over the PINCH_START_THRESHOLD in 584 // GestureEventListener.cpp 585 MultiTouchInput mtiMove1 = 586 MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0); 587 mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId, focus)); 588 mtiMove1.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus)); 589 apzc->ReceiveInputEvent(mtiMove1); 590 mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT); 591 592 focus.y -= 100; // do a two-finger scroll of 100 screen pixels 593 MultiTouchInput mtiMove2 = 594 MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, 0, mcc->Time(), 0); 595 mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId, focus)); 596 mtiMove2.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus)); 597 apzc->ReceiveInputEvent(mtiMove2); 598 mcc->AdvanceBy(TIME_BETWEEN_TOUCH_EVENT); 599 600 MultiTouchInput mtiEnd = 601 MultiTouchInput(MultiTouchInput::MULTITOUCH_END, 0, mcc->Time(), 0); 602 mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId, focus)); 603 mtiEnd.mTouches.AppendElement(CreateSingleTouchData(inputId + 1, focus)); 604 apzc->ReceiveInputEvent(mtiEnd); 605 606 // Done, check the metrics to make sure we scrolled by 100 screen pixels, 607 // which is 50 CSS pixels for the pinchable frame metrics. 608 609 FrameMetrics fm = apzc->GetFrameMetrics(); 610 EXPECT_EQ(originalMetrics.GetZoom(), fm.GetZoom()); 611 EXPECT_EQ(originalMetrics.GetVisualScrollOffset().x, 612 fm.GetVisualScrollOffset().x); 613 EXPECT_EQ(originalMetrics.GetVisualScrollOffset().y + 50, 614 fm.GetVisualScrollOffset().y); 615 616 apzc->AssertStateIsReset(); 617 } 618 619 TEST_F(APZCPinchTester, Pinch_TwoFinger_APZZoom_Disabled_Bug1354185) { 620 // Set up APZ such that mZoomConstraints.mAllowZoom is false. 621 SCOPED_GFX_PREF_BOOL("apz.allow_zooming", false); 622 apzc->SetFrameMetrics(GetPinchableFrameMetrics()); 623 MakeApzcUnzoomable(); 624 625 // We expect a repaint request for scrolling. 626 EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); 627 628 // Send only the PINCHGESTURE_START and PINCHGESTURE_SCALE events, 629 // in order to trigger a call to AsyncPanZoomController::OnScale 630 // but not to AsyncPanZoomController::OnScaleEnd. 631 ScreenIntPoint aFocus(250, 350); 632 ScreenIntPoint aSecondFocus(200, 300); 633 float aScale = 10; 634 auto event = CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_START, 635 aFocus, 10.0, 10.0, mcc->Time()); 636 apzc->ReceiveInputEvent(event); 637 638 event = 639 CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE, 640 aSecondFocus, 10.0f * aScale, 10.0, mcc->Time()); 641 apzc->ReceiveInputEvent(event); 642 } 643 644 TEST_F(APZCPinchLockingTester, Pinch_Locking_Free) { 645 SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 0); // PINCH_FREE 646 647 twoFingerPan(); 648 EXPECT_FALSE(isPinchLockActive()); 649 } 650 651 TEST_F(APZCPinchLockingTester, Pinch_Locking_Normal_Lock) { 652 SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 1); // PINCH_NORMAL 653 654 twoFingerPan(); 655 EXPECT_TRUE(isPinchLockActive()); 656 } 657 658 TEST_F(APZCPinchLockingTester, Pinch_Locking_Normal_Lock_Break) { 659 SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 1); // PINCH_NORMAL 660 661 twoFingerPan(); 662 twoFingerZoom(); 663 EXPECT_TRUE(isPinchLockActive()); 664 } 665 666 TEST_F(APZCPinchLockingTester, Pinch_Locking_Sticky_Lock) { 667 SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 2); // PINCH_STICKY 668 669 twoFingerPan(); 670 EXPECT_TRUE(isPinchLockActive()); 671 } 672 673 TEST_F(APZCPinchLockingTester, Pinch_Locking_Sticky_Lock_Break) { 674 SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 2); // PINCH_STICKY 675 676 twoFingerPan(); 677 twoFingerZoom(); 678 EXPECT_FALSE(isPinchLockActive()); 679 } 680 681 TEST_F(APZCPinchLockingTester, Pinch_Locking_Sticky_Lock_Break_Lock) { 682 SCOPED_GFX_PREF_INT("apz.pinch_lock.mode", 2); // PINCH_STICKY 683 684 twoFingerPan(); 685 twoFingerZoom(); 686 twoFingerPan(); 687 EXPECT_TRUE(isPinchLockActive()); 688 }