--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -235,16 +235,22 @@ typedef GenericFlingAnimation FlingAnima
* \li\b apz.fling_friction
* Amount of friction applied during flings. This is used in the following
* formula: v(t1) = v(t0) * (1 - f)^(t1 - t0), where v(t1) is the velocity
* for a new sample, v(t0) is the velocity at the previous sample, f is the
* value of this pref, and (t1 - t0) is the amount of time, in milliseconds,
* that has elapsed between the two samples.\n
* NOTE: Not currently used in Android fling calculations.
*
+ * \li\b apz.fling_min_velocity_threshold
+ * Minimum velocity for a fling to actually kick off. If the user pans and lifts
+ * their finger such that the velocity is smaller than this amount, no fling
+ * is initiated.\n
+ * Units: screen pixels per millisecond
+ *
* \li\b apz.fling_stop_on_tap_threshold
* When flinging, if the velocity is above this number, then a tap on the
* screen will stop the fling without dispatching a tap to content. If the
* velocity is below this threshold a tap will also be dispatched.
* Note: when modifying this pref be sure to run the APZC gtests as some of
* them depend on the value of this pref.\n
* Units: screen pixels per millisecond
*
@@ -1235,17 +1241,24 @@ nsEventStatus AsyncPanZoomController::On
mX.SetVelocity(0);
mY.SetVelocity(0);
// Clear our state so that we don't stay in the PANNING state
// if DispatchFling() gives the fling to somone else. However,
// don't send the state change notification until we've determined
// what our final state is to avoid notification churn.
StateChangeNotificationBlocker blocker(this);
SetState(NOTHING);
- APZC_LOG("%p starting a fling animation\n", this);
+
+ APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
+ flingVelocity.Length(), gfxPrefs::APZFlingMinVelocityThreshold());
+
+ if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
+ return nsEventStatus_eConsumeNoDefault;
+ }
+
// Make a local copy of the tree manager pointer and check that it's not
// null before calling DispatchFling(). This is necessary because Destroy(),
// which nulls out mTreeManager, could be called concurrently.
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
FlingHandoffState handoffState{flingVelocity,
CurrentTouchBlock()->GetOverscrollHandoffChain(),
false /* not handoff */,
CurrentTouchBlock()->GetScrolledApzc()};
--- a/gfx/layers/apz/test/gtest/TestBasic.cpp
+++ b/gfx/layers/apz/test/gtest/TestBasic.cpp
@@ -141,16 +141,17 @@ TEST_F(APZCBasicTester, ComplexTransform
childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut);
EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
childApzc->Destroy();
}
TEST_F(APZCBasicTester, Fling) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
int touchStart = 50;
int touchEnd = 10;
ParentLayerPoint pointOut;
AsyncTransform viewTransformOut;
// Fling down. Each step scroll further down
Pan(apzc, touchStart, touchEnd);
ParentLayerPoint lastPoint;
@@ -159,16 +160,17 @@ TEST_F(APZCBasicTester, Fling) {
EXPECT_GT(pointOut.y, lastPoint.y);
lastPoint = pointOut;
}
}
TEST_F(APZCBasicTester, FlingIntoOverscroll) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
// Scroll down by 25 px. Don't fling for simplicity.
ApzcPanNoFling(apzc, 50, 25);
// Now scroll back up by 20px, this time flinging after.
// The fling should cover the remaining 5 px of room to scroll, then
// go into overscroll, and finally snap-back to recover from overscroll.
Pan(apzc, 25, 45);
--- a/gfx/layers/apz/test/gtest/TestGestureDetector.cpp
+++ b/gfx/layers/apz/test/gtest/TestGestureDetector.cpp
@@ -266,28 +266,32 @@ protected:
// clean up
TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time());
apzc->AssertStateIsReset();
}
};
TEST_F(APZCFlingStopTester, FlingStop) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
DoFlingStopTest(false);
}
TEST_F(APZCFlingStopTester, FlingStopTap) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
DoFlingStopTest(true);
}
TEST_F(APZCFlingStopTester, FlingStopSlowListener) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
DoFlingStopWithSlowListener(false);
}
TEST_F(APZCFlingStopTester, FlingStopPreventDefault) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
DoFlingStopWithSlowListener(true);
}
TEST_F(APZCGestureDetectorTester, ShortPress) {
MakeApzcUnzoomable();
MockFunction<void(std::string checkPointName)> check;
{
--- a/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
+++ b/gfx/layers/apz/test/gtest/TestScrollHandoff.cpp
@@ -204,16 +204,17 @@ TEST_F(APZScrollHandoffTester, LayerStru
EXPECT_EQ(-10, middleApzc->GetFrameMetrics().GetScrollOffset().y);
}
// Test that putting a second finger down on an APZC while a down-chain APZC
// is overscrolled doesn't result in being stuck in overscroll.
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1073250) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
// Pan, causing the parent APZC to overscroll.
Pan(manager, 10, 40, true /* keep finger down */);
EXPECT_FALSE(child->IsOverscrolled());
@@ -241,16 +242,17 @@ TEST_F(APZScrollHandoffTester, StuckInOv
}
// This is almost exactly like StuckInOverscroll_Bug1073250, except the
// APZC receiving the input events for the first touch block is the child
// (and thus not the same APZC that overscrolls, which is the parent).
TEST_F(APZScrollHandoffTester, StuckInOverscroll_Bug1231228) {
// Enable overscrolling.
SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true);
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
CreateScrollHandoffLayerTree1();
TestAsyncPanZoomController* child = ApzcOf(layers[1]);
// Pan, causing the parent APZC to overscroll.
Pan(manager, 60, 90, true /* keep finger down */);
EXPECT_FALSE(child->IsOverscrolled());
@@ -378,16 +380,18 @@ TEST_F(APZScrollHandoffTester, PartialFl
// Assert that partial handoff has occurred.
child->AssertStateIsFling();
parent->AssertStateIsFling();
}
// Here we test that if two flings are happening simultaneously, overscroll
// is handed off correctly for each.
TEST_F(APZScrollHandoffTester, SimultaneousFlings) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
+
// Set up an initial APZC tree.
CreateScrollHandoffLayerTree3();
RefPtr<TestAsyncPanZoomController> parent1 = ApzcOf(layers[1]);
RefPtr<TestAsyncPanZoomController> child1 = ApzcOf(layers[2]);
RefPtr<TestAsyncPanZoomController> parent2 = ApzcOf(layers[3]);
RefPtr<TestAsyncPanZoomController> child2 = ApzcOf(layers[4]);
@@ -423,35 +427,38 @@ TEST_F(APZScrollHandoffTester, Scrollgra
Pan(childApzc, 80, 45);
// Check that the parent and child have scrolled as much as we expect.
EXPECT_EQ(20, rootApzc->GetFrameMetrics().GetScrollOffset().y);
EXPECT_EQ(15, childApzc->GetFrameMetrics().GetScrollOffset().y);
}
TEST_F(APZScrollHandoffTester, ScrollgrabFling) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
// Set up the layer tree
CreateScrollgrabLayerTree();
RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
// Pan on the child, not enough to fully scroll the scrollgrab parent.
Pan(childApzc, 80, 70);
// Check that it is the scrollgrab parent that's in a fling, not the child.
rootApzc->AssertStateIsFling();
childApzc->AssertStateIsReset();
}
TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration1) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
CreateScrollgrabLayerTree(true /* make parent scrollable */);
TestFlingAcceleration();
}
TEST_F(APZScrollHandoffTester, ScrollgrabFlingAcceleration2) {
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
CreateScrollgrabLayerTree(false /* do not make parent scrollable */);
TestFlingAcceleration();
}
TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Pan) {
SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
CreateScrollHandoffLayerTree1();
@@ -473,16 +480,17 @@ TEST_F(APZScrollHandoffTester, Immediate
Pan(childApzc, 60, 50);
// Verify that the parent scrolled.
EXPECT_EQ(10, parentApzc->GetFrameMetrics().GetScrollOffset().y);
}
TEST_F(APZScrollHandoffTester, ImmediateHandoffDisallowed_Fling) {
SCOPED_GFX_PREF(APZAllowImmediateHandoff, bool, false);
+ SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f);
CreateScrollHandoffLayerTree1();
RefPtr<TestAsyncPanZoomController> parentApzc = ApzcOf(root);
RefPtr<TestAsyncPanZoomController> childApzc = ApzcOf(layers[1]);
// Pan on the child, enough to get very close to the end, so that the
// subsequent fling reaches the end and has leftover velocity to hand off.
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -151,16 +151,17 @@ private:
DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500);
DECL_GFX_PREF(Live, "apz.fling_accel_supplemental_mult", APZFlingAccelSupplementalMultiplier, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_x1", APZCurveFunctionX1, float, 0.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_x2", APZCurveFunctionX2, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_y1", APZCurveFunctionY1, float, 0.0f);
DECL_GFX_PREF(Once, "apz.fling_curve_function_y2", APZCurveFunctionY2, float, 1.0f);
DECL_GFX_PREF(Live, "apz.fling_curve_threshold_inches_per_ms", APZCurveThreshold, float, -1.0f);
DECL_GFX_PREF(Live, "apz.fling_friction", APZFlingFriction, float, 0.002f);
+ DECL_GFX_PREF(Live, "apz.fling_min_velocity_threshold", APZFlingMinVelocityThreshold, float, 0.5f);
DECL_GFX_PREF(Live, "apz.fling_stop_on_tap_threshold", APZFlingStopOnTapThreshold, float, 0.05f);
DECL_GFX_PREF(Live, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f);
DECL_GFX_PREF(Live, "apz.highlight_checkerboarded_areas", APZHighlightCheckerboardedAreas, bool, false);
DECL_GFX_PREF(Live, "apz.max_velocity_inches_per_ms", APZMaxVelocity, float, -1.0f);
DECL_GFX_PREF(Once, "apz.max_velocity_queue_size", APZMaxVelocityQueueSize, uint32_t, 5);
DECL_GFX_PREF(Live, "apz.min_skate_speed", APZMinSkateSpeed, float, 1.0f);
DECL_GFX_PREF(Live, "apz.minimap.enabled", APZMinimap, bool, false);
DECL_GFX_PREF(Live, "apz.minimap.visibility.enabled", APZMinimapVisibilityEnabled, bool, false);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -607,16 +607,17 @@ pref("apz.fling_accel_base_mult", "1.0")
pref("apz.fling_accel_interval_ms", 500);
pref("apz.fling_accel_supplemental_mult", "1.0");
pref("apz.fling_curve_function_x1", "0.0");
pref("apz.fling_curve_function_y1", "0.0");
pref("apz.fling_curve_function_x2", "1.0");
pref("apz.fling_curve_function_y2", "1.0");
pref("apz.fling_curve_threshold_inches_per_ms", "-1.0");
pref("apz.fling_friction", "0.002");
+pref("apz.fling_min_velocity_threshold", "0.5");
pref("apz.fling_stop_on_tap_threshold", "0.05");
pref("apz.fling_stopped_threshold", "0.01");
pref("apz.highlight_checkerboarded_areas", false);
pref("apz.max_velocity_inches_per_ms", "-1.0");
pref("apz.max_velocity_queue_size", 5);
pref("apz.min_skate_speed", "1.0");
pref("apz.minimap.enabled", false);
pref("apz.minimap.visibility.enabled", false);