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 draft
authorBotond Ballo <botond@mozilla.com>
Tue, 14 Apr 2015 11:39:54 -0400
changeset 257077 f14d3c29a1ad36e1481c1eff71ab96a51a312f95
parent 257076 dee516a8358d8fd6ee27258871a58e03d4fc8d7a
child 506101 180573d1b64ab03afe3e5fe6394c3299ef7cfeee
push id1521
push userbballo@mozilla.com
push dateTue, 14 Apr 2015 15:47:38 +0000
reviewerskats
bugs1153711
milestone40.0a1
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
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
@@ -436,27 +436,27 @@ public:
                  bool aApplyAcceleration)
     : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
     , mApzc(aApzc)
     , mOverscrollHandoffChain(aOverscrollHandoffChain)
   {
     MOZ_ASSERT(mOverscrollHandoffChain);
     TimeStamp now = AsyncPanZoomController::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.
@@ -1475,16 +1475,27 @@ AsyncPanZoomController::CanScroll(const 
 bool
 AsyncPanZoomController::CanScroll(double aDeltaX, double aDeltaY) const
 {
   ReentrantMonitorAutoEnter lock(mMonitor);
   return mX.CanScroll(aDeltaX) || mY.CanScroll(aDeltaY);
 }
 
 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;
+  }
+}
+
+bool
 AsyncPanZoomController::AllowScrollHandoffInWheelTransaction() const
 {
   WheelBlockState* block = mInputQueue->CurrentWheelBlock();
   return block->AllowScrollHandoff();
 }
 
 nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEvent)
 {
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -17,16 +17,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 {
@@ -365,16 +366,20 @@ public:
   // Return whether or not a wheel event will be able to scroll in either
   // direction.
   bool CanScroll(const ScrollWheelInput& aEvent) const;
 
   // Return whether or not a scroll delta will be able to scroll in either
   // direction.
   bool CanScroll(double aDeltaX, double aDeltaY) const;
 
+  // Return whether or not there is room to scroll this APZC
+  // in the given direction.
+  bool CanScroll(Layer::ScrollDirection aDirection) const;
+
   void NotifyMozMouseScrollEvent(const nsString& aString) const;
 
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   ~AsyncPanZoomController();
 
   /**
    * Helper method for touches beginning. Sets everything up for panning and any
--- a/gfx/layers/apz/src/OverscrollHandoffState.cpp
+++ b/gfx/layers/apz/src/OverscrollHandoffState.cpp
@@ -139,16 +139,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;
 
   nsRefPtr<AsyncPanZoomController> FindFirstScrollable(const ScrollWheelInput& aInput) const;