Bug 1700215 - Generate OverscrollAnimation only if it's overscrolled on the axis. r=botond

This is a prerequisite change to keep momentum scrolls happening on the other
axis where no overscroll animation is running.

Differential Revision: https://phabricator.services.mozilla.com/D110793
This commit is contained in:
Hiroyuki Ikezoe 2021-04-14 23:29:37 +00:00
parent a1a4fe1d55
commit a41405e106
11 changed files with 86 additions and 27 deletions

View File

@ -56,7 +56,7 @@ void AxisPhysicsMSDModel::SetDestination(double aDestination) {
mDestination = aDestination;
}
bool AxisPhysicsMSDModel::IsFinished(double aSmallestVisibleIncrement) {
bool AxisPhysicsMSDModel::IsFinished(double aSmallestVisibleIncrement) const {
// In order to satisfy the condition of reaching the destination, the distance
// between the simulation position and the destination must be less than
// aSmallestVisibleIncrement while the speed is simultaneously less than

View File

@ -38,7 +38,7 @@ class AxisPhysicsMSDModel : public AxisPhysicsModel {
* Returns true when the position is close to the destination and the
* velocity is low.
*/
bool IsFinished(double aSmallestVisibleIncrement);
bool IsFinished(double aSmallestVisibleIncrement) const;
protected:
double Acceleration(const State& aState) override;

View File

@ -109,6 +109,24 @@ bool ShouldUseProgressivePaint() {
#endif
}
SideBits GetOverscrollSideBits(const ParentLayerPoint& aOverscrollAmount) {
SideBits sides = SideBits::eNone;
if (aOverscrollAmount.x < 0) {
sides |= SideBits::eLeft;
} else if (aOverscrollAmount.x > 0) {
sides |= SideBits::eRight;
}
if (aOverscrollAmount.y < 0) {
sides |= SideBits::eTop;
} else if (aOverscrollAmount.y > 0) {
sides |= SideBits::eBottom;
}
return sides;
}
} // namespace apz
} // namespace layers
} // namespace mozilla

View File

@ -205,6 +205,12 @@ bool AboutToCheckerboard(const FrameMetrics& aPaintedMetrics,
* using the StaticPrefs getter directly.
*/
bool ShouldUseProgressivePaint();
/**
* Returns SideBits where the given |aOverscrollAmount| overscrolls.
*/
SideBits GetOverscrollSideBits(const ParentLayerPoint& aOverscrollAmount);
} // namespace apz
} // namespace layers

View File

@ -2721,7 +2721,7 @@ nsEventStatus AsyncPanZoomController::OnPan(
if (aFingersOnTouchpad == FingersOnTouchpad::No) {
if (IsOverscrolled() && mState != OVERSCROLL_ANIMATION) {
StartOverscrollAnimation(velocity);
StartOverscrollAnimation(velocity, GetOverscrollSideBits());
} else if (!consumed) {
// If there is unconsumed scroll and we're in the momentum part of the
// pan gesture, terminate the momentum scroll. This prevents momentum
@ -2754,7 +2754,7 @@ nsEventStatus AsyncPanZoomController::OnPanEnd(const PanGestureInput& aEvent) {
if (IsOverscrolled() && mState != OVERSCROLL_ANIMATION) {
// If we are in overscrolled state, trigger OverscrollAnimation to
// ensure we will snap back to the scroll edge.
StartOverscrollAnimation(GetVelocityVector());
StartOverscrollAnimation(GetVelocityVector(), GetOverscrollSideBits());
} else {
SetState(NOTHING);
}
@ -3635,7 +3635,7 @@ bool AsyncPanZoomController::OverscrollBehaviorAllowsSwipe() const {
}
void AsyncPanZoomController::HandleFlingOverscroll(
const ParentLayerPoint& aVelocity,
const ParentLayerPoint& aVelocity, SideBits aOverscrollSideBits,
const RefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
const RefPtr<const AsyncPanZoomController>& aScrolledApzc) {
APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
@ -3659,17 +3659,19 @@ void AsyncPanZoomController::HandleFlingOverscroll(
}
if (!IsZero(residualVelocity)) {
mOverscrollEffect->HandleFlingOverscroll(residualVelocity);
mOverscrollEffect->HandleFlingOverscroll(residualVelocity,
aOverscrollSideBits);
}
}
}
}
void AsyncPanZoomController::HandleSmoothScrollOverscroll(
const ParentLayerPoint& aVelocity) {
const ParentLayerPoint& aVelocity, SideBits aOverscrollSideBits) {
// We must call BuildOverscrollHandoffChain from this deferred callback
// function in order to avoid a deadlock when acquiring the tree lock.
HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain(), nullptr);
HandleFlingOverscroll(aVelocity, aOverscrollSideBits,
BuildOverscrollHandoffChain(), nullptr);
}
void AsyncPanZoomController::SmoothScrollTo(const CSSPoint& aDestination,
@ -3730,13 +3732,13 @@ void AsyncPanZoomController::SmoothMsdScrollTo(const CSSPoint& aDestination) {
}
void AsyncPanZoomController::StartOverscrollAnimation(
const ParentLayerPoint& aVelocity) {
const ParentLayerPoint& aVelocity, SideBits aOverscrollSideBits) {
SetState(OVERSCROLL_ANIMATION);
ParentLayerPoint velocity = aVelocity;
AdjustDeltaForAllowedScrollDirections(velocity,
GetOverscrollableDirections());
StartAnimation(new OverscrollAnimation(*this, velocity));
StartAnimation(new OverscrollAnimation(*this, velocity, aOverscrollSideBits));
}
bool AsyncPanZoomController::CallDispatchScroll(
@ -3834,6 +3836,10 @@ ParentLayerPoint AsyncPanZoomController::GetOverscrollAmount() const {
return {mX.GetOverscroll(), mY.GetOverscroll()};
}
SideBits AsyncPanZoomController::GetOverscrollSideBits() const {
return apz::GetOverscrollSideBits({mX.GetOverscroll(), mY.GetOverscroll()});
}
void AsyncPanZoomController::RestoreOverscrollAmount(
const ParentLayerPoint& aOverscroll) {
mX.RestoreOverscroll(aOverscroll.x);
@ -4175,7 +4181,7 @@ bool AsyncPanZoomController::SnapBackIfOverscrolled() {
// animation - if so, don't start a new one.
if (IsOverscrolled() && mState != OVERSCROLL_ANIMATION) {
APZC_LOG("%p is overscrolled, starting snap-back\n", this);
StartOverscrollAnimation(ParentLayerPoint(0, 0));
StartOverscrollAnimation(ParentLayerPoint(0, 0), GetOverscrollSideBits());
return true;
}
// If we don't kick off an overscroll animation, we still need to ask the

View File

@ -809,6 +809,12 @@ class AsyncPanZoomController {
* Gets the amount by which this APZC is overscrolled along both axes.
*/
ParentLayerPoint GetOverscrollAmount() const;
/**
* Returns SideBits where this APZC is overscrolled.
*/
SideBits GetOverscrollSideBits() const;
/**
* Restore the amount by which this APZC is overscrolled along both axes
* to the specified amount. This is for test-related use; overscrolling
@ -1452,14 +1458,16 @@ class AsyncPanZoomController {
// later in the handoff chain, or if there are no takers, continuing the
// fling and entering an overscrolled state.
void HandleFlingOverscroll(
const ParentLayerPoint& aVelocity,
const ParentLayerPoint& aVelocity, SideBits aOverscrollSideBits,
const RefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
const RefPtr<const AsyncPanZoomController>& aScrolledApzc);
void HandleSmoothScrollOverscroll(const ParentLayerPoint& aVelocity);
void HandleSmoothScrollOverscroll(const ParentLayerPoint& aVelocity,
SideBits aOverscrollSideBits);
// Start an overscroll animation with the given initial velocity.
void StartOverscrollAnimation(const ParentLayerPoint& aVelocity);
void StartOverscrollAnimation(const ParentLayerPoint& aVelocity,
SideBits aOverscrollSideBits);
// Return the directions in which this APZC allows overscrolling.
ScrollDirections GetOverscrollableDirections() const;

View File

@ -233,6 +233,10 @@ bool Axis::SampleOverscrollAnimation(const TimeDuration& aDelta) {
return true;
}
bool Axis::IsOverscrollAnimationRunning() const {
return !mMSDModel.IsFinished(1.0);
}
bool Axis::IsOverscrolled() const { return mOverscroll != 0.f; }
void Axis::ClearOverscroll() {

View File

@ -174,6 +174,11 @@ class Axis {
*/
void ClearOverscroll();
/**
* Returns whether the overscroll animation is running.
*/
bool IsOverscrollAnimationRunning() const;
/**
* Gets the starting position of the touch supplied in StartTouch().
*/

View File

@ -164,12 +164,13 @@ class GenericFlingAnimation : public AsyncPanZoomAnimation,
FLING_LOG("%p fling went into overscroll, handing off with velocity %s\n",
&mApzc, ToString(velocity).c_str());
mDeferredTasks.AppendElement(
NewRunnableMethod<ParentLayerPoint,
NewRunnableMethod<ParentLayerPoint, SideBits,
RefPtr<const OverscrollHandoffChain>,
RefPtr<const AsyncPanZoomController>>(
"layers::AsyncPanZoomController::HandleFlingOverscroll", &mApzc,
&AsyncPanZoomController::HandleFlingOverscroll, velocity,
mOverscrollHandoffChain, mScrolledApzc));
apz::GetOverscrollSideBits(overscroll), mOverscrollHandoffChain,
mScrolledApzc));
// If there is a remaining velocity on this APZC, continue this fling
// as well. (This fling and the handed-off fling will run concurrently.)

View File

@ -19,10 +19,15 @@ namespace layers {
class OverscrollAnimation : public AsyncPanZoomAnimation {
public:
OverscrollAnimation(AsyncPanZoomController& aApzc,
const ParentLayerPoint& aVelocity)
const ParentLayerPoint& aVelocity,
SideBits aOverscrollSideBits)
: mApzc(aApzc) {
mApzc.mX.StartOverscrollAnimation(aVelocity.x);
mApzc.mY.StartOverscrollAnimation(aVelocity.y);
if ((aOverscrollSideBits & SideBits::eLeftRight) != SideBits::eNone) {
mApzc.mX.StartOverscrollAnimation(aVelocity.x);
}
if ((aOverscrollSideBits & SideBits::eTopBottom) != SideBits::eNone) {
mApzc.mY.StartOverscrollAnimation(aVelocity.y);
}
}
virtual ~OverscrollAnimation() {
mApzc.mX.EndOverscrollAnimation();
@ -32,8 +37,10 @@ class OverscrollAnimation : public AsyncPanZoomAnimation {
virtual bool DoSample(FrameMetrics& aFrameMetrics,
const TimeDuration& aDelta) override {
// Can't inline these variables due to short-circuit evaluation.
bool continueX = mApzc.mX.SampleOverscrollAnimation(aDelta);
bool continueY = mApzc.mY.SampleOverscrollAnimation(aDelta);
bool continueX = mApzc.mX.IsOverscrollAnimationRunning() &&
mApzc.mX.SampleOverscrollAnimation(aDelta);
bool continueY = mApzc.mY.IsOverscrollAnimationRunning() &&
mApzc.mY.SampleOverscrollAnimation(aDelta);
if (!continueX && !continueY) {
// If we got into overscroll from a fling, that fling did not request a
// fling snap to avoid a resulting scrollTo from cancelling the overscroll
@ -65,7 +72,8 @@ class OverscrollEffectBase {
virtual ~OverscrollEffectBase() = default;
virtual void ConsumeOverscroll(ParentLayerPoint& aOverscroll,
ScrollDirections aOverscrolableDirections) = 0;
virtual void HandleFlingOverscroll(const ParentLayerPoint& aVelocity) = 0;
virtual void HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
SideBits aOverscrollSideBits) = 0;
};
// A generic overscroll effect, implemented by AsyncPanZoomController itself.
@ -91,8 +99,9 @@ class GenericOverscrollEffect : public OverscrollEffectBase {
}
}
void HandleFlingOverscroll(const ParentLayerPoint& aVelocity) override {
mApzc.StartOverscrollAnimation(aVelocity);
void HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
SideBits aOverscrollSideBits) override {
mApzc.StartOverscrollAnimation(aVelocity, aOverscrollSideBits);
}
private:
@ -117,7 +126,8 @@ class WidgetOverscrollEffect : public OverscrollEffectBase {
}
}
void HandleFlingOverscroll(const ParentLayerPoint& aVelocity) override {
void HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
SideBits aOverscrollSideBits) override {
RefPtr<GeckoContentController> controller =
mApzc.GetGeckoContentController();
if (controller) {

View File

@ -103,9 +103,10 @@ bool SmoothMsdScrollAnimation::DoSample(FrameMetrics& aFrameMetrics,
// violate the lock ordering. Instead we schedule
// HandleSmoothScrollOverscroll() to be called after mRecursiveMutex is
// released.
mDeferredTasks.AppendElement(NewRunnableMethod<ParentLayerPoint>(
mDeferredTasks.AppendElement(NewRunnableMethod<ParentLayerPoint, SideBits>(
"layers::AsyncPanZoomController::HandleSmoothScrollOverscroll", &mApzc,
&AsyncPanZoomController::HandleSmoothScrollOverscroll, velocity));
&AsyncPanZoomController::HandleSmoothScrollOverscroll, velocity,
apz::GetOverscrollSideBits(overscroll)));
return false;
}