diff options
Diffstat (limited to 'gfx/layers/apz/src/FlingAccelerator.cpp')
-rw-r--r-- | gfx/layers/apz/src/FlingAccelerator.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/gfx/layers/apz/src/FlingAccelerator.cpp b/gfx/layers/apz/src/FlingAccelerator.cpp new file mode 100644 index 0000000000..f37d04c77b --- /dev/null +++ b/gfx/layers/apz/src/FlingAccelerator.cpp @@ -0,0 +1,128 @@ +/* -*- 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 "FlingAccelerator.h" + +#include "mozilla/StaticPrefs_apz.h" + +#include "GenericFlingAnimation.h" // for FLING_LOG and FlingHandoffState + +namespace mozilla { +namespace layers { + +void FlingAccelerator::Reset() { + mPreviousFlingStartingVelocity = ParentLayerPoint{}; + mPreviousFlingCancelVelocity = ParentLayerPoint{}; + mIsTracking = false; +} + +static bool SameDirection(float aVelocity1, float aVelocity2) { + return (aVelocity1 == 0.0f) || (aVelocity2 == 0.0f) || + (IsNegative(aVelocity1) == IsNegative(aVelocity2)); +} + +static float Accelerate(float aBase, float aSupplemental) { + return (aBase * StaticPrefs::apz_fling_accel_base_mult()) + + (aSupplemental * StaticPrefs::apz_fling_accel_supplemental_mult()); +} + +ParentLayerPoint FlingAccelerator::GetFlingStartingVelocity( + const SampleTime& aNow, const ParentLayerPoint& aVelocity, + const FlingHandoffState& aHandoffState) { + // If the fling should be accelerated and is in the same direction as the + // previous fling, boost the velocity to be the sum of the two. Check separate + // axes separately because we could have two vertical flings with small + // horizontal components on the opposite side of zero, and we still want the + // y-fling to get accelerated. + ParentLayerPoint velocity = aVelocity; + if (ShouldAccelerate(aNow, aVelocity, aHandoffState)) { + if (velocity.x != 0 && + SameDirection(velocity.x, mPreviousFlingStartingVelocity.x)) { + velocity.x = Accelerate(velocity.x, mPreviousFlingStartingVelocity.x); + FLING_LOG("%p Applying fling x-acceleration from %f to %f (delta %f)\n", + this, aVelocity.x.value, velocity.x.value, + mPreviousFlingStartingVelocity.x.value); + } + if (velocity.y != 0 && + SameDirection(velocity.y, mPreviousFlingStartingVelocity.y)) { + velocity.y = Accelerate(velocity.y, mPreviousFlingStartingVelocity.y); + FLING_LOG("%p Applying fling y-acceleration from %f to %f (delta %f)\n", + this, aVelocity.y.value, velocity.y.value, + mPreviousFlingStartingVelocity.y.value); + } + } + + Reset(); + + mPreviousFlingStartingVelocity = velocity; + mIsTracking = true; + + return velocity; +} + +bool FlingAccelerator::ShouldAccelerate( + const SampleTime& aNow, const ParentLayerPoint& aVelocity, + const FlingHandoffState& aHandoffState) const { + if (!IsTracking()) { + FLING_LOG("%p Fling accelerator was reset, not accelerating.\n", this); + return false; + } + + if (!aHandoffState.mTouchStartRestingTime) { + FLING_LOG("%p Don't have a touch start resting time, not accelerating.\n", + this); + return false; + } + + double msBetweenTouchStartAndPanStart = + aHandoffState.mTouchStartRestingTime->ToMilliseconds(); + FLING_LOG( + "%p ShouldAccelerate with pan velocity %f pixels/ms, min pan velocity %f " + "pixels/ms, previous fling cancel velocity %f pixels/ms, time elapsed " + "since starting previous time between touch start and pan " + "start %fms.\n", + this, float(aVelocity.Length()), float(aHandoffState.mMinPanVelocity), + float(mPreviousFlingCancelVelocity.Length()), + float(msBetweenTouchStartAndPanStart)); + + if (aVelocity.Length() < StaticPrefs::apz_fling_accel_min_fling_velocity()) { + FLING_LOG("%p Fling velocity too low (%f), not accelerating.\n", this, + float(aVelocity.Length())); + return false; + } + + if (aHandoffState.mMinPanVelocity < + StaticPrefs::apz_fling_accel_min_pan_velocity()) { + FLING_LOG( + "%p Panning velocity was too slow at some point during the pan (%f), " + "not accelerating.\n", + this, float(aHandoffState.mMinPanVelocity)); + return false; + } + + if (mPreviousFlingCancelVelocity.Length() < + StaticPrefs::apz_fling_accel_min_fling_velocity()) { + FLING_LOG( + "%p The previous fling animation had slowed down too much when it was " + "interrupted (%f), not accelerating.\n", + this, float(mPreviousFlingCancelVelocity.Length())); + return false; + } + + if (msBetweenTouchStartAndPanStart >= + StaticPrefs::apz_fling_accel_max_pause_interval_ms()) { + FLING_LOG( + "%p Too much time (%fms) elapsed between touch start and pan start, " + "not accelerating.\n", + this, msBetweenTouchStartAndPanStart); + return false; + } + + return true; +} + +} // namespace layers +} // namespace mozilla |