Bug 1270955 - When hit-testing on fixed-pos layers, find the root APZC for the scroll container rather than the layers id. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 11 May 2016 10:37:50 -0400
changeset 365923 291888c4ebb02a514bbf5cb91f1ae52fc949f744
parent 365730 3461f3cae78495f100a0f7d3d2e0b89292d3ec02
child 365924 8f0c94e8d153d5385c7f26ea1f794753081c52ea
push id17840
push userkgupta@mozilla.com
push dateWed, 11 May 2016 14:38:28 +0000
reviewersbotond
bugs1270955
milestone49.0a1
Bug 1270955 - When hit-testing on fixed-pos layers, find the root APZC for the scroll container rather than the layers id. r?botond MozReview-Commit-ID: 5NHsF6WDUwY
gfx/layers/LayerMetricsWrapper.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/HitTestingTreeNode.cpp
gfx/layers/apz/src/HitTestingTreeNode.h
--- a/gfx/layers/LayerMetricsWrapper.h
+++ b/gfx/layers/LayerMetricsWrapper.h
@@ -429,16 +429,23 @@ public:
   }
 
   bool IsScrollbarContainer() const
   {
     MOZ_ASSERT(IsValid());
     return mLayer->IsScrollbarContainer();
   }
 
+  FrameMetrics::ViewID GetFixedPositionScrollContainerId() const
+  {
+    MOZ_ASSERT(IsValid());
+
+    return mLayer->GetFixedPositionScrollContainerId();
+  }
+
   // Expose an opaque pointer to the layer. Mostly used for printf
   // purposes. This is not intended to be a general-purpose accessor
   // for the underlying layer.
   const void* GetLayer() const
   {
     MOZ_ASSERT(IsValid());
 
     return (void*)mLayer;
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -364,16 +364,17 @@ APZCTreeManager::PrepareNodeForLayer(con
         GetEventRegions(aLayer),
         aLayer.GetTransformTyped(),
         aLayer.GetClipRect() ? Some(ParentLayerIntRegion(*aLayer.GetClipRect())) : Nothing(),
         GetEventRegionsOverride(aParent, aLayer));
     node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
                            aLayer.GetScrollbarDirection(),
                            aLayer.GetScrollbarSize(),
                            aLayer.IsScrollbarContainer());
+    node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
     return node;
   }
 
   AsyncPanZoomController* apzc = nullptr;
   // If we get here, aLayer is a scrollable layer and somebody
   // has registered a GeckoContentController for it, so we need to ensure
   // it has an APZC instance to manage its scrolling.
 
@@ -544,16 +545,17 @@ APZCTreeManager::PrepareNodeForLayer(con
         Some(clipRegion),
         GetEventRegionsOverride(aParent, aLayer));
   }
 
   node->SetScrollbarData(aLayer.GetScrollbarTargetContainerId(),
                          aLayer.GetScrollbarDirection(),
                          aLayer.GetScrollbarSize(),
                          aLayer.IsScrollbarContainer());
+  node->SetFixedPosData(aLayer.GetFixedPositionScrollContainerId());
   return node;
 }
 
 HitTestingTreeNode*
 APZCTreeManager::UpdateHitTestingTree(TreeBuildingState& aState,
                                       const LayerMetricsWrapper& aLayer,
                                       uint64_t aLayersId,
                                       const gfx::Matrix4x4& aAncestorTransform,
@@ -1768,40 +1770,55 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti
       MOZ_ASSERT(resultNode);
       if (aOutHitScrollbar) {
         for (HitTestingTreeNode* n = resultNode; n; n = n->GetParent()) {
           if (n->IsScrollbarNode()) {
             *aOutHitScrollbar = true;
           }
         }
       }
-      AsyncPanZoomController* result = resultNode->GetNearestContainingApzcWithSameLayersId();
+
+      AsyncPanZoomController* result = nullptr;
+
+      FrameMetrics::ViewID fpTarget =
+          resultNode->GetNearestAncestorFixedPosTargetWithSameLayersId();
+      if (fpTarget != FrameMetrics::NULL_SCROLL_ID) {
+        result = FindRootApzcForLayersId(resultNode->GetLayersId(), fpTarget);
+        APZCTM_LOG("Found target %p using fixed-pos lookup on %" PRIu64 "\n", result, fpTarget);
+      }
       if (!result) {
-        result = FindRootApzcForLayersId(resultNode->GetLayersId());
+        result = resultNode->GetNearestContainingApzcWithSameLayersId();
+        APZCTM_LOG("Found target %p using ancestor lookup\n", result);
+      }
+      if (!result) {
+        result = FindRootApzcForLayersId(resultNode->GetLayersId(), FrameMetrics::NULL_SCROLL_ID);
         MOZ_ASSERT(result);
+        APZCTM_LOG("Found target %p using root lookup\n", result);
       }
       APZCTM_LOG("Successfully matched APZC %p via node %p (hit result %d)\n",
           result, resultNode, *aOutHitResult);
       return result;
   }
 
   return nullptr;
 }
 
 AsyncPanZoomController*
-APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId) const
+APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId, FrameMetrics::ViewID aScrollId) const
 {
   mTreeLock.AssertCurrentThreadOwns();
 
   HitTestingTreeNode* resultNode = BreadthFirstSearch(mRootNode.get(),
-      [aLayersId](HitTestingTreeNode* aNode) {
+      [aLayersId, aScrollId](HitTestingTreeNode* aNode) {
         AsyncPanZoomController* apzc = aNode->GetApzc();
         return apzc
             && apzc->GetLayersId() == aLayersId
-            && apzc->IsRootForLayersId();
+            && (aScrollId == FrameMetrics::NULL_SCROLL_ID
+                ? apzc->IsRootForLayersId()
+                : apzc->GetGuid().mScrollId == aScrollId);
       });
   return resultNode ? resultNode->GetApzc() : nullptr;
 }
 
 AsyncPanZoomController*
 APZCTreeManager::FindRootContentApzcForLayersId(uint64_t aLayersId) const
 {
   mTreeLock.AssertCurrentThreadOwns();
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -461,17 +461,20 @@ private:
                                                      GuidComparator aComparator);
   HitTestingTreeNode* FindTargetNode(HitTestingTreeNode* aNode,
                                      const ScrollableLayerGuid& aGuid,
                                      GuidComparator aComparator);
   AsyncPanZoomController* GetAPZCAtPoint(HitTestingTreeNode* aNode,
                                          const ParentLayerPoint& aHitTestPoint,
                                          HitTestResult* aOutHitResult,
                                          bool* aOutHitScrollbar);
-  AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const;
+  // Find the root APZC for the given layers id; if the provided scrollid is
+  // not NULL_SCROLL_ID, this further filters APZCs to ones that match that
+  // scrollid.
+  AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId, FrameMetrics::ViewID aScrollId) const;
   AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const;
   AsyncPanZoomController* FindRootContentOrRootApzc() const;
   already_AddRefed<AsyncPanZoomController> GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
                                                                   HitTestResult* aOutHitResult);
   nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
                                   ScrollableLayerGuid* aOutTargetGuid,
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -24,16 +24,17 @@ HitTestingTreeNode::HitTestingTreeNode(A
                                        uint64_t aLayersId)
   : mApzc(aApzc)
   , mIsPrimaryApzcHolder(aIsPrimaryHolder)
   , mLayersId(aLayersId)
   , mScrollViewId(FrameMetrics::NULL_SCROLL_ID)
   , mScrollDir(Layer::NONE)
   , mScrollSize(0)
   , mIsScrollbarContainer(false)
+  , mFixedPosTarget(FrameMetrics::NULL_SCROLL_ID)
   , mOverride(EventRegionsOverride::NoOverride)
 {
 if (mIsPrimaryApzcHolder) {
     MOZ_ASSERT(mApzc);
   }
   MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
 }
 
@@ -122,16 +123,35 @@ HitTestingTreeNode::GetScrollSize() cons
 
 bool
 HitTestingTreeNode::IsScrollbarNode() const
 {
   return mIsScrollbarContainer || (mScrollDir != Layer::NONE);
 }
 
 void
+HitTestingTreeNode::SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget)
+{
+  mFixedPosTarget = aFixedPosTarget;
+}
+
+FrameMetrics::ViewID
+HitTestingTreeNode::GetNearestAncestorFixedPosTargetWithSameLayersId() const
+{
+  for (const HitTestingTreeNode* n = this;
+       n && n->mLayersId == mLayersId;
+       n = n->GetParent()) {
+    if (n->mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) {
+      return n->mFixedPosTarget;
+    }
+  }
+  return FrameMetrics::NULL_SCROLL_ID;
+}
+
+void
 HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling)
 {
   mPrevSibling = aSibling;
   if (aSibling) {
     aSibling->mParent = mParent;
 
     if (aSibling->GetApzc()) {
       AsyncPanZoomController* parent = mParent ? mParent->GetNearestContainingApzc() : nullptr;
@@ -288,21 +308,22 @@ HitTestingTreeNode::GetEventRegionsOverr
 }
 
 void
 HitTestingTreeNode::Dump(const char* aPrefix) const
 {
   if (mPrevSibling) {
     mPrevSibling->Dump(aPrefix);
   }
-  printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %s%sr=(%s) t=(%s) c=(%s)\n",
+  printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %s%s%sr=(%s) t=(%s) c=(%s)\n",
     aPrefix, this, mApzc.get(),
     mApzc ? Stringify(mApzc->GetGuid()).c_str() : nsPrintfCString("l=%" PRIu64, mLayersId).get(),
     (mOverride & EventRegionsOverride::ForceDispatchToContent) ? "fdtc " : "",
     (mOverride & EventRegionsOverride::ForceEmptyHitRegion) ? "fehr " : "",
+    (mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) ? nsPrintfCString("fixed=%" PRIu64 " ", mFixedPosTarget).get() : "",
     Stringify(mEventRegions).c_str(), Stringify(mTransform).c_str(),
     mClipRegion ? Stringify(mClipRegion.ref()).c_str() : "none");
   if (mLastChild) {
     mLastChild->Dump(nsPrintfCString("%s  ", aPrefix).get());
   }
 }
 
 void
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -95,16 +95,21 @@ public:
   void SetScrollbarData(FrameMetrics::ViewID aScrollViewId,
                         Layer::ScrollDirection aDir,
                         int32_t aScrollSize,
                         bool aIsScrollContainer);
   bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
   int32_t GetScrollSize() const;
   bool IsScrollbarNode() const;
 
+  /* Fixed pos info */
+
+  void SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget);
+  FrameMetrics::ViewID GetNearestAncestorFixedPosTargetWithSameLayersId() const;
+
   /* Convert aPoint into the LayerPixel space for the layer corresponding to
    * this node. */
   Maybe<LayerPoint> Untransform(const ParentLayerPoint& aPoint) const;
   /* Assuming aPoint is inside the clip region for this node, check which of the
    * event region spaces it falls inside. */
   HitTestResult HitTest(const ParentLayerPoint& aPoint) const;
   /* Returns the mOverride flag. */
   EventRegionsOverride GetEventRegionsOverride() const;
@@ -124,16 +129,18 @@ private:
 
   uint64_t mLayersId;
 
   FrameMetrics::ViewID mScrollViewId;
   Layer::ScrollDirection mScrollDir;
   int32_t mScrollSize;
   bool mIsScrollbarContainer;
 
+  FrameMetrics::ViewID mFixedPosTarget;
+
   /* Let {L,M} be the {layer, scrollable metrics} pair that this node
    * corresponds to in the layer tree. mEventRegions contains the event regions
    * from L, in the case where event-regions are enabled. If event-regions are
    * disabled, it will contain the visible region of L, which we use as an
    * approximation to the hit region for the purposes of obscuring other layers.
    * This value is in L's LayerPixels.
    */
   EventRegions mEventRegions;