Bug 1062483 - Make the overscroll effect harder to trigger accidentally. r=kats

--HG--
rename : gfx/layers/apz/src/OverscrollHandoffChain.cpp => gfx/layers/apz/src/OverscrollHandoffState.cpp
rename : gfx/layers/apz/src/OverscrollHandoffChain.h => gfx/layers/apz/src/OverscrollHandoffState.h
extra : rebase_source : 155c68fcd76c5f1e7a4e57818d238908bc8eb3c2
This commit is contained in:
Botond Ballo 2014-09-23 11:38:05 -04:00
Родитель a6b78c05d6
Коммит ce4474100b
10 изменённых файлов: 101 добавлений и 36 удалений

Просмотреть файл

@ -23,7 +23,7 @@
#include "mozilla/gfx/Logging.h" // for gfx::TreeLog #include "mozilla/gfx/Logging.h" // for gfx::TreeLog
#include "UnitTransforms.h" // for ViewAs #include "UnitTransforms.h" // for ViewAs
#include "gfxPrefs.h" // for gfxPrefs #include "gfxPrefs.h" // for gfxPrefs
#include "OverscrollHandoffChain.h" // for OverscrollHandoffChain #include "OverscrollHandoffState.h" // for OverscrollHandoffState
#include "LayersLogging.h" // for Stringify #include "LayersLogging.h" // for Stringify
#define APZCTM_LOG(...) #define APZCTM_LOG(...)
@ -896,18 +896,19 @@ bool
APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev, APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
ScreenPoint aStartPoint, ScreenPoint aStartPoint,
ScreenPoint aEndPoint, ScreenPoint aEndPoint,
const OverscrollHandoffChain& aOverscrollHandoffChain, OverscrollHandoffState& aOverscrollHandoffState)
uint32_t aOverscrollHandoffChainIndex)
{ {
const OverscrollHandoffChain& overscrollHandoffChain = aOverscrollHandoffState.mChain;
uint32_t overscrollHandoffChainIndex = aOverscrollHandoffState.mChainIndex;
nsRefPtr<AsyncPanZoomController> next; nsRefPtr<AsyncPanZoomController> next;
// If we have reached the end of the overscroll handoff chain, there is // If we have reached the end of the overscroll handoff chain, there is
// nothing more to scroll, so we ignore the rest of the pan gesture. // nothing more to scroll, so we ignore the rest of the pan gesture.
if (aOverscrollHandoffChainIndex >= aOverscrollHandoffChain.Length()) { if (overscrollHandoffChainIndex >= overscrollHandoffChain.Length()) {
// Nothing more to scroll - ignore the rest of the pan gesture. // Nothing more to scroll - ignore the rest of the pan gesture.
return false; return false;
} }
next = aOverscrollHandoffChain.GetApzcAtIndex(aOverscrollHandoffChainIndex); next = overscrollHandoffChain.GetApzcAtIndex(overscrollHandoffChainIndex);
if (next == nullptr || next->IsDestroyed()) { if (next == nullptr || next->IsDestroyed()) {
return false; return false;
@ -924,8 +925,7 @@ APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev,
// Scroll |next|. If this causes overscroll, it will call DispatchScroll() // Scroll |next|. If this causes overscroll, it will call DispatchScroll()
// again with an incremented index. // again with an incremented index.
return next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffChain, return next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffState);
aOverscrollHandoffChainIndex);
} }
bool bool

Просмотреть файл

@ -44,6 +44,7 @@ class AsyncPanZoomController;
class CompositorParent; class CompositorParent;
class APZPaintLogHelper; class APZPaintLogHelper;
class OverscrollHandoffChain; class OverscrollHandoffChain;
class OverscrollHandoffState;
class LayerMetricsWrapper; class LayerMetricsWrapper;
/** /**
@ -312,8 +313,7 @@ public:
bool DispatchScroll(AsyncPanZoomController* aApzc, bool DispatchScroll(AsyncPanZoomController* aApzc,
ScreenPoint aStartPoint, ScreenPoint aStartPoint,
ScreenPoint aEndPoint, ScreenPoint aEndPoint,
const OverscrollHandoffChain& aOverscrollHandoffChain, OverscrollHandoffState& aOverscrollHandoffState);
uint32_t aOverscrollHandoffChainIndex);
/** /**
* This is a callback for AsyncPanZoomController to call when it wants to * This is a callback for AsyncPanZoomController to call when it wants to

Просмотреть файл

@ -15,7 +15,7 @@
#include "GestureEventListener.h" // for GestureEventListener #include "GestureEventListener.h" // for GestureEventListener
#include "InputData.h" // for MultiTouchInput, etc #include "InputData.h" // for MultiTouchInput, etc
#include "InputBlockState.h" // for InputBlockState, TouchBlockState #include "InputBlockState.h" // for InputBlockState, TouchBlockState
#include "OverscrollHandoffChain.h" // for OverscrollHandoffChain #include "OverscrollHandoffState.h" // for OverscrollHandoffState
#include "Units.h" // for CSSRect, CSSPoint, etc #include "Units.h" // for CSSRect, CSSPoint, etc
#include "UnitTransforms.h" // for TransformTo #include "UnitTransforms.h" // for TransformTo
#include "base/message_loop.h" // for MessageLoop #include "base/message_loop.h" // for MessageLoop
@ -269,6 +269,11 @@ typedef mozilla::gfx::Matrix4x4 Matrix4x4;
* number, we stop the fling. * number, we stop the fling.
* Units: screen pixels per millisecond * Units: screen pixels per millisecond
* *
* "apz.overscroll.min_pan_distance_ratio"
* The minimum ratio of the pan distance along one axis to the pan distance
* along the other axis needed to initiate overscroll along the first axis
* during panning.
*
* "apz.overscroll.stretch_factor" * "apz.overscroll.stretch_factor"
* How much overscrolling can stretch content along an axis. * How much overscrolling can stretch content along an axis.
* The maximum stretch along an axis is a factor of (1 + kStretchFactor). * The maximum stretch along an axis is a factor of (1 + kStretchFactor).
@ -1573,8 +1578,10 @@ nsEventStatus AsyncPanZoomController::OnPan(const PanGestureInput& aEvent, bool
// TODO: Handle pan events sent without pan begin / pan end events properly. // TODO: Handle pan events sent without pan begin / pan end events properly.
if (mPanGestureState) { if (mPanGestureState) {
OverscrollHandoffState handoffState(
*mPanGestureState->GetOverscrollHandoffChain(), panDisplacement);
CallDispatchScroll(aEvent.mPanStartPoint, aEvent.mPanStartPoint + aEvent.mPanDisplacement, CallDispatchScroll(aEvent.mPanStartPoint, aEvent.mPanStartPoint + aEvent.mPanDisplacement,
*mPanGestureState->GetOverscrollHandoffChain(), 0); handoffState);
} }
return nsEventStatus_eConsumeNoDefault; return nsEventStatus_eConsumeNoDefault;
@ -1837,16 +1844,16 @@ void AsyncPanZoomController::HandlePanning(double aAngle) {
} }
} }
void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aDelta) { void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance) {
// If we're axis-locked, check if the user is trying to break the lock // If we're axis-locked, check if the user is trying to break the lock
if (GetAxisLockMode() == STICKY && !mPanDirRestricted) { if (GetAxisLockMode() == STICKY && !mPanDirRestricted) {
double angle = atan2(aDelta.y, aDelta.x); // range [-pi, pi] double angle = atan2(aPanDistance.y, aPanDistance.x); // range [-pi, pi]
angle = fabs(angle); // range [0, pi] angle = fabs(angle); // range [0, pi]
float breakThreshold = gfxPrefs::APZAxisBreakoutThreshold() * APZCTreeManager::GetDPI(); float breakThreshold = gfxPrefs::APZAxisBreakoutThreshold() * APZCTreeManager::GetDPI();
if (fabs(aDelta.x) > breakThreshold || fabs(aDelta.y) > breakThreshold) { if (fabs(aPanDistance.x) > breakThreshold || fabs(aPanDistance.y) > breakThreshold) {
if (mState == PANNING_LOCKED_X || mState == CROSS_SLIDING_X) { if (mState == PANNING_LOCKED_X || mState == CROSS_SLIDING_X) {
if (!IsCloseToHorizontal(angle, gfxPrefs::APZAxisBreakoutAngle())) { if (!IsCloseToHorizontal(angle, gfxPrefs::APZAxisBreakoutAngle())) {
mY.SetAxisLocked(false); mY.SetAxisLocked(false);
@ -1905,8 +1912,7 @@ void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput&
bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint, bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
const ScreenPoint& aEndPoint, const ScreenPoint& aEndPoint,
const OverscrollHandoffChain& aOverscrollHandoffChain, OverscrollHandoffState& aOverscrollHandoffState) {
uint32_t aOverscrollHandoffChainIndex) {
// "start - end" rather than "end - start" because e.g. moving your finger // "start - end" rather than "end - start" because e.g. moving your finger
// down (*positive* direction along y axis) causes the vertical scroll offset // down (*positive* direction along y axis) causes the vertical scroll offset
@ -1941,8 +1947,9 @@ bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
// overscroll). // overscroll).
// Note: "+ overscroll" rather than "- overscroll" because "overscroll" // Note: "+ overscroll" rather than "- overscroll" because "overscroll"
// is what's left of "displacement", and "displacement" is "start - end". // is what's left of "displacement", and "displacement" is "start - end".
++aOverscrollHandoffState.mChainIndex;
if (CallDispatchScroll(aEndPoint + overscroll, aEndPoint, if (CallDispatchScroll(aEndPoint + overscroll, aEndPoint,
aOverscrollHandoffChain, aOverscrollHandoffChainIndex + 1)) { aOverscrollHandoffState)) {
return true; return true;
} }
@ -1950,7 +1957,24 @@ bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
// overscroll, try to accept it ourselves. We only accept it if we // overscroll, try to accept it ourselves. We only accept it if we
// are pannable. // are pannable.
APZC_LOG("%p taking overscroll during panning\n", this); APZC_LOG("%p taking overscroll during panning\n", this);
return OverscrollBy(overscroll); return OverscrollForPanning(overscroll, aOverscrollHandoffState.mPanDistance);
}
bool AsyncPanZoomController::OverscrollForPanning(ScreenPoint aOverscroll,
const ScreenPoint& aPanDistance) {
// Only allow entering overscroll along an axis if the pan distance along
// that axis is greater than the pan distance along the other axis by a
// configurable factor. If we are already overscrolled, don't check this.
if (!IsOverscrolled()) {
if (aPanDistance.x < gfxPrefs::APZMinPanDistanceRatio() * aPanDistance.y) {
aOverscroll.x = 0;
}
if (aPanDistance.y < gfxPrefs::APZMinPanDistanceRatio() * aPanDistance.x) {
aOverscroll.y = 0;
}
}
return OverscrollBy(aOverscroll);
} }
bool AsyncPanZoomController::OverscrollBy(const ScreenPoint& aOverscroll) { bool AsyncPanZoomController::OverscrollBy(const ScreenPoint& aOverscroll) {
@ -2066,33 +2090,32 @@ void AsyncPanZoomController::StartSnapBack() {
bool AsyncPanZoomController::CallDispatchScroll(const ScreenPoint& aStartPoint, bool AsyncPanZoomController::CallDispatchScroll(const ScreenPoint& aStartPoint,
const ScreenPoint& aEndPoint, const ScreenPoint& aEndPoint,
const OverscrollHandoffChain& aOverscrollHandoffChain, OverscrollHandoffState& aOverscrollHandoffState) {
uint32_t aOverscrollHandoffChainIndex) {
// Make a local copy of the tree manager pointer and check if it's not // Make a local copy of the tree manager pointer and check if it's not
// null before calling DispatchScroll(). This is necessary because // null before calling DispatchScroll(). This is necessary because
// Destroy(), which nulls out mTreeManager, could be called concurrently. // Destroy(), which nulls out mTreeManager, could be called concurrently.
APZCTreeManager* treeManagerLocal = GetApzcTreeManager(); APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
return treeManagerLocal return treeManagerLocal
&& treeManagerLocal->DispatchScroll(this, aStartPoint, aEndPoint, && treeManagerLocal->DispatchScroll(this, aStartPoint, aEndPoint,
aOverscrollHandoffChain, aOverscrollHandoffState);
aOverscrollHandoffChainIndex);
} }
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) { void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
ScreenPoint prevTouchPoint(mX.GetPos(), mY.GetPos()); ScreenPoint prevTouchPoint(mX.GetPos(), mY.GetPos());
ScreenPoint touchPoint = GetFirstTouchScreenPoint(aEvent); ScreenPoint touchPoint = GetFirstTouchScreenPoint(aEvent);
ScreenPoint delta(mX.PanDistance(touchPoint.x), ScreenPoint panDistance(mX.PanDistance(touchPoint.x),
mY.PanDistance(touchPoint.y)); mY.PanDistance(touchPoint.y));
const ScreenPoint panStart = PanStart(); const ScreenPoint panStart = PanStart();
ToGlobalScreenCoordinates(&delta, panStart); ToGlobalScreenCoordinates(&panDistance, panStart);
HandlePanningUpdate(delta); HandlePanningUpdate(panDistance);
UpdateWithTouchAtDevicePoint(aEvent); UpdateWithTouchAtDevicePoint(aEvent);
if (prevTouchPoint != touchPoint) { if (prevTouchPoint != touchPoint) {
CallDispatchScroll(prevTouchPoint, touchPoint, OverscrollHandoffState handoffState(
*CurrentTouchBlock()->GetOverscrollHandoffChain(), 0); *CurrentTouchBlock()->GetOverscrollHandoffChain(), panDistance);
CallDispatchScroll(prevTouchPoint, touchPoint, handoffState);
} }
} }

Просмотреть файл

@ -1010,8 +1010,7 @@ public:
* an overscrolled state itself if it can. * an overscrolled state itself if it can.
*/ */
bool AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint, bool AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
const OverscrollHandoffChain& aOverscrollHandoffChain, OverscrollHandoffState& aOverscrollHandoffState);
uint32_t aOverscrollHandoffChainIndex = 0);
void FlushRepaintForOverscrollHandoff(); void FlushRepaintForOverscrollHandoff();
@ -1029,8 +1028,15 @@ private:
*/ */
bool CallDispatchScroll(const ScreenPoint& aStartPoint, bool CallDispatchScroll(const ScreenPoint& aStartPoint,
const ScreenPoint& aEndPoint, const ScreenPoint& aEndPoint,
const OverscrollHandoffChain& aOverscrollHandoffChain, OverscrollHandoffState& aOverscrollHandoffState);
uint32_t aOverscrollHandoffChainIndex);
/**
* A helper function for overscrolling during panning. This is a wrapper
* around OverscrollBy() that also implements restrictions on entering
* overscroll based on the pan angle.
*/
bool OverscrollForPanning(ScreenPoint aOverscroll,
const ScreenPoint& aPanDistance);
/** /**
* Try to overscroll by 'aOverscroll'. * Try to overscroll by 'aOverscroll'.

Просмотреть файл

@ -7,7 +7,7 @@
#include "InputBlockState.h" #include "InputBlockState.h"
#include "mozilla/layers/APZCTreeManager.h" // for AllowedTouchBehavior #include "mozilla/layers/APZCTreeManager.h" // for AllowedTouchBehavior
#include "gfxPrefs.h" // for gfxPrefs #include "gfxPrefs.h" // for gfxPrefs
#include "OverscrollHandoffChain.h" #include "OverscrollHandoffState.h"
#define TBS_LOG(...) #define TBS_LOG(...)
// #define TBS_LOG(...) printf_stderr("TBS: " __VA_ARGS__) // #define TBS_LOG(...) printf_stderr("TBS: " __VA_ARGS__)

Просмотреть файл

@ -4,7 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OverscrollHandoffChain.h" #include "OverscrollHandoffState.h"
#include <algorithm> // for std::stable_sort #include <algorithm> // for std::stable_sort
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
@ -90,13 +90,25 @@ OverscrollHandoffChain::ClearOverscroll() const
void void
OverscrollHandoffChain::SnapBackOverscrolledApzc() const OverscrollHandoffChain::SnapBackOverscrolledApzc() const
{ {
for (uint32_t i = 0; i < Length(); ++i) { uint32_t i = 0;
for (i = 0; i < Length(); ++i) {
AsyncPanZoomController* apzc = mChain[i]; AsyncPanZoomController* apzc = mChain[i];
if (!apzc->IsDestroyed() && apzc->SnapBackIfOverscrolled()) { if (!apzc->IsDestroyed() && apzc->SnapBackIfOverscrolled()) {
// At most one APZC along the hand-off chain can be overscrolled. // At most one APZC along the hand-off chain can be overscrolled.
break; break;
} }
} }
// In debug builds, verify our assumption that only one APZC is overscrolled.
#ifdef DEBUG
++i;
for (; i < Length(); ++i) {
AsyncPanZoomController* apzc = mChain[i];
if (!apzc->IsDestroyed()) {
MOZ_ASSERT(!apzc->IsOverscrolled());
}
}
#endif
} }
bool bool

Просмотреть файл

@ -110,6 +110,28 @@ private:
void ForEachApzc(APZCMethod aMethod) const; void ForEachApzc(APZCMethod aMethod) const;
}; };
/**
* This class groups the state maintained during overscroll handoff.
*/
struct OverscrollHandoffState {
OverscrollHandoffState(const OverscrollHandoffChain& aChain,
const ScreenPoint& aPanDistance)
: mChain(aChain), mChainIndex(0), mPanDistance(aPanDistance) {}
// The chain of APZCs along which we hand off scroll.
// This is const to indicate that the chain does not change over the
// course of handoff.
const OverscrollHandoffChain& mChain;
// The index of the APZC in the chain that we are currently giving scroll to.
// This is non-const to indicate that this changes over the course of handoff.
uint32_t mChainIndex;
// The total distance since touch-start of the pan that triggered the
// handoff. This is const to indicate that it does not change over the
// course of handoff.
const ScreenPoint mPanDistance;
};
// Don't pollute other files with this macro for now. // Don't pollute other files with this macro for now.
#undef NS_INLINE_DECL_THREADSAFE_MUTABLE_REFCOUNTING #undef NS_INLINE_DECL_THREADSAFE_MUTABLE_REFCOUNTING

Просмотреть файл

@ -244,7 +244,7 @@ UNIFIED_SOURCES += [
'apz/src/Axis.cpp', 'apz/src/Axis.cpp',
'apz/src/GestureEventListener.cpp', 'apz/src/GestureEventListener.cpp',
'apz/src/InputBlockState.cpp', 'apz/src/InputBlockState.cpp',
'apz/src/OverscrollHandoffChain.cpp', 'apz/src/OverscrollHandoffState.cpp',
'apz/src/TaskThrottler.cpp', 'apz/src/TaskThrottler.cpp',
'apz/testutil/APZTestData.cpp', 'apz/testutil/APZTestData.cpp',
'apz/util/ActiveElementManager.cpp', 'apz/util/ActiveElementManager.cpp',

Просмотреть файл

@ -157,6 +157,7 @@ private:
DECL_GFX_PREF(Live, "apz.overscroll.enabled", APZOverscrollEnabled, bool, false); DECL_GFX_PREF(Live, "apz.overscroll.enabled", APZOverscrollEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.overscroll.fling_friction", APZOverscrollFlingFriction, float, 0.02f); DECL_GFX_PREF(Live, "apz.overscroll.fling_friction", APZOverscrollFlingFriction, float, 0.02f);
DECL_GFX_PREF(Live, "apz.overscroll.fling_stopped_threshold", APZOverscrollFlingStoppedThreshold, float, 0.4f); DECL_GFX_PREF(Live, "apz.overscroll.fling_stopped_threshold", APZOverscrollFlingStoppedThreshold, float, 0.4f);
DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor", APZOverscrollStretchFactor, float, 0.5f); DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor", APZOverscrollStretchFactor, float, 0.5f);
DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_stiffness", APZOverscrollSnapBackSpringStiffness, float, 0.6f); DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_stiffness", APZOverscrollSnapBackSpringStiffness, float, 0.6f);
DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_friction", APZOverscrollSnapBackSpringFriction, float, 0.1f); DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_friction", APZOverscrollSnapBackSpringFriction, float, 0.1f);

Просмотреть файл

@ -464,6 +464,7 @@ pref("apz.num_paint_duration_samples", 3);
pref("apz.overscroll.enabled", false); pref("apz.overscroll.enabled", false);
pref("apz.overscroll.fling_friction", "0.02"); pref("apz.overscroll.fling_friction", "0.02");
pref("apz.overscroll.fling_stopped_threshold", "0.4"); pref("apz.overscroll.fling_stopped_threshold", "0.4");
pref("apz.overscroll.min_pan_distance_ratio", "1.0");
pref("apz.overscroll.stretch_factor", "0.5"); pref("apz.overscroll.stretch_factor", "0.5");
pref("apz.overscroll.snap_back.spring_stiffness", "0.6"); pref("apz.overscroll.snap_back.spring_stiffness", "0.6");
pref("apz.overscroll.snap_back.spring_friction", "0.1"); pref("apz.overscroll.snap_back.spring_friction", "0.1");