TestOverscroll.cpp (105319B)
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 "APZCTreeManagerTester.h" 9 #include "APZTestCommon.h" 10 #include "mozilla/RelativeTo.h" 11 #include "mozilla/ScrollPositionUpdate.h" 12 #include "mozilla/layers/ScrollableLayerGuid.h" 13 #include "mozilla/layers/WebRenderScrollDataWrapper.h" 14 15 #include "InputUtils.h" 16 17 using LayersUpdateFlags = AsyncPanZoomController::LayersUpdateFlags; 18 19 class APZCOverscrollTester : public APZCBasicTester { 20 public: 21 explicit APZCOverscrollTester( 22 AsyncPanZoomController::GestureBehavior aGestureBehavior = 23 AsyncPanZoomController::DEFAULT_GESTURES) 24 : APZCBasicTester(aGestureBehavior) {} 25 26 protected: 27 UniquePtr<ScopedLayerTreeRegistration> registration; 28 29 void TestOverscroll() { 30 // Pan sufficiently to hit overscroll behavior 31 PanIntoOverscroll(); 32 33 // Check that we recover from overscroll via an animation. 34 ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost()); 35 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 36 } 37 38 void PanIntoOverscroll() { 39 int touchStart = 500; 40 int touchEnd = 10; 41 Pan(apzc, touchStart, touchEnd); 42 EXPECT_TRUE(apzc->IsOverscrolled()); 43 } 44 45 /** 46 * Sample animations until we recover from overscroll. 47 * @param aExpectedScrollOffset the expected reported scroll offset 48 * throughout the animation 49 */ 50 void SampleAnimationUntilRecoveredFromOverscroll( 51 const ParentLayerPoint& aExpectedScrollOffset) { 52 const TimeDuration increment = TimeDuration::FromMilliseconds(1); 53 bool recoveredFromOverscroll = false; 54 ParentLayerPoint pointOut; 55 AsyncTransform viewTransformOut; 56 while (apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut)) { 57 // The reported scroll offset should be the same throughout. 58 EXPECT_EQ(aExpectedScrollOffset, pointOut); 59 60 // Trigger computation of the overscroll tranform, to make sure 61 // no assetions fire during the calculation. 62 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 63 64 if (!apzc->IsOverscrolled()) { 65 recoveredFromOverscroll = true; 66 } 67 68 mcc->AdvanceBy(increment); 69 } 70 EXPECT_TRUE(recoveredFromOverscroll); 71 apzc->AssertStateIsReset(); 72 } 73 74 ScrollableLayerGuid CreateSimpleRootScrollableForWebRender() { 75 ScrollableLayerGuid guid; 76 guid.mScrollId = ScrollableLayerGuid::START_SCROLL_ID; 77 guid.mLayersId = LayersId{0}; 78 79 ScrollMetadata metadata; 80 FrameMetrics& metrics = metadata.GetMetrics(); 81 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 82 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 83 metrics.SetScrollId(guid.mScrollId); 84 metadata.SetIsLayersIdRoot(true); 85 86 WebRenderLayerScrollData rootLayerScrollData; 87 rootLayerScrollData.InitializeRoot(0); 88 WebRenderScrollData scrollData; 89 rootLayerScrollData.AppendScrollMetadata(scrollData, metadata); 90 scrollData.AddLayerData(std::move(rootLayerScrollData)); 91 92 registration = MakeUnique<ScopedLayerTreeRegistration>(guid.mLayersId, mcc); 93 tm->UpdateHitTestingTree(WebRenderScrollDataWrapper(*updater, &scrollData), 94 guid.mLayersId, 0); 95 return guid; 96 } 97 }; 98 99 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 100 TEST_F(APZCOverscrollTester, FlingIntoOverscroll) { 101 // Enable overscrolling. 102 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 103 SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f); 104 105 // Scroll down by 25 px. Don't fling for simplicity. 106 Pan(apzc, 50, 25, PanOptions::NoFling); 107 108 // Now scroll back up by 20px, this time flinging after. 109 // The fling should cover the remaining 5 px of room to scroll, then 110 // go into overscroll, and finally snap-back to recover from overscroll. 111 Pan(apzc, 25, 45); 112 const TimeDuration increment = TimeDuration::FromMilliseconds(1); 113 bool reachedOverscroll = false; 114 bool recoveredFromOverscroll = false; 115 while (apzc->AdvanceAnimations(mcc->GetSampleTime())) { 116 if (!reachedOverscroll && apzc->IsOverscrolled()) { 117 reachedOverscroll = true; 118 } 119 if (reachedOverscroll && !apzc->IsOverscrolled()) { 120 recoveredFromOverscroll = true; 121 } 122 mcc->AdvanceBy(increment); 123 } 124 EXPECT_TRUE(reachedOverscroll); 125 EXPECT_TRUE(recoveredFromOverscroll); 126 } 127 #endif 128 129 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 130 TEST_F(APZCOverscrollTester, OverScrollPanning) { 131 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 132 133 TestOverscroll(); 134 } 135 #endif 136 137 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 138 // Tests that an overscroll animation doesn't trigger an assertion failure 139 // in the case where a sample has a velocity of zero. 140 TEST_F(APZCOverscrollTester, OverScroll_Bug1152051a) { 141 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 142 143 // Doctor the prefs to make the velocity zero at the end of the first sample. 144 145 // This ensures our incoming velocity to the overscroll animation is 146 // a round(ish) number, 4.9 (that being the distance of the pan before 147 // overscroll, which is 500 - 10 = 490 pixels, divided by the duration of 148 // the pan, which is 100 ms). 149 SCOPED_GFX_PREF_FLOAT("apz.fling_friction", 0); 150 151 TestOverscroll(); 152 } 153 #endif 154 155 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 156 // Tests that ending an overscroll animation doesn't leave around state that 157 // confuses the next overscroll animation. 158 TEST_F(APZCOverscrollTester, OverScroll_Bug1152051b) { 159 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 160 SCOPED_GFX_PREF_FLOAT("apz.overscroll.stop_distance_threshold", 0.1f); 161 162 // Pan sufficiently to hit overscroll behavior 163 PanIntoOverscroll(); 164 165 // Sample animations once, to give the fling animation started on touch-up 166 // a chance to realize it's overscrolled, and schedule a call to 167 // HandleFlingOverscroll(). 168 SampleAnimationOnce(); 169 170 // This advances the time and runs the HandleFlingOverscroll task scheduled in 171 // the previous call, which starts an overscroll animation. It then samples 172 // the overscroll animation once, to get it to initialize the first overscroll 173 // sample. 174 SampleAnimationOnce(); 175 176 // Do a touch-down to cancel the overscroll animation, and then a touch-up 177 // to schedule a new one since we're still overscrolled. We don't pan because 178 // panning can trigger functions that clear the overscroll animation state 179 // in other ways. 180 APZEventResult result = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time()); 181 if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) { 182 SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); 183 } 184 TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time()); 185 186 // Sample the second overscroll animation to its end. 187 // If the ending of the first overscroll animation fails to clear state 188 // properly, this will assert. 189 ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost()); 190 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 191 } 192 #endif 193 194 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 195 // Tests that the page doesn't get stuck in an 196 // overscroll animation after a low-velocity pan. 197 TEST_F(APZCOverscrollTester, OverScrollAfterLowVelocityPan_Bug1343775) { 198 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 199 200 // Pan into overscroll with a velocity less than the 201 // apz.fling_min_velocity_threshold preference. 202 Pan(apzc, 10, 30); 203 204 EXPECT_TRUE(apzc->IsOverscrolled()); 205 206 apzc->AdvanceAnimationsUntilEnd(); 207 208 // Check that we recovered from overscroll. 209 EXPECT_FALSE(apzc->IsOverscrolled()); 210 } 211 #endif 212 213 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 214 TEST_F(APZCOverscrollTester, OverScrollAbort) { 215 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 216 217 // Pan sufficiently to hit overscroll behavior 218 int touchStart = 500; 219 int touchEnd = 10; 220 Pan(apzc, touchStart, touchEnd); 221 EXPECT_TRUE(apzc->IsOverscrolled()); 222 223 ParentLayerPoint pointOut; 224 AsyncTransform viewTransformOut; 225 226 // This sample call will run to the end of the fling animation 227 // and will schedule the overscroll animation. 228 apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, 229 TimeDuration::FromMilliseconds(10000)); 230 EXPECT_TRUE(apzc->IsOverscrolled()); 231 232 // At this point, we have an active overscroll animation. 233 // Check that cancelling the animation clears the overscroll. 234 apzc->CancelAnimation(); 235 EXPECT_FALSE(apzc->IsOverscrolled()); 236 apzc->AssertStateIsReset(); 237 } 238 #endif 239 240 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 241 TEST_F(APZCOverscrollTester, OverScrollPanningAbort) { 242 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 243 244 // Pan sufficiently to hit overscroll behaviour. Keep the finger down so 245 // the pan does not end. 246 int touchStart = 500; 247 int touchEnd = 10; 248 Pan(apzc, touchStart, touchEnd, PanOptions::KeepFingerDown); 249 EXPECT_TRUE(apzc->IsOverscrolled()); 250 251 // Check that calling CancelAnimation() while the user is still panning 252 // (and thus no fling or snap-back animation has had a chance to start) 253 // clears the overscroll. 254 apzc->CancelAnimation(); 255 EXPECT_FALSE(apzc->IsOverscrolled()); 256 apzc->AssertStateIsReset(); 257 } 258 #endif 259 260 #ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android 261 TEST_F(APZCOverscrollTester, OverscrollByVerticalPanGestures) { 262 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 263 264 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 265 ScreenPoint(0, -2), mcc->Time()); 266 mcc->AdvanceByMillis(5); 267 apzc->AdvanceAnimations(mcc->GetSampleTime()); 268 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 269 ScreenPoint(0, -10), mcc->Time()); 270 mcc->AdvanceByMillis(5); 271 apzc->AdvanceAnimations(mcc->GetSampleTime()); 272 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 273 ScreenPoint(0, -2), mcc->Time()); 274 mcc->AdvanceByMillis(5); 275 apzc->AdvanceAnimations(mcc->GetSampleTime()); 276 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 277 ScreenPoint(0, 0), mcc->Time()); 278 279 EXPECT_TRUE(apzc->IsOverscrolled()); 280 281 // Check that we recover from overscroll via an animation. 282 ParentLayerPoint expectedScrollOffset(0, 0); 283 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 284 } 285 #endif 286 287 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 288 TEST_F(APZCOverscrollTester, StuckInOverscroll_Bug1767337) { 289 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 290 291 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 292 ScreenPoint(0, -2), mcc->Time()); 293 mcc->AdvanceByMillis(5); 294 apzc->AdvanceAnimations(mcc->GetSampleTime()); 295 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 296 ScreenPoint(0, -10), mcc->Time()); 297 mcc->AdvanceByMillis(5); 298 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 299 ScreenPoint(0, -10), mcc->Time()); 300 mcc->AdvanceByMillis(5); 301 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 302 ScreenPoint(0, -10), mcc->Time()); 303 mcc->AdvanceByMillis(5); 304 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 305 ScreenPoint(0, -10), mcc->Time()); 306 mcc->AdvanceByMillis(5); 307 apzc->AdvanceAnimations(mcc->GetSampleTime()); 308 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 309 ScreenPoint(0, -2), mcc->Time()); 310 mcc->AdvanceByMillis(5); 311 apzc->AdvanceAnimations(mcc->GetSampleTime()); 312 313 // Send two PANGESTURE_END in a row, to see if the second one gets us 314 // stuck in overscroll. 315 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 316 ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, true); 317 SampleAnimationOnce(); 318 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 319 ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, true); 320 321 EXPECT_TRUE(apzc->IsOverscrolled()); 322 323 // Check that we recover from overscroll via an animation. 324 ParentLayerPoint expectedScrollOffset(0, 0); 325 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 326 } 327 #endif 328 329 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 330 TEST_F(APZCOverscrollTester, OverscrollByVerticalAndHorizontalPanGestures) { 331 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 332 333 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 334 ScreenPoint(0, -2), mcc->Time()); 335 mcc->AdvanceByMillis(5); 336 apzc->AdvanceAnimations(mcc->GetSampleTime()); 337 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 338 ScreenPoint(0, -10), mcc->Time()); 339 mcc->AdvanceByMillis(5); 340 apzc->AdvanceAnimations(mcc->GetSampleTime()); 341 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 342 ScreenPoint(0, -2), mcc->Time()); 343 344 mcc->AdvanceByMillis(5); 345 apzc->AdvanceAnimations(mcc->GetSampleTime()); 346 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 347 ScreenPoint(-10, 0), mcc->Time()); 348 mcc->AdvanceByMillis(5); 349 apzc->AdvanceAnimations(mcc->GetSampleTime()); 350 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 351 ScreenPoint(-2, 0), mcc->Time()); 352 353 mcc->AdvanceByMillis(5); 354 apzc->AdvanceAnimations(mcc->GetSampleTime()); 355 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 356 ScreenPoint(0, 0), mcc->Time()); 357 358 EXPECT_TRUE(apzc->IsOverscrolled()); 359 360 // Check that we recover from overscroll via an animation. 361 ParentLayerPoint expectedScrollOffset(0, 0); 362 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 363 } 364 #endif 365 366 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 367 TEST_F(APZCOverscrollTester, OverscrollByPanMomentumGestures) { 368 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 369 370 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 371 ScreenPoint(0, 2), mcc->Time()); 372 mcc->AdvanceByMillis(5); 373 apzc->AdvanceAnimations(mcc->GetSampleTime()); 374 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 375 ScreenPoint(0, 10), mcc->Time()); 376 mcc->AdvanceByMillis(5); 377 apzc->AdvanceAnimations(mcc->GetSampleTime()); 378 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 379 ScreenPoint(0, 2), mcc->Time()); 380 mcc->AdvanceByMillis(5); 381 apzc->AdvanceAnimations(mcc->GetSampleTime()); 382 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 383 ScreenPoint(0, 0), mcc->Time()); 384 385 // Make sure we are not yet in overscrolled region. 386 EXPECT_TRUE(!apzc->IsOverscrolled()); 387 388 mcc->AdvanceByMillis(5); 389 apzc->AdvanceAnimations(mcc->GetSampleTime()); 390 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 391 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 392 mcc->AdvanceByMillis(5); 393 apzc->AdvanceAnimations(mcc->GetSampleTime()); 394 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 395 ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time()); 396 mcc->AdvanceByMillis(5); 397 apzc->AdvanceAnimations(mcc->GetSampleTime()); 398 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 399 ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time()); 400 mcc->AdvanceByMillis(5); 401 apzc->AdvanceAnimations(mcc->GetSampleTime()); 402 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 403 ScreenIntPoint(50, 80), ScreenPoint(0, 2), mcc->Time()); 404 mcc->AdvanceByMillis(5); 405 apzc->AdvanceAnimations(mcc->GetSampleTime()); 406 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 407 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 408 409 EXPECT_TRUE(apzc->IsOverscrolled()); 410 411 // Check that we recover from overscroll via an animation. 412 ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost()); 413 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 414 } 415 #endif 416 417 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 418 TEST_F(APZCOverscrollTester, IgnoreMomemtumDuringOverscroll) { 419 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 420 421 float yMost = GetScrollRange().YMost(); 422 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 423 ScreenPoint(0, yMost / 10), mcc->Time()); 424 mcc->AdvanceByMillis(5); 425 apzc->AdvanceAnimations(mcc->GetSampleTime()); 426 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 427 ScreenPoint(0, yMost), mcc->Time()); 428 mcc->AdvanceByMillis(5); 429 apzc->AdvanceAnimations(mcc->GetSampleTime()); 430 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 431 ScreenPoint(0, yMost / 10), mcc->Time()); 432 mcc->AdvanceByMillis(5); 433 apzc->AdvanceAnimations(mcc->GetSampleTime()); 434 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 435 ScreenPoint(0, 0), mcc->Time()); 436 437 // Make sure we've started an overscroll animation. 438 EXPECT_TRUE(apzc->IsOverscrolled()); 439 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 440 441 // And check the overscrolled transform value before/after calling PanGesture 442 // to make sure the overscroll amount isn't affected by momentum events. 443 mcc->AdvanceByMillis(5); 444 apzc->AdvanceAnimations(mcc->GetSampleTime()); 445 AsyncTransformComponentMatrix overscrolledTransform = 446 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 447 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 448 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 449 EXPECT_EQ( 450 overscrolledTransform, 451 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)); 452 453 mcc->AdvanceByMillis(5); 454 apzc->AdvanceAnimations(mcc->GetSampleTime()); 455 overscrolledTransform = 456 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 457 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 458 ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time()); 459 EXPECT_EQ( 460 overscrolledTransform, 461 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)); 462 463 mcc->AdvanceByMillis(5); 464 apzc->AdvanceAnimations(mcc->GetSampleTime()); 465 overscrolledTransform = 466 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 467 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 468 ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time()); 469 EXPECT_EQ( 470 overscrolledTransform, 471 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)); 472 473 mcc->AdvanceByMillis(5); 474 apzc->AdvanceAnimations(mcc->GetSampleTime()); 475 overscrolledTransform = 476 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 477 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 478 ScreenIntPoint(50, 80), ScreenPoint(0, 2), mcc->Time()); 479 EXPECT_EQ( 480 overscrolledTransform, 481 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)); 482 483 mcc->AdvanceByMillis(5); 484 apzc->AdvanceAnimations(mcc->GetSampleTime()); 485 overscrolledTransform = 486 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 487 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 488 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 489 EXPECT_EQ( 490 overscrolledTransform, 491 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)); 492 493 // Check that we've recovered from overscroll via an animation. 494 ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost()); 495 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 496 } 497 #endif 498 499 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 500 TEST_F(APZCOverscrollTester, VerticalOnlyOverscroll) { 501 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 502 503 // Make the content scrollable only vertically. 504 ScrollMetadata metadata; 505 FrameMetrics& metrics = metadata.GetMetrics(); 506 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 507 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 508 apzc->SetFrameMetrics(metrics); 509 510 // Scroll up into overscroll a bit. 511 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 512 ScreenPoint(-2, -2), mcc->Time()); 513 mcc->AdvanceByMillis(5); 514 apzc->AdvanceAnimations(mcc->GetSampleTime()); 515 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 516 ScreenPoint(-10, -10), mcc->Time()); 517 mcc->AdvanceByMillis(5); 518 apzc->AdvanceAnimations(mcc->GetSampleTime()); 519 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 520 ScreenPoint(-2, -2), mcc->Time()); 521 mcc->AdvanceByMillis(5); 522 apzc->AdvanceAnimations(mcc->GetSampleTime()); 523 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 524 ScreenPoint(0, 0), mcc->Time()); 525 // Now it's overscrolled. 526 EXPECT_TRUE(apzc->IsOverscrolled()); 527 AsyncTransformComponentMatrix overscrolledTransform = 528 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 529 // The overscroll shouldn't happen horizontally. 530 EXPECT_TRUE(overscrolledTransform._41 == 0); 531 // Happens only vertically. 532 EXPECT_TRUE(overscrolledTransform._42 != 0); 533 534 // Send pan momentum events including horizontal bits. 535 mcc->AdvanceByMillis(5); 536 apzc->AdvanceAnimations(mcc->GetSampleTime()); 537 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 538 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 539 mcc->AdvanceByMillis(5); 540 apzc->AdvanceAnimations(mcc->GetSampleTime()); 541 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 542 ScreenIntPoint(50, 80), ScreenPoint(-10, -100), mcc->Time()); 543 overscrolledTransform = 544 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 545 // The overscroll shouldn't happen horizontally. 546 EXPECT_TRUE(overscrolledTransform._41 == 0); 547 EXPECT_TRUE(overscrolledTransform._42 != 0); 548 549 mcc->AdvanceByMillis(5); 550 apzc->AdvanceAnimations(mcc->GetSampleTime()); 551 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 552 ScreenIntPoint(50, 80), ScreenPoint(-5, -50), mcc->Time()); 553 overscrolledTransform = 554 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 555 EXPECT_TRUE(overscrolledTransform._41 == 0); 556 EXPECT_TRUE(overscrolledTransform._42 != 0); 557 558 mcc->AdvanceByMillis(5); 559 apzc->AdvanceAnimations(mcc->GetSampleTime()); 560 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 561 ScreenIntPoint(50, 80), ScreenPoint(0, -2), mcc->Time()); 562 overscrolledTransform = 563 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 564 EXPECT_TRUE(overscrolledTransform._41 == 0); 565 EXPECT_TRUE(overscrolledTransform._42 != 0); 566 567 mcc->AdvanceByMillis(5); 568 apzc->AdvanceAnimations(mcc->GetSampleTime()); 569 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 570 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 571 overscrolledTransform = 572 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 573 EXPECT_TRUE(overscrolledTransform._41 == 0); 574 EXPECT_TRUE(overscrolledTransform._42 != 0); 575 576 // Check that we recover from overscroll via an animation. 577 ParentLayerPoint expectedScrollOffset(0, 0); 578 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 579 } 580 #endif 581 582 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 583 TEST_F(APZCOverscrollTester, VerticalOnlyOverscrollByPanMomentum) { 584 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 585 586 // Make the content scrollable only vertically. 587 ScrollMetadata metadata; 588 FrameMetrics& metrics = metadata.GetMetrics(); 589 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 590 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 591 // Scrolls the content down a bit. 592 metrics.SetVisualScrollOffset(CSSPoint(0, 50)); 593 apzc->SetFrameMetrics(metrics); 594 595 // Scroll up a bit where overscroll will not happen. 596 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 597 ScreenPoint(0, -2), mcc->Time()); 598 mcc->AdvanceByMillis(5); 599 apzc->AdvanceAnimations(mcc->GetSampleTime()); 600 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 601 ScreenPoint(0, -10), mcc->Time()); 602 mcc->AdvanceByMillis(5); 603 apzc->AdvanceAnimations(mcc->GetSampleTime()); 604 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 605 ScreenPoint(0, -2), mcc->Time()); 606 mcc->AdvanceByMillis(5); 607 apzc->AdvanceAnimations(mcc->GetSampleTime()); 608 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 609 ScreenPoint(0, 0), mcc->Time()); 610 611 // Make sure it's not yet overscrolled. 612 EXPECT_TRUE(!apzc->IsOverscrolled()); 613 614 // Send pan momentum events including horizontal bits. 615 mcc->AdvanceByMillis(5); 616 apzc->AdvanceAnimations(mcc->GetSampleTime()); 617 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 618 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 619 mcc->AdvanceByMillis(5); 620 apzc->AdvanceAnimations(mcc->GetSampleTime()); 621 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 622 ScreenIntPoint(50, 80), ScreenPoint(-10, -100), mcc->Time()); 623 // Now it's overscrolled. 624 EXPECT_TRUE(apzc->IsOverscrolled()); 625 626 AsyncTransformComponentMatrix overscrolledTransform = 627 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 628 // But the overscroll shouldn't happen horizontally. 629 EXPECT_TRUE(overscrolledTransform._41 == 0); 630 // Happens only vertically. 631 EXPECT_TRUE(overscrolledTransform._42 != 0); 632 633 mcc->AdvanceByMillis(5); 634 apzc->AdvanceAnimations(mcc->GetSampleTime()); 635 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 636 ScreenIntPoint(50, 80), ScreenPoint(-5, -50), mcc->Time()); 637 overscrolledTransform = 638 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 639 EXPECT_TRUE(overscrolledTransform._41 == 0); 640 EXPECT_TRUE(overscrolledTransform._42 != 0); 641 642 mcc->AdvanceByMillis(5); 643 apzc->AdvanceAnimations(mcc->GetSampleTime()); 644 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 645 ScreenIntPoint(50, 80), ScreenPoint(0, -2), mcc->Time()); 646 overscrolledTransform = 647 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 648 EXPECT_TRUE(overscrolledTransform._41 == 0); 649 EXPECT_TRUE(overscrolledTransform._42 != 0); 650 651 mcc->AdvanceByMillis(5); 652 apzc->AdvanceAnimations(mcc->GetSampleTime()); 653 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 654 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 655 overscrolledTransform = 656 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 657 EXPECT_TRUE(overscrolledTransform._41 == 0); 658 EXPECT_TRUE(overscrolledTransform._42 != 0); 659 660 // Check that we recover from overscroll via an animation. 661 ParentLayerPoint expectedScrollOffset(0, 0); 662 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 663 } 664 #endif 665 666 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 667 TEST_F(APZCOverscrollTester, DisallowOverscrollInSingleLineTextControl) { 668 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 669 670 // Create a horizontal scrollable frame with `vertical disregarded direction`. 671 ScrollMetadata metadata; 672 FrameMetrics& metrics = metadata.GetMetrics(); 673 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 10)); 674 metrics.SetScrollableRect(CSSRect(0, 0, 1000, 10)); 675 apzc->SetFrameMetrics(metrics); 676 metadata.SetDisregardedDirection(Some(ScrollDirection::eVertical)); 677 apzc->NotifyLayersUpdated( 678 metadata, 679 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 680 681 // Try to overscroll up and left with pan gestures. 682 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 5), 683 ScreenPoint(-2, -2), mcc->Time()); 684 mcc->AdvanceByMillis(5); 685 apzc->AdvanceAnimations(mcc->GetSampleTime()); 686 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 5), 687 ScreenPoint(-10, -10), mcc->Time()); 688 mcc->AdvanceByMillis(5); 689 apzc->AdvanceAnimations(mcc->GetSampleTime()); 690 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 5), 691 ScreenPoint(-2, -2), mcc->Time()); 692 mcc->AdvanceByMillis(5); 693 apzc->AdvanceAnimations(mcc->GetSampleTime()); 694 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 5), 695 ScreenPoint(0, 0), mcc->Time()); 696 697 // No overscrolling should happen. 698 EXPECT_TRUE(!apzc->IsOverscrolled()); 699 700 // Send pan momentum events too. 701 mcc->AdvanceByMillis(5); 702 apzc->AdvanceAnimations(mcc->GetSampleTime()); 703 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 704 ScreenIntPoint(50, 5), ScreenPoint(0, 0), mcc->Time()); 705 mcc->AdvanceByMillis(5); 706 apzc->AdvanceAnimations(mcc->GetSampleTime()); 707 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 708 ScreenIntPoint(50, 5), ScreenPoint(-100, -100), mcc->Time()); 709 mcc->AdvanceByMillis(5); 710 apzc->AdvanceAnimations(mcc->GetSampleTime()); 711 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 712 ScreenIntPoint(50, 5), ScreenPoint(-50, -50), mcc->Time()); 713 mcc->AdvanceByMillis(5); 714 apzc->AdvanceAnimations(mcc->GetSampleTime()); 715 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 716 ScreenIntPoint(50, 5), ScreenPoint(-2, -2), mcc->Time()); 717 mcc->AdvanceByMillis(5); 718 apzc->AdvanceAnimations(mcc->GetSampleTime()); 719 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 720 ScreenIntPoint(50, 5), ScreenPoint(0, 0), mcc->Time()); 721 // No overscrolling should happen either. 722 EXPECT_TRUE(!apzc->IsOverscrolled()); 723 } 724 #endif 725 726 #ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android 727 // Tests that horizontal overscroll animation keeps running with vertical 728 // pan momentum scrolling. 729 TEST_F(APZCOverscrollTester, 730 HorizontalOverscrollAnimationWithVerticalPanMomentumScrolling) { 731 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 732 733 ScrollMetadata metadata; 734 FrameMetrics& metrics = metadata.GetMetrics(); 735 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 736 metrics.SetScrollableRect(CSSRect(0, 0, 1000, 5000)); 737 apzc->SetFrameMetrics(metrics); 738 739 // Try to overscroll left with pan gestures. 740 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 741 ScreenPoint(-2, 0), mcc->Time()); 742 mcc->AdvanceByMillis(5); 743 apzc->AdvanceAnimations(mcc->GetSampleTime()); 744 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 745 ScreenPoint(-10, 0), mcc->Time()); 746 mcc->AdvanceByMillis(5); 747 apzc->AdvanceAnimations(mcc->GetSampleTime()); 748 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 749 ScreenPoint(-2, 0), mcc->Time()); 750 mcc->AdvanceByMillis(5); 751 apzc->AdvanceAnimations(mcc->GetSampleTime()); 752 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 753 ScreenPoint(0, 0), mcc->Time()); 754 755 // Make sure we've started an overscroll animation. 756 EXPECT_TRUE(apzc->IsOverscrolled()); 757 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 758 AsyncTransformComponentMatrix initialOverscrolledTransform = 759 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 760 761 // Send lengthy downward momentums to make sure the overscroll animation 762 // doesn't clobber the momentums scrolling. 763 mcc->AdvanceByMillis(5); 764 apzc->AdvanceAnimations(mcc->GetSampleTime()); 765 // The overscroll amount on X axis has started being managed by the overscroll 766 // animation. 767 AsyncTransformComponentMatrix currentOverscrolledTransform = 768 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 769 EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41); 770 // There is no overscroll on Y axis. 771 EXPECT_EQ(currentOverscrolledTransform._42, 0); 772 ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset( 773 AsyncPanZoomController::eForEventHandling); 774 // The scroll offset shouldn't be changed by the overscroll animation. 775 EXPECT_EQ(scrollOffset.y, 0); 776 777 // Simple gesture on the Y axis to ensure that we can send a vertical 778 // momentum scroll 779 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 780 ScreenPoint(0, -2), mcc->Time()); 781 mcc->AdvanceByMillis(5); 782 apzc->AdvanceAnimations(mcc->GetSampleTime()); 783 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 784 ScreenPoint(0, 2), mcc->Time()); 785 mcc->AdvanceByMillis(5); 786 apzc->AdvanceAnimations(mcc->GetSampleTime()); 787 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 788 ScreenPoint(0, 0), mcc->Time()); 789 790 ParentLayerPoint offsetAfterPan = apzc->GetCurrentAsyncScrollOffset( 791 AsyncPanZoomController::eForEventHandling); 792 793 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 794 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 795 EXPECT_TRUE(apzc->IsOverscrolled()); 796 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 797 // The overscroll amount on both axes shouldn't be changed by this pan 798 // momentum start event since the displacement is zero. 799 EXPECT_EQ( 800 currentOverscrolledTransform._41, 801 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 802 ._41); 803 EXPECT_EQ( 804 currentOverscrolledTransform._42, 805 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 806 ._42); 807 808 mcc->AdvanceByMillis(5); 809 apzc->AdvanceAnimations(mcc->GetSampleTime()); 810 // The overscroll amount should be managed by the overscroll animation. 811 EXPECT_NE( 812 currentOverscrolledTransform._41, 813 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 814 ._41); 815 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 816 AsyncPanZoomController::eForEventHandling); 817 // Not yet started scrolling. 818 EXPECT_EQ(scrollOffset.y, offsetAfterPan.y); 819 EXPECT_EQ(scrollOffset.x, 0); 820 821 currentOverscrolledTransform = 822 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 823 824 // Send a long pan momentum. 825 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 826 ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time()); 827 EXPECT_TRUE(apzc->IsOverscrolled()); 828 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 829 // The overscroll amount on X axis shouldn't be changed by this momentum pan. 830 EXPECT_EQ( 831 currentOverscrolledTransform._41, 832 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 833 ._41); 834 // Now it started scrolling vertically. 835 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 836 AsyncPanZoomController::eForEventHandling); 837 EXPECT_GT(scrollOffset.y, 0); 838 EXPECT_EQ(scrollOffset.x, 0); 839 840 currentOverscrolledTransform = 841 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 842 mcc->AdvanceByMillis(5); 843 apzc->AdvanceAnimations(mcc->GetSampleTime()); 844 // The overscroll on X axis keeps being managed by the overscroll animation. 845 EXPECT_NE( 846 currentOverscrolledTransform._41, 847 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 848 ._41); 849 // The scroll offset on Y axis shouldn't be changed by the overscroll 850 // animation. 851 EXPECT_EQ(scrollOffset.y, apzc->GetCurrentAsyncScrollOffset( 852 AsyncPanZoomController::eForEventHandling) 853 .y); 854 855 currentOverscrolledTransform = 856 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 857 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 858 AsyncPanZoomController::eForEventHandling); 859 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 860 ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time()); 861 EXPECT_TRUE(apzc->IsOverscrolled()); 862 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 863 // The overscroll amount on X axis shouldn't be changed by this momentum pan. 864 EXPECT_EQ( 865 currentOverscrolledTransform._41, 866 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 867 ._41); 868 // Scrolling keeps going by momentum. 869 EXPECT_GT(apzc->GetCurrentAsyncScrollOffset( 870 AsyncPanZoomController::eForEventHandling) 871 .y, 872 scrollOffset.y); 873 874 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 875 AsyncPanZoomController::eForEventHandling); 876 mcc->AdvanceByMillis(5); 877 apzc->AdvanceAnimations(mcc->GetSampleTime()); 878 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 879 ScreenIntPoint(50, 80), ScreenPoint(0, 10), mcc->Time()); 880 EXPECT_TRUE(apzc->IsOverscrolled()); 881 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 882 // Scrolling keeps going by momentum. 883 EXPECT_GT(apzc->GetCurrentAsyncScrollOffset( 884 AsyncPanZoomController::eForEventHandling) 885 .y, 886 scrollOffset.y); 887 888 currentOverscrolledTransform = 889 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 890 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 891 AsyncPanZoomController::eForEventHandling); 892 mcc->AdvanceByMillis(5); 893 apzc->AdvanceAnimations(mcc->GetSampleTime()); 894 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 895 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 896 EXPECT_TRUE(apzc->IsOverscrolled()); 897 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 898 // This momentum event doesn't change the scroll offset since its 899 // displacement is zero. 900 EXPECT_EQ(apzc->GetCurrentAsyncScrollOffset( 901 AsyncPanZoomController::eForEventHandling) 902 .y, 903 scrollOffset.y); 904 905 // Check that we recover from the horizontal overscroll via the animation. 906 ParentLayerPoint expectedScrollOffset(0, scrollOffset.y); 907 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 908 } 909 #endif 910 911 #ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android 912 // Similar to above 913 // HorizontalOverscrollAnimationWithVerticalPanMomentumScrolling, 914 // but having OverscrollAnimation on both axes initially. 915 TEST_F(APZCOverscrollTester, 916 BothAxesOverscrollAnimationWithPanMomentumScrolling) { 917 // TODO: This test currently requires gestures that cause movement on both 918 // axis, which excludes DOMINANT_AXIS locking mode. The gestures should be 919 // broken up into multiple gestures to cause the overscroll. 920 SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2); 921 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 922 923 ScrollMetadata metadata; 924 FrameMetrics& metrics = metadata.GetMetrics(); 925 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 926 metrics.SetScrollableRect(CSSRect(0, 0, 1000, 5000)); 927 apzc->SetFrameMetrics(metrics); 928 929 // Try to overscroll up and left with pan gestures. 930 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 931 ScreenPoint(-2, -2), mcc->Time()); 932 mcc->AdvanceByMillis(5); 933 apzc->AdvanceAnimations(mcc->GetSampleTime()); 934 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 935 ScreenPoint(-10, -10), mcc->Time()); 936 mcc->AdvanceByMillis(5); 937 apzc->AdvanceAnimations(mcc->GetSampleTime()); 938 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 939 ScreenPoint(-2, -2), mcc->Time()); 940 mcc->AdvanceByMillis(5); 941 apzc->AdvanceAnimations(mcc->GetSampleTime()); 942 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 943 ScreenPoint(0, 0), mcc->Time()); 944 945 // Make sure we've started an overscroll animation. 946 EXPECT_TRUE(apzc->IsOverscrolled()); 947 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 948 AsyncTransformComponentMatrix initialOverscrolledTransform = 949 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 950 951 // Send lengthy downward momentums to make sure the overscroll animation 952 // doesn't clobber the momentums scrolling. 953 mcc->AdvanceByMillis(5); 954 apzc->AdvanceAnimations(mcc->GetSampleTime()); 955 // The overscroll amount has started being managed by the overscroll 956 // animation. 957 AsyncTransformComponentMatrix currentOverscrolledTransform = 958 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 959 EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41); 960 EXPECT_NE(initialOverscrolledTransform._42, currentOverscrolledTransform._42); 961 962 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 963 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 964 EXPECT_TRUE(apzc->IsOverscrolled()); 965 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 966 // The overscroll amount on both axes shouldn't be changed by this pan 967 // momentum start event since the displacement is zero. 968 EXPECT_EQ( 969 currentOverscrolledTransform._41, 970 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 971 ._41); 972 EXPECT_EQ( 973 currentOverscrolledTransform._42, 974 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 975 ._42); 976 977 mcc->AdvanceByMillis(5); 978 apzc->AdvanceAnimations(mcc->GetSampleTime()); 979 // Still being managed by the overscroll animation. 980 EXPECT_NE( 981 currentOverscrolledTransform._41, 982 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 983 ._41); 984 EXPECT_NE( 985 currentOverscrolledTransform._42, 986 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 987 ._42); 988 989 currentOverscrolledTransform = 990 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 991 // Send a long pan momentum. 992 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 993 ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time()); 994 EXPECT_TRUE(apzc->IsOverscrolled()); 995 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 996 // The overscroll amount on X axis shouldn't be changed by this momentum pan. 997 EXPECT_EQ( 998 currentOverscrolledTransform._41, 999 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1000 ._41); 1001 // But now the overscroll amount on Y axis should be changed by this momentum 1002 // pan. 1003 EXPECT_NE( 1004 currentOverscrolledTransform._42, 1005 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1006 ._42); 1007 // Actually it's no longer overscrolled. 1008 EXPECT_EQ( 1009 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1010 ._42, 1011 0); 1012 1013 ParentLayerPoint currentScrollOffset = apzc->GetCurrentAsyncScrollOffset( 1014 AsyncPanZoomController::eForEventHandling); 1015 // Now it started scrolling. 1016 EXPECT_GT(currentScrollOffset.y, 0); 1017 1018 currentOverscrolledTransform = 1019 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1020 mcc->AdvanceByMillis(5); 1021 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1022 // The overscroll on X axis keeps being managed by the overscroll animation. 1023 EXPECT_NE( 1024 currentOverscrolledTransform._41, 1025 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1026 ._41); 1027 // But the overscroll on Y axis is no longer affected by the overscroll 1028 // animation. 1029 EXPECT_EQ( 1030 currentOverscrolledTransform._42, 1031 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1032 ._42); 1033 // The scroll offset on Y axis shouldn't be changed by the overscroll 1034 // animation. 1035 EXPECT_EQ(currentScrollOffset.y, 1036 apzc->GetCurrentAsyncScrollOffset( 1037 AsyncPanZoomController::eForEventHandling) 1038 .y); 1039 1040 currentOverscrolledTransform = 1041 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1042 currentScrollOffset = apzc->GetCurrentAsyncScrollOffset( 1043 AsyncPanZoomController::eForEventHandling); 1044 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 1045 ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time()); 1046 EXPECT_TRUE(apzc->IsOverscrolled()); 1047 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1048 // The overscroll amount on X axis shouldn't be changed by this momentum pan. 1049 EXPECT_EQ( 1050 currentOverscrolledTransform._41, 1051 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1052 ._41); 1053 // Keeping no overscrolling on Y axis. 1054 EXPECT_EQ( 1055 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1056 ._42, 1057 0); 1058 // Scrolling keeps going by momentum. 1059 EXPECT_GT(apzc->GetCurrentAsyncScrollOffset( 1060 AsyncPanZoomController::eForEventHandling) 1061 .y, 1062 currentScrollOffset.y); 1063 1064 currentScrollOffset = apzc->GetCurrentAsyncScrollOffset( 1065 AsyncPanZoomController::eForEventHandling); 1066 mcc->AdvanceByMillis(5); 1067 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1068 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 1069 ScreenIntPoint(50, 80), ScreenPoint(0, 10), mcc->Time()); 1070 EXPECT_TRUE(apzc->IsOverscrolled()); 1071 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1072 // Keeping no overscrolling on Y axis. 1073 EXPECT_EQ( 1074 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1075 ._42, 1076 0); 1077 // Scrolling keeps going by momentum. 1078 EXPECT_GT(apzc->GetCurrentAsyncScrollOffset( 1079 AsyncPanZoomController::eForEventHandling) 1080 .y, 1081 currentScrollOffset.y); 1082 1083 currentOverscrolledTransform = 1084 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1085 currentScrollOffset = apzc->GetCurrentAsyncScrollOffset( 1086 AsyncPanZoomController::eForEventHandling); 1087 mcc->AdvanceByMillis(5); 1088 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1089 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 1090 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 1091 EXPECT_TRUE(apzc->IsOverscrolled()); 1092 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1093 // Keeping no overscrolling on Y axis. 1094 EXPECT_EQ( 1095 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1096 ._42, 1097 0); 1098 // This momentum event doesn't change the scroll offset since its 1099 // displacement is zero. 1100 EXPECT_EQ(apzc->GetCurrentAsyncScrollOffset( 1101 AsyncPanZoomController::eForEventHandling) 1102 .y, 1103 currentScrollOffset.y); 1104 1105 // Check that we recover from the horizontal overscroll via the animation. 1106 ParentLayerPoint expectedScrollOffset(0, currentScrollOffset.y); 1107 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 1108 } 1109 #endif 1110 1111 #ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android 1112 // This is another variant of 1113 // HorizontalOverscrollAnimationWithVerticalPanMomentumScrolling. In this test, 1114 // after a horizontal overscroll animation started, upwards pan moments happen, 1115 // thus there should be a new vertical overscroll animation in addition to 1116 // the horizontal one. 1117 TEST_F( 1118 APZCOverscrollTester, 1119 VerticalOverscrollAnimationInAdditionToExistingHorizontalOverscrollAnimation) { 1120 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1121 1122 ScrollMetadata metadata; 1123 FrameMetrics& metrics = metadata.GetMetrics(); 1124 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1125 metrics.SetScrollableRect(CSSRect(0, 0, 1000, 5000)); 1126 // Scrolls the content 50px down. 1127 metrics.SetVisualScrollOffset(CSSPoint(0, 50)); 1128 apzc->SetFrameMetrics(metrics); 1129 1130 // Try to overscroll left with pan gestures. 1131 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 1132 ScreenPoint(-2, 0), mcc->Time()); 1133 mcc->AdvanceByMillis(5); 1134 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1135 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 1136 ScreenPoint(-10, 0), mcc->Time()); 1137 mcc->AdvanceByMillis(5); 1138 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1139 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 1140 ScreenPoint(-2, 0), mcc->Time()); 1141 mcc->AdvanceByMillis(5); 1142 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1143 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 1144 ScreenPoint(0, 0), mcc->Time()); 1145 1146 // Make sure we've started an overscroll animation. 1147 EXPECT_TRUE(apzc->IsOverscrolled()); 1148 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1149 AsyncTransformComponentMatrix initialOverscrolledTransform = 1150 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1151 1152 // Send lengthy __upward__ momentums to make sure the overscroll animation 1153 // doesn't clobber the momentums scrolling. 1154 mcc->AdvanceByMillis(5); 1155 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1156 // The overscroll amount on X axis has started being managed by the overscroll 1157 // animation. 1158 AsyncTransformComponentMatrix currentOverscrolledTransform = 1159 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1160 EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41); 1161 // There is no overscroll on Y axis. 1162 EXPECT_EQ( 1163 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1164 ._42, 1165 0); 1166 ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset( 1167 AsyncPanZoomController::eForEventHandling); 1168 // The scroll offset shouldn't be changed by the overscroll animation. 1169 EXPECT_EQ(scrollOffset.y, 50); 1170 1171 // Simple gesture on the Y axis to ensure that we can send a vertical 1172 // momentum scroll 1173 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 1174 ScreenPoint(0, -2), mcc->Time()); 1175 mcc->AdvanceByMillis(5); 1176 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1177 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80), 1178 ScreenPoint(0, 2), mcc->Time()); 1179 mcc->AdvanceByMillis(5); 1180 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1181 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80), 1182 ScreenPoint(0, 0), mcc->Time()); 1183 1184 ParentLayerPoint offsetAfterPan = apzc->GetCurrentAsyncScrollOffset( 1185 AsyncPanZoomController::eForEventHandling); 1186 1187 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc, 1188 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 1189 EXPECT_TRUE(apzc->IsOverscrolled()); 1190 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1191 // The overscroll amount on both axes shouldn't be changed by this pan 1192 // momentum start event since the displacement is zero. 1193 EXPECT_EQ( 1194 currentOverscrolledTransform._41, 1195 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1196 ._41); 1197 EXPECT_EQ( 1198 currentOverscrolledTransform._42, 1199 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1200 ._42); 1201 1202 mcc->AdvanceByMillis(5); 1203 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1204 // The overscroll amount should be managed by the overscroll animation. 1205 EXPECT_NE( 1206 currentOverscrolledTransform._41, 1207 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1208 ._41); 1209 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 1210 AsyncPanZoomController::eForEventHandling); 1211 // Not yet started scrolling. 1212 EXPECT_EQ(scrollOffset.y, offsetAfterPan.y); 1213 EXPECT_EQ(scrollOffset.x, 0); 1214 1215 currentOverscrolledTransform = 1216 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1217 1218 // Send a long pan momentum. 1219 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 1220 ScreenIntPoint(50, 80), ScreenPoint(0, -200), mcc->Time()); 1221 EXPECT_TRUE(apzc->IsOverscrolled()); 1222 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1223 // The overscroll amount on X axis shouldn't be changed by this momentum pan. 1224 EXPECT_EQ( 1225 currentOverscrolledTransform._41, 1226 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1227 ._41); 1228 // Now it started scrolling vertically. 1229 scrollOffset = apzc->GetCurrentAsyncScrollOffset( 1230 AsyncPanZoomController::eForEventHandling); 1231 EXPECT_EQ(scrollOffset.y, 0); 1232 EXPECT_EQ(scrollOffset.x, 0); 1233 // Actually it's also vertically overscrolled. 1234 EXPECT_GT( 1235 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1236 ._42, 1237 0); 1238 1239 currentOverscrolledTransform = 1240 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1241 mcc->AdvanceByMillis(5); 1242 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1243 // The overscroll on X axis keeps being managed by the overscroll animation. 1244 EXPECT_NE( 1245 currentOverscrolledTransform._41, 1246 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1247 ._41); 1248 // The overscroll on Y Axis hasn't been changed by the overscroll animation at 1249 // this moment, sine the last displacement was consumed in the last pan 1250 // momentum. 1251 EXPECT_EQ( 1252 currentOverscrolledTransform._42, 1253 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1254 ._42); 1255 1256 currentOverscrolledTransform = 1257 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1258 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 1259 ScreenIntPoint(50, 80), ScreenPoint(0, -100), mcc->Time()); 1260 EXPECT_TRUE(apzc->IsOverscrolled()); 1261 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1262 // The overscroll amount on X axis shouldn't be changed by this momentum pan. 1263 EXPECT_EQ( 1264 currentOverscrolledTransform._41, 1265 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1266 ._41); 1267 // Now the overscroll amount on Y axis shouldn't be changed by this momentum 1268 // pan either. 1269 EXPECT_EQ( 1270 currentOverscrolledTransform._42, 1271 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1272 ._42); 1273 1274 currentOverscrolledTransform = 1275 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1276 mcc->AdvanceByMillis(5); 1277 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1278 EXPECT_NE( 1279 currentOverscrolledTransform._41, 1280 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1281 ._41); 1282 // And now the overscroll on Y Axis should be also managed by the overscroll 1283 // animation. 1284 EXPECT_NE( 1285 currentOverscrolledTransform._42, 1286 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1287 ._42); 1288 1289 currentOverscrolledTransform = 1290 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1291 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc, 1292 ScreenIntPoint(50, 80), ScreenPoint(0, -10), mcc->Time()); 1293 EXPECT_TRUE(apzc->IsOverscrolled()); 1294 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1295 // The overscroll amount on both axes shouldn't be changed by momentum event. 1296 EXPECT_EQ( 1297 currentOverscrolledTransform._41, 1298 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1299 ._41); 1300 EXPECT_EQ( 1301 currentOverscrolledTransform._42, 1302 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling) 1303 ._42); 1304 1305 currentOverscrolledTransform = 1306 apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling); 1307 mcc->AdvanceByMillis(5); 1308 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1309 PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc, 1310 ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time()); 1311 EXPECT_TRUE(apzc->IsOverscrolled()); 1312 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1313 1314 // Check that we recover from the horizontal overscroll via the animation. 1315 ParentLayerPoint expectedScrollOffset(0, 0); 1316 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 1317 } 1318 #endif 1319 1320 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 1321 TEST_F(APZCOverscrollTester, OverscrollByPanGesturesInterruptedByReflowZoom) { 1322 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1323 SCOPED_GFX_PREF_INT("mousewheel.with_control.action", 3); // reflow zoom. 1324 1325 // A sanity check that pan gestures with ctrl modifier will not be handled by 1326 // APZ. 1327 PanGestureInput panInput(PanGestureInput::PANGESTURE_START, mcc->Time(), 1328 ScreenIntPoint(5, 5), ScreenPoint(0, -2), 1329 MODIFIER_CONTROL); 1330 WidgetWheelEvent wheelEvent = panInput.ToWidgetEvent(nullptr); 1331 EXPECT_FALSE(APZInputBridge::ActionForWheelEvent(&wheelEvent).isSome()); 1332 1333 ScrollableLayerGuid rootGuid = CreateSimpleRootScrollableForWebRender(); 1334 RefPtr<AsyncPanZoomController> apzc = 1335 tm->GetTargetAPZC(rootGuid.mLayersId, rootGuid.mScrollId); 1336 1337 PanGesture(PanGestureInput::PANGESTURE_START, tm, ScreenIntPoint(50, 80), 1338 ScreenPoint(0, -2), mcc->Time()); 1339 mcc->AdvanceByMillis(5); 1340 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1341 PanGesture(PanGestureInput::PANGESTURE_PAN, tm, ScreenIntPoint(50, 80), 1342 ScreenPoint(0, -10), mcc->Time()); 1343 mcc->AdvanceByMillis(5); 1344 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1345 1346 // Make sure overscrolling has started. 1347 EXPECT_TRUE(apzc->IsOverscrolled()); 1348 1349 // Press ctrl until PANGESTURE_END. 1350 PanGestureWithModifiers(PanGestureInput::PANGESTURE_PAN, MODIFIER_CONTROL, tm, 1351 ScreenIntPoint(50, 80), ScreenPoint(0, -2), 1352 mcc->Time()); 1353 mcc->AdvanceByMillis(5); 1354 apzc->AdvanceAnimations(mcc->GetSampleTime()); 1355 // At this moment (i.e. PANGESTURE_PAN), still in overscrolling state. 1356 EXPECT_TRUE(apzc->IsOverscrolled()); 1357 1358 PanGestureWithModifiers(PanGestureInput::PANGESTURE_END, MODIFIER_CONTROL, tm, 1359 ScreenIntPoint(50, 80), ScreenPoint(0, 0), 1360 mcc->Time()); 1361 // The overscrolling state should have been restored. 1362 EXPECT_TRUE(!apzc->IsOverscrolled()); 1363 } 1364 #endif 1365 1366 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1367 TEST_F(APZCOverscrollTester, SmoothTransitionFromPanToAnimation) { 1368 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1369 1370 ScrollMetadata metadata; 1371 FrameMetrics& metrics = metadata.GetMetrics(); 1372 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1373 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1374 // Start scrolled down to y=500px. 1375 metrics.SetVisualScrollOffset(CSSPoint(0, 500)); 1376 apzc->SetFrameMetrics(metrics); 1377 1378 int frameLength = 10; // milliseconds; 10 to keep the math simple 1379 float panVelocity = 10; // pixels per millisecond 1380 int panPixelsPerFrame = frameLength * panVelocity; // 100 pixels per frame 1381 1382 ScreenIntPoint panPoint(50, 50); 1383 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1384 ScreenPoint(0, -1), mcc->Time()); 1385 // Pan up for 6 frames at 100 pixels per frame. This should reduce 1386 // the vertical scroll offset from 500 to 0, and get us into overscroll. 1387 for (int i = 0; i < 6; ++i) { 1388 mcc->AdvanceByMillis(frameLength); 1389 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1390 ScreenPoint(0, -panPixelsPerFrame), mcc->Time()); 1391 } 1392 EXPECT_TRUE(apzc->IsOverscrolled()); 1393 1394 // Pan further into overscroll at the same input velocity, enough 1395 // for the frames while we are in overscroll to dominate the computation 1396 // in the velocity tracker. 1397 // Importantly, while the input velocity is still 100 pixels per frame, 1398 // in the overscrolled state the page only visual moves by at most 8 pixels 1399 // per frame. 1400 int frames = StaticPrefs::apz_velocity_relevance_time_ms() / frameLength; 1401 for (int i = 0; i < frames; ++i) { 1402 mcc->AdvanceByMillis(frameLength); 1403 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1404 ScreenPoint(0, -panPixelsPerFrame), mcc->Time()); 1405 } 1406 EXPECT_TRUE(apzc->IsOverscrolled()); 1407 1408 // End the pan, allowing an overscroll animation to start. 1409 mcc->AdvanceByMillis(frameLength); 1410 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 1411 mcc->Time()); 1412 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1413 1414 // Check that the velocity reflects the actual movement (no more than 8 1415 // pixels/frame ==> 0.8 pixels per millisecond), not the input velocity 1416 // (100 pixels/frame ==> 10 pixels per millisecond). This ensures that 1417 // the transition from the pan to the animation appears smooth. 1418 // (Note: velocities are negative since they are upwards.) 1419 EXPECT_LT(apzc->GetVelocityVector().y, 0); 1420 EXPECT_GT(apzc->GetVelocityVector().y, -0.8); 1421 } 1422 #endif 1423 1424 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1425 TEST_F(APZCOverscrollTester, NoOverscrollForMousewheel) { 1426 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1427 1428 ScrollMetadata metadata; 1429 FrameMetrics& metrics = metadata.GetMetrics(); 1430 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1431 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1432 // Start scrolled down just a few pixels from the top. 1433 metrics.SetVisualScrollOffset(CSSPoint(0, 3)); 1434 // Set line and page scroll amounts. Otherwise, even though Wheel() uses 1435 // SCROLLDELTA_PIXEL, the wheel handling code will get confused by things 1436 // like the "don't scroll more than one page" check. 1437 metadata.SetPageScrollAmount(LayoutDeviceIntSize(50, 100)); 1438 metadata.SetLineScrollAmount(LayoutDeviceIntSize(5, 10)); 1439 apzc->SetScrollMetadata(metadata); 1440 1441 // Send a wheel with enough delta to scrollto y=0 *and* overscroll. 1442 Wheel(apzc, ScreenIntPoint(10, 10), ScreenPoint(0, -10), mcc->Time()); 1443 1444 // Check that we did not actually go into overscroll. 1445 EXPECT_FALSE(apzc->IsOverscrolled()); 1446 } 1447 #endif 1448 1449 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1450 TEST_F(APZCOverscrollTester, ClickWhileOverscrolled) { 1451 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1452 1453 ScrollMetadata metadata; 1454 FrameMetrics& metrics = metadata.GetMetrics(); 1455 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1456 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1457 metrics.SetVisualScrollOffset(CSSPoint(0, 0)); 1458 apzc->SetFrameMetrics(metrics); 1459 1460 // Pan into overscroll at the top. 1461 ScreenIntPoint panPoint(50, 50); 1462 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1463 ScreenPoint(0, -1), mcc->Time()); 1464 mcc->AdvanceByMillis(10); 1465 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1466 ScreenPoint(0, -100), mcc->Time()); 1467 EXPECT_TRUE(apzc->IsOverscrolled()); 1468 EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top 1469 1470 // End the pan. This should start an overscroll animation. 1471 mcc->AdvanceByMillis(10); 1472 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 1473 mcc->Time()); 1474 EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top 1475 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1476 1477 // Send a mouse-down. This should interrupt the animation but not relieve 1478 // overscroll yet. 1479 ParentLayerPoint overscrollBefore = apzc->GetOverscrollAmount(); 1480 MouseDown(apzc, panPoint, mcc->Time()); 1481 EXPECT_FALSE(apzc->IsOverscrollAnimationRunning()); 1482 EXPECT_EQ(overscrollBefore, apzc->GetOverscrollAmount()); 1483 1484 // Send a mouse-up. This should start an overscroll animation again. 1485 MouseUp(apzc, panPoint, mcc->Time()); 1486 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 1487 1488 SampleAnimationUntilRecoveredFromOverscroll(ParentLayerPoint(0, 0)); 1489 } 1490 #endif 1491 1492 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1493 TEST_F(APZCOverscrollTester, DynamicallyLoadingContent) { 1494 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1495 1496 ScrollMetadata metadata; 1497 FrameMetrics& metrics = metadata.GetMetrics(); 1498 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1499 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1500 metrics.SetVisualScrollOffset(CSSPoint(0, 0)); 1501 apzc->SetFrameMetrics(metrics); 1502 1503 // Pan to the bottom of the page, and further, into overscroll. 1504 ScreenIntPoint panPoint(50, 50); 1505 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1506 ScreenPoint(0, 1), mcc->Time()); 1507 for (int i = 0; i < 12; ++i) { 1508 mcc->AdvanceByMillis(10); 1509 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1510 ScreenPoint(0, 100), mcc->Time()); 1511 } 1512 EXPECT_TRUE(apzc->IsOverscrolled()); 1513 EXPECT_TRUE(apzc->GetOverscrollAmount().y > 0); // overscrolled at bottom 1514 1515 // Grow the scrollable rect at the bottom, simulating the page loading content 1516 // dynamically. 1517 CSSRect scrollableRect = metrics.GetScrollableRect(); 1518 scrollableRect.height += 500; 1519 metrics.SetScrollableRect(scrollableRect); 1520 apzc->NotifyLayersUpdated( 1521 metadata, 1522 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 1523 1524 // Check that the modified scrollable rect cleared the overscroll. 1525 EXPECT_FALSE(apzc->IsOverscrolled()); 1526 1527 // Pan back up to the top, and further, into overscroll. 1528 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1529 ScreenPoint(0, -1), mcc->Time()); 1530 for (int i = 0; i < 12; ++i) { 1531 mcc->AdvanceByMillis(10); 1532 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1533 ScreenPoint(0, -100), mcc->Time()); 1534 } 1535 EXPECT_TRUE(apzc->IsOverscrolled()); 1536 ParentLayerPoint overscrollAmount = apzc->GetOverscrollAmount(); 1537 EXPECT_TRUE(overscrollAmount.y < 0); // overscrolled at top 1538 1539 // Grow the scrollable rect at the bottom again. 1540 scrollableRect = metrics.GetScrollableRect(); 1541 scrollableRect.height += 500; 1542 metrics.SetScrollableRect(scrollableRect); 1543 apzc->NotifyLayersUpdated( 1544 metadata, 1545 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 1546 1547 // Check that the modified scrollable rect did NOT clear overscroll at the 1548 // top. 1549 EXPECT_TRUE(apzc->IsOverscrolled()); 1550 EXPECT_EQ(overscrollAmount, 1551 apzc->GetOverscrollAmount()); // overscroll did not change at all 1552 } 1553 #endif 1554 1555 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1556 TEST_F(APZCOverscrollTester, SmallAmountOfOverscroll) { 1557 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1558 1559 ScrollMetadata metadata; 1560 FrameMetrics& metrics = metadata.GetMetrics(); 1561 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1562 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1563 1564 // Do vertical overscroll first. 1565 ScreenIntPoint panPoint(50, 50); 1566 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1567 ScreenPoint(0, -10), mcc->Time()); 1568 mcc->AdvanceByMillis(10); 1569 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1570 ScreenPoint(0, -10), mcc->Time()); 1571 mcc->AdvanceByMillis(10); 1572 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 1573 mcc->Time()); 1574 mcc->AdvanceByMillis(10); 1575 1576 // Then do small horizontal overscroll which will be considered as "finished" 1577 // by our overscroll animation physics model. 1578 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1579 ScreenPoint(-0.1, 0), mcc->Time()); 1580 mcc->AdvanceByMillis(10); 1581 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1582 ScreenPoint(-0.2, 0), mcc->Time()); 1583 mcc->AdvanceByMillis(10); 1584 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 1585 mcc->Time()); 1586 mcc->AdvanceByMillis(10); 1587 1588 EXPECT_TRUE(apzc->IsOverscrolled()); 1589 EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top 1590 EXPECT_TRUE(apzc->GetOverscrollAmount().x < 0); // and overscrolled at left 1591 1592 // Then do vertical scroll. 1593 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 1594 ScreenPoint(0, 10), mcc->Time()); 1595 mcc->AdvanceByMillis(10); 1596 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 1597 ScreenPoint(0, 100), mcc->Time()); 1598 mcc->AdvanceByMillis(10); 1599 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 1600 mcc->Time()); 1601 1602 ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset( 1603 AsyncPanZoomController::eForEventHandling); 1604 EXPECT_GT(scrollOffset.y, 0); // Make sure the vertical scroll offset is 1605 // greater than zero. 1606 1607 // The small horizontal overscroll amount should be restored to zero. 1608 ParentLayerPoint expectedScrollOffset(0, scrollOffset.y); 1609 SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); 1610 } 1611 #endif 1612 1613 #ifdef MOZ_WIDGET_ANDROID 1614 TEST_F(APZCOverscrollTester, StretchUpDown_Bug1892177) { 1615 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1616 1617 ScrollMetadata metadata; 1618 FrameMetrics& metrics = metadata.GetMetrics(); 1619 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1620 // Composition bounds show all of the horizontal space of that scrollable rect 1621 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1622 apzc->SetFrameMetrics(metrics); 1623 1624 MockFunction<void(std::string checkPointName)> checkScroll; 1625 { 1626 // Motion of the scrollable screen: 1627 // - Up to the vertical y limit of the page. 1628 // - Right 1629 InSequence s; 1630 EXPECT_CALL(checkScroll, Call("Touch Scroll Diagonally Upwards Start")); 1631 1632 // Even though the touch gesture includes horizontal movement, 1633 // do not show a horizontal overscroll effect because the page 1634 // is not scrollable horizontally. 1635 EXPECT_CALL(*mcc, UpdateOverscrollOffset(_, 0, _, _)).Times(AtLeast(1)); 1636 1637 EXPECT_CALL(checkScroll, Call("Touch Scroll Diagonally Upwards End")); 1638 } 1639 1640 checkScroll.Call("Touch Scroll Diagonally Upwards Start"); 1641 // Scroll up 1642 ScreenIntPoint startPoint(10, 50); 1643 ScreenIntPoint endPoint(20, 100); 1644 Pan(apzc, startPoint, endPoint, PanOptions::KeepFingerDown); 1645 1646 checkScroll.Call("Touch Scroll Diagonally Upwards End"); 1647 1648 EXPECT_TRUE(apzc->IsOverscrolled()); 1649 } 1650 #endif 1651 1652 #ifdef MOZ_WIDGET_ANDROID // Only applies to WidgetOverscrollEffect 1653 TEST_F(APZCOverscrollTester, StuckInOverscroll_Bug1786452) { 1654 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1655 1656 ScrollMetadata metadata; 1657 FrameMetrics& metrics = metadata.GetMetrics(); 1658 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 1659 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 1660 1661 // Over the course of the test, expect one or more calls to 1662 // UpdateOverscrollOffset(), followed by a call to UpdateOverscrollVelocity(). 1663 // The latter ensures the widget has a chance to end its overscroll effect. 1664 InSequence s; 1665 EXPECT_CALL(*mcc, UpdateOverscrollOffset(_, _, _, _)).Times(AtLeast(1)); 1666 EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(1); 1667 1668 // Pan into overscroll, keeping the finger down 1669 ScreenIntPoint startPoint(10, 500); 1670 ScreenIntPoint endPoint(10, 10); 1671 Pan(apzc, startPoint, endPoint, PanOptions::KeepFingerDown); 1672 EXPECT_TRUE(apzc->IsOverscrolled()); 1673 1674 // Linger a while to cause the velocity to drop to very low or zero 1675 mcc->AdvanceByMillis(100); 1676 TouchMove(apzc, endPoint, mcc->Time()); 1677 EXPECT_LT(apzc->GetVelocityVector().Length(), 1678 StaticPrefs::apz_fling_min_velocity_threshold()); 1679 EXPECT_TRUE(apzc->IsOverscrolled()); 1680 1681 // Lift the finger 1682 mcc->AdvanceByMillis(20); 1683 TouchUp(apzc, endPoint, mcc->Time()); 1684 EXPECT_FALSE(apzc->IsOverscrolled()); 1685 } 1686 #endif 1687 1688 class APZCOverscrollTesterMock : public APZCTreeManagerTester { 1689 public: 1690 APZCOverscrollTesterMock() { CreateMockHitTester(); } 1691 1692 UniquePtr<ScopedLayerTreeRegistration> registration; 1693 TestAsyncPanZoomController* rootApzc; 1694 }; 1695 1696 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 1697 TEST_F(APZCOverscrollTesterMock, OverscrollHandoff) { 1698 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1699 1700 const char* treeShape = "x(x)"; 1701 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), 1702 LayerIntRect(0, 0, 100, 50)}; 1703 CreateScrollData(treeShape, layerVisibleRect); 1704 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1705 CSSRect(0, 0, 200, 200)); 1706 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 1707 // same size as the visible region so that 1708 // the container is not scrollable in any directions 1709 // actually. This is simulating overflow: hidden 1710 // iframe document in Fission, though we don't set 1711 // a different layers id. 1712 CSSRect(0, 0, 100, 50)); 1713 1714 SetScrollHandoff(layers[1], root); 1715 1716 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 1717 UpdateHitTestingTree(); 1718 rootApzc = ApzcOf(root); 1719 rootApzc->GetFrameMetrics().SetIsRootContent(true); 1720 1721 // A pan gesture on the child scroller (which is not scrollable though). 1722 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1723 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20), 1724 ScreenPoint(0, -2), mcc->Time()); 1725 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1726 } 1727 #endif 1728 1729 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 1730 TEST_F(APZCOverscrollTesterMock, VerticalOverscrollHandoffToScrollableRoot) { 1731 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1732 1733 // Create a layer tree having two vertical scrollable layers. 1734 const char* treeShape = "x(x)"; 1735 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), 1736 LayerIntRect(0, 0, 100, 50)}; 1737 CreateScrollData(treeShape, layerVisibleRect); 1738 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1739 CSSRect(0, 0, 100, 200)); 1740 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 1741 CSSRect(0, 0, 100, 200)); 1742 1743 SetScrollHandoff(layers[1], root); 1744 1745 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 1746 UpdateHitTestingTree(); 1747 rootApzc = ApzcOf(root); 1748 rootApzc->GetFrameMetrics().SetIsRootContent(true); 1749 1750 // A vertical pan gesture on the child scroller which will be handed off to 1751 // the root APZC. 1752 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1753 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20), 1754 ScreenPoint(0, -2), mcc->Time()); 1755 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1756 EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled()); 1757 } 1758 #endif 1759 1760 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 1761 TEST_F(APZCOverscrollTesterMock, NoOverscrollHandoffToNonScrollableRoot) { 1762 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1763 1764 // Create a layer tree having non-scrollable root and a vertical scrollable 1765 // child. 1766 const char* treeShape = "x(x)"; 1767 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), 1768 LayerIntRect(0, 0, 100, 50)}; 1769 CreateScrollData(treeShape, layerVisibleRect); 1770 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1771 CSSRect(0, 0, 100, 100)); 1772 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 1773 CSSRect(0, 0, 100, 200)); 1774 1775 SetScrollHandoff(layers[1], root); 1776 1777 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 1778 UpdateHitTestingTree(); 1779 rootApzc = ApzcOf(root); 1780 rootApzc->GetFrameMetrics().SetIsRootContent(true); 1781 1782 // A vertical pan gesture on the child scroller which should not be handed 1783 // off the root APZC. 1784 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1785 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20), 1786 ScreenPoint(0, -2), mcc->Time()); 1787 EXPECT_FALSE(rootApzc->IsOverscrolled()); 1788 EXPECT_TRUE(ApzcOf(layers[1])->IsOverscrolled()); 1789 } 1790 #endif 1791 1792 #ifndef MOZ_WIDGET_ANDROID // Currently fails on Android 1793 TEST_F(APZCOverscrollTesterMock, NoOverscrollHandoffOrthogonalPanGesture) { 1794 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1795 1796 // Create a layer tree having horizontal scrollable root and a vertical 1797 // scrollable child. 1798 const char* treeShape = "x(x)"; 1799 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), 1800 LayerIntRect(0, 0, 100, 50)}; 1801 CreateScrollData(treeShape, layerVisibleRect); 1802 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1803 CSSRect(0, 0, 200, 100)); 1804 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 1805 CSSRect(0, 0, 100, 200)); 1806 1807 SetScrollHandoff(layers[1], root); 1808 1809 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 1810 UpdateHitTestingTree(); 1811 rootApzc = ApzcOf(root); 1812 rootApzc->GetFrameMetrics().SetIsRootContent(true); 1813 1814 // A vertical pan gesture on the child scroller which should not be handed 1815 // off the root APZC because the root APZC is not scrollable vertically. 1816 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1817 PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20), 1818 ScreenPoint(0, -2), mcc->Time()); 1819 EXPECT_FALSE(rootApzc->IsOverscrolled()); 1820 EXPECT_TRUE(ApzcOf(layers[1])->IsOverscrolled()); 1821 } 1822 #endif 1823 1824 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1825 TEST_F(APZCOverscrollTesterMock, 1826 RetriggerCancelledOverscrollAnimationByNewPanGesture) { 1827 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1828 1829 // Create a layer tree having vertical scrollable root and a horizontal 1830 // scrollable child. 1831 const char* treeShape = "x(x)"; 1832 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), 1833 LayerIntRect(0, 0, 100, 50)}; 1834 CreateScrollData(treeShape, layerVisibleRect); 1835 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1836 CSSRect(0, 0, 100, 200)); 1837 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 1838 CSSRect(0, 0, 200, 50)); 1839 1840 SetScrollHandoff(layers[1], root); 1841 1842 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 1843 UpdateHitTestingTree(); 1844 rootApzc = ApzcOf(root); 1845 rootApzc->GetFrameMetrics().SetIsRootContent(true); 1846 1847 ScreenIntPoint panPoint(50, 20); 1848 // A vertical pan gesture on the child scroller which should be handed off the 1849 // root APZC. 1850 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1851 PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint, 1852 ScreenPoint(0, -2), mcc->Time()); 1853 mcc->AdvanceByMillis(10); 1854 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1855 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 1856 ScreenPoint(0, -10), mcc->Time()); 1857 mcc->AdvanceByMillis(10); 1858 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1859 PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint, 1860 ScreenPoint(0, 0), mcc->Time()); 1861 1862 // The root APZC should be overscrolled and the child APZC should not be. 1863 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1864 EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled()); 1865 1866 mcc->AdvanceByMillis(10); 1867 1868 // Make sure the root APZC is still overscrolled. 1869 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1870 1871 // Start a new horizontal pan gesture on the child scroller which should be 1872 // handled by the child APZC now. 1873 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1874 APZEventResult result = PanGesture(PanGestureInput::PANGESTURE_START, manager, 1875 panPoint, ScreenPoint(-2, 0), mcc->Time()); 1876 // The above horizontal pan start event was flagged as "this event may trigger 1877 // swipe" and either the root scrollable frame or the horizontal child 1878 // scrollable frame is not scrollable in the pan start direction, thus the pan 1879 // start event run into the short circuit path for swipe-to-navigation in 1880 // InputQueue::ReceivePanGestureInput, which means it's waiting for the 1881 // content response, so we need to respond explicitly here. 1882 manager->ContentReceivedInputBlock(result.mInputBlockId, false); 1883 mcc->AdvanceByMillis(10); 1884 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1885 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 1886 ScreenPoint(-10, 0), mcc->Time()); 1887 mcc->AdvanceByMillis(10); 1888 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1889 PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint, 1890 ScreenPoint(0, 0), mcc->Time()); 1891 1892 // Now both APZCs should be overscrolled. 1893 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1894 EXPECT_TRUE(ApzcOf(layers[1])->IsOverscrolled()); 1895 1896 // Sample all animations until all of them have been finished. 1897 while (SampleAnimationsOnce()); 1898 1899 // After the animations finished, all overscrolled states should have been 1900 // restored. 1901 EXPECT_FALSE(rootApzc->IsOverscrolled()); 1902 EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled()); 1903 } 1904 #endif 1905 1906 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1907 TEST_F(APZCOverscrollTesterMock, RetriggeredOverscrollAnimationVelocity) { 1908 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1909 1910 // Setup two nested vertical scrollable frames. 1911 const char* treeShape = "x(x)"; 1912 LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100), 1913 LayerIntRect(0, 0, 100, 50)}; 1914 CreateScrollData(treeShape, layerVisibleRect); 1915 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1916 CSSRect(0, 0, 100, 200)); 1917 SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1, 1918 CSSRect(0, 0, 100, 200)); 1919 1920 SetScrollHandoff(layers[1], root); 1921 1922 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 1923 UpdateHitTestingTree(); 1924 rootApzc = ApzcOf(root); 1925 rootApzc->GetFrameMetrics().SetIsRootContent(true); 1926 1927 ScreenIntPoint panPoint(50, 20); 1928 // A vertical upward pan gesture on the child scroller which should be handed 1929 // off the root APZC. 1930 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1931 PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint, 1932 ScreenPoint(0, -2), mcc->Time()); 1933 mcc->AdvanceByMillis(10); 1934 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1935 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 1936 ScreenPoint(0, -10), mcc->Time()); 1937 mcc->AdvanceByMillis(10); 1938 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1939 PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint, 1940 ScreenPoint(0, 0), mcc->Time()); 1941 1942 // The root APZC should be overscrolled and the child APZC should not be. 1943 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1944 EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled()); 1945 1946 mcc->AdvanceByMillis(10); 1947 1948 // Make sure the root APZC is still overscrolled and there's an overscroll 1949 // animation. 1950 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1951 EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning()); 1952 1953 // And make sure the overscroll animation's velocity is a certain amount in 1954 // the upward direction. 1955 EXPECT_LT(rootApzc->GetVelocityVector().y, 0); 1956 1957 // Start a new downward pan gesture on the child scroller which 1958 // should be handled by the child APZC now. 1959 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1960 PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint, 1961 ScreenPoint(0, 2), mcc->Time()); 1962 mcc->AdvanceByMillis(10); 1963 // The new pan-start gesture stops the overscroll animation at this moment. 1964 EXPECT_TRUE(!rootApzc->IsOverscrollAnimationRunning()); 1965 1966 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1967 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 1968 ScreenPoint(0, 10), mcc->Time()); 1969 mcc->AdvanceByMillis(10); 1970 // There's no overscroll animation yet even if the root APZC is still 1971 // overscrolled. 1972 EXPECT_TRUE(!rootApzc->IsOverscrollAnimationRunning()); 1973 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1974 1975 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1); 1976 PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint, 1977 ScreenPoint(0, 10), mcc->Time()); 1978 1979 // Now an overscroll animation should have been triggered by the pan-end 1980 // gesture. 1981 EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning()); 1982 EXPECT_TRUE(rootApzc->IsOverscrolled()); 1983 // And the newly created overscroll animation's positions should never exceed 1984 // 0. 1985 while (SampleAnimationsOnce()) { 1986 EXPECT_LE(rootApzc->GetOverscrollAmount().y, 0); 1987 } 1988 } 1989 #endif 1990 1991 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 1992 TEST_F(APZCOverscrollTesterMock, OverscrollIntoPreventDefault) { 1993 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 1994 1995 const char* treeShape = "x"; 1996 LayerIntRect layerVisibleRects[] = {LayerIntRect(0, 0, 100, 100)}; 1997 CreateScrollData(treeShape, layerVisibleRects); 1998 SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID, 1999 CSSRect(0, 0, 100, 200)); 2000 2001 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 2002 UpdateHitTestingTree(); 2003 rootApzc = ApzcOf(root); 2004 2005 // Start a pan gesture a few pixels below the 20px DTC region. 2006 ScreenIntPoint cursorLocation(10, 25); 2007 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 2008 APZEventResult result = 2009 PanGesture(PanGestureInput::PANGESTURE_START, manager, cursorLocation, 2010 ScreenPoint(0, -2), mcc->Time()); 2011 2012 // At this point, we should be overscrolled. 2013 EXPECT_TRUE(rootApzc->IsOverscrolled()); 2014 2015 // Pan further, until the DTC region is under the cursor. 2016 // Note that, due to ApplyResistance(), we need a large input delta to cause a 2017 // visual transform enough to bridge the 5px to the DTC region. 2018 mcc->AdvanceByMillis(10); 2019 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 2020 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, cursorLocation, 2021 ScreenPoint(0, -100), mcc->Time()); 2022 2023 // At this point, we are still overscrolled. Record the overscroll amount. 2024 EXPECT_TRUE(rootApzc->IsOverscrolled()); 2025 float overscrollY = rootApzc->GetOverscrollAmount().y; 2026 2027 // Send a content response with preventDefault = true. 2028 manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid}); 2029 manager->ContentReceivedInputBlock(result.mInputBlockId, 2030 /*aPreventDefault=*/true); 2031 2032 // The content response has the effect of interrupting the input block 2033 // but no processing happens yet (as there are no events in the block). 2034 EXPECT_TRUE(rootApzc->IsOverscrolled()); 2035 EXPECT_EQ(overscrollY, rootApzc->GetOverscrollAmount().y); 2036 2037 // Send one more pan event. This starts a new, *unconfirmed* input block 2038 // (via the "transmogrify" codepath). 2039 mcc->AdvanceByMillis(10); 2040 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID, 2041 {CompositorHitTestFlags::eVisibleToHitTest, 2042 CompositorHitTestFlags::eIrregularArea}); 2043 result = PanGesture(PanGestureInput::PANGESTURE_PAN, manager, cursorLocation, 2044 ScreenPoint(0, -10), mcc->Time()); 2045 2046 // No overscroll occurs (the event is waiting in the queue for confirmation). 2047 EXPECT_TRUE(rootApzc->IsOverscrolled()); 2048 EXPECT_EQ(overscrollY, rootApzc->GetOverscrollAmount().y); 2049 2050 // preventDefault the new event as well 2051 manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid}); 2052 manager->ContentReceivedInputBlock(result.mInputBlockId, 2053 /*aPreventDefault=*/true); 2054 2055 // This should trigger clearing the overscrolling and resetting the state. 2056 EXPECT_FALSE(rootApzc->IsOverscrolled()); 2057 rootApzc->AssertStateIsReset(); 2058 2059 // If there are momentum events after this point, they should not cause 2060 // further scrolling or overscorll. 2061 mcc->AdvanceByMillis(10); 2062 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 2063 result = PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager, 2064 cursorLocation, ScreenPoint(0, -100), mcc->Time()); 2065 mcc->AdvanceByMillis(10); 2066 QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID); 2067 result = PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager, 2068 cursorLocation, ScreenPoint(0, -100), mcc->Time()); 2069 EXPECT_FALSE(rootApzc->IsOverscrolled()); 2070 EXPECT_EQ(rootApzc->GetFrameMetrics().GetVisualScrollOffset(), 2071 CSSPoint(0, 0)); 2072 } 2073 #endif 2074 2075 #ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect 2076 TEST_F(APZCOverscrollTesterMock, StuckInOverscroll_Bug1810935) { 2077 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2078 2079 using ViewID = ScrollableLayerGuid::ViewID; 2080 ViewID rootScrollId = ScrollableLayerGuid::START_SCROLL_ID; 2081 ViewID subframeScrollId = ScrollableLayerGuid::START_SCROLL_ID + 1; 2082 2083 const char* treeShape = "x(x)"; 2084 LayerIntRect layerVisibleRects[] = {LayerIntRect(0, 0, 100, 100), 2085 LayerIntRect(50, 0, 50, 100)}; 2086 CreateScrollData(treeShape, layerVisibleRects); 2087 SetScrollableFrameMetrics(root, rootScrollId, CSSRect(0, 0, 100, 200)); 2088 SetScrollableFrameMetrics(layers[1], subframeScrollId, 2089 CSSRect(0, 0, 50, 200)); 2090 SetScrollHandoff(layers[1], root); 2091 2092 registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc); 2093 UpdateHitTestingTree(); 2094 rootApzc = ApzcOf(root); 2095 auto* subframeApzc = ApzcOf(layers[1]); 2096 rootApzc->GetFrameMetrics().SetIsRootContent(true); 2097 2098 // Try to scroll upwards over the subframe. 2099 ScreenIntPoint panPoint(75, 50); 2100 QueueMockHitResult(subframeScrollId); 2101 PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint, 2102 ScreenPoint(0, -10), mcc->Time()); 2103 mcc->AdvanceByMillis(10); 2104 QueueMockHitResult(subframeScrollId); 2105 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 2106 ScreenPoint(0, -50), mcc->Time()); 2107 mcc->AdvanceByMillis(10); 2108 QueueMockHitResult(subframeScrollId); 2109 PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint, 2110 ScreenPoint(0, 0), mcc->Time()); 2111 2112 // The root APZC should be overscrolled. (The subframe APZC should be be.) 2113 EXPECT_TRUE(rootApzc->IsOverscrolled()); 2114 EXPECT_FALSE(subframeApzc->IsOverscrolled()); 2115 2116 // Give the overscroll animation on the root a chance to start. 2117 mcc->AdvanceByMillis(10); 2118 EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning()); 2119 2120 // Scroll the subframe downwards, with a large delta. 2121 QueueMockHitResult(subframeScrollId); 2122 PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint, 2123 ScreenPoint(0, 50), mcc->Time()); 2124 2125 // Already after the first event, the overscroll animation should be 2126 // interrupted. 2127 EXPECT_FALSE(rootApzc->IsOverscrollAnimationRunning()); 2128 2129 // Cotninue the downward scroll gesture. 2130 mcc->AdvanceByMillis(10); 2131 QueueMockHitResult(subframeScrollId); 2132 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 2133 ScreenPoint(0, 100), mcc->Time()); 2134 mcc->AdvanceByMillis(10); 2135 QueueMockHitResult(subframeScrollId); 2136 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 2137 ScreenPoint(0, 100), mcc->Time()); 2138 mcc->AdvanceByMillis(10); 2139 QueueMockHitResult(subframeScrollId); 2140 PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint, 2141 ScreenPoint(0, 100), mcc->Time()); 2142 mcc->AdvanceByMillis(10); 2143 QueueMockHitResult(subframeScrollId); 2144 // Important: pass aSimulateMomentum=true for the pan-end to exercise the bug. 2145 PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint, 2146 ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, 2147 /*aSimulateMomentum=*/true); 2148 2149 // The root and the subframe should both be overscrolled. 2150 EXPECT_TRUE(rootApzc->IsOverscrolled()); 2151 EXPECT_TRUE(subframeApzc->IsOverscrolled()); 2152 2153 // Sample animations until all of them have been finished. 2154 while (SampleAnimationsOnce()); 2155 2156 // All overscrolled APZCs should have snapped back. 2157 EXPECT_FALSE(rootApzc->IsOverscrolled()); 2158 EXPECT_FALSE(subframeApzc->IsOverscrolled()); 2159 } 2160 #endif 2161 2162 #ifndef MOZ_WIDGET_ANDROID // Not valid on Android 2163 // Tests that the scroll offset is shifted with the overscroll amount when the 2164 // content scroll range got expaned. 2165 TEST_F(APZCOverscrollTester, FillOutGutterWhilePanning) { 2166 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2167 2168 // Scroll to the bottom edge. 2169 ScrollMetadata metadata = apzc->GetScrollMetadata(); 2170 metadata.GetMetrics().SetLayoutScrollOffset( 2171 CSSPoint(0, GetScrollRange().YMost())); 2172 nsTArray<ScrollPositionUpdate> scrollUpdates; 2173 scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll( 2174 ScrollOrigin::Other, 2175 CSSPoint::ToAppUnits(CSSPoint(0, GetScrollRange().YMost())))); 2176 metadata.SetScrollUpdates(scrollUpdates); 2177 metadata.GetMetrics().SetScrollGeneration( 2178 scrollUpdates.LastElement().GetGeneration()); 2179 apzc->NotifyLayersUpdated( 2180 metadata, 2181 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 2182 2183 CSSPoint scrollOffset = metadata.GetMetrics().GetLayoutScrollOffset(); 2184 2185 // Start panning to overscroll the content. 2186 Pan(apzc, 20, 10, PanOptions::KeepFingerDown); 2187 EXPECT_TRUE(apzc->IsOverscrolled()); 2188 float overscrollY = apzc->GetOverscrollAmount().y; 2189 EXPECT_GT(overscrollY, 0); 2190 2191 // Expand the content scroll range. 2192 metadata = apzc->GetScrollMetadata(); 2193 FrameMetrics& metrics = metadata.GetMetrics(); 2194 const CSSRect& scrollableRect = metrics.GetScrollableRect(); 2195 metrics.SetScrollableRect(scrollableRect + 2196 CSSSize(0, scrollableRect.height + 10)); 2197 apzc->NotifyLayersUpdated( 2198 metadata, 2199 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 2200 2201 // Now that the scroll position was shifted with the overscroll amount. 2202 EXPECT_EQ(apzc->GetScrollMetadata().GetMetrics().GetVisualScrollOffset().y, 2203 scrollOffset.y + overscrollY); 2204 EXPECT_FALSE(apzc->IsOverscrolled()); 2205 } 2206 2207 // Similar to FillOutGutterWhilePanning but expanding the content while an 2208 // overscroll animation is running. 2209 TEST_F(APZCOverscrollTester, FillOutGutterWhileAnimating) { 2210 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2211 2212 // Scroll to the bottom edge. 2213 ScrollMetadata metadata = apzc->GetScrollMetadata(); 2214 metadata.GetMetrics().SetLayoutScrollOffset( 2215 CSSPoint(0, GetScrollRange().YMost())); 2216 nsTArray<ScrollPositionUpdate> scrollUpdates; 2217 scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll( 2218 ScrollOrigin::Other, 2219 CSSPoint::ToAppUnits(CSSPoint(0, GetScrollRange().YMost())))); 2220 metadata.SetScrollUpdates(scrollUpdates); 2221 metadata.GetMetrics().SetScrollGeneration( 2222 scrollUpdates.LastElement().GetGeneration()); 2223 apzc->NotifyLayersUpdated( 2224 metadata, 2225 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 2226 2227 CSSPoint scrollOffset = metadata.GetMetrics().GetLayoutScrollOffset(); 2228 2229 PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80), 2230 ScreenPoint(0, 20), mcc->Time()); 2231 mcc->AdvanceByMillis(5); 2232 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 60), 2233 ScreenPoint(0, 10), mcc->Time()); 2234 mcc->AdvanceByMillis(5); 2235 apzc->AdvanceAnimations(mcc->GetSampleTime()); 2236 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50), 2237 ScreenPoint(0, 10), mcc->Time()); 2238 mcc->AdvanceByMillis(5); 2239 PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 50), 2240 ScreenPoint(0, 0), mcc->Time()); 2241 mcc->AdvanceByMillis(5); 2242 2243 EXPECT_TRUE(apzc->IsOverscrolled()); 2244 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 2245 float overscrollY = apzc->GetOverscrollAmount().y; 2246 EXPECT_GT(overscrollY, 0); 2247 2248 // Expand the content scroll range. 2249 metadata = apzc->GetScrollMetadata(); 2250 FrameMetrics& metrics = metadata.GetMetrics(); 2251 const CSSRect& scrollableRect = metrics.GetScrollableRect(); 2252 metrics.SetScrollableRect(scrollableRect + 2253 CSSSize(0, scrollableRect.height + 10)); 2254 apzc->NotifyLayersUpdated( 2255 metadata, 2256 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 2257 2258 // Now that the scroll position was shifted with the overscroll amount. 2259 EXPECT_EQ(apzc->GetScrollMetadata().GetMetrics().GetVisualScrollOffset().y, 2260 scrollOffset.y + overscrollY); 2261 EXPECT_FALSE(apzc->IsOverscrolled()); 2262 } 2263 #endif 2264 2265 // Test that a programmatic scroll animation does NOT trigger overscroll. 2266 TEST_F(APZCOverscrollTester, ProgrammaticScroll) { 2267 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2268 2269 // Send a SmoothMsd scroll update to a destination far outside of the 2270 // scroll range (here, y=100000). This probably shouldn't happen in the 2271 // first place, but even if it does for whatever reason, the smooth scroll 2272 // should not trigger overscroll. 2273 ScrollMetadata metadata = apzc->GetScrollMetadata(); 2274 nsTArray<ScrollPositionUpdate> scrollUpdates; 2275 scrollUpdates.AppendElement(ScrollPositionUpdate::NewSmoothScroll( 2276 ScrollMode::SmoothMsd, ScrollOrigin::Other, 2277 CSSPoint::ToAppUnits(CSSPoint(0, 100000)), ScrollTriggeredByScript::Yes, 2278 nullptr, ViewportType::Visual)); 2279 metadata.SetScrollUpdates(scrollUpdates); 2280 metadata.GetMetrics().SetScrollGeneration( 2281 scrollUpdates.LastElement().GetGeneration()); 2282 apzc->NotifyLayersUpdated( 2283 metadata, 2284 LayersUpdateFlags{.mIsFirstPaint = false, .mThisLayerTreeUpdated = true}); 2285 2286 apzc->AssertInSmoothMsdScroll(); 2287 2288 while (SampleAnimationOneFrame()) { 2289 EXPECT_FALSE(apzc->IsOverscrolled()); 2290 } 2291 } 2292 2293 // A touchpad hold gesture should pause any ongoing overscroll animation (so 2294 // that the page is not moving while the fingers are down on the touchpad), 2295 // but should not cancel it. The animation should continue if the finger is 2296 // lifted. 2297 #ifndef MOZ_WIDGET_ANDROID // Requires GenericOverscrollEffect 2298 TEST_F(APZCOverscrollTester, HoldGestureDuringOverscroll) { 2299 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2300 2301 ScrollMetadata metadata; 2302 FrameMetrics& metrics = metadata.GetMetrics(); 2303 metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); 2304 metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000)); 2305 metrics.SetVisualScrollOffset(CSSPoint(0, 0)); 2306 apzc->SetFrameMetrics(metrics); 2307 2308 // Pan into overscroll at the top. 2309 ScreenIntPoint panPoint(50, 50); 2310 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 2311 ScreenPoint(0, -1), mcc->Time()); 2312 mcc->AdvanceByMillis(10); 2313 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 2314 ScreenPoint(0, -100), mcc->Time()); 2315 EXPECT_TRUE(apzc->IsOverscrolled()); 2316 EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top 2317 2318 // End the pan. This should start an overscroll animation. 2319 mcc->AdvanceByMillis(10); 2320 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 2321 mcc->Time()); 2322 EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top 2323 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 2324 2325 // Start a hold gesture (represented using PANGESTURE_MAYSTART). 2326 // This should interrupt the animation but not relieve overscroll yet. 2327 ParentLayerPoint overscrollBefore = apzc->GetOverscrollAmount(); 2328 mcc->AdvanceByMillis(10); 2329 PanGesture(PanGestureInput::PANGESTURE_MAYSTART, apzc, panPoint, 2330 ScreenPoint(0, 0), mcc->Time()); 2331 EXPECT_FALSE(apzc->IsOverscrollAnimationRunning()); 2332 EXPECT_EQ(overscrollBefore, apzc->GetOverscrollAmount()); 2333 2334 // End the hold gesture (represented using PANGESTURE_CANCELLED). 2335 // This should start an overscroll animation again. 2336 mcc->AdvanceByMillis(10); 2337 PanGesture(PanGestureInput::PANGESTURE_CANCELLED, apzc, panPoint, 2338 ScreenPoint(0, 0), mcc->Time()); 2339 EXPECT_TRUE(apzc->IsOverscrollAnimationRunning()); 2340 2341 SampleAnimationUntilRecoveredFromOverscroll(ParentLayerPoint(0, 0)); 2342 } 2343 #endif 2344 2345 #ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect 2346 TEST_F(APZCOverscrollTester, NoResetTouchInputStateCalled) { 2347 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2348 2349 MakeApzcWaitForMainThread(); 2350 2351 InSequence s; 2352 // The UpdateOverscrollVelocity should never be called since there's no 2353 // overscrolling state. 2354 EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(0); 2355 2356 ScreenIntPoint touchPoint(5, 5); 2357 APZEventResult result = TouchDown(apzc, touchPoint, mcc->Time()); 2358 SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); 2359 apzc->ContentReceivedInputBlock(result.mInputBlockId, 2360 /*aPreventDefault=*/true); 2361 2362 for (int i = 0; i < 5; ++i) { 2363 touchPoint.y -= 1; 2364 mcc->AdvanceByMillis(10); 2365 TouchMove(apzc, touchPoint, mcc->Time()); 2366 } 2367 2368 mcc->AdvanceByMillis(10); 2369 TouchUp(apzc, touchPoint, mcc->Time()); 2370 } 2371 #endif 2372 2373 #ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect 2374 TEST_F(APZCOverscrollTester, ResetTouchInputStateJustOnce) { 2375 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2376 SCOPED_GFX_PREF_FLOAT("apz.touch_start_tolerance", 0.1f); 2377 SCOPED_GFX_PREF_FLOAT("apz.touch_move_tolerance", 0.0f); 2378 // To avoid falling into a fast fling state so that the second touch-start 2379 // event can be preventDefault-ed. 2380 SCOPED_GFX_PREF_FLOAT("apz.fling_stop_on_tap_threshold", 1000.0f); 2381 2382 InSequence s; 2383 // The UpdateOverscrollVelocity should be called just once for the second 2384 // touchdown event which will be preventDefault-ed. 2385 EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(1); 2386 2387 // Overscroll once. 2388 PanIntoOverscroll(); 2389 2390 // Now the touch-start event will be preventDefault-ed. 2391 MakeApzcWaitForMainThread(); 2392 2393 ScreenIntPoint touchPoint(5, 5); 2394 APZEventResult result = TouchDown(apzc, touchPoint, mcc->Time()); 2395 SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId); 2396 apzc->ContentReceivedInputBlock(result.mInputBlockId, 2397 /*aPreventDefault=*/true); 2398 2399 for (int i = 0; i < 5; ++i) { 2400 touchPoint.y -= 1; 2401 mcc->AdvanceByMillis(10); 2402 TouchMove(apzc, touchPoint, mcc->Time()); 2403 } 2404 2405 mcc->AdvanceByMillis(10); 2406 TouchUp(apzc, touchPoint, mcc->Time()); 2407 } 2408 #endif 2409 2410 #ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect 2411 TEST_F(APZCOverscrollTester, NoResetPanGestureInputStateCalled) { 2412 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2413 2414 MakeApzcWaitForMainThread(); 2415 2416 InSequence s; 2417 // The UpdateOverscrollVelocity should never be called since there's no 2418 // overscrolling state. 2419 EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(0); 2420 2421 ScreenIntPoint panPoint(5, 5); 2422 APZEventResult result = PanGesture(PanGestureInput::PANGESTURE_START, apzc, 2423 panPoint, ScreenPoint(0, 1), mcc->Time()); 2424 apzc->ContentReceivedInputBlock(result.mInputBlockId, 2425 /*aPreventDefault=*/true); 2426 for (int i = 0; i < 5; ++i) { 2427 mcc->AdvanceByMillis(10); 2428 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 2429 ScreenPoint(0, 1), mcc->Time()); 2430 } 2431 2432 mcc->AdvanceByMillis(10); 2433 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 2434 mcc->Time()); 2435 } 2436 #endif 2437 2438 #ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect 2439 TEST_F(APZCOverscrollTester, ResetPanGestureInputStateJustOnce) { 2440 SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true); 2441 2442 InSequence s; 2443 // The UpdateOverscrollVelocity should be called just once because 2444 // the second pan-start event (wheel event) during overscrolling 2445 // which will be preventDefault-ed. 2446 EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(1); 2447 2448 // NOTE: PanIntoOverscroll uses touch events. We do overscroll with pan 2449 // gestures. 2450 ScreenIntPoint panPoint(5, 5); 2451 PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint, 2452 ScreenPoint(0, -10), mcc->Time()); 2453 mcc->AdvanceByMillis(10); 2454 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 2455 ScreenPoint(0, -100), mcc->Time()); 2456 // Make sure it's overscrolling. 2457 EXPECT_TRUE(apzc->IsOverscrolled()); 2458 // Finish the pan gesture. 2459 mcc->AdvanceByMillis(10); 2460 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 2461 mcc->Time()); 2462 2463 // Now the next pan gesture event will be preventDefault-ed. 2464 MakeApzcWaitForMainThread(); 2465 2466 APZEventResult result = PanGesture(PanGestureInput::PANGESTURE_START, apzc, 2467 panPoint, ScreenPoint(0, 10), mcc->Time()); 2468 apzc->ContentReceivedInputBlock(result.mInputBlockId, 2469 /*aPreventDefault=*/true); 2470 for (int i = 0; i < 5; ++i) { 2471 mcc->AdvanceByMillis(10); 2472 PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint, 2473 ScreenPoint(0, 10), mcc->Time()); 2474 } 2475 2476 mcc->AdvanceByMillis(10); 2477 PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0), 2478 mcc->Time()); 2479 } 2480 #endif