Bug 1448439 - Expose some of the tunable parameters in AndroidFlingPhysics as prefs. r=kats
MozReview-Commit-ID: J4QRmMdGE0l
--- a/gfx/layers/apz/src/AndroidFlingPhysics.cpp
+++ b/gfx/layers/apz/src/AndroidFlingPhysics.cpp
@@ -26,62 +26,87 @@ static double ComputeDeceleration(float
* 160.f // pixels/inch
* aFriction;
}
// == std::log(0.78f) / std::log(0.9f)
const float kDecelerationRate = 2.3582018f;
// Default friction constant in android.view.ViewConfiguration.
-const float kFlingFriction = 0.015f;
+static float GetFlingFriction()
+{
+ return gfxPrefs::APZChromeFlingPhysicsFriction();
+}
-// Tension lines cross at (kInflexion, 1).
-const float kInflexion = 0.35f;
+// Tension lines cross at (GetInflexion(), 1).
+static float GetInflexion()
+{
+ // Clamp the inflexion to the range [0,1]. Values outside of this range
+ // do not make sense in the physics model, and for negative values the
+ // approximation used to compute the spline curve does not converge.
+ const float inflexion = gfxPrefs::APZChromeFlingPhysicsInflexion();
+ if (inflexion < 0.0f) {
+ return 0.0f;
+ }
+ if (inflexion > 1.0f) {
+ return 1.0f;
+ }
+ return inflexion;
+}
// Fling scroll is stopped when the scroll position is |kThresholdForFlingEnd|
// pixels or closer from the end.
-const float kThresholdForFlingEnd = 0.1;
+static float GetThresholdForFlingEnd()
+{
+ return gfxPrefs::APZChromeFlingPhysicsStopThreshold();
+}
const float kTuningCoeff = ComputeDeceleration(0.84f);
static double ComputeSplineDeceleration(ParentLayerCoord aVelocity)
{
float velocityPerSec = aVelocity * 1000.0f;
- return std::log(kInflexion * velocityPerSec / (kFlingFriction * kTuningCoeff));
+ return std::log(GetInflexion() * velocityPerSec / (GetFlingFriction() * kTuningCoeff));
}
static TimeDuration ComputeFlingDuration(ParentLayerCoord aVelocity)
{
const double splineDecel = ComputeSplineDeceleration(aVelocity);
const double timeSeconds = std::exp(splineDecel / (kDecelerationRate - 1.0));
return TimeDuration::FromSeconds(timeSeconds);
}
static ParentLayerCoord ComputeFlingDistance(ParentLayerCoord aVelocity)
{
const double splineDecel = ComputeSplineDeceleration(aVelocity);
- return kFlingFriction * kTuningCoeff *
+ return GetFlingFriction() * kTuningCoeff *
std::exp(kDecelerationRate / (kDecelerationRate - 1.0) * splineDecel);
}
struct SplineConstants {
public:
SplineConstants() {
const float kStartTension = 0.5f;
const float kEndTension = 1.0f;
- const float kP1 = kStartTension * kInflexion;
- const float kP2 = 1.0f - kEndTension * (1.0f - kInflexion);
+ const float kP1 = kStartTension * GetInflexion();
+ const float kP2 = 1.0f - kEndTension * (1.0f - GetInflexion());
float xMin = 0.0f;
for (int i = 0; i < kNumSamples; i++) {
const float alpha = static_cast<float>(i) / kNumSamples;
float xMax = 1.0f;
float x, tx, coef;
- while (true) {
+ // While the inflexion can be overridden by the user, it's clamped to
+ // [0,1]. For values in this range, the approximation algorithm below
+ // should converge in < 20 iterations. For good measure, we impose an
+ // iteration limit as well.
+ static const int sIterationLimit = 100;
+ int iterations = 0;
+ while (iterations++ < sIterationLimit) {
x = xMin + (xMax - xMin) / 2.0f;
coef = 3.0f * x * (1.0f - x);
tx = coef * ((1.0f - x) * kP1 + x * kP2) + x * x * x;
if (FuzzyEqualsAdditive(tx, alpha)) {
break;
}
if (tx > alpha) {
xMax = x;
@@ -173,17 +198,18 @@ bool AndroidFlingPhysics::SampleImpl(con
gSplineConstants->CalculateCoefficients(timeRatio, &distanceCoef, &velocityCoef);
// The caller expects the velocity in pixels per _millisecond_.
*aOutVelocity = velocityCoef * mTargetDistance / mTargetDuration.ToMilliseconds();
mCurrentPos = mTargetPos * distanceCoef;
ParentLayerPoint remainder = mTargetPos - mCurrentPos;
- if (fabsf(remainder.x) < kThresholdForFlingEnd && fabsf(remainder.y) < kThresholdForFlingEnd) {
+ const float threshold = GetThresholdForFlingEnd();
+ if (fabsf(remainder.x) < threshold && fabsf(remainder.y) < threshold) {
return false;
}
return true;
}
} // namespace layers
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -137,16 +137,31 @@ typedef PlatformSpecificStateBase Platfo
* If set to true, scroll can be handed off from one APZC to another within
* a single input block. If set to false, a single input block can only
* scroll one APZC.
*
* \li\b apz.android.chrome_fling_physics.enabled
* If set to true, APZ uses a fling physical model similar to Chrome's
* on Android, rather than Android's StackScroller.
*
+ * \li\b apz.android.chrome_fling_physics.friction
+ * A tunable parameter for Chrome fling physics on Android that governs
+ * how quickly a fling animation slows down due to friction (and therefore
+ * also how far it reaches). Should be in the range [0-1].
+ *
+ * \li\b apz.android.chrome_fling_physics.inflexion
+ * A tunable parameter for Chrome fling physics on Android that governs
+ * the shape of the fling curve. Should be in the range [0-1].
+ *
+ * \li\b apz.android.chrome_fling_physics.stop_threshold
+ * A tunable parameter for Chrome fling physics on Android that governs
+ * how close the fling animation has to get to its target destination
+ * before it stops.
+ * Units: ParentLayer pixels
+ *
* \li\b apz.autoscroll.enabled
* If set to true, autoscrolling is driven by APZ rather than the content
* process main thread.
*
* \li\b apz.axis_lock.mode
* The preferred axis locking style. See AxisLockMode for possible values.
*
* \li\b apz.axis_lock.lock_angle
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -286,16 +286,19 @@ private:
DECL_GFX_PREF(Live, "accessibility.browsewithcaret", AccessibilityBrowseWithCaret, bool, false);
// The apz prefs are explained in AsyncPanZoomController.cpp
DECL_GFX_PREF(Live, "apz.allow_checkerboarding", APZAllowCheckerboarding, bool, true);
DECL_GFX_PREF(Live, "apz.allow_immediate_handoff", APZAllowImmediateHandoff, bool, true);
DECL_GFX_PREF(Live, "apz.allow_zooming", APZAllowZooming, bool, false);
DECL_GFX_PREF(Live, "apz.android.chrome_fling_physics.enabled", APZUseChromeFlingPhysics, bool, false);
+ DECL_GFX_PREF(Live, "apz.android.chrome_fling_physics.friction", APZChromeFlingPhysicsFriction, float, 0.015f);
+ DECL_GFX_PREF(Live, "apz.android.chrome_fling_physics.inflexion", APZChromeFlingPhysicsInflexion, float, 0.35f);
+ DECL_GFX_PREF(Live, "apz.android.chrome_fling_physics.stop_threshold", APZChromeFlingPhysicsStopThreshold, float, 0.1f);
DECL_GFX_PREF(Live, "apz.autoscroll.enabled", APZAutoscrollEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle", APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold", APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle", APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.lock_angle", APZAxisLockAngle, float, float(M_PI / 6.0) /* 30 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.mode", APZAxisLockMode, int32_t, 0);
DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 400);
DECL_GFX_PREF(Live, "apz.danger_zone_x", APZDangerZoneX, int32_t, 50);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -622,16 +622,19 @@ pref("layers.geometry.basic.enabled", tr
pref("layers.geometry.d3d11.enabled", true);
// APZ preferences. For documentation/details on what these prefs do, check
// gfx/layers/apz/src/AsyncPanZoomController.cpp.
pref("apz.allow_checkerboarding", true);
pref("apz.allow_immediate_handoff", true);
pref("apz.allow_zooming", false);
pref("apz.android.chrome_fling_physics.enabled", false);
+pref("apz.android.chrome_fling_physics.friction", "0.015");
+pref("apz.android.chrome_fling_physics.inflexion", "0.35");
+pref("apz.android.chrome_fling_physics.stop_threshold", "0.1");
pref("apz.autoscroll.enabled", true);
// Whether to lock touch scrolling to one axis at a time
// 0 = FREE (No locking at all)
// 1 = STANDARD (Once locked, remain locked until scrolling ends)
// 2 = STICKY (Allow lock to be broken, with hysteresis)
pref("apz.axis_lock.mode", 0);
pref("apz.axis_lock.lock_angle", "0.5235987"); // PI / 6 (30 degrees)