Bug 1153711 - Do not discard a component of a fling if an APZC further in the handoff chain has room to scroll in that direction. r=kats, a=bajaj
authorBotond Ballo <botond@mozilla.com>
Wed, 15 Apr 2015 12:38:26 -0400
changeset 238204 a25acc174d8420afc1ef542409a8e531a6500337
parent 238203 fb1b63d73aec903c96c9595e23b223b3d6ab3be9
child 238205 35742de4b8b668eb8919b0873e054e267993c897
push id515
push userryanvm@gmail.com
push dateTue, 21 Apr 2015 17:05:41 +0000
treeherdermozilla-b2g37_v2_2@35742de4b8b6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, bajaj
bugs1153711
milestone37.0
Bug 1153711 - Do not discard a component of a fling if an APZC further in the handoff chain has room to scroll in that direction. r=kats, a=bajaj
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/layers/apz/src/OverscrollHandoffState.cpp
gfx/layers/apz/src/OverscrollHandoffState.h
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -479,27 +479,27 @@ public:
                  bool aApplyAcceleration)
     : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
     , mApzc(aApzc)
     , mOverscrollHandoffChain(aOverscrollHandoffChain)
   {
     MOZ_ASSERT(mOverscrollHandoffChain);
     TimeStamp now = GetFrameTime();
 
-    // Drop any velocity on axes where we don't have room to scroll anyways.
+    // Drop any velocity on axes where we don't have room to scroll anyways
+    // (in this APZC, or an APZC further in the handoff chain).
     // This ensures that we don't take the 'overscroll' path in Sample()
     // on account of one axis which can't scroll having a velocity.
-    {
+    if (!mOverscrollHandoffChain->CanScrollInDirection(&mApzc, Layer::HORIZONTAL)) {
       ReentrantMonitorAutoEnter lock(mApzc.mMonitor);
-      if (!mApzc.mX.CanScroll()) {
-        mApzc.mX.SetVelocity(0);
-      }
-      if (!mApzc.mY.CanScroll()) {
-        mApzc.mY.SetVelocity(0);
-      }
+      mApzc.mX.SetVelocity(0);
+    }
+    if (!mOverscrollHandoffChain->CanScrollInDirection(&mApzc, Layer::VERTICAL)) {
+      ReentrantMonitorAutoEnter lock(mApzc.mMonitor);
+      mApzc.mY.SetVelocity(0);
     }
 
     ParentLayerPoint velocity = mApzc.GetVelocityVector();
 
     // If the last fling was very recent and in the same direction as this one,
     // boost the velocity to be the sum of the two. Check separate axes separately
     // because we could have two vertical flings with small horizontal components
     // on the opposite side of zero, and we still want the y-fling to get accelerated.
@@ -1509,16 +1509,27 @@ nsEventStatus AsyncPanZoomController::On
       StartSmoothScroll();
       break;
     }
   }
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
+bool
+AsyncPanZoomController::CanScroll(Layer::ScrollDirection aDirection) const
+{
+  ReentrantMonitorAutoEnter lock(mMonitor);
+  switch (aDirection) {
+  case Layer::HORIZONTAL: return mX.CanScroll();
+  case Layer::VERTICAL:   return mY.CanScroll();
+  default:                MOZ_ASSERT(false); return false;
+  }
+}
+
 nsEventStatus AsyncPanZoomController::OnPanMayBegin(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-maybegin in state %d\n", this, mState);
 
   mX.StartTouch(aEvent.mLocalPanStartPoint.x, aEvent.mTime);
   mY.StartTouch(aEvent.mLocalPanStartPoint.y, aEvent.mTime);
   if (mPanGestureState) {
     mPanGestureState->GetOverscrollHandoffChain()->CancelAnimations();
   } else {
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -16,16 +16,17 @@
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Atomics.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "InputQueue.h"
 #include "APZUtils.h"
+#include "Layers.h"                     // for Layer::ScrollDirection
 #include "LayersTypes.h"
 #include "TaskThrottler.h"
 #include "mozilla/gfx/Matrix.h"
 #include "nsRegion.h"
 
 #include "base/message_loop.h"
 
 namespace mozilla {
@@ -362,16 +363,20 @@ public:
    * The anchor is necessary because with 3D tranforms, the location of the
    * vector can affect the result of the transform.
    * To respect the lock ordering, mMonitor must NOT be held when calling
    * this function (since this function acquires the tree lock).
    */
   ParentLayerPoint ToParentLayerCoordinates(const ScreenPoint& aVector,
                                             const ScreenPoint& aAnchor) const;
 
+  // Return whether or not there is room to scroll this APZC
+  // in the given direction.
+  bool CanScroll(Layer::ScrollDirection aDirection) const;
+
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   ~AsyncPanZoomController();
 
   /**
    * Helper method for touches beginning. Sets everything up for panning and any
    * multitouch gestures.
    */
--- a/gfx/layers/apz/src/OverscrollHandoffState.cpp
+++ b/gfx/layers/apz/src/OverscrollHandoffState.cpp
@@ -140,16 +140,34 @@ OverscrollHandoffChain::CanBePanned(cons
       return true;
     }
   }
 
   return false;
 }
 
 bool
+OverscrollHandoffChain::CanScrollInDirection(const AsyncPanZoomController* aApzc,
+                                             Layer::ScrollDirection aDirection) const
+{
+  // Find |aApzc| in the handoff chain.
+  uint32_t i = IndexOf(aApzc);
+
+  // See whether any APZC in the handoff chain starting from |aApzc|
+  // has room to scroll in the given direction.
+  for (uint32_t j = i; j < Length(); ++j) {
+    if (mChain[j]->CanScroll(aDirection)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool
 OverscrollHandoffChain::HasOverscrolledApzc() const
 {
   return AnyApzc(&AsyncPanZoomController::IsOverscrolled);
 }
 
 bool
 OverscrollHandoffChain::HasFastMovingApzc() const
 {
--- a/gfx/layers/apz/src/OverscrollHandoffState.h
+++ b/gfx/layers/apz/src/OverscrollHandoffState.h
@@ -5,18 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_OverscrollHandoffChain_h
 #define mozilla_layers_OverscrollHandoffChain_h
 
 #include <vector>
 #include "nsAutoPtr.h"
 #include "nsISupportsImpl.h"  // for NS_INLINE_DECL_REFCOUNTING
+#include "APZUtils.h"         // for CancelAnimationFlags
+#include "Layers.h"           // for Layer::ScrollDirection
 #include "Units.h"            // for ScreenPoint
-#include "APZUtils.h"         // for CancelAnimationFlags
 
 namespace mozilla {
 namespace layers {
 
 class AsyncPanZoomController;
 
 /**
  * A variant of NS_INLINE_DECL_THREADSAFE_REFCOUNTING which makes the refcount
@@ -102,16 +103,21 @@ public:
   // Snap back the APZC that is overscrolled on the subset of the chain from
   // |aStart| onwards, if any.
   void SnapBackOverscrolledApzc(const AsyncPanZoomController* aStart) const;
 
   // Determine whether the given APZC, or any APZC further in the chain,
   // has room to be panned.
   bool CanBePanned(const AsyncPanZoomController* aApzc) const;
 
+  // Determine whether the given APZC, or any APZC further in the chain,
+  // can scroll in the given direction.
+  bool CanScrollInDirection(const AsyncPanZoomController* aApzc,
+                            Layer::ScrollDirection aDirection) const;
+
   // Determine whether any APZC along this handoff chain is overscrolled.
   bool HasOverscrolledApzc() const;
 
   // Determine whether any APZC along this handoff chain is moving fast.
   bool HasFastMovingApzc() const;
 
 private:
   std::vector<nsRefPtr<AsyncPanZoomController>> mChain;