Bug 951793 - Obey overscroll-behavior for fling handoff. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Fri, 03 Nov 2017 16:03:38 -0400
changeset 702261 ec34dab506352cccfde7432b100509b530948000
parent 702260 3e152aa070fdf320553630d2abef900371fa3c7b
child 702262 8f4c02e31893e7589259ef33a26c7c8639988350
push id90422
push userbballo@mozilla.com
push dateWed, 22 Nov 2017 22:10:14 +0000
reviewerskats
bugs951793
milestone59.0a1
Bug 951793 - Obey overscroll-behavior for fling handoff. r=kats MozReview-Commit-ID: 9i2AgmW3Inm
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -2076,46 +2076,61 @@ APZCTreeManager::DispatchFling(AsyncPanZ
 
     // Make sure the apzc about to be handled can be handled
     if (current == nullptr || current->IsDestroyed()) {
       break;
     }
 
     endPoint = startPoint + currentVelocity;
 
+    RefPtr<AsyncPanZoomController> prevApzc = (startIndex > 0)
+                                            ? chain->GetApzcAtIndex(startIndex - 1)
+                                            : nullptr;
+
     // Only transform when current apzc can be transformed with previous
-    if (startIndex > 0) {
+    if (prevApzc) {
       if (!TransformDisplacement(this,
-                                 chain->GetApzcAtIndex(startIndex - 1),
+                                 prevApzc,
                                  current,
                                  startPoint,
                                  endPoint)) {
         break;
       }
     }
 
+    ParentLayerPoint availableVelocity = (endPoint - startPoint);
+    ParentLayerPoint residualVelocity;
+
     FlingHandoffState transformedHandoffState = aHandoffState;
-    transformedHandoffState.mVelocity = (endPoint - startPoint);
+    transformedHandoffState.mVelocity = availableVelocity;
 
-    ParentLayerPoint residualVelocity = current->AttemptFling(transformedHandoffState);
+    // Obey overscroll-behavior.
+    if (prevApzc) {
+      residualVelocity += prevApzc->AdjustHandoffVelocityForOverscrollBehavior(transformedHandoffState.mVelocity);
+    }
+
+    residualVelocity += current->AttemptFling(transformedHandoffState);
 
     // If there's no residual velocity, there's nothing more to hand off.
     if (IsZero(residualVelocity)) {
       return ParentLayerPoint();
     }
 
     // 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,
+    // Note: it's important to compare |residualVelocity| to |availableVelocity|
+    // here and not to |transformedHandoffState.mVelocity|, since the latter
+    // may have been modified by AdjustHandoffVelocityForOverscrollBehavior().
+    if (!FuzzyEqualsAdditive(availableVelocity.x,
                              residualVelocity.x, COORDINATE_EPSILON)) {
-      finalResidualVelocity.x *= (residualVelocity.x / transformedHandoffState.mVelocity.x);
+      finalResidualVelocity.x *= (residualVelocity.x / availableVelocity.x);
     }
-    if (!FuzzyEqualsAdditive(transformedHandoffState.mVelocity.y,
+    if (!FuzzyEqualsAdditive(availableVelocity.y,
                              residualVelocity.y, COORDINATE_EPSILON)) {
-      finalResidualVelocity.y *= (residualVelocity.y / transformedHandoffState.mVelocity.y);
+      finalResidualVelocity.y *= (residualVelocity.y / availableVelocity.y);
     }
 
     currentVelocity = residualVelocity;
   }
 
   // Return any residual velocity left over after the entire handoff process.
   return finalResidualVelocity;
 }
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2821,16 +2821,32 @@ ParentLayerPoint AsyncPanZoomController:
         aHandoffState.mIsHandoff,
         aHandoffState.mScrolledApzc);
     StartAnimation(fling);
   }
 
   return residualVelocity;
 }
 
+ParentLayerPoint AsyncPanZoomController::AdjustHandoffVelocityForOverscrollBehavior(ParentLayerPoint& aHandoffVelocity) const
+{
+  RecursiveMutexAutoLock lock(mRecursiveMutex);
+  ParentLayerPoint residualVelocity;
+  if (!mX.OverscrollBehaviorAllowsHandoff()) {
+    residualVelocity.x = aHandoffVelocity.x;
+    aHandoffVelocity.x = 0;
+  }
+  if (!mY.OverscrollBehaviorAllowsHandoff()) {
+    residualVelocity.y = aHandoffVelocity.y;
+    aHandoffVelocity.y = 0;
+  }
+  return residualVelocity;
+}
+
+
 void AsyncPanZoomController::HandleFlingOverscroll(const ParentLayerPoint& aVelocity,
                                                    const RefPtr<const OverscrollHandoffChain>& aOverscrollHandoffChain,
                                                    const RefPtr<const AsyncPanZoomController>& aScrolledApzc) {
   APZCTreeManager* treeManagerLocal = GetApzcTreeManager();
   if (treeManagerLocal) {
     const FlingHandoffState handoffState{aVelocity,
                                          aOverscrollHandoffChain,
                                          true /* handoff */,
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -1006,16 +1006,18 @@ public:
    * 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.
    */
   ParentLayerPoint AttemptFling(const FlingHandoffState& aHandoffState);
 
+  ParentLayerPoint AdjustHandoffVelocityForOverscrollBehavior(ParentLayerPoint& aHandoffVelocity) const;
+
 private:
   friend class AndroidFlingAnimation;
   friend class AutoscrollAnimation;
   friend class GenericFlingAnimation;
   friend class OverscrollAnimation;
   friend class SmoothScrollAnimation;
   friend class GenericScrollAnimation;
   friend class WheelScrollAnimation;