Bug 951793 - Light refactoring to the fling handoff code. r=kats
Passing FlingHandoffState around as an in-out parameter was making
the next change (respecting overscroll-behavior) messy.
MozReview-Commit-ID: 4wuoll20Jt7
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -2024,110 +2024,106 @@ APZCTreeManager::DispatchScroll(AsyncPan
// displacement in its own coordinate space, and make use of it
// (e.g. by going into overscroll).
if (!TransformDisplacement(this, next, aPrev, aStartPoint, aEndPoint)) {
NS_WARNING("Failed to untransform scroll points during dispatch");
}
}
}
-void
+ParentLayerPoint
APZCTreeManager::DispatchFling(AsyncPanZoomController* aPrev,
- FlingHandoffState& aHandoffState)
+ const FlingHandoffState& aHandoffState)
{
// If immediate handoff is disallowed, do not allow handoff beyond the
// single APZC that's scrolled by the input block that triggered this fling.
if (aHandoffState.mIsHandoff &&
!gfxPrefs::APZAllowImmediateHandoff() &&
aHandoffState.mScrolledApzc == aPrev) {
- return;
+ return aHandoffState.mVelocity;
}
const OverscrollHandoffChain* chain = aHandoffState.mChain;
RefPtr<AsyncPanZoomController> current;
uint32_t overscrollHandoffChainLength = chain->Length();
uint32_t startIndex;
- // This will store any velocity left over after the entire handoff.
- ParentLayerPoint finalResidualVelocity = aHandoffState.mVelocity;
-
// The fling's velocity needs to be transformed from the screen coordinates
// of |aPrev| to the screen coordinates of |next|. To transform a velocity
// correctly, we need to convert it to a displacement. For now, we do this
// by anchoring it to a start point of (0, 0).
// TODO: For this to be correct in the presence of 3D transforms, we should
// use the end point of the touch that started the fling as the start point
// rather than (0, 0).
ParentLayerPoint startPoint; // (0, 0)
ParentLayerPoint endPoint;
if (aHandoffState.mIsHandoff) {
startIndex = chain->IndexOf(aPrev) + 1;
// IndexOf will return aOverscrollHandoffChain->Length() if
// |aPrev| is not found.
if (startIndex >= overscrollHandoffChainLength) {
- return;
+ return aHandoffState.mVelocity;
}
} else {
startIndex = 0;
}
+ // This will store any velocity left over after the entire handoff.
+ ParentLayerPoint finalResidualVelocity = aHandoffState.mVelocity;
+
+ ParentLayerPoint currentVelocity = aHandoffState.mVelocity;
for (; startIndex < overscrollHandoffChainLength; startIndex++) {
current = chain->GetApzcAtIndex(startIndex);
- // Make sure the apcz about to be handled can be handled
+ // Make sure the apzc about to be handled can be handled
if (current == nullptr || current->IsDestroyed()) {
- return;
+ break;
}
- endPoint = startPoint + aHandoffState.mVelocity;
+ endPoint = startPoint + currentVelocity;
- // Only transform when current apcz can be transformed with previous
+ // Only transform when current apzc can be transformed with previous
if (startIndex > 0) {
if (!TransformDisplacement(this,
chain->GetApzcAtIndex(startIndex - 1),
current,
startPoint,
endPoint)) {
- return;
+ break;
}
}
- ParentLayerPoint transformedVelocity = endPoint - startPoint;
- aHandoffState.mVelocity = transformedVelocity;
+ FlingHandoffState transformedHandoffState = aHandoffState;
+ transformedHandoffState.mVelocity = (endPoint - startPoint);
+
+ ParentLayerPoint residualVelocity = current->AttemptFling(transformedHandoffState);
- if (current->AttemptFling(aHandoffState)) {
- // Coming out of AttemptFling(), the handoff state's velocity is the
- // residual velocity after attempting to fling |current|.
- ParentLayerPoint residualVelocity = aHandoffState.mVelocity;
+ // If there's no residual velocity, there's nothing more to hand off.
+ if (IsZero(residualVelocity)) {
+ return ParentLayerPoint();
+ }
- // If there's no residual velocity, there's nothing more to hand off.
- if (IsZero(residualVelocity)) {
- finalResidualVelocity = ParentLayerPoint();
- break;
- }
+ // If any of the velocity available to be handed off was consumed,
+ // subtract the proportion of consumed velocity from finalResidualVelocity.
+ if (!FuzzyEqualsAdditive(transformedHandoffState.mVelocity.x,
+ residualVelocity.x, COORDINATE_EPSILON)) {
+ finalResidualVelocity.x *= (residualVelocity.x / transformedHandoffState.mVelocity.x);
+ }
+ if (!FuzzyEqualsAdditive(transformedHandoffState.mVelocity.y,
+ residualVelocity.y, COORDINATE_EPSILON)) {
+ finalResidualVelocity.y *= (residualVelocity.y / transformedHandoffState.mVelocity.y);
+ }
- // If there is residual velocity, subtract the proportion of used
- // velocity from finalResidualVelocity and continue handoff along the
- // chain.
- if (!FuzzyEqualsAdditive(transformedVelocity.x,
- residualVelocity.x, COORDINATE_EPSILON)) {
- finalResidualVelocity.x *= (residualVelocity.x / transformedVelocity.x);
- }
- if (!FuzzyEqualsAdditive(transformedVelocity.y,
- residualVelocity.y, COORDINATE_EPSILON)) {
- finalResidualVelocity.y *= (residualVelocity.y / transformedVelocity.y);
- }
- }
+ currentVelocity = residualVelocity;
}
- // Set the handoff state's velocity to any residual velocity left over
- // after the entire handoff process.
- aHandoffState.mVelocity = finalResidualVelocity;
+ // Return any residual velocity left over after the entire handoff process.
+ return finalResidualVelocity;
}
bool
APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
{
RefPtr<AsyncPanZoomController> target = GetTargetAPZC(aPoint, nullptr);
return target != nullptr;
}
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -417,23 +417,24 @@ public:
* mChain the chain of APZCs along which the fling
* should be handed off
* mIsHandoff is true if |aApzc| is handing off an existing fling (in
* this case the fling is given to the next APZC in the
* handoff chain after |aApzc|), and false is |aApzc| wants
* start a fling (in this case the fling is given to the
* first APZC in the chain)
*
- * aHandoffState.mVelocity will be modified depending on how much of that
- * velocity has been consumed by APZCs in the overscroll hand-off chain.
+ * The return value is the "residual velocity", the portion of
+ * |aHandoffState.mVelocity| that was not consumed by APZCs in the
+ * handoff chain doing flings.
* The caller can use this value to determine whether it should consume
- * the excess velocity by going into an overscroll fling.
+ * the excess velocity by going into overscroll.
*/
- void DispatchFling(AsyncPanZoomController* aApzc,
- FlingHandoffState& aHandoffState);
+ ParentLayerPoint DispatchFling(AsyncPanZoomController* aApzc,
+ const FlingHandoffState& aHandoffState);
void StartScrollbarDrag(
const ScrollableLayerGuid& aGuid,
const AsyncDragMetrics& aDragMetrics) override;
bool StartAutoscroll(const ScrollableLayerGuid& aGuid,
const ScreenPoint& aAnchorLocation) override;
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1587,20 +1587,20 @@ nsEventStatus AsyncPanZoomController::Ha
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
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,
- GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
- false /* not handoff */,
- GetCurrentTouchBlock()->GetScrolledApzc()};
+ const FlingHandoffState handoffState{flingVelocity,
+ GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
+ false /* not handoff */,
+ GetCurrentTouchBlock()->GetScrolledApzc()};
treeManagerLocal->DispatchFling(this, handoffState);
}
return nsEventStatus_eConsumeNoDefault;
}
bool
AsyncPanZoomController::ConvertToGecko(const ScreenIntPoint& aPoint, LayoutDevicePoint* aOut)
{
@@ -2782,69 +2782,66 @@ RefPtr<const OverscrollHandoffChain> Asy
// This APZC IsDestroyed(). To avoid callers having to special-case this
// scenario, just build a 1-element chain containing ourselves.
OverscrollHandoffChain* result = new OverscrollHandoffChain;
result->Add(this);
return result;
}
-void AsyncPanZoomController::AcceptFling(FlingHandoffState& aHandoffState) {
+ParentLayerPoint AsyncPanZoomController::AttemptFling(const FlingHandoffState& aHandoffState) {
RecursiveMutexAutoLock lock(mRecursiveMutex);
+ if (!IsPannable()) {
+ return aHandoffState.mVelocity;
+ }
+
// We may have a pre-existing velocity for whatever reason (for example,
// a previously handed off fling). We don't want to clobber that.
APZC_LOG("%p accepting fling with velocity %s\n", this,
Stringify(aHandoffState.mVelocity).c_str());
+ ParentLayerPoint residualVelocity = aHandoffState.mVelocity;
if (mX.CanScroll()) {
mX.SetVelocity(mX.GetVelocity() + aHandoffState.mVelocity.x);
- aHandoffState.mVelocity.x = 0;
+ residualVelocity.x = 0;
}
if (mY.CanScroll()) {
mY.SetVelocity(mY.GetVelocity() + aHandoffState.mVelocity.y);
- aHandoffState.mVelocity.y = 0;
+ residualVelocity.y = 0;
}
// If there's a scroll snap point near the predicted fling destination,
// scroll there using a smooth scroll animation. Otherwise, start a
// fling animation.
ScrollSnapToDestination();
if (mState != SMOOTH_SCROLL) {
SetState(FLING);
FlingAnimation *fling = new FlingAnimation(*this,
GetPlatformSpecificState(),
aHandoffState.mChain,
aHandoffState.mIsHandoff,
aHandoffState.mScrolledApzc);
StartAnimation(fling);
}
-}
-
-bool AsyncPanZoomController::AttemptFling(FlingHandoffState& aHandoffState) {
- // If we are pannable, take over the fling ourselves.
- if (IsPannable()) {
- AcceptFling(aHandoffState);
- return true;
- }
-
- return false;
+
+ return residualVelocity;
}
void AsyncPanZoomController::HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
const RefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
const RefPtr<const AsyncPanZoomController>& aScrolledApzc) {
APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
if (treeManagerLocal) {
- FlingHandoffState handoffState{aVelocity,
- aOverscrollHandoffChain,
- true /* handoff */,
- aScrolledApzc};
- treeManagerLocal->DispatchFling(this, handoffState);
- if (!IsZero(handoffState.mVelocity) && IsPannable() && gfxPrefs::APZOverscrollEnabled()) {
- mOverscrollEffect->HandleFlingOverscroll(handoffState.mVelocity);
+ const FlingHandoffState handoffState{aVelocity,
+ aOverscrollHandoffChain,
+ true /* handoff */,
+ aScrolledApzc};
+ ParentLayerPoint residualVelocity = treeManagerLocal->DispatchFling(this, handoffState);
+ if (!IsZero(residualVelocity) && IsPannable() && gfxPrefs::APZOverscrollEnabled()) {
+ mOverscrollEffect->HandleFlingOverscroll(residualVelocity);
}
}
}
void AsyncPanZoomController::HandleSmoothScrollOverscroll(const ParentLayerPoint& aVelocity) {
// We must call BuildOverscrollHandoffChain from this deferred callback
// function in order to avoid a deadlock when acquiring the tree lock.
HandleFlingOverscroll(aVelocity, BuildOverscrollHandoffChain(), nullptr);
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -997,26 +997,24 @@ private:
/* ===================================================================
* The functions and members in this section are used to manage
* fling animations, smooth scroll animations, and overscroll
* during a fling or smooth scroll.
*/
public:
/**
* Attempt a fling with the velocity specified in |aHandoffState|.
- * If we are not pannable, the fling is handed off to the next APZC in
- * the handoff chain via mTreeManager->DispatchFling().
- * Returns true iff. the entire velocity of the fling was consumed by
- * this APZC. |aHandoffState.mVelocity| is modified to contain any
- * unused, residual velocity.
* |aHandoffState.mIsHandoff| should be true iff. the fling was handed off
* from a previous APZC, and determines whether acceleration is applied
* to the fling.
+ * We only accept the fling in the direction(s) in which we are pannable.
+ * Returns the "residual velocity", i.e. the portion of
+ * |aHandoffState.mVelocity| that this APZC did not consume.
*/
- bool AttemptFling(FlingHandoffState& aHandoffState);
+ ParentLayerPoint AttemptFling(const FlingHandoffState& aHandoffState);
private:
friend class AndroidFlingAnimation;
friend class AutoscrollAnimation;
friend class GenericFlingAnimation;
friend class OverscrollAnimation;
friend class SmoothScrollAnimation;
friend class GenericScrollAnimation;
@@ -1039,19 +1037,16 @@ private:
// later in the handoff chain, or if there are no takers, continuing the
// fling and entering an overscrolled state.
void HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
const RefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
const RefPtr<const AsyncPanZoomController>& aScrolledApzc);
void HandleSmoothScrollOverscroll(const ParentLayerPoint& aVelocity);
- // Helper function used by AttemptFling().
- void AcceptFling(FlingHandoffState& aHandoffState);
-
// Start an overscroll animation with the given initial velocity.
void StartOverscrollAnimation(const ParentLayerPoint& aVelocity);
void SmoothScrollTo(const CSSPoint& aDestination);
// Returns whether overscroll is allowed during an event.
bool AllowScrollHandoffInCurrentBlock() const;