TestAxisLock.cpp (30851B)
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 "APZCTreeManagerTester.h" 8 #include "APZTestCommon.h" 9 10 #include "InputUtils.h" 11 #include "gtest/gtest.h" 12 13 #include <cmath> 14 15 class APZCAxisLockCompatTester : public APZCTreeManagerTester, 16 public testing::WithParamInterface<int> { 17 public: 18 APZCAxisLockCompatTester() : oldAxisLockMode(0) { CreateMockHitTester(); } 19 20 int oldAxisLockMode; 21 22 UniquePtr<ScopedLayerTreeRegistration> registration; 23 24 RefPtr<TestAsyncPanZoomController> apzc; 25 26 void SetUp() { 27 APZCTreeManagerTester::SetUp(); 28 29 oldAxisLockMode = Preferences::GetInt("apz.axis_lock.mode"); 30 31 Preferences::SetInt("apz.axis_lock.mode", GetParam()); 32 } 33 34 void TearDown() { 35 APZCTreeManagerTester::TearDown(); 36 37 Preferences::SetInt("apz.axis_lock.mode", oldAxisLockMode); 38 } 39 40 static std::string PrintFromParam(const testing::TestParamInfo<int>& info) { 41 switch (info.param) { 42 case 0: 43 return "FREE"; 44 case 1: 45 return "STANDARD"; 46 case 2: 47 return "STICKY"; 48 case 3: 49 return "DOMINANT_AXIS"; 50 case 4: 51 return "BREAKABLE"; 52 default: 53 return "UNKNOWN"; 54 } 55 } 56 }; 57 58 class APZCAxisLockTester : public APZCTreeManagerTester { 59 public: 60 APZCAxisLockTester() { CreateMockHitTester(); } 61 62 UniquePtr<ScopedLayerTreeRegistration> registration; 63 64 RefPtr<TestAsyncPanZoomController> apzc; 65 66 void SetupBasicTest() { 67 const char* treeShape = "x"; 68 LayerIntRect layerVisibleRect[] = { 69 LayerIntRect(0, 0, 100, 100), 70 }; 71 CreateScrollData(treeShape, layerVisibleRect); 72 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 73 CSSRect(0, 0, 500, 500)); 74 75 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 76 77 UpdateHitTestingTree(); 78 } 79 80 void BreakStickyAxisLockTestGesture(const ScrollDirections& aDirections) { 81 float panX = 0; 82 float panY = 0; 83 84 if (aDirections.contains(ScrollDirection::eVertical)) { 85 panY = 30; 86 } 87 if (aDirections.contains(ScrollDirection::eHorizontal)) { 88 panX = 30; 89 } 90 91 // Kick off the gesture that may lock onto an axis 92 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 93 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 94 ScreenPoint(panX, panY), mcc->Time()); 95 mcc->AdvanceByMillis(5); 96 apzc->AdvanceAnimations(mcc->GetSampleTime()); 97 98 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 99 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 100 ScreenPoint(panX, panY), mcc->Time()); 101 } 102 103 void BreakStickyAxisLockTest(const ScrollDirections& aDirections) { 104 // Create the gesture for the test. 105 BreakStickyAxisLockTestGesture(aDirections); 106 107 // Based on the scroll direction(s) ensure the state is what we expect. 108 if (aDirections == ScrollDirection::eVertical) { 109 apzc->AssertStateIsPanningLockedY(); 110 apzc->AssertAxisLocked(ScrollDirection::eVertical); 111 EXPECT_GT(apzc->GetVelocityVector().y, 0); 112 EXPECT_EQ(apzc->GetVelocityVector().x, 0); 113 } else if (aDirections == ScrollDirection::eHorizontal) { 114 apzc->AssertStateIsPanningLockedX(); 115 apzc->AssertAxisLocked(ScrollDirection::eHorizontal); 116 EXPECT_GT(apzc->GetVelocityVector().x, 0); 117 EXPECT_EQ(apzc->GetVelocityVector().y, 0); 118 } else { 119 apzc->AssertStateIsPanning(); 120 apzc->AssertNotAxisLocked(); 121 EXPECT_GT(apzc->GetVelocityVector().x, 0); 122 EXPECT_GT(apzc->GetVelocityVector().y, 0); 123 } 124 125 // Cleanup for next test. 126 apzc->AdvanceAnimationsUntilEnd(); 127 } 128 }; 129 130 TEST_F(APZCAxisLockTester, BasicDominantAxisUse) { 131 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 1); 132 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); 133 134 SetupBasicTest(); 135 136 apzc = ApzcOf(root); 137 138 // Kick off the initial gesture that triggers the momentum scroll. 139 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 140 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 141 ScreenIntPoint(1, 2), mcc->Time()); 142 mcc->AdvanceByMillis(5); 143 apzc->AdvanceAnimations(mcc->GetSampleTime()); 144 145 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 146 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 147 ScreenPoint(15, 30), mcc->Time()); 148 mcc->AdvanceByMillis(5); 149 apzc->AdvanceAnimations(mcc->GetSampleTime()); 150 151 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 152 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 153 ScreenPoint(15, 30), mcc->Time()); 154 155 // Should be in a PANNING_LOCKED_Y state with no horizontal velocity. 156 apzc->AssertStateIsPanningLockedY(); 157 apzc->AssertAxisLocked(ScrollDirection::eVertical); 158 EXPECT_GT(apzc->GetVelocityVector().y, 0); 159 EXPECT_EQ(apzc->GetVelocityVector().x, 0); 160 161 mcc->AdvanceByMillis(5); 162 apzc->AdvanceAnimations(mcc->GetSampleTime()); 163 164 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 165 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 166 ScreenPoint(0, 0), mcc->Time()); 167 mcc->AdvanceByMillis(5); 168 apzc->AdvanceAnimations(mcc->GetSampleTime()); 169 170 // Ensure that we have not panned on the horizontal axis. 171 ParentLayerPoint panEndOffset = apzc->GetCurrentAsyncScrollOffset( 172 AsyncTransformConsumer::eForEventHandling); 173 EXPECT_EQ(panEndOffset.x, 0); 174 175 // The lock onto the Y axis extends into momentum scroll. 176 apzc->AssertAxisLocked(ScrollDirection::eVertical); 177 178 // Start the momentum scroll. 179 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 180 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager, 181 ScreenIntPoint(50, 50), ScreenPoint(30, 90), mcc->Time()); 182 mcc->AdvanceByMillis(10); 183 apzc->AdvanceAnimations(mcc->GetSampleTime()); 184 185 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 186 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, 187 ScreenIntPoint(50, 50), ScreenPoint(10, 30), mcc->Time()); 188 mcc->AdvanceByMillis(10); 189 apzc->AdvanceAnimations(mcc->GetSampleTime()); 190 191 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 192 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, 193 ScreenIntPoint(50, 50), ScreenPoint(10, 30), mcc->Time()); 194 mcc->AdvanceByMillis(10); 195 apzc->AdvanceAnimations(mcc->GetSampleTime()); 196 197 // In momentum locking mode, we should still be locked onto the Y axis. 198 apzc->AssertStateIsPanMomentum(); 199 apzc->AssertAxisLocked(ScrollDirection::eVertical); 200 EXPECT_GT(apzc->GetVelocityVector().y, 0); 201 EXPECT_EQ(apzc->GetVelocityVector().x, 0); 202 203 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 204 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, manager, 205 ScreenIntPoint(50, 50), ScreenPoint(0, 0), mcc->Time()); 206 207 // After momentum scroll end, ensure we are no longer locked onto an axis. 208 apzc->AssertNotAxisLocked(); 209 210 // Wait until the end of the animation and ensure the final state is 211 // reasonable. 212 apzc->AdvanceAnimationsUntilEnd(); 213 ParentLayerPoint finalOffset = apzc->GetCurrentAsyncScrollOffset( 214 AsyncTransformConsumer::eForEventHandling); 215 216 // Ensure we have scrolled some amount on the Y axis in momentum scroll. 217 EXPECT_GT(finalOffset.y, panEndOffset.y); 218 EXPECT_EQ(finalOffset.x, 0.0f); 219 } 220 221 TEST_F(APZCAxisLockTester, NewGestureBreaksMomentumAxisLock) { 222 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 1); 223 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); 224 225 SetupBasicTest(); 226 227 apzc = ApzcOf(root); 228 229 // Kick off the initial gesture that triggers the momentum scroll. 230 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 231 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 232 ScreenIntPoint(2, 1), mcc->Time()); 233 mcc->AdvanceByMillis(5); 234 apzc->AdvanceAnimations(mcc->GetSampleTime()); 235 236 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 237 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 238 ScreenPoint(30, 15), mcc->Time()); 239 mcc->AdvanceByMillis(5); 240 apzc->AdvanceAnimations(mcc->GetSampleTime()); 241 242 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 243 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 244 ScreenPoint(30, 15), mcc->Time()); 245 246 // Should be in a PANNING_LOCKED_X state with no vertical velocity. 247 apzc->AssertStateIsPanningLockedX(); 248 apzc->AssertAxisLocked(ScrollDirection::eHorizontal); 249 EXPECT_GT(apzc->GetVelocityVector().x, 0); 250 EXPECT_EQ(apzc->GetVelocityVector().y, 0); 251 252 mcc->AdvanceByMillis(5); 253 apzc->AdvanceAnimations(mcc->GetSampleTime()); 254 255 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 256 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 257 ScreenPoint(0, 0), mcc->Time()); 258 mcc->AdvanceByMillis(5); 259 apzc->AdvanceAnimations(mcc->GetSampleTime()); 260 261 // Double check that we have not panned on the vertical axis. 262 ParentLayerPoint panEndOffset = apzc->GetCurrentAsyncScrollOffset( 263 AsyncTransformConsumer::eForEventHandling); 264 EXPECT_EQ(panEndOffset.y, 0); 265 266 // Ensure that the axis locks extends into momentum scroll. 267 apzc->AssertAxisLocked(ScrollDirection::eHorizontal); 268 269 // Start the momentum scroll. 270 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 271 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager, 272 ScreenIntPoint(50, 50), ScreenPoint(80, 40), mcc->Time()); 273 mcc->AdvanceByMillis(10); 274 apzc->AdvanceAnimations(mcc->GetSampleTime()); 275 276 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 277 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, 278 ScreenIntPoint(50, 50), ScreenPoint(20, 10), mcc->Time()); 279 mcc->AdvanceByMillis(10); 280 apzc->AdvanceAnimations(mcc->GetSampleTime()); 281 282 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 283 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, 284 ScreenIntPoint(50, 50), ScreenPoint(20, 10), mcc->Time()); 285 mcc->AdvanceByMillis(10); 286 apzc->AdvanceAnimations(mcc->GetSampleTime()); 287 288 // In momentum locking mode, we should still be locked onto the X axis. 289 apzc->AssertStateIsPanMomentum(); 290 apzc->AssertAxisLocked(ScrollDirection::eHorizontal); 291 EXPECT_GT(apzc->GetVelocityVector().x, 0); 292 EXPECT_EQ(apzc->GetVelocityVector().y, 0); 293 294 ParentLayerPoint beforeBreakOffset = apzc->GetCurrentAsyncScrollOffset( 295 AsyncTransformConsumer::eForEventHandling); 296 EXPECT_EQ(beforeBreakOffset.y, 0); 297 // Ensure we have scrolled some amount on the X axis in momentum scroll. 298 EXPECT_GT(beforeBreakOffset.x, panEndOffset.x); 299 300 // Kick off the gesture that breaks the lock onto the X axis. 301 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 302 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 303 ScreenIntPoint(1, 2), mcc->Time()); 304 mcc->AdvanceByMillis(5); 305 apzc->AdvanceAnimations(mcc->GetSampleTime()); 306 307 ParentLayerPoint afterBreakOffset = apzc->GetCurrentAsyncScrollOffset( 308 AsyncTransformConsumer::eForEventHandling); 309 310 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 311 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 312 ScreenPoint(15, 30), mcc->Time()); 313 mcc->AdvanceByMillis(5); 314 apzc->AdvanceAnimations(mcc->GetSampleTime()); 315 316 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 317 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 318 ScreenPoint(15, 30), mcc->Time()); 319 320 // The lock onto the X axis should be broken and we now should be locked 321 // onto the Y axis. 322 apzc->AssertStateIsPanningLockedY(); 323 apzc->AssertAxisLocked(ScrollDirection::eVertical); 324 EXPECT_GT(apzc->GetVelocityVector().y, 0); 325 EXPECT_EQ(apzc->GetVelocityVector().x, 0); 326 327 mcc->AdvanceByMillis(5); 328 apzc->AdvanceAnimations(mcc->GetSampleTime()); 329 330 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 331 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 332 ScreenPoint(0, 0), mcc->Time()); 333 mcc->AdvanceByMillis(5); 334 apzc->AdvanceAnimations(mcc->GetSampleTime()); 335 336 // The lock onto the Y axis extends into momentum scroll. 337 apzc->AssertAxisLocked(ScrollDirection::eVertical); 338 339 // Wait until the end of the animation and ensure the final state is 340 // reasonable. 341 apzc->AdvanceAnimationsUntilEnd(); 342 ParentLayerPoint finalOffset = apzc->GetCurrentAsyncScrollOffset( 343 AsyncTransformConsumer::eForEventHandling); 344 345 EXPECT_GT(finalOffset.y, 0); 346 // Ensure that we did not scroll on the X axis after the vertical scroll 347 // started. 348 EXPECT_EQ(finalOffset.x, afterBreakOffset.x); 349 } 350 351 TEST_F(APZCAxisLockTester, BreakStickyAxisLock) { 352 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 353 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 6.0f); 354 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 6.0f); 355 356 SetupBasicTest(); 357 358 apzc = ApzcOf(root); 359 360 // Start a gesture to get us locked onto the Y axis. 361 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 362 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 363 ScreenIntPoint(0, 2), mcc->Time()); 364 mcc->AdvanceByMillis(5); 365 apzc->AdvanceAnimations(mcc->GetSampleTime()); 366 367 // Ensure that we have locked onto the Y axis. 368 apzc->AssertStateIsPanningLockedY(); 369 370 // Test switch to locking onto the X axis. 371 BreakStickyAxisLockTest(ScrollDirection::eHorizontal); 372 373 // Test switch back to locking onto the Y axis. 374 BreakStickyAxisLockTest(ScrollDirection::eVertical); 375 376 // Test breaking all axis locks from a Y axis lock. 377 BreakStickyAxisLockTest(ScrollDirections(ScrollDirection::eHorizontal, 378 ScrollDirection::eVertical)); 379 380 // We should be in a panning state. 381 apzc->AssertStateIsPanning(); 382 apzc->AssertNotAxisLocked(); 383 384 // Lock back to the X axis. 385 BreakStickyAxisLockTestGesture(ScrollDirection::eHorizontal); 386 387 // End the gesture. 388 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 389 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 390 ScreenPoint(0, 0), mcc->Time()); 391 mcc->AdvanceByMillis(5); 392 apzc->AdvanceAnimations(mcc->GetSampleTime()); 393 394 // Start a gesture to get us locked onto the X axis. 395 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 396 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 397 ScreenIntPoint(2, 0), mcc->Time()); 398 mcc->AdvanceByMillis(5); 399 apzc->AdvanceAnimations(mcc->GetSampleTime()); 400 401 // Ensure that we have locked onto the X axis. 402 apzc->AssertStateIsPanningLockedX(); 403 404 // Test breaking all axis locks from a X axis lock. 405 BreakStickyAxisLockTest(ScrollDirections(ScrollDirection::eHorizontal, 406 ScrollDirection::eVertical)); 407 408 // We should be in a panning state. 409 apzc->AssertStateIsPanning(); 410 apzc->AssertNotAxisLocked(); 411 412 // Test switch back to locking onto the Y axis. 413 BreakStickyAxisLockTest(ScrollDirection::eVertical); 414 } 415 416 TEST_F(APZCAxisLockTester, BreakAxisLockByLockAngle) { 417 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 418 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); 419 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 8.0f); 420 421 SetupBasicTest(); 422 423 apzc = ApzcOf(root); 424 425 // Start a gesture to get us locked onto the Y axis. 426 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 427 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 428 ScreenIntPoint(1, 10), mcc->Time()); 429 mcc->AdvanceByMillis(5); 430 apzc->AdvanceAnimations(mcc->GetSampleTime()); 431 432 // Ensure that we have locked onto the Y axis. 433 apzc->AssertStateIsPanningLockedY(); 434 435 // Stay within 45 degrees from the X axis, and more than 22.5 degrees from 436 // the Y axis. This should break the Y lock and lock us to the X axis. 437 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 438 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, ScreenIntPoint(50, 50), 439 ScreenIntPoint(12, 10), mcc->Time()); 440 apzc->AdvanceAnimations(mcc->GetSampleTime()); 441 442 // Ensure that we have locked onto the X axis. 443 apzc->AssertStateIsPanningLockedX(); 444 445 // End the gesture. 446 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 447 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 448 ScreenPoint(0, 0), mcc->Time()); 449 apzc->AdvanceAnimations(mcc->GetSampleTime()); 450 } 451 452 TEST_F(APZCAxisLockTester, TestCanBreakBreakableAxisLock) { 453 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 4); 454 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", M_PI / 4.0f); 455 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", M_PI / 8.0f); 456 457 SetupBasicTest(); 458 459 apzc = ApzcOf(root); 460 461 // Start a gesture to get us locked onto the Y axis. 462 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 463 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 464 ScreenIntPoint(0, 10), mcc->Time()); 465 mcc->AdvanceByMillis(5); 466 apzc->AdvanceAnimations(mcc->GetSampleTime()); 467 468 // Ensure that we have locked onto the Y axis. 469 apzc->AssertStateIsPanningLockedY(); 470 471 // Break the Y axis in a way that would lock onto the X axis if the 472 // AxisLockMode is STICKY, but should freely pan if it is BREAKABLE. 473 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 474 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, ScreenIntPoint(50, 50), 475 ScreenIntPoint(10, 0), mcc->Time()); 476 apzc->AdvanceAnimations(mcc->GetSampleTime()); 477 478 // Ensure that we have broken the Y axis, and are not locked onto the X axis. 479 apzc->AssertStateIsPanning(); 480 481 // Do a gesture that would re-lock on the Y axis if we were STICKY. 482 // Should not re-lock. 483 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 484 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, ScreenIntPoint(50, 50), 485 ScreenIntPoint(0, -10), mcc->Time()); 486 apzc->AdvanceAnimations(mcc->GetSampleTime()); 487 488 // Ensure that we have not acquired a lock on the Y axis. 489 apzc->AssertStateIsPanning(); 490 491 // End the gesture. 492 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 493 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 494 ScreenPoint(0, 0), mcc->Time()); 495 apzc->AdvanceAnimations(mcc->GetSampleTime()); 496 } 497 498 TEST_F(APZCAxisLockTester, TestDominantAxisScrolling) { 499 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 3); 500 501 int panY; 502 int panX; 503 504 SetupBasicTest(); 505 506 apzc = ApzcOf(root); 507 508 ParentLayerPoint lastOffset = apzc->GetCurrentAsyncScrollOffset( 509 AsyncPanZoomController::eForEventHandling); 510 511 // In dominant axis mode, test pan gesture events with varying gesture 512 // angles and ensure that we only pan on one axis. 513 for (panX = 0, panY = 50; panY >= 0; panY -= 10, panX += 5) { 514 // Gesture that should be locked onto one axis 515 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 516 PanGesture(PanGestureInput::PANGESTURE_START, manager, 517 ScreenIntPoint(50, 50), ScreenIntPoint(panX, panY), mcc->Time()); 518 mcc->AdvanceByMillis(5); 519 apzc->AdvanceAnimations(mcc->GetSampleTime()); 520 521 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 522 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 523 ScreenPoint(static_cast<float>(panX), static_cast<float>(panY)), 524 mcc->Time()); 525 mcc->AdvanceByMillis(5); 526 apzc->AdvanceAnimations(mcc->GetSampleTime()); 527 528 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 529 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 530 ScreenPoint(0, 0), mcc->Time()); 531 apzc->AdvanceAnimationsUntilEnd(); 532 533 ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset( 534 AsyncPanZoomController::eForEventHandling); 535 536 if (panX > panY) { 537 // If we're closer to the X axis ensure that we moved on the horizontal 538 // axis and there was no movement on the vertical axis. 539 EXPECT_GT(scrollOffset.x, lastOffset.x); 540 EXPECT_EQ(scrollOffset.y, lastOffset.y); 541 } else { 542 // If we're closer to the Y axis ensure that we moved on the vertical 543 // axis and there was no movement on the horizontal axis. 544 EXPECT_GT(scrollOffset.y, lastOffset.y); 545 EXPECT_EQ(scrollOffset.x, lastOffset.x); 546 } 547 548 lastOffset = scrollOffset; 549 } 550 } 551 552 TEST_F(APZCAxisLockTester, TestCanScrollWithAxisLock) { 553 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 554 555 SetupBasicTest(); 556 557 apzc = ApzcOf(root); 558 559 // The axis locks do not impact CanScroll() 560 apzc->SetAxisLocked(ScrollDirection::eHorizontal, true); 561 EXPECT_EQ(apzc->CanScroll(ParentLayerPoint(10, 0)), true); 562 563 apzc->SetAxisLocked(ScrollDirection::eHorizontal, false); 564 apzc->SetAxisLocked(ScrollDirection::eVertical, true); 565 EXPECT_EQ(apzc->CanScroll(ParentLayerPoint(0, 10)), true); 566 } 567 568 TEST_F(APZCAxisLockTester, TestScrollHandoffAxisLockConflict) { 569 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 570 571 // Create two scrollable frames. One parent frame with one child. 572 const char* treeShape = "x(x)"; 573 LayerIntRect layerVisibleRect[] = { 574 LayerIntRect(0, 0, 100, 100), 575 LayerIntRect(0, 0, 100, 100), 576 }; 577 CreateScrollData(treeShape, layerVisibleRect); 578 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 579 CSSRect(0, 0, 500, 500)); 580 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 581 CSSRect(0, 0, 500, 500)); 582 SetScrollHandoff(layers[1], root); 583 584 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 585 586 UpdateHitTestingTree(); 587 588 RefPtr<TestAsyncPanZoomController> rootApzc = ApzcOf(root); 589 apzc = ApzcOf(layers[1]); 590 591 // Create a gesture on the y-axis that should lock the x axis. 592 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 593 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 594 ScreenIntPoint(0, 2), mcc->Time()); 595 mcc->AdvanceByMillis(5); 596 apzc->AdvanceAnimations(mcc->GetSampleTime()); 597 598 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 599 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 600 ScreenPoint(0, 15), mcc->Time()); 601 mcc->AdvanceByMillis(5); 602 apzc->AdvanceAnimations(mcc->GetSampleTime()); 603 604 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 605 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 606 ScreenPoint(0, 0), mcc->Time()); 607 mcc->AdvanceByMillis(5); 608 apzc->AdvanceAnimationsUntilEnd(); 609 610 // We are locked onto the y-axis. 611 apzc->AssertAxisLocked(ScrollDirection::eVertical); 612 613 // There should be movement in the child. 614 ParentLayerPoint childCurrentOffset = apzc->GetCurrentAsyncScrollOffset( 615 AsyncTransformConsumer::eForEventHandling); 616 EXPECT_GT(childCurrentOffset.y, 0); 617 EXPECT_EQ(childCurrentOffset.x, 0); 618 619 // There should be no movement in the parent. 620 ParentLayerPoint parentCurrentOffset = rootApzc->GetCurrentAsyncScrollOffset( 621 AsyncTransformConsumer::eForEventHandling); 622 EXPECT_EQ(parentCurrentOffset.y, 0); 623 EXPECT_EQ(parentCurrentOffset.x, 0); 624 625 // Create a gesture on the x-axis, that should be directed 626 // at the child, even if the x-axis is locked. 627 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 628 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 629 ScreenIntPoint(2, 0), mcc->Time()); 630 mcc->AdvanceByMillis(5); 631 apzc->AdvanceAnimations(mcc->GetSampleTime()); 632 633 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 634 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 635 ScreenPoint(15, 0), mcc->Time()); 636 mcc->AdvanceByMillis(5); 637 apzc->AdvanceAnimations(mcc->GetSampleTime()); 638 639 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 640 PanGesture(PanGestureInput::PANGESTURE_END, manager, ScreenIntPoint(50, 50), 641 ScreenPoint(0, 0), mcc->Time()); 642 mcc->AdvanceByMillis(5); 643 apzc->AdvanceAnimationsUntilEnd(); 644 645 // We broke the y-axis lock and are now locked onto the x-axis. 646 apzc->AssertAxisLocked(ScrollDirection::eHorizontal); 647 648 // There should be some movement in the child on the x-axis. 649 ParentLayerPoint childFinalOffset = apzc->GetCurrentAsyncScrollOffset( 650 AsyncTransformConsumer::eForEventHandling); 651 EXPECT_GT(childFinalOffset.x, 0); 652 653 // There should still be no movement in the parent. 654 ParentLayerPoint parentFinalOffset = rootApzc->GetCurrentAsyncScrollOffset( 655 AsyncTransformConsumer::eForEventHandling); 656 EXPECT_EQ(parentFinalOffset.y, 0); 657 EXPECT_EQ(parentFinalOffset.x, 0); 658 } 659 660 // The delta from the initial pan gesture should be reflected in the 661 // current offset for all axis locking modes. 662 TEST_P(APZCAxisLockCompatTester, TestPanGestureStart) { 663 const char* treeShape = "x"; 664 LayerIntRect layerVisibleRect[] = { 665 LayerIntRect(0, 0, 100, 100), 666 }; 667 CreateScrollData(treeShape, layerVisibleRect); 668 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 669 CSSRect(0, 0, 500, 500)); 670 671 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 672 673 UpdateHitTestingTree(); 674 675 apzc = ApzcOf(root); 676 677 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 678 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 50), 679 ScreenIntPoint(0, 10), mcc->Time()); 680 mcc->AdvanceByMillis(5); 681 apzc->AdvanceAnimationsUntilEnd(); 682 ParentLayerPoint currentOffset = apzc->GetCurrentAsyncScrollOffset( 683 AsyncTransformConsumer::eForEventHandling); 684 685 EXPECT_EQ(currentOffset.x, 0); 686 EXPECT_EQ(currentOffset.y, 10); 687 } 688 689 #ifdef MOZ_WIDGET_ANDROID 690 TEST_F(APZCAxisLockTester, TouchScrollWithStickyAxisLocking) { 691 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 692 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_threshold", 10); 693 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", 0.392699); 694 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", 0.523599); 695 696 SetupBasicTest(); 697 698 apzc = ApzcOf(root); 699 700 // Scroll somewhere into the middle of the scroll range, so that we have 701 // lots of space to scroll in both directions. 702 apzc->GetFrameMetrics().SetVisualScrollOffset(CSSPoint(250, 250)); 703 704 UpdateHitTestingTree(); 705 706 // Trigger a touch scroll that will cause us to lock onto the 707 // y-axis. 708 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 709 (void)TouchDown(apzc, ScreenIntPoint(50, 50), mcc->Time()); 710 mcc->AdvanceByMillis(50); 711 712 (void)TouchMove(apzc, ScreenIntPoint(50, 60), mcc->Time()); 713 mcc->AdvanceByMillis(400); 714 715 (void)TouchMove(apzc, ScreenIntPoint(50, 70), mcc->Time()); 716 mcc->AdvanceByMillis(400); 717 718 apzc->AssertStateIsPanningLockedY(); 719 720 ParentLayerPoint currentOffset = apzc->GetCurrentAsyncScrollOffset( 721 AsyncTransformConsumer::eForEventHandling); 722 ParentLayerPoint lastOffset = currentOffset; 723 724 // A touch scroll in the reverse direction with slight movement 725 // on the x-axis should not cause us to break the y-axis lock. 726 (void)TouchMove(apzc, ScreenIntPoint(55, 60), mcc->Time()); 727 mcc->AdvanceByMillis(200); 728 729 // We should have scrolled only on the y-axis. 730 currentOffset = apzc->GetCurrentAsyncScrollOffset( 731 AsyncTransformConsumer::eForEventHandling); 732 EXPECT_GT(currentOffset.y, lastOffset.y); 733 EXPECT_EQ(currentOffset.x, lastOffset.x); 734 lastOffset = currentOffset; 735 apzc->AssertStateIsPanningLockedY(); 736 737 (void)TouchMove(apzc, ScreenIntPoint(60, 50), mcc->Time()); 738 mcc->AdvanceByMillis(200); 739 740 // We should continue to scroll only on the y-axis. 741 currentOffset = apzc->GetCurrentAsyncScrollOffset( 742 AsyncTransformConsumer::eForEventHandling); 743 EXPECT_GT(currentOffset.y, lastOffset.y); 744 EXPECT_EQ(currentOffset.x, lastOffset.x); 745 apzc->AssertStateIsPanningLockedY(); 746 lastOffset = currentOffset; 747 748 (void)TouchMove(apzc, ScreenIntPoint(60, 40), mcc->Time()); 749 mcc->AdvanceByMillis(200); 750 751 currentOffset = apzc->GetCurrentAsyncScrollOffset( 752 AsyncTransformConsumer::eForEventHandling); 753 EXPECT_GT(currentOffset.y, lastOffset.y); 754 EXPECT_EQ(currentOffset.x, lastOffset.x); 755 apzc->AssertStateIsPanningLockedY(); 756 lastOffset = currentOffset; 757 758 (void)TouchUp(apzc, ScreenIntPoint(65, 40), mcc->Time()); 759 } 760 #endif 761 762 // TODO(bug 1915260): Make this test pass. 763 #ifdef MOZ_WIDGET_ANDROID 764 TEST_F(APZCAxisLockTester, TouchScrollWithStickyAxisLockingBug1915260) { 765 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 766 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_threshold", 10); 767 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.breakout_angle", 0.392699); 768 SCOPED_GFX_PREF_FLOAT("apz.axis_lock.lock_angle", 0.523599); 769 770 SetupBasicTest(); 771 772 apzc = ApzcOf(root); 773 774 // Scroll somewhere into the middle of the scroll range, so that we have 775 // lots of space to scroll in both directions. 776 apzc->GetFrameMetrics().SetVisualScrollOffset(CSSPoint(250, 250)); 777 778 // Trigger a touch scroll that will cause us to lock onto the 779 // y-axis. 780 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 781 (void)TouchDown(apzc, ScreenIntPoint(50, 50), mcc->Time()); 782 mcc->AdvanceByMillis(10); 783 784 (void)TouchMove(apzc, ScreenIntPoint(50, 60), mcc->Time()); 785 mcc->AdvanceByMillis(200); 786 787 (void)TouchMove(apzc, ScreenIntPoint(50, 70), mcc->Time()); 788 mcc->AdvanceByMillis(200); 789 790 // We should be locked on the y-axis at this point. 791 // apzc->AssertStateIsPanningLockedY(); 792 793 // Assuming the last event in the historical touch scroll buffer 794 // we use to determine touch scroll direction is (50,60), this 795 // touch-move event will exceed the breakout threshold and will 796 // be considered to be a horizontal scroll, thus breaking the 797 // lock onto the y-axis. 798 (void)TouchMove(apzc, ScreenIntPoint(60, 60), mcc->Time()); 799 mcc->AdvanceByMillis(100); 800 // TODO(bug 1915260): We should still be be locked on the y-axis at this 801 // point. 802 // apzc->AssertStateIsPanningLockedY(); 803 804 (void)TouchUp(apzc, ScreenIntPoint(65, 45), mcc->Time()); 805 } 806 #endif 807 808 // All APZCAxisLockCompatTester tests should be run for each apz.axis_lock.mode. 809 // If another mode is added, the value should be added to this list. 810 INSTANTIATE_TEST_SUITE_P(APZCAxisLockCompat, APZCAxisLockCompatTester, 811 testing::Values(0, 1, 2, 3, 4), 812 APZCAxisLockCompatTester::PrintFromParam);