Bug 982888 - Use the scroll handoff parent field while building the handoff chain. r=
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 11 Apr 2014 19:39:22 -0400
changeset 178154 ef0556d23d2757fba9148a44398fab13fdadd58a
parent 178153 f1822d4ddb96df5f47b4e5510fe1f6ca3f00ed89
child 178155 bcda3d79ffbe4162e878788b14d0365eaff0fcdd
push id42193
push userkgupta@mozilla.com
push dateFri, 11 Apr 2014 23:39:36 +0000
treeherdermozilla-inbound@bcda3d79ffbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs982888
milestone31.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 982888 - Use the scroll handoff parent field while building the handoff chain. r=
gfx/layers/composite/APZCTreeManager.cpp
gfx/layers/composite/APZCTreeManager.h
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -210,16 +210,17 @@ APZCTreeManager::UpdatePanZoomController
           aApzcsToDestroy->RemoveElement(apzc);
           apzc->SetPrevSibling(nullptr);
           apzc->SetLastChild(nullptr);
         }
         APZC_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer, aLayersId, container->GetFrameMetrics().GetScrollId());
 
         apzc->NotifyLayersUpdated(metrics,
                                   aIsFirstPaint && (aLayersId == aFirstPaintLayersId));
+        apzc->SetScrollHandoffParentId(container->GetScrollHandoffParentId());
 
         // Use the composition bounds as the hit test region.
         // Optionally, the GeckoContentController can provide a touch-sensitive
         // region that constrains all frames associated with the controller.
         // In this case we intersect the composition bounds with that region.
         ParentLayerRect visible(metrics.mCompositionBounds);
         CSSRect touchSensitiveRegion;
         if (state->mController->GetTouchSensitiveRegion(&touchSensitiveRegion)) {
@@ -863,37 +864,94 @@ APZCTreeManager::BuildOverscrollHandoffC
   // order in which scroll will be handed off to them.
 
   // Grab tree lock to protect mOverscrollHandoffChain from concurrent
   // access between the input and compositor threads.
   MonitorAutoLock lock(mTreeLock);
 
   mOverscrollHandoffChain.clear();
 
-  // Start with the child -> parent chain.
-  for (AsyncPanZoomController* apzc = aInitialTarget; apzc; apzc = apzc->GetParent()) {
+  // Build the chain. If there is a scroll parent link, we use that. This is
+  // needed to deal with scroll info layers, because they participate in handoff
+  // but do not follow the expected layer tree structure. If there are no
+  // scroll parent links we just walk up the tree to find the scroll parent.
+  AsyncPanZoomController* apzc = aInitialTarget;
+  while (apzc != nullptr) {
     if (!mOverscrollHandoffChain.append(apzc)) {
       NS_WARNING("Vector::append failed");
       mOverscrollHandoffChain.clear();
       return;
     }
+    if (apzc->GetScrollHandoffParentId() == FrameMetrics::NULL_SCROLL_ID) {
+      if (!apzc->IsRootForLayersId()) {
+        // This probably indicates a bug or missed case in layout code
+        NS_WARNING("Found a non-root APZ with no handoff parent");
+      }
+      apzc = apzc->GetParent();
+      continue;
+    }
+
+    // Find the AsyncPanZoomController instance with a matching layersId and
+    // the scroll id that matches apzc->GetScrollHandoffParentId(). To do this
+    // search the subtree with the same layersId for the apzc with the specified
+    // scroll id.
+    AsyncPanZoomController* scrollParent = nullptr;
+    AsyncPanZoomController* parent = apzc;
+    while (!parent->IsRootForLayersId()) {
+      parent = parent->GetParent();
+      // While walking up to find the root of the subtree, if we encounter the
+      // handoff parent, we don't actually need to do the search so we can
+      // just abort here.
+      if (parent->GetGuid().mScrollId == apzc->GetScrollHandoffParentId()) {
+        scrollParent = parent;
+        break;
+      }
+    }
+    if (!scrollParent) {
+      scrollParent = FindTargetAPZC(parent, apzc->GetScrollHandoffParentId());
+    }
+    apzc = scrollParent;
   }
 
   // Now adjust the chain to account for scroll grabbing. Sorting is a bit
   // of an overkill here, but scroll grabbing will likely be generalized
   // to scroll priorities, so we might as well do it this way.
   // The sorting being stable ensures that the relative order between
   // non-scrollgrabbing APZCs remains child -> parent.
   // (The relative order between scrollgrabbing APZCs will also remain
   // child -> parent, though that's just an artefact of the implementation
   // and users of 'scrollgrab' should not rely on this.)
   std::stable_sort(mOverscrollHandoffChain.begin(), mOverscrollHandoffChain.end(),
                    CompareByScrollPriority());
 }
 
+/* Find the apzc in the subtree rooted at aApzc that has the same layers id as
+   aApzc, and that has the given scroll id. Generally this function should be called
+   with aApzc being the root of its layers id subtree. */
+AsyncPanZoomController*
+APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId)
+{
+  mTreeLock.AssertCurrentThreadOwns();
+
+  if (aApzc->GetGuid().mScrollId == aScrollId) {
+    return aApzc;
+  }
+  for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
+    if (child->GetGuid().mLayersId != aApzc->GetGuid().mLayersId) {
+      continue;
+    }
+    AsyncPanZoomController* match = FindTargetAPZC(child, aScrollId);
+    if (match) {
+      return match;
+    }
+  }
+
+  return nullptr;
+}
+
 void
 APZCTreeManager::ClearOverscrollHandoffChain()
 {
   MonitorAutoLock lock(mTreeLock);
   mOverscrollHandoffChain.clear();
 }
 
 AsyncPanZoomController*
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -293,16 +293,17 @@ public:
      used by other production code.
   */
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
   void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
                           gfx3DMatrix& aTransformToGeckoOut);
 private:
   /* Helpers */
+  AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
   AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
   already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent);
   nsEventStatus ProcessTouchEvent(WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid);
   nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid);
   void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -419,16 +419,17 @@ AsyncPanZoomController::AsyncPanZoomCont
      mLastAsyncScrollOffset(0, 0),
      mCurrentAsyncScrollOffset(0, 0),
      mAsyncScrollTimeoutTask(nullptr),
      mHandlingTouchQueue(false),
      mAllowedTouchBehaviorSet(false),
      mPreventDefault(false),
      mPreventDefaultSet(false),
      mTreeManager(aTreeManager),
+     mScrollParentId(FrameMetrics::NULL_SCROLL_ID),
      mAPZCId(sAsyncPanZoomControllerCount++),
      mSharedFrameMetricsBuffer(nullptr),
      mSharedLock(nullptr)
 {
   MOZ_COUNT_CTOR(AsyncPanZoomController);
 
   if (aGestures == USE_GESTURE_DETECTOR) {
     mGestureEventListener = new GestureEventListener(this);
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -812,16 +812,33 @@ private:
   // pointer out in Destroy() will prevent accessing deleted memory.
   Atomic<APZCTreeManager*> mTreeManager;
 
   nsRefPtr<AsyncPanZoomController> mLastChild;
   nsRefPtr<AsyncPanZoomController> mPrevSibling;
   nsRefPtr<AsyncPanZoomController> mParent;
 
 
+  /* The functions and members in this section are used in building the
+   * scroll handoff chain, so that we can have seamless scrolling continue
+   * across APZC instances.
+   */
+public:
+  void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId) {
+    mScrollParentId = aScrollParentId;
+  }
+
+  FrameMetrics::ViewID GetScrollHandoffParentId() const {
+    return mScrollParentId;
+  }
+
+private:
+  FrameMetrics::ViewID mScrollParentId;
+
+
   /* The functions and members in this section are used to maintain the
    * area that this APZC instance is responsible for. This is used when
    * hit-testing to see which APZC instance should handle touch events.
    */
 public:
   void SetLayerHitTestData(const ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer,
                            const gfx3DMatrix& aTransformForLayer) {
     mVisibleRect = aRect;