Bug 1260588 - C++ APZ should only allow handoff to ancestor APZC r=botond
authorRandall Barker <rbarker@mozilla.com>
Tue, 29 Mar 2016 16:46:29 -0700
changeset 291356 5620c5785d8e80ce0f50fa557d14a134741e1c02
parent 291355 d82bdcd0b640dc5aefb0c10ea108a2c04c81d98c
child 291357 95e61ede373da7ae3755ca149da42ff873e05a42
push id30132
push userryanvm@gmail.com
push dateSat, 02 Apr 2016 17:18:33 +0000
treeherdermozilla-central@df803eb33993 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1260588
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1260588 - C++ APZ should only allow handoff to ancestor APZC r=botond
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/InputBlockState.cpp
gfx/layers/apz/src/InputBlockState.h
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2355,21 +2355,21 @@ bool AsyncPanZoomController::AttemptScro
   ParentLayerPoint displacement = aStartPoint - aEndPoint;
 
   ParentLayerPoint overscroll;  // will be used outside monitor block
 
   // If the direction of panning is reversed within the same input block,
   // a later event in the block could potentially scroll an APZC earlier
   // in the handoff chain, than an earlier event in the block (because
   // the earlier APZC was scrolled to its extent in the original direction).
-  // If immediate handoff is disallowed, we want to disallow this (to
-  // preserve the property that a single input block only scrolls one APZC),
-  // so we skip the earlier APZC.
-  bool scrollThisApzc = gfxPrefs::APZAllowImmediateHandoff() ||
-      (CurrentInputBlock() && (!CurrentInputBlock()->GetScrolledApzc() || this == CurrentInputBlock()->GetScrolledApzc()));
+  // We want to disallow this.
+  bool scrollThisApzc = false;
+  if (InputBlockState* block = CurrentInputBlock()) {
+    scrollThisApzc = !block->GetScrolledApzc() || block->IsDownchainOfScrolledApzc(this);
+  }
 
   if (scrollThisApzc) {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
     ParentLayerPoint adjustedDisplacement;
     bool forceVerticalOverscroll =
       (aOverscrollHandoffState.mScrollSource == ScrollSource::Wheel &&
        !mFrameMetrics.AllowVerticalScrollWithWheel());
@@ -2378,31 +2378,29 @@ bool AsyncPanZoomController::AttemptScro
     bool xChanged = mX.AdjustDisplacement(displacement.x, adjustedDisplacement.x, overscroll.x);
 
     if (xChanged || yChanged) {
       ScheduleComposite();
     }
 
     if (!IsZero(adjustedDisplacement)) {
       ScrollBy(adjustedDisplacement / mFrameMetrics.GetZoom());
-      if (!gfxPrefs::APZAllowImmediateHandoff()) {
-        if (InputBlockState* block = CurrentInputBlock()) {
-          block->SetScrolledApzc(this);
-        }
+      if (InputBlockState* block = CurrentInputBlock()) {
+        block->SetScrolledApzc(this);
       }
       ScheduleCompositeAndMaybeRepaint();
       UpdateSharedCompositorFrameMetrics();
     }
+
+    // Adjust the start point to reflect the consumed portion of the scroll.
+    aStartPoint = aEndPoint + overscroll;
   } else {
     overscroll = displacement;
   }
 
-  // Adjust the start point to reflect the consumed portion of the scroll.
-  aStartPoint = aEndPoint + overscroll;
-
   // If we consumed the entire displacement as a normal scroll, great.
   if (IsZero(overscroll)) {
     return true;
   }
 
   if (AllowScrollHandoffInCurrentBlock()) {
     // If there is overscroll, first try to hand it off to an APZC later
     // in the handoff chain to consume (either as a normal scroll or as
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -83,17 +83,17 @@ InputBlockState::GetBlockId() const
 
 bool
 InputBlockState::IsTargetConfirmed() const
 {
   return mTargetConfirmed;
 }
 
 bool
-InputBlockState::IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB)
+InputBlockState::IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const
 {
   if (aA == aB) {
     return true;
   }
 
   bool seenA = false;
   for (size_t i = 0; i < mOverscrollHandoffChain->Length(); ++i) {
     AsyncPanZoomController* apzc = mOverscrollHandoffChain->GetApzcAtIndex(i);
@@ -107,27 +107,35 @@ InputBlockState::IsAncestorOf(AsyncPanZo
   return false;
 }
 
 
 void
 InputBlockState::SetScrolledApzc(AsyncPanZoomController* aApzc)
 {
   // An input block should only have one scrolled APZC.
-  MOZ_ASSERT(!mScrolledApzc || mScrolledApzc == aApzc);
+  MOZ_ASSERT(!mScrolledApzc || (gfxPrefs::APZAllowImmediateHandoff() ? IsDownchainOf(mScrolledApzc, aApzc) : mScrolledApzc == aApzc));
 
   mScrolledApzc = aApzc;
 }
 
 AsyncPanZoomController*
 InputBlockState::GetScrolledApzc() const
 {
   return mScrolledApzc;
 }
 
+bool
+InputBlockState::IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const
+{
+  MOZ_ASSERT(aApzc && mScrolledApzc);
+
+  return IsDownchainOf(mScrolledApzc, aApzc);
+}
+
 CancelableBlockState::CancelableBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
                                            bool aTargetConfirmed)
   : InputBlockState(aTargetApzc, aTargetConfirmed)
   , mPreventDefault(false)
   , mContentResponded(false)
   , mContentResponseTimerExpired(false)
 {
 }
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -47,24 +47,25 @@ public:
   const RefPtr<AsyncPanZoomController>& GetTargetApzc() const;
   const RefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
   uint64_t GetBlockId() const;
 
   bool IsTargetConfirmed() const;
 
   void SetScrolledApzc(AsyncPanZoomController* aApzc);
   AsyncPanZoomController* GetScrolledApzc() const;
+  bool IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const;
 
 protected:
   virtual void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc);
 
 private:
   // Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
   // |mOverscrollHandoffChain|.
-  bool IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB);
+  bool IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const;
 
 private:
   RefPtr<AsyncPanZoomController> mTargetApzc;
   bool mTargetConfirmed;
   const uint64_t mBlockId;
 
   // The APZC that was actually scrolled by events in this input block.
   // This is used in configurations where a single input block is only