2428 lines
101 KiB
C++
2428 lines
101 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "APZCBasicTester.h"
|
|
#include "APZCTreeManagerTester.h"
|
|
#include "APZTestCommon.h"
|
|
#include "mozilla/ScrollPositionUpdate.h"
|
|
#include "mozilla/layers/ScrollableLayerGuid.h"
|
|
#include "mozilla/layers/WebRenderScrollDataWrapper.h"
|
|
|
|
#include "InputUtils.h"
|
|
|
|
class APZCOverscrollTester : public APZCBasicTester {
|
|
public:
|
|
explicit APZCOverscrollTester(
|
|
AsyncPanZoomController::GestureBehavior aGestureBehavior =
|
|
AsyncPanZoomController::DEFAULT_GESTURES)
|
|
: APZCBasicTester(aGestureBehavior) {}
|
|
|
|
protected:
|
|
UniquePtr<ScopedLayerTreeRegistration> registration;
|
|
|
|
void TestOverscroll() {
|
|
// Pan sufficiently to hit overscroll behavior
|
|
PanIntoOverscroll();
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost());
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
|
|
void PanIntoOverscroll() {
|
|
int touchStart = 500;
|
|
int touchEnd = 10;
|
|
Pan(apzc, touchStart, touchEnd);
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
}
|
|
|
|
/**
|
|
* Sample animations until we recover from overscroll.
|
|
* @param aExpectedScrollOffset the expected reported scroll offset
|
|
* throughout the animation
|
|
*/
|
|
void SampleAnimationUntilRecoveredFromOverscroll(
|
|
const ParentLayerPoint& aExpectedScrollOffset) {
|
|
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
|
bool recoveredFromOverscroll = false;
|
|
ParentLayerPoint pointOut;
|
|
AsyncTransform viewTransformOut;
|
|
while (apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut)) {
|
|
// The reported scroll offset should be the same throughout.
|
|
EXPECT_EQ(aExpectedScrollOffset, pointOut);
|
|
|
|
// Trigger computation of the overscroll tranform, to make sure
|
|
// no assetions fire during the calculation.
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
|
|
if (!apzc->IsOverscrolled()) {
|
|
recoveredFromOverscroll = true;
|
|
}
|
|
|
|
mcc->AdvanceBy(increment);
|
|
}
|
|
EXPECT_TRUE(recoveredFromOverscroll);
|
|
apzc->AssertStateIsReset();
|
|
}
|
|
|
|
ScrollableLayerGuid CreateSimpleRootScrollableForWebRender() {
|
|
ScrollableLayerGuid guid;
|
|
guid.mScrollId = ScrollableLayerGuid::START_SCROLL_ID;
|
|
guid.mLayersId = LayersId{0};
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
metrics.SetScrollId(guid.mScrollId);
|
|
metadata.SetIsLayersIdRoot(true);
|
|
|
|
WebRenderLayerScrollData rootLayerScrollData;
|
|
rootLayerScrollData.InitializeRoot(0);
|
|
WebRenderScrollData scrollData;
|
|
rootLayerScrollData.AppendScrollMetadata(scrollData, metadata);
|
|
scrollData.AddLayerData(std::move(rootLayerScrollData));
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(guid.mLayersId, mcc);
|
|
tm->UpdateHitTestingTree(WebRenderScrollDataWrapper(*updater, &scrollData),
|
|
guid.mLayersId, 0);
|
|
return guid;
|
|
}
|
|
};
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, FlingIntoOverscroll) {
|
|
// Enable overscrolling.
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
|
|
|
|
// Scroll down by 25 px. Don't fling for simplicity.
|
|
Pan(apzc, 50, 25, PanOptions::NoFling);
|
|
|
|
// Now scroll back up by 20px, this time flinging after.
|
|
// The fling should cover the remaining 5 px of room to scroll, then
|
|
// go into overscroll, and finally snap-back to recover from overscroll.
|
|
Pan(apzc, 25, 45);
|
|
const TimeDuration increment = TimeDuration::FromMilliseconds(1);
|
|
bool reachedOverscroll = false;
|
|
bool recoveredFromOverscroll = false;
|
|
while (apzc->AdvanceAnimations(mcc->GetSampleTime())) {
|
|
if (!reachedOverscroll && apzc->IsOverscrolled()) {
|
|
reachedOverscroll = true;
|
|
}
|
|
if (reachedOverscroll && !apzc->IsOverscrolled()) {
|
|
recoveredFromOverscroll = true;
|
|
}
|
|
mcc->AdvanceBy(increment);
|
|
}
|
|
EXPECT_TRUE(reachedOverscroll);
|
|
EXPECT_TRUE(recoveredFromOverscroll);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, OverScrollPanning) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
TestOverscroll();
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
// Tests that an overscroll animation doesn't trigger an assertion failure
|
|
// in the case where a sample has a velocity of zero.
|
|
TEST_F(APZCOverscrollTester, OverScroll_Bug1152051a) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Doctor the prefs to make the velocity zero at the end of the first sample.
|
|
|
|
// This ensures our incoming velocity to the overscroll animation is
|
|
// a round(ish) number, 4.9 (that being the distance of the pan before
|
|
// overscroll, which is 500 - 10 = 490 pixels, divided by the duration of
|
|
// the pan, which is 100 ms).
|
|
SCOPED_GFX_PREF_FLOAT("apz.fling_friction", 0);
|
|
|
|
TestOverscroll();
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
// Tests that ending an overscroll animation doesn't leave around state that
|
|
// confuses the next overscroll animation.
|
|
TEST_F(APZCOverscrollTester, OverScroll_Bug1152051b) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
SCOPED_GFX_PREF_FLOAT("apz.overscroll.stop_distance_threshold", 0.1f);
|
|
|
|
// Pan sufficiently to hit overscroll behavior
|
|
PanIntoOverscroll();
|
|
|
|
// Sample animations once, to give the fling animation started on touch-up
|
|
// a chance to realize it's overscrolled, and schedule a call to
|
|
// HandleFlingOverscroll().
|
|
SampleAnimationOnce();
|
|
|
|
// This advances the time and runs the HandleFlingOverscroll task scheduled in
|
|
// the previous call, which starts an overscroll animation. It then samples
|
|
// the overscroll animation once, to get it to initialize the first overscroll
|
|
// sample.
|
|
SampleAnimationOnce();
|
|
|
|
// Do a touch-down to cancel the overscroll animation, and then a touch-up
|
|
// to schedule a new one since we're still overscrolled. We don't pan because
|
|
// panning can trigger functions that clear the overscroll animation state
|
|
// in other ways.
|
|
APZEventResult result = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time());
|
|
if (result.GetStatus() != nsEventStatus_eConsumeNoDefault) {
|
|
SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
|
|
}
|
|
TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
|
|
|
|
// Sample the second overscroll animation to its end.
|
|
// If the ending of the first overscroll animation fails to clear state
|
|
// properly, this will assert.
|
|
ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost());
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
// Tests that the page doesn't get stuck in an
|
|
// overscroll animation after a low-velocity pan.
|
|
TEST_F(APZCOverscrollTester, OverScrollAfterLowVelocityPan_Bug1343775) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Pan into overscroll with a velocity less than the
|
|
// apz.fling_min_velocity_threshold preference.
|
|
Pan(apzc, 10, 30);
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
apzc->AdvanceAnimationsUntilEnd();
|
|
|
|
// Check that we recovered from overscroll.
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, OverScrollAbort) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Pan sufficiently to hit overscroll behavior
|
|
int touchStart = 500;
|
|
int touchEnd = 10;
|
|
Pan(apzc, touchStart, touchEnd);
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
ParentLayerPoint pointOut;
|
|
AsyncTransform viewTransformOut;
|
|
|
|
// This sample call will run to the end of the fling animation
|
|
// and will schedule the overscroll animation.
|
|
apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut,
|
|
TimeDuration::FromMilliseconds(10000));
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// At this point, we have an active overscroll animation.
|
|
// Check that cancelling the animation clears the overscroll.
|
|
apzc->CancelAnimation();
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
apzc->AssertStateIsReset();
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, OverScrollPanningAbort) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Pan sufficiently to hit overscroll behaviour. Keep the finger down so
|
|
// the pan does not end.
|
|
int touchStart = 500;
|
|
int touchEnd = 10;
|
|
Pan(apzc, touchStart, touchEnd, PanOptions::KeepFingerDown);
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Check that calling CancelAnimation() while the user is still panning
|
|
// (and thus no fling or snap-back animation has had a chance to start)
|
|
// clears the overscroll.
|
|
apzc->CancelAnimation();
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
apzc->AssertStateIsReset();
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android
|
|
TEST_F(APZCOverscrollTester, OverscrollByVerticalPanGestures) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, 0);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, StuckInOverscroll_Bug1767337) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
|
|
// Send two PANGESTURE_END in a row, to see if the second one gets us
|
|
// stuck in overscroll.
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, true);
|
|
SampleAnimationOnce();
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE, true);
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, 0);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, OverscrollByVerticalAndHorizontalPanGestures) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-10, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, 0), mcc->Time());
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, 0);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, OverscrollByPanMomentumGestures) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Make sure we are not yet in overscrolled region.
|
|
EXPECT_TRUE(!apzc->IsOverscrolled());
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost());
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, IgnoreMomemtumDuringOverscroll) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
float yMost = GetScrollRange().YMost();
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, yMost / 10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, yMost), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, yMost / 10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Make sure we've started an overscroll animation.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
// And check the overscrolled transform value before/after calling PanGesture
|
|
// to make sure the overscroll amount isn't affected by momentum events.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
AsyncTransformComponentMatrix overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_EQ(
|
|
overscrolledTransform,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling));
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time());
|
|
EXPECT_EQ(
|
|
overscrolledTransform,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling));
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time());
|
|
EXPECT_EQ(
|
|
overscrolledTransform,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling));
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 2), mcc->Time());
|
|
EXPECT_EQ(
|
|
overscrolledTransform,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling));
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_EQ(
|
|
overscrolledTransform,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling));
|
|
|
|
// Check that we've recovered from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost());
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, VerticalOnlyOverscroll) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Make the content scrollable only vertically.
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Scroll up into overscroll a bit.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-10, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
// Now it's overscrolled.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
AsyncTransformComponentMatrix overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
// The overscroll shouldn't happen horizontally.
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
// Happens only vertically.
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
// Send pan momentum events including horizontal bits.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(-10, -100), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
// The overscroll shouldn't happen horizontally.
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(-5, -50), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, -2), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, 0);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, VerticalOnlyOverscrollByPanMomentum) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Make the content scrollable only vertically.
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
// Scrolls the content down a bit.
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 50));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Scroll up a bit where overscroll will not happen.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Make sure it's not yet overscrolled.
|
|
EXPECT_TRUE(!apzc->IsOverscrolled());
|
|
|
|
// Send pan momentum events including horizontal bits.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(-10, -100), mcc->Time());
|
|
// Now it's overscrolled.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
AsyncTransformComponentMatrix overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
// But the overscroll shouldn't happen horizontally.
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
// Happens only vertically.
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(-5, -50), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, -2), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
overscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_TRUE(overscrolledTransform._41 == 0);
|
|
EXPECT_TRUE(overscrolledTransform._42 != 0);
|
|
|
|
// Check that we recover from overscroll via an animation.
|
|
ParentLayerPoint expectedScrollOffset(0, 0);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, DisallowOverscrollInSingleLineTextControl) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Create a horizontal scrollable frame with `vertical disregarded direction`.
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 10));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 1000, 10));
|
|
apzc->SetFrameMetrics(metrics);
|
|
metadata.SetDisregardedDirection(Some(ScrollDirection::eVertical));
|
|
apzc->NotifyLayersUpdated(metadata, /*aIsFirstPaint=*/false,
|
|
/*aThisLayerTreeUpdated=*/true);
|
|
|
|
// Try to overscroll up and left with pan gestures.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 5),
|
|
ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 5),
|
|
ScreenPoint(-10, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 5),
|
|
ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 5),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// No overscrolling should happen.
|
|
EXPECT_TRUE(!apzc->IsOverscrolled());
|
|
|
|
// Send pan momentum events too.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 5), ScreenPoint(0, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 5), ScreenPoint(-100, -100), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 5), ScreenPoint(-50, -50), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 5), ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 5), ScreenPoint(0, 0), mcc->Time());
|
|
// No overscrolling should happen either.
|
|
EXPECT_TRUE(!apzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android
|
|
// Tests that horizontal overscroll animation keeps running with vertical
|
|
// pan momentum scrolling.
|
|
TEST_F(APZCOverscrollTester,
|
|
HorizontalOverscrollAnimationWithVerticalPanMomentumScrolling) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 1000, 5000));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Try to overscroll left with pan gestures.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-10, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Make sure we've started an overscroll animation.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
AsyncTransformComponentMatrix initialOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
|
|
// Send lengthy downward momentums to make sure the overscroll animation
|
|
// doesn't clobber the momentums scrolling.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll amount on X axis has started being managed by the overscroll
|
|
// animation.
|
|
AsyncTransformComponentMatrix currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41);
|
|
// There is no overscroll on Y axis.
|
|
EXPECT_EQ(currentOverscrolledTransform._42, 0);
|
|
ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
// The scroll offset shouldn't be changed by the overscroll animation.
|
|
EXPECT_EQ(scrollOffset.y, 0);
|
|
|
|
// Simple gesture on the Y axis to ensure that we can send a vertical
|
|
// momentum scroll
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
ParentLayerPoint offsetAfterPan = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on both axes shouldn't be changed by this pan
|
|
// momentum start event since the displacement is zero.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll amount should be managed by the overscroll animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
// Not yet started scrolling.
|
|
EXPECT_EQ(scrollOffset.y, offsetAfterPan.y);
|
|
EXPECT_EQ(scrollOffset.x, 0);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
|
|
// Send a long pan momentum.
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on X axis shouldn't be changed by this momentum pan.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// Now it started scrolling vertically.
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_GT(scrollOffset.y, 0);
|
|
EXPECT_EQ(scrollOffset.x, 0);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll on X axis keeps being managed by the overscroll animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// The scroll offset on Y axis shouldn't be changed by the overscroll
|
|
// animation.
|
|
EXPECT_EQ(scrollOffset.y, apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on X axis shouldn't be changed by this momentum pan.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// Scrolling keeps going by momentum.
|
|
EXPECT_GT(apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y,
|
|
scrollOffset.y);
|
|
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 10), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// Scrolling keeps going by momentum.
|
|
EXPECT_GT(apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y,
|
|
scrollOffset.y);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// This momentum event doesn't change the scroll offset since its
|
|
// displacement is zero.
|
|
EXPECT_EQ(apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y,
|
|
scrollOffset.y);
|
|
|
|
// Check that we recover from the horizontal overscroll via the animation.
|
|
ParentLayerPoint expectedScrollOffset(0, scrollOffset.y);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android
|
|
// Similar to above
|
|
// HorizontalOverscrollAnimationWithVerticalPanMomentumScrolling,
|
|
// but having OverscrollAnimation on both axes initially.
|
|
TEST_F(APZCOverscrollTester,
|
|
BothAxesOverscrollAnimationWithPanMomentumScrolling) {
|
|
// TODO: This test currently requires gestures that cause movement on both
|
|
// axis, which excludes DOMINANT_AXIS locking mode. The gestures should be
|
|
// broken up into multiple gestures to cause the overscroll.
|
|
SCOPED_GFX_PREF_INT("apz.axis_lock.mode", 2);
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 1000, 5000));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Try to overscroll up and left with pan gestures.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-10, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Make sure we've started an overscroll animation.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
AsyncTransformComponentMatrix initialOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
|
|
// Send lengthy downward momentums to make sure the overscroll animation
|
|
// doesn't clobber the momentums scrolling.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll amount has started being managed by the overscroll
|
|
// animation.
|
|
AsyncTransformComponentMatrix currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41);
|
|
EXPECT_NE(initialOverscrolledTransform._42, currentOverscrolledTransform._42);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on both axes shouldn't be changed by this pan
|
|
// momentum start event since the displacement is zero.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// Still being managed by the overscroll animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
// Send a long pan momentum.
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 200), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on X axis shouldn't be changed by this momentum pan.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// But now the overscroll amount on Y axis should be changed by this momentum
|
|
// pan.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
// Actually it's no longer overscrolled.
|
|
EXPECT_EQ(
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42,
|
|
0);
|
|
|
|
ParentLayerPoint currentScrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
// Now it started scrolling.
|
|
EXPECT_GT(currentScrollOffset.y, 0);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll on X axis keeps being managed by the overscroll animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// But the overscroll on Y axis is no longer affected by the overscroll
|
|
// animation.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
// The scroll offset on Y axis shouldn't be changed by the overscroll
|
|
// animation.
|
|
EXPECT_EQ(currentScrollOffset.y,
|
|
apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
currentScrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 100), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on X axis shouldn't be changed by this momentum pan.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// Keeping no overscrolling on Y axis.
|
|
EXPECT_EQ(
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42,
|
|
0);
|
|
// Scrolling keeps going by momentum.
|
|
EXPECT_GT(apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y,
|
|
currentScrollOffset.y);
|
|
|
|
currentScrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 10), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// Keeping no overscrolling on Y axis.
|
|
EXPECT_EQ(
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42,
|
|
0);
|
|
// Scrolling keeps going by momentum.
|
|
EXPECT_GT(apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y,
|
|
currentScrollOffset.y);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
currentScrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// Keeping no overscrolling on Y axis.
|
|
EXPECT_EQ(
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42,
|
|
0);
|
|
// This momentum event doesn't change the scroll offset since its
|
|
// displacement is zero.
|
|
EXPECT_EQ(apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling)
|
|
.y,
|
|
currentScrollOffset.y);
|
|
|
|
// Check that we recover from the horizontal overscroll via the animation.
|
|
ParentLayerPoint expectedScrollOffset(0, currentScrollOffset.y);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Maybe fails on Android
|
|
// This is another variant of
|
|
// HorizontalOverscrollAnimationWithVerticalPanMomentumScrolling. In this test,
|
|
// after a horizontal overscroll animation started, upwards pan moments happen,
|
|
// thus there should be a new vertical overscroll animation in addition to
|
|
// the horizontal one.
|
|
TEST_F(
|
|
APZCOverscrollTester,
|
|
VerticalOverscrollAnimationInAdditionToExistingHorizontalOverscrollAnimation) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 1000, 5000));
|
|
// Scrolls the content 50px down.
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 50));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Try to overscroll left with pan gestures.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-10, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(-2, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Make sure we've started an overscroll animation.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
AsyncTransformComponentMatrix initialOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
|
|
// Send lengthy __upward__ momentums to make sure the overscroll animation
|
|
// doesn't clobber the momentums scrolling.
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll amount on X axis has started being managed by the overscroll
|
|
// animation.
|
|
AsyncTransformComponentMatrix currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_NE(initialOverscrolledTransform._41, currentOverscrolledTransform._41);
|
|
// There is no overscroll on Y axis.
|
|
EXPECT_EQ(
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42,
|
|
0);
|
|
ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
// The scroll offset shouldn't be changed by the overscroll animation.
|
|
EXPECT_EQ(scrollOffset.y, 50);
|
|
|
|
// Simple gesture on the Y axis to ensure that we can send a vertical
|
|
// momentum scroll
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
ParentLayerPoint offsetAfterPan = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on both axes shouldn't be changed by this pan
|
|
// momentum start event since the displacement is zero.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll amount should be managed by the overscroll animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
// Not yet started scrolling.
|
|
EXPECT_EQ(scrollOffset.y, offsetAfterPan.y);
|
|
EXPECT_EQ(scrollOffset.x, 0);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
|
|
// Send a long pan momentum.
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, -200), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on X axis shouldn't be changed by this momentum pan.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// Now it started scrolling vertically.
|
|
scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_EQ(scrollOffset.y, 0);
|
|
EXPECT_EQ(scrollOffset.x, 0);
|
|
// Actually it's also vertically overscrolled.
|
|
EXPECT_GT(
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42,
|
|
0);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// The overscroll on X axis keeps being managed by the overscroll animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// The overscroll on Y Axis hasn't been changed by the overscroll animation at
|
|
// this moment, sine the last displacement was consumed in the last pan
|
|
// momentum.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, -100), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on X axis shouldn't be changed by this momentum pan.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// Now the overscroll amount on Y axis shouldn't be changed by this momentum
|
|
// pan either.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
// And now the overscroll on Y Axis should be also managed by the overscroll
|
|
// animation.
|
|
EXPECT_NE(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, -10), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
// The overscroll amount on both axes shouldn't be changed by momentum event.
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._41,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._41);
|
|
EXPECT_EQ(
|
|
currentOverscrolledTransform._42,
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling)
|
|
._42);
|
|
|
|
currentOverscrolledTransform =
|
|
apzc->GetOverscrollTransform(AsyncPanZoomController::eForEventHandling);
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_MOMENTUMEND, apzc,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
// Check that we recover from the horizontal overscroll via the animation.
|
|
ParentLayerPoint expectedScrollOffset(0, 0);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTester, OverscrollByPanGesturesInterruptedByReflowZoom) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
SCOPED_GFX_PREF_INT("mousewheel.with_control.action", 3); // reflow zoom.
|
|
|
|
// A sanity check that pan gestures with ctrl modifier will not be handled by
|
|
// APZ.
|
|
PanGestureInput panInput(PanGestureInput::PANGESTURE_START, mcc->Time(),
|
|
ScreenIntPoint(5, 5), ScreenPoint(0, -2),
|
|
MODIFIER_CONTROL);
|
|
WidgetWheelEvent wheelEvent = panInput.ToWidgetEvent(nullptr);
|
|
EXPECT_FALSE(APZInputBridge::ActionForWheelEvent(&wheelEvent).isSome());
|
|
|
|
ScrollableLayerGuid rootGuid = CreateSimpleRootScrollableForWebRender();
|
|
RefPtr<AsyncPanZoomController> apzc =
|
|
tm->GetTargetAPZC(rootGuid.mLayersId, rootGuid.mScrollId);
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_START, tm, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, tm, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
|
|
// Make sure overscrolling has started.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Press ctrl until PANGESTURE_END.
|
|
PanGestureWithModifiers(PanGestureInput::PANGESTURE_PAN, MODIFIER_CONTROL, tm,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, -2),
|
|
mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
// At this moment (i.e. PANGESTURE_PAN), still in overscrolling state.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
PanGestureWithModifiers(PanGestureInput::PANGESTURE_END, MODIFIER_CONTROL, tm,
|
|
ScreenIntPoint(50, 80), ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
// The overscrolling state should have been restored.
|
|
EXPECT_TRUE(!apzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, SmoothTransitionFromPanToAnimation) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
// Start scrolled down to y=500px.
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 500));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
int frameLength = 10; // milliseconds; 10 to keep the math simple
|
|
float panVelocity = 10; // pixels per millisecond
|
|
int panPixelsPerFrame = frameLength * panVelocity; // 100 pixels per frame
|
|
|
|
ScreenIntPoint panPoint(50, 50);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, -1), mcc->Time());
|
|
// Pan up for 6 frames at 100 pixels per frame. This should reduce
|
|
// the vertical scroll offset from 500 to 0, and get us into overscroll.
|
|
for (int i = 0; i < 6; ++i) {
|
|
mcc->AdvanceByMillis(frameLength);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -panPixelsPerFrame), mcc->Time());
|
|
}
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Pan further into overscroll at the same input velocity, enough
|
|
// for the frames while we are in overscroll to dominate the computation
|
|
// in the velocity tracker.
|
|
// Importantly, while the input velocity is still 100 pixels per frame,
|
|
// in the overscrolled state the page only visual moves by at most 8 pixels
|
|
// per frame.
|
|
int frames = StaticPrefs::apz_velocity_relevance_time_ms() / frameLength;
|
|
for (int i = 0; i < frames; ++i) {
|
|
mcc->AdvanceByMillis(frameLength);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -panPixelsPerFrame), mcc->Time());
|
|
}
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// End the pan, allowing an overscroll animation to start.
|
|
mcc->AdvanceByMillis(frameLength);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
// Check that the velocity reflects the actual movement (no more than 8
|
|
// pixels/frame ==> 0.8 pixels per millisecond), not the input velocity
|
|
// (100 pixels/frame ==> 10 pixels per millisecond). This ensures that
|
|
// the transition from the pan to the animation appears smooth.
|
|
// (Note: velocities are negative since they are upwards.)
|
|
EXPECT_LT(apzc->GetVelocityVector().y, 0);
|
|
EXPECT_GT(apzc->GetVelocityVector().y, -0.8);
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, NoOverscrollForMousewheel) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
// Start scrolled down just a few pixels from the top.
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 3));
|
|
// Set line and page scroll amounts. Otherwise, even though Wheel() uses
|
|
// SCROLLDELTA_PIXEL, the wheel handling code will get confused by things
|
|
// like the "don't scroll more than one page" check.
|
|
metadata.SetPageScrollAmount(LayoutDeviceIntSize(50, 100));
|
|
metadata.SetLineScrollAmount(LayoutDeviceIntSize(5, 10));
|
|
apzc->SetScrollMetadata(metadata);
|
|
|
|
// Send a wheel with enough delta to scrollto y=0 *and* overscroll.
|
|
Wheel(apzc, ScreenIntPoint(10, 10), ScreenPoint(0, -10), mcc->Time());
|
|
|
|
// Check that we did not actually go into overscroll.
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, ClickWhileOverscrolled) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 0));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Pan into overscroll at the top.
|
|
ScreenIntPoint panPoint(50, 50);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, -1), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -100), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top
|
|
|
|
// End the pan. This should start an overscroll animation.
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
// Send a mouse-down. This should interrupt the animation but not relieve
|
|
// overscroll yet.
|
|
ParentLayerPoint overscrollBefore = apzc->GetOverscrollAmount();
|
|
MouseDown(apzc, panPoint, mcc->Time());
|
|
EXPECT_FALSE(apzc->IsOverscrollAnimationRunning());
|
|
EXPECT_EQ(overscrollBefore, apzc->GetOverscrollAmount());
|
|
|
|
// Send a mouse-up. This should start an overscroll animation again.
|
|
MouseUp(apzc, panPoint, mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
SampleAnimationUntilRecoveredFromOverscroll(ParentLayerPoint(0, 0));
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, DynamicallyLoadingContent) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 0));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Pan to the bottom of the page, and further, into overscroll.
|
|
ScreenIntPoint panPoint(50, 50);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, 1), mcc->Time());
|
|
for (int i = 0; i < 12; ++i) {
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, 100), mcc->Time());
|
|
}
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().y > 0); // overscrolled at bottom
|
|
|
|
// Grow the scrollable rect at the bottom, simulating the page loading content
|
|
// dynamically.
|
|
CSSRect scrollableRect = metrics.GetScrollableRect();
|
|
scrollableRect.height += 500;
|
|
metrics.SetScrollableRect(scrollableRect);
|
|
apzc->NotifyLayersUpdated(metadata, false, true);
|
|
|
|
// Check that the modified scrollable rect cleared the overscroll.
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
|
|
// Pan back up to the top, and further, into overscroll.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, -1), mcc->Time());
|
|
for (int i = 0; i < 12; ++i) {
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -100), mcc->Time());
|
|
}
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
ParentLayerPoint overscrollAmount = apzc->GetOverscrollAmount();
|
|
EXPECT_TRUE(overscrollAmount.y < 0); // overscrolled at top
|
|
|
|
// Grow the scrollable rect at the bottom again.
|
|
scrollableRect = metrics.GetScrollableRect();
|
|
scrollableRect.height += 500;
|
|
metrics.SetScrollableRect(scrollableRect);
|
|
apzc->NotifyLayersUpdated(metadata, false, true);
|
|
|
|
// Check that the modified scrollable rect did NOT clear overscroll at the
|
|
// top.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_EQ(overscrollAmount,
|
|
apzc->GetOverscrollAmount()); // overscroll did not change at all
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, SmallAmountOfOverscroll) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
|
|
// Do vertical overscroll first.
|
|
ScreenIntPoint panPoint(50, 50);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
|
|
// Then do small horizontal overscroll which will be considered as "finished"
|
|
// by our overscroll animation physics model.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(-0.1, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(-0.2, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().x < 0); // and overscrolled at left
|
|
|
|
// Then do vertical scroll.
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, 100), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
|
|
ParentLayerPoint scrollOffset = apzc->GetCurrentAsyncScrollOffset(
|
|
AsyncPanZoomController::eForEventHandling);
|
|
EXPECT_GT(scrollOffset.y, 0); // Make sure the vertical scroll offset is
|
|
// greater than zero.
|
|
|
|
// The small horizontal overscroll amount should be restored to zero.
|
|
ParentLayerPoint expectedScrollOffset(0, scrollOffset.y);
|
|
SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID // Only applies to WidgetOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, StuckInOverscroll_Bug1786452) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
|
|
// Over the course of the test, expect one or more calls to
|
|
// UpdateOverscrollOffset(), followed by a call to UpdateOverscrollVelocity().
|
|
// The latter ensures the widget has a chance to end its overscroll effect.
|
|
InSequence s;
|
|
EXPECT_CALL(*mcc, UpdateOverscrollOffset(_, _, _, _)).Times(AtLeast(1));
|
|
EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(1);
|
|
|
|
// Pan into overscroll, keeping the finger down
|
|
ScreenIntPoint startPoint(10, 500);
|
|
ScreenIntPoint endPoint(10, 10);
|
|
Pan(apzc, startPoint, endPoint, PanOptions::KeepFingerDown);
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Linger a while to cause the velocity to drop to very low or zero
|
|
mcc->AdvanceByMillis(100);
|
|
TouchMove(apzc, endPoint, mcc->Time());
|
|
EXPECT_LT(apzc->GetVelocityVector().Length(),
|
|
StaticPrefs::apz_fling_min_velocity_threshold());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
|
|
// Lift the finger
|
|
mcc->AdvanceByMillis(20);
|
|
TouchUp(apzc, endPoint, mcc->Time());
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
class APZCOverscrollTesterMock : public APZCTreeManagerTester {
|
|
public:
|
|
APZCOverscrollTesterMock() { CreateMockHitTester(); }
|
|
|
|
UniquePtr<ScopedLayerTreeRegistration> registration;
|
|
TestAsyncPanZoomController* rootApzc;
|
|
};
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTesterMock, OverscrollHandoff) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50)};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 200, 200));
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
// same size as the visible region so that
|
|
// the container is not scrollable in any directions
|
|
// actually. This is simulating overflow: hidden
|
|
// iframe document in Fission, though we don't set
|
|
// a different layers id.
|
|
CSSRect(0, 0, 100, 50));
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
// A pan gesture on the child scroller (which is not scrollable though).
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTesterMock, VerticalOverscrollHandoffToScrollableRoot) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Create a layer tree having two vertical scrollable layers.
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50)};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 100, 200));
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
CSSRect(0, 0, 100, 200));
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
// A vertical pan gesture on the child scroller which will be handed off to
|
|
// the root APZC.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTesterMock, NoOverscrollHandoffToNonScrollableRoot) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Create a layer tree having non-scrollable root and a vertical scrollable
|
|
// child.
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50)};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 100, 100));
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
CSSRect(0, 0, 100, 200));
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
// A vertical pan gesture on the child scroller which should not be handed
|
|
// off the root APZC.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
EXPECT_TRUE(ApzcOf(layers[1])->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Currently fails on Android
|
|
TEST_F(APZCOverscrollTesterMock, NoOverscrollHandoffOrthogonalPanGesture) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Create a layer tree having horizontal scrollable root and a vertical
|
|
// scrollable child.
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50)};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 200, 100));
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
CSSRect(0, 0, 100, 200));
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
// A vertical pan gesture on the child scroller which should not be handed
|
|
// off the root APZC because the root APZC is not scrollable vertically.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, ScreenIntPoint(50, 20),
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
EXPECT_TRUE(ApzcOf(layers[1])->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTesterMock,
|
|
RetriggerCancelledOverscrollAnimationByNewPanGesture) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Create a layer tree having vertical scrollable root and a horizontal
|
|
// scrollable child.
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50)};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 100, 200));
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
CSSRect(0, 0, 200, 50));
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
ScreenIntPoint panPoint(50, 20);
|
|
// A vertical pan gesture on the child scroller which should be handed off the
|
|
// root APZC.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// The root APZC should be overscrolled and the child APZC should not be.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled());
|
|
|
|
mcc->AdvanceByMillis(10);
|
|
|
|
// Make sure the root APZC is still overscrolled.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
|
|
// Start a new horizontal pan gesture on the child scroller which should be
|
|
// handled by the child APZC now.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
APZEventResult result = PanGesture(PanGestureInput::PANGESTURE_START, manager,
|
|
panPoint, ScreenPoint(-2, 0), mcc->Time());
|
|
// The above horizontal pan start event was flagged as "this event may trigger
|
|
// swipe" and either the root scrollable frame or the horizontal child
|
|
// scrollable frame is not scrollable in the pan start direction, thus the pan
|
|
// start event run into the short circuit path for swipe-to-navigation in
|
|
// InputQueue::ReceivePanGestureInput, which means it's waiting for the
|
|
// content response, so we need to respond explicitly here.
|
|
manager->ContentReceivedInputBlock(result.mInputBlockId, false);
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(-10, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// Now both APZCs should be overscrolled.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_TRUE(ApzcOf(layers[1])->IsOverscrolled());
|
|
|
|
// Sample all animations until all of them have been finished.
|
|
while (SampleAnimationsOnce());
|
|
|
|
// After the animations finished, all overscrolled states should have been
|
|
// restored.
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTesterMock, RetriggeredOverscrollAnimationVelocity) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Setup two nested vertical scrollable frames.
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRect[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(0, 0, 100, 50)};
|
|
CreateScrollData(treeShape, layerVisibleRect);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 100, 200));
|
|
SetScrollableFrameMetrics(layers[1], ScrollableLayerGuid::START_SCROLL_ID + 1,
|
|
CSSRect(0, 0, 100, 200));
|
|
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
ScreenIntPoint panPoint(50, 20);
|
|
// A vertical upward pan gesture on the child scroller which should be handed
|
|
// off the root APZC.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// The root APZC should be overscrolled and the child APZC should not be.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_FALSE(ApzcOf(layers[1])->IsOverscrolled());
|
|
|
|
mcc->AdvanceByMillis(10);
|
|
|
|
// Make sure the root APZC is still overscrolled and there's an overscroll
|
|
// animation.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning());
|
|
|
|
// And make sure the overscroll animation's velocity is a certain amount in
|
|
// the upward direction.
|
|
EXPECT_LT(rootApzc->GetVelocityVector().y, 0);
|
|
|
|
// Start a new downward pan gesture on the child scroller which
|
|
// should be handled by the child APZC now.
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
|
ScreenPoint(0, 2), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
// The new pan-start gesture stops the overscroll animation at this moment.
|
|
EXPECT_TRUE(!rootApzc->IsOverscrollAnimationRunning());
|
|
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
// There's no overscroll animation yet even if the root APZC is still
|
|
// overscrolled.
|
|
EXPECT_TRUE(!rootApzc->IsOverscrollAnimationRunning());
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID + 1);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
|
|
// Now an overscroll animation should have been triggered by the pan-end
|
|
// gesture.
|
|
EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning());
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
// And the newly created overscroll animation's positions should never exceed
|
|
// 0.
|
|
while (SampleAnimationsOnce()) {
|
|
EXPECT_LE(rootApzc->GetOverscrollAmount().y, 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTesterMock, OverscrollIntoPreventDefault) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
const char* treeShape = "x";
|
|
LayerIntRect layerVisibleRects[] = {LayerIntRect(0, 0, 100, 100)};
|
|
CreateScrollData(treeShape, layerVisibleRects);
|
|
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID,
|
|
CSSRect(0, 0, 100, 200));
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
|
|
// Start a pan gesture a few pixels below the 20px DTC region.
|
|
ScreenIntPoint cursorLocation(10, 25);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
|
|
APZEventResult result =
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, cursorLocation,
|
|
ScreenPoint(0, -2), mcc->Time());
|
|
|
|
// At this point, we should be overscrolled.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
|
|
// Pan further, until the DTC region is under the cursor.
|
|
// Note that, due to ApplyResistance(), we need a large input delta to cause a
|
|
// visual transform enough to bridge the 5px to the DTC region.
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, cursorLocation,
|
|
ScreenPoint(0, -100), mcc->Time());
|
|
|
|
// At this point, we are still overscrolled. Record the overscroll amount.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
float overscrollY = rootApzc->GetOverscrollAmount().y;
|
|
|
|
// Send a content response with preventDefault = true.
|
|
manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid});
|
|
manager->ContentReceivedInputBlock(result.mInputBlockId,
|
|
/*aPreventDefault=*/true);
|
|
|
|
// The content response has the effect of interrupting the input block
|
|
// but no processing happens yet (as there are no events in the block).
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_EQ(overscrollY, rootApzc->GetOverscrollAmount().y);
|
|
|
|
// Send one more pan event. This starts a new, *unconfirmed* input block
|
|
// (via the "transmogrify" codepath).
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID,
|
|
{CompositorHitTestFlags::eVisibleToHitTest,
|
|
CompositorHitTestFlags::eIrregularArea});
|
|
result = PanGesture(PanGestureInput::PANGESTURE_PAN, manager, cursorLocation,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
|
|
// No overscroll occurs (the event is waiting in the queue for confirmation).
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_EQ(overscrollY, rootApzc->GetOverscrollAmount().y);
|
|
|
|
// preventDefault the new event as well
|
|
manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid});
|
|
manager->ContentReceivedInputBlock(result.mInputBlockId,
|
|
/*aPreventDefault=*/true);
|
|
|
|
// This should trigger clearing the overscrolling and resetting the state.
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
rootApzc->AssertStateIsReset();
|
|
|
|
// If there are momentum events after this point, they should not cause
|
|
// further scrolling or overscorll.
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
|
|
result = PanGesture(PanGestureInput::PANGESTURE_MOMENTUMSTART, manager,
|
|
cursorLocation, ScreenPoint(0, -100), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(ScrollableLayerGuid::START_SCROLL_ID);
|
|
result = PanGesture(PanGestureInput::PANGESTURE_MOMENTUMPAN, manager,
|
|
cursorLocation, ScreenPoint(0, -100), mcc->Time());
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
EXPECT_EQ(rootApzc->GetFrameMetrics().GetVisualScrollOffset(),
|
|
CSSPoint(0, 0));
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Only applies to GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTesterMock, StuckInOverscroll_Bug1810935) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
using ViewID = ScrollableLayerGuid::ViewID;
|
|
ViewID rootScrollId = ScrollableLayerGuid::START_SCROLL_ID;
|
|
ViewID subframeScrollId = ScrollableLayerGuid::START_SCROLL_ID + 1;
|
|
|
|
const char* treeShape = "x(x)";
|
|
LayerIntRect layerVisibleRects[] = {LayerIntRect(0, 0, 100, 100),
|
|
LayerIntRect(50, 0, 50, 100)};
|
|
CreateScrollData(treeShape, layerVisibleRects);
|
|
SetScrollableFrameMetrics(root, rootScrollId, CSSRect(0, 0, 100, 200));
|
|
SetScrollableFrameMetrics(layers[1], subframeScrollId,
|
|
CSSRect(0, 0, 50, 200));
|
|
SetScrollHandoff(layers[1], root);
|
|
|
|
registration = MakeUnique<ScopedLayerTreeRegistration>(LayersId{0}, mcc);
|
|
UpdateHitTestingTree();
|
|
rootApzc = ApzcOf(root);
|
|
auto* subframeApzc = ApzcOf(layers[1]);
|
|
rootApzc->GetFrameMetrics().SetIsRootContent(true);
|
|
|
|
// Try to scroll upwards over the subframe.
|
|
ScreenIntPoint panPoint(75, 50);
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, -50), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
|
|
// The root APZC should be overscrolled. (The subframe APZC should be be.)
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_FALSE(subframeApzc->IsOverscrolled());
|
|
|
|
// Give the overscroll animation on the root a chance to start.
|
|
mcc->AdvanceByMillis(10);
|
|
EXPECT_TRUE(rootApzc->IsOverscrollAnimationRunning());
|
|
|
|
// Scroll the subframe downwards, with a large delta.
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, manager, panPoint,
|
|
ScreenPoint(0, 50), mcc->Time());
|
|
|
|
// Already after the first event, the overscroll animation should be
|
|
// interrupted.
|
|
EXPECT_FALSE(rootApzc->IsOverscrollAnimationRunning());
|
|
|
|
// Cotninue the downward scroll gesture.
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, 100), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, 100), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(subframeScrollId);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, manager, panPoint,
|
|
ScreenPoint(0, 100), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
QueueMockHitResult(subframeScrollId);
|
|
// Important: pass aSimulateMomentum=true for the pan-end to exercise the bug.
|
|
PanGesture(PanGestureInput::PANGESTURE_END, manager, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time(), MODIFIER_NONE,
|
|
/*aSimulateMomentum=*/true);
|
|
|
|
// The root and the subframe should both be overscrolled.
|
|
EXPECT_TRUE(rootApzc->IsOverscrolled());
|
|
EXPECT_TRUE(subframeApzc->IsOverscrolled());
|
|
|
|
// Sample animations until all of them have been finished.
|
|
while (SampleAnimationsOnce());
|
|
|
|
// All overscrolled APZCs should have snapped back.
|
|
EXPECT_FALSE(rootApzc->IsOverscrolled());
|
|
EXPECT_FALSE(subframeApzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
#ifndef MOZ_WIDGET_ANDROID // Not valid on Android
|
|
// Tests that the scroll offset is shifted with the overscroll amount when the
|
|
// content scroll range got expaned.
|
|
TEST_F(APZCOverscrollTester, FillOutGutterWhilePanning) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Scroll to the bottom edge.
|
|
ScrollMetadata metadata = apzc->GetScrollMetadata();
|
|
metadata.GetMetrics().SetLayoutScrollOffset(
|
|
CSSPoint(0, GetScrollRange().YMost()));
|
|
nsTArray<ScrollPositionUpdate> scrollUpdates;
|
|
scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
|
|
ScrollOrigin::Other,
|
|
CSSPoint::ToAppUnits(CSSPoint(0, GetScrollRange().YMost()))));
|
|
metadata.SetScrollUpdates(scrollUpdates);
|
|
metadata.GetMetrics().SetScrollGeneration(
|
|
scrollUpdates.LastElement().GetGeneration());
|
|
apzc->NotifyLayersUpdated(metadata, /*aIsFirstPaint=*/false,
|
|
/*aThisLayerTreeUpdated=*/true);
|
|
|
|
CSSPoint scrollOffset = metadata.GetMetrics().GetLayoutScrollOffset();
|
|
|
|
// Start panning to overscroll the content.
|
|
Pan(apzc, 20, 10, PanOptions::KeepFingerDown);
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
float overscrollY = apzc->GetOverscrollAmount().y;
|
|
EXPECT_GT(overscrollY, 0);
|
|
|
|
// Expand the content scroll range.
|
|
metadata = apzc->GetScrollMetadata();
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
const CSSRect& scrollableRect = metrics.GetScrollableRect();
|
|
metrics.SetScrollableRect(scrollableRect +
|
|
CSSSize(0, scrollableRect.height + 10));
|
|
apzc->NotifyLayersUpdated(metadata, /*aIsFirstPaint=*/false,
|
|
/*aThisLayerTreeUpdated=*/true);
|
|
|
|
// Now that the scroll position was shifted with the overscroll amount.
|
|
EXPECT_EQ(apzc->GetScrollMetadata().GetMetrics().GetVisualScrollOffset().y,
|
|
scrollOffset.y + overscrollY);
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
}
|
|
|
|
// Similar to FillOutGutterWhilePanning but expanding the content while an
|
|
// overscroll animation is running.
|
|
TEST_F(APZCOverscrollTester, FillOutGutterWhileAnimating) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Scroll to the bottom edge.
|
|
ScrollMetadata metadata = apzc->GetScrollMetadata();
|
|
metadata.GetMetrics().SetLayoutScrollOffset(
|
|
CSSPoint(0, GetScrollRange().YMost()));
|
|
nsTArray<ScrollPositionUpdate> scrollUpdates;
|
|
scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
|
|
ScrollOrigin::Other,
|
|
CSSPoint::ToAppUnits(CSSPoint(0, GetScrollRange().YMost()))));
|
|
metadata.SetScrollUpdates(scrollUpdates);
|
|
metadata.GetMetrics().SetScrollGeneration(
|
|
scrollUpdates.LastElement().GetGeneration());
|
|
apzc->NotifyLayersUpdated(metadata, /*aIsFirstPaint=*/false,
|
|
/*aThisLayerTreeUpdated=*/true);
|
|
|
|
CSSPoint scrollOffset = metadata.GetMetrics().GetLayoutScrollOffset();
|
|
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, ScreenIntPoint(50, 80),
|
|
ScreenPoint(0, 20), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 60),
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
apzc->AdvanceAnimations(mcc->GetSampleTime());
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, ScreenIntPoint(50, 50),
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, ScreenIntPoint(50, 50),
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
mcc->AdvanceByMillis(5);
|
|
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
float overscrollY = apzc->GetOverscrollAmount().y;
|
|
EXPECT_GT(overscrollY, 0);
|
|
|
|
// Expand the content scroll range.
|
|
metadata = apzc->GetScrollMetadata();
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
const CSSRect& scrollableRect = metrics.GetScrollableRect();
|
|
metrics.SetScrollableRect(scrollableRect +
|
|
CSSSize(0, scrollableRect.height + 10));
|
|
apzc->NotifyLayersUpdated(metadata, /*aIsFirstPaint=*/false,
|
|
/*aThisLayerTreeUpdated=*/true);
|
|
|
|
// Now that the scroll position was shifted with the overscroll amount.
|
|
EXPECT_EQ(apzc->GetScrollMetadata().GetMetrics().GetVisualScrollOffset().y,
|
|
scrollOffset.y + overscrollY);
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
}
|
|
#endif
|
|
|
|
// Test that a programmatic scroll animation does NOT trigger overscroll.
|
|
TEST_F(APZCOverscrollTester, ProgrammaticScroll) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
// Send a SmoothMsd scroll update to a destination far outside of the
|
|
// scroll range (here, y=100000). This probably shouldn't happen in the
|
|
// first place, but even if it does for whatever reason, the smooth scroll
|
|
// should not trigger overscroll.
|
|
ScrollMetadata metadata = apzc->GetScrollMetadata();
|
|
nsTArray<ScrollPositionUpdate> scrollUpdates;
|
|
scrollUpdates.AppendElement(ScrollPositionUpdate::NewSmoothScroll(
|
|
ScrollMode::SmoothMsd, ScrollOrigin::Other,
|
|
CSSPoint::ToAppUnits(CSSPoint(0, 100000)), ScrollTriggeredByScript::Yes,
|
|
nullptr));
|
|
metadata.SetScrollUpdates(scrollUpdates);
|
|
metadata.GetMetrics().SetScrollGeneration(
|
|
scrollUpdates.LastElement().GetGeneration());
|
|
apzc->NotifyLayersUpdated(metadata, /*aIsFirstPaint=*/false,
|
|
/*aThisLayerTreeUpdated=*/true);
|
|
|
|
apzc->AssertStateIsSmoothMsdScroll();
|
|
|
|
while (SampleAnimationOneFrame()) {
|
|
EXPECT_FALSE(apzc->IsOverscrolled());
|
|
}
|
|
}
|
|
|
|
// A touchpad hold gesture should pause any ongoing overscroll animation (so
|
|
// that the page is not moving while the fingers are down on the touchpad),
|
|
// but should not cancel it. The animation should continue if the finger is
|
|
// lifted.
|
|
#ifndef MOZ_WIDGET_ANDROID // Requires GenericOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, HoldGestureDuringOverscroll) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
ScrollMetadata metadata;
|
|
FrameMetrics& metrics = metadata.GetMetrics();
|
|
metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
|
|
metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
|
|
metrics.SetVisualScrollOffset(CSSPoint(0, 0));
|
|
apzc->SetFrameMetrics(metrics);
|
|
|
|
// Pan into overscroll at the top.
|
|
ScreenIntPoint panPoint(50, 50);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, -1), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -100), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top
|
|
|
|
// End the pan. This should start an overscroll animation.
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
EXPECT_TRUE(apzc->GetOverscrollAmount().y < 0); // overscrolled at top
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
// Start a hold gesture (represented using PANGESTURE_MAYSTART).
|
|
// This should interrupt the animation but not relieve overscroll yet.
|
|
ParentLayerPoint overscrollBefore = apzc->GetOverscrollAmount();
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_MAYSTART, apzc, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_FALSE(apzc->IsOverscrollAnimationRunning());
|
|
EXPECT_EQ(overscrollBefore, apzc->GetOverscrollAmount());
|
|
|
|
// End the hold gesture (represented using PANGESTURE_CANCELLED).
|
|
// This should start an overscroll animation again.
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_CANCELLED, apzc, panPoint,
|
|
ScreenPoint(0, 0), mcc->Time());
|
|
EXPECT_TRUE(apzc->IsOverscrollAnimationRunning());
|
|
|
|
SampleAnimationUntilRecoveredFromOverscroll(ParentLayerPoint(0, 0));
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, NoResetTouchInputStateCalled) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
MakeApzcWaitForMainThread();
|
|
|
|
InSequence s;
|
|
// The UpdateOverscrollVelocity should never be called since there's no
|
|
// overscrolling state.
|
|
EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(0);
|
|
|
|
ScreenIntPoint touchPoint(5, 5);
|
|
APZEventResult result = TouchDown(apzc, touchPoint, mcc->Time());
|
|
SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
|
|
apzc->ContentReceivedInputBlock(result.mInputBlockId,
|
|
/*aPreventDefault=*/true);
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
touchPoint.y -= 1;
|
|
mcc->AdvanceByMillis(10);
|
|
TouchMove(apzc, touchPoint, mcc->Time());
|
|
}
|
|
|
|
mcc->AdvanceByMillis(10);
|
|
TouchUp(apzc, touchPoint, mcc->Time());
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, ResetTouchInputStateJustOnce) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
SCOPED_GFX_PREF_FLOAT("apz.touch_start_tolerance", 0.1f);
|
|
SCOPED_GFX_PREF_FLOAT("apz.touch_move_tolerance", 0.0f);
|
|
// To avoid falling into a fast fling state so that the second touch-start
|
|
// event can be preventDefault-ed.
|
|
SCOPED_GFX_PREF_FLOAT("apz.fling_stop_on_tap_threshold", 1000.0f);
|
|
|
|
InSequence s;
|
|
// The UpdateOverscrollVelocity should be called just once for the second
|
|
// touchdown event which will be preventDefault-ed.
|
|
EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(1);
|
|
|
|
// Overscroll once.
|
|
PanIntoOverscroll();
|
|
|
|
// Now the touch-start event will be preventDefault-ed.
|
|
MakeApzcWaitForMainThread();
|
|
|
|
ScreenIntPoint touchPoint(5, 5);
|
|
APZEventResult result = TouchDown(apzc, touchPoint, mcc->Time());
|
|
SetDefaultAllowedTouchBehavior(apzc, result.mInputBlockId);
|
|
apzc->ContentReceivedInputBlock(result.mInputBlockId,
|
|
/*aPreventDefault=*/true);
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
touchPoint.y -= 1;
|
|
mcc->AdvanceByMillis(10);
|
|
TouchMove(apzc, touchPoint, mcc->Time());
|
|
}
|
|
|
|
mcc->AdvanceByMillis(10);
|
|
TouchUp(apzc, touchPoint, mcc->Time());
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, NoResetPanGestureInputStateCalled) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
MakeApzcWaitForMainThread();
|
|
|
|
InSequence s;
|
|
// The UpdateOverscrollVelocity should never be called since there's no
|
|
// overscrolling state.
|
|
EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(0);
|
|
|
|
ScreenIntPoint panPoint(5, 5);
|
|
APZEventResult result = PanGesture(PanGestureInput::PANGESTURE_START, apzc,
|
|
panPoint, ScreenPoint(0, 1), mcc->Time());
|
|
apzc->ContentReceivedInputBlock(result.mInputBlockId,
|
|
/*aPreventDefault=*/true);
|
|
for (int i = 0; i < 5; ++i) {
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, 1), mcc->Time());
|
|
}
|
|
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
}
|
|
#endif
|
|
|
|
#ifdef MOZ_WIDGET_ANDROID // Only testable with WidgetOverscrollEffect
|
|
TEST_F(APZCOverscrollTester, ResetPanGestureInputStateJustOnce) {
|
|
SCOPED_GFX_PREF_BOOL("apz.overscroll.enabled", true);
|
|
|
|
InSequence s;
|
|
// The UpdateOverscrollVelocity should be called just once because
|
|
// the second pan-start event (wheel event) during overscrolling
|
|
// which will be preventDefault-ed.
|
|
EXPECT_CALL(*mcc, UpdateOverscrollVelocity(_, _, _, _)).Times(1);
|
|
|
|
// NOTE: PanIntoOverscroll uses touch events. We do overscroll with pan
|
|
// gestures.
|
|
ScreenIntPoint panPoint(5, 5);
|
|
PanGesture(PanGestureInput::PANGESTURE_START, apzc, panPoint,
|
|
ScreenPoint(0, -10), mcc->Time());
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, -100), mcc->Time());
|
|
// Make sure it's overscrolling.
|
|
EXPECT_TRUE(apzc->IsOverscrolled());
|
|
// Finish the pan gesture.
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
|
|
// Now the next pan gesture event will be preventDefault-ed.
|
|
MakeApzcWaitForMainThread();
|
|
|
|
APZEventResult result = PanGesture(PanGestureInput::PANGESTURE_START, apzc,
|
|
panPoint, ScreenPoint(0, 10), mcc->Time());
|
|
apzc->ContentReceivedInputBlock(result.mInputBlockId,
|
|
/*aPreventDefault=*/true);
|
|
for (int i = 0; i < 5; ++i) {
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_PAN, apzc, panPoint,
|
|
ScreenPoint(0, 10), mcc->Time());
|
|
}
|
|
|
|
mcc->AdvanceByMillis(10);
|
|
PanGesture(PanGestureInput::PANGESTURE_END, apzc, panPoint, ScreenPoint(0, 0),
|
|
mcc->Time());
|
|
}
|
|
#endif
|