summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/FlingAccelerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/apz/src/FlingAccelerator.cpp')
-rw-r--r--gfx/layers/apz/src/FlingAccelerator.cpp128
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