diff --git a/gfx/layers/apz/src/AndroidAPZ.cpp b/gfx/layers/apz/src/AndroidAPZ.cpp index bc5229ce8ad5..4a5207e547f2 100644 --- a/gfx/layers/apz/src/AndroidAPZ.cpp +++ b/gfx/layers/apz/src/AndroidAPZ.cpp @@ -47,12 +47,14 @@ AndroidSpecificState::AndroidSpecificState() { AsyncPanZoomAnimation* AndroidSpecificState::CreateFlingAnimation(AsyncPanZoomController& aApzc, - const FlingHandoffState& aHandoffState) { + const FlingHandoffState& aHandoffState, + float aPLPPI) { if (gfxPrefs::APZUseChromeFlingPhysics()) { return new GenericFlingAnimation(aApzc, aHandoffState.mChain, aHandoffState.mIsHandoff, - aHandoffState.mScrolledApzc); + aHandoffState.mScrolledApzc, + aPLPPI); } else { return new StackScrollerFlingAnimation(aApzc, this, diff --git a/gfx/layers/apz/src/AndroidAPZ.h b/gfx/layers/apz/src/AndroidAPZ.h index 191c4ba7eac4..200273d6023f 100644 --- a/gfx/layers/apz/src/AndroidAPZ.h +++ b/gfx/layers/apz/src/AndroidAPZ.h @@ -23,7 +23,8 @@ public: } virtual AsyncPanZoomAnimation* CreateFlingAnimation(AsyncPanZoomController& aApzc, - const FlingHandoffState& aHandoffState) override; + const FlingHandoffState& aHandoffState, + float aPLPPI) override; static void InitializeGlobalState(); diff --git a/gfx/layers/apz/src/AndroidFlingPhysics.cpp b/gfx/layers/apz/src/AndroidFlingPhysics.cpp index 052bb7d7dd9f..2fef3a196c30 100644 --- a/gfx/layers/apz/src/AndroidFlingPhysics.cpp +++ b/gfx/layers/apz/src/AndroidFlingPhysics.cpp @@ -18,13 +18,14 @@ namespace layers { // Chrome's implementation of fling physics on Android: // https://cs.chromium.org/chromium/src/ui/events/android/scroller.cc?rcl=3ae3aaff927038a5c644926842cb0c31dea60c79 -static double ComputeDeceleration(float aFriction) +static double ComputeDeceleration(float aDPI) { + const float kFriction = 0.84f; const float kGravityEarth = 9.80665f; return kGravityEarth // g (m/s^2) * 39.37f // inch/meter - * 160.f // pixels/inch - * aFriction; + * aDPI // pixels/inch + * kFriction; } // == std::log(0.78f) / std::log(0.9f) @@ -59,25 +60,23 @@ static float GetThresholdForFlingEnd() return gfxPrefs::APZChromeFlingPhysicsStopThreshold(); } -const float kTuningCoeff = ComputeDeceleration(0.84f); - -static double ComputeSplineDeceleration(ParentLayerCoord aVelocity) +static double ComputeSplineDeceleration(ParentLayerCoord aVelocity, double aTuningCoeff) { float velocityPerSec = aVelocity * 1000.0f; - return std::log(GetInflexion() * velocityPerSec / (GetFlingFriction() * kTuningCoeff)); + return std::log(GetInflexion() * velocityPerSec / (GetFlingFriction() * aTuningCoeff)); } -static TimeDuration ComputeFlingDuration(ParentLayerCoord aVelocity) +static TimeDuration ComputeFlingDuration(ParentLayerCoord aVelocity, double aTuningCoeff) { - const double splineDecel = ComputeSplineDeceleration(aVelocity); + const double splineDecel = ComputeSplineDeceleration(aVelocity, aTuningCoeff); const double timeSeconds = std::exp(splineDecel / (kDecelerationRate - 1.0)); return TimeDuration::FromSeconds(timeSeconds); } -static ParentLayerCoord ComputeFlingDistance(ParentLayerCoord aVelocity) +static ParentLayerCoord ComputeFlingDistance(ParentLayerCoord aVelocity, double aTuningCoeff) { - const double splineDecel = ComputeSplineDeceleration(aVelocity); - return GetFlingFriction() * kTuningCoeff * + const double splineDecel = ComputeSplineDeceleration(aVelocity, aTuningCoeff); + return GetFlingFriction() * aTuningCoeff * std::exp(kDecelerationRate / (kDecelerationRate - 1.0) * splineDecel); } @@ -148,17 +147,19 @@ StaticAutoPtr gSplineConstants; ClearOnShutdown(&gSplineConstants); } -void AndroidFlingPhysics::Init(const ParentLayerPoint& aStartingVelocity) +void AndroidFlingPhysics::Init(const ParentLayerPoint& aStartingVelocity, + float aPLPPI) { mVelocity = aStartingVelocity.Length(); - mTargetDuration = ComputeFlingDuration(mVelocity); + const double tuningCoeff = ComputeDeceleration(aPLPPI); + mTargetDuration = ComputeFlingDuration(mVelocity, tuningCoeff); MOZ_ASSERT(!mTargetDuration.IsZero()); mDurationSoFar = TimeDuration(); mLastPos = ParentLayerPoint(); mCurrentPos = ParentLayerPoint(); float coeffX = mVelocity == 0 ? 1.0f : aStartingVelocity.x / mVelocity; float coeffY = mVelocity == 0 ? 1.0f : aStartingVelocity.y / mVelocity; - mTargetDistance = ComputeFlingDistance(mVelocity); + mTargetDistance = ComputeFlingDistance(mVelocity, tuningCoeff); mTargetPos = ParentLayerPoint(mTargetDistance * coeffX, mTargetDistance * coeffY); const float hyp = mTargetPos.Length(); diff --git a/gfx/layers/apz/src/AndroidFlingPhysics.h b/gfx/layers/apz/src/AndroidFlingPhysics.h index 0c9fa8992b57..d58dd1d1135c 100644 --- a/gfx/layers/apz/src/AndroidFlingPhysics.h +++ b/gfx/layers/apz/src/AndroidFlingPhysics.h @@ -17,7 +17,7 @@ namespace layers { class AndroidFlingPhysics { public: - void Init(const ParentLayerPoint& aVelocity); + void Init(const ParentLayerPoint& aVelocity, float aPLPPI); void Sample(const TimeDuration& aDelta, ParentLayerPoint* aOutVelocity, ParentLayerPoint* aOutOffset); diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 8771ab162256..508c60dc6657 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -536,12 +536,14 @@ static uint32_t sAsyncPanZoomControllerCount = 0; AsyncPanZoomAnimation* PlatformSpecificStateBase::CreateFlingAnimation(AsyncPanZoomController& aApzc, - const FlingHandoffState& aHandoffState) + const FlingHandoffState& aHandoffState, + float aPLPPI) { return new GenericFlingAnimation(aApzc, aHandoffState.mChain, aHandoffState.mIsHandoff, - aHandoffState.mScrolledApzc); + aHandoffState.mScrolledApzc, + aPLPPI); } TimeStamp @@ -3015,6 +3017,11 @@ RefPtr AsyncPanZoomController::BuildOverscrollHand } ParentLayerPoint AsyncPanZoomController::AttemptFling(const FlingHandoffState& aHandoffState) { + // The PLPPI computation acquires the tree lock, so it needs to be performed + // on the controller thread, and before the APZC lock is acquired. + APZThreadUtils::AssertOnControllerThread(); + float PLPPI = ComputePLPPI(PanStart(), aHandoffState.mVelocity); + RecursiveMutexAutoLock lock(mRecursiveMutex); if (!IsPannable()) { @@ -3041,13 +3048,29 @@ ParentLayerPoint AsyncPanZoomController::AttemptFling(const FlingHandoffState& a ScrollSnapToDestination(); if (mState != SMOOTH_SCROLL) { SetState(FLING); - AsyncPanZoomAnimation* fling = GetPlatformSpecificState()->CreateFlingAnimation(*this, aHandoffState); + AsyncPanZoomAnimation* fling = GetPlatformSpecificState()->CreateFlingAnimation( + *this, aHandoffState, PLPPI); StartAnimation(fling); } return residualVelocity; } +float AsyncPanZoomController::ComputePLPPI(ParentLayerPoint aPoint, ParentLayerPoint aDirection) const +{ + // Convert |aDirection| into a unit vector. + aDirection = aDirection / aDirection.Length(); + + // Place the vector at |aPoint| and convert to screen coordinates. + // The length of the resulting vector is the number of Screen coordinates + // that equal 1 ParentLayer coordinate in the given direction. + float screenPerParent = ToScreenCoordinates(aDirection, aPoint).Length(); + + // Finally, factor in the DPI scale. + return GetDPI() / screenPerParent; +} + + ParentLayerPoint AsyncPanZoomController::AdjustHandoffVelocityForOverscrollBehavior(ParentLayerPoint& aHandoffVelocity) const { RecursiveMutexAutoLock lock(mRecursiveMutex); diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 27a90ab30b9e..c05158999987 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -71,8 +71,10 @@ class PlatformSpecificStateBase { public: virtual ~PlatformSpecificStateBase() = default; virtual AndroidSpecificState* AsAndroidSpecificState() { return nullptr; } + // PLPPI = "ParentLayer pixels per (Screen) inch" virtual AsyncPanZoomAnimation* CreateFlingAnimation(AsyncPanZoomController& aApzc, - const FlingHandoffState& aHandoffState); + const FlingHandoffState& aHandoffState, + float aPLPPI); static void InitializeGlobalState() {} }; @@ -1207,6 +1209,10 @@ private: // Invoked by the pinch repaint timer. void DoDelayedRequestContentRepaint(); + // Compute the number of ParentLayer pixels per (Screen) inch at the given + // point and in the given direction. + float ComputePLPPI(ParentLayerPoint aPoint, ParentLayerPoint aDirection) const; + /* =================================================================== * The functions and members in this section are used to make ancestor chains * out of APZC instances. These chains can only be walked or manipulated diff --git a/gfx/layers/apz/src/DesktopFlingPhysics.h b/gfx/layers/apz/src/DesktopFlingPhysics.h index 19c19600ea41..6d78c51db470 100644 --- a/gfx/layers/apz/src/DesktopFlingPhysics.h +++ b/gfx/layers/apz/src/DesktopFlingPhysics.h @@ -20,7 +20,7 @@ namespace layers { class DesktopFlingPhysics { public: - void Init(const ParentLayerPoint& aStartingVelocity) + void Init(const ParentLayerPoint& aStartingVelocity, float aPLPPI /* unused */) { mVelocity = aStartingVelocity; } diff --git a/gfx/layers/apz/src/GenericFlingAnimation.h b/gfx/layers/apz/src/GenericFlingAnimation.h index c33fa5a83296..07305f45a1ca 100644 --- a/gfx/layers/apz/src/GenericFlingAnimation.h +++ b/gfx/layers/apz/src/GenericFlingAnimation.h @@ -33,8 +33,10 @@ namespace layers { * * - Default constructor. * - * - Init(const ParentLayerPoint& aStartingVelocity). - * Called at the beginning of the fling, with the fling's starting velocity. + * - Init(const ParentLayerPoint& aStartingVelocity, float aPLPPI). + * Called at the beginning of the fling, with the fling's starting velocity, + * and the number of ParentLayer pixels per (Screen) inch at the point of + * the fling's start in the fling's direction. * * - Sample(const TimeDuration& aDelta, * ParentLayerPoint* aOutVelocity, @@ -54,7 +56,8 @@ public: GenericFlingAnimation(AsyncPanZoomController& aApzc, const RefPtr& aOverscrollHandoffChain, bool aFlingIsHandedOff, - const RefPtr& aScrolledApzc) + const RefPtr& aScrolledApzc, + float aPLPPI) : mApzc(aApzc) , mOverscrollHandoffChain(aOverscrollHandoffChain) , mScrolledApzc(aScrolledApzc) @@ -107,7 +110,7 @@ public: mApzc.mLastFlingTime = now; mApzc.mLastFlingVelocity = velocity; - FlingPhysics::Init(mApzc.GetVelocityVector()); + FlingPhysics::Init(mApzc.GetVelocityVector(), aPLPPI); } /**