Bug 1418387 - Add CompositorHitTestInfo bits for scrollbars. r?mstange draft
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 24 Nov 2017 16:23:06 -0500
changeset 703340 133b72a8ff6351182746ebf6d42a57d171ebad25
parent 703339 e4248e57686c8077e49a23b88e65a5084ef74da8
child 703341 4f378c336dd70104877f4c49fd8461151d97304d
push id90784
push userkgupta@mozilla.com
push dateFri, 24 Nov 2017 21:25:10 +0000
reviewersmstange
bugs1418387
milestone59.0a1
Bug 1418387 - Add CompositorHitTestInfo bits for scrollbars. r?mstange MozReview-Commit-ID: KTfpXoESOxF
gfx/src/CompositorHitTestInfo.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/gfx/src/CompositorHitTestInfo.h
+++ b/gfx/src/CompositorHitTestInfo.h
@@ -29,16 +29,27 @@ enum class CompositorHitTestInfo : uint1
   // The touch action flags are set up so that the default of
   // touch-action:auto on an element leaves all the flags as 0.
   eTouchActionPanXDisabled = 1 << 2,
   eTouchActionPanYDisabled = 1 << 3,
   eTouchActionPinchZoomDisabled = 1 << 4,
   eTouchActionDoubleTapZoomDisabled = 1 << 5,
   // Mask to check for all the touch-action flags at once
   eTouchActionMask = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5),
+
+  // The frame is a scrollbar or a subframe inside a scrollbar (including
+  // scroll thumbs)
+  eScrollbar = 1 << 6,
+  // The frame is a scrollthumb. If this is set then eScrollbar will also be
+  // set, unless gecko somehow generates a scroll thumb without a containing
+  // scrollbar.
+  eScrollbarThumb = 1 << 7,
+  // If eScrollbar is set, this flag indicates if the scrollbar is a vertical
+  // one (if set) or a horizontal one (if not set)
+  eScrollbarVertical = 1 << 8,
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CompositorHitTestInfo)
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_COMPOSITORHITTESTINFO_H_ */
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -11281,16 +11281,33 @@ nsIFrame::GetCompositorHitTestInfo(nsDis
       result |= CompositorHitTestInfo::eTouchActionPinchZoomDisabled
               | CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled;
       // pan-x and pan-y disabled flags will already have been set above
       MOZ_ASSERT(result & CompositorHitTestInfo::eTouchActionPanXDisabled);
       MOZ_ASSERT(result & CompositorHitTestInfo::eTouchActionPanYDisabled);
     }
   }
 
+  nsDisplayOwnLayerFlags flags = aBuilder->GetCurrentScrollbarFlags();
+  if (flags != nsDisplayOwnLayerFlags::eNone) {
+    if (GetContent()->IsXULElement(nsGkAtoms::thumb)) {
+      result |= CompositorHitTestInfo::eScrollbarThumb;
+    }
+    // The only flags that get set in nsDisplayListBuilder::mCurrentScrollbarFlags
+    // are the scrollbar direction flags
+    if (flags == nsDisplayOwnLayerFlags::eVerticalScrollbar) {
+      result |= CompositorHitTestInfo::eScrollbarVertical;
+    } else {
+      MOZ_ASSERT(flags == nsDisplayOwnLayerFlags::eHorizontalScrollbar);
+    }
+    // includes the ScrollbarFrame, SliderFrame, anything else that
+    // might be inside the xul:scrollbar
+    result |= CompositorHitTestInfo::eScrollbar;
+  }
+
   return result;
 }
 
 // Box layout debugging
 #ifdef DEBUG_REFLOW
 int32_t gIndent2 = 0;
 
 void
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -4141,16 +4141,23 @@ public:
   void SetHasOverrideDirtyRegion(bool aHasDirtyRegion) { mHasOverrideDirtyRegion = aHasDirtyRegion; }
 
   bool MayHaveWillChangeBudget() { return mMayHaveWillChangeBudget; }
   void SetMayHaveWillChangeBudget(bool aHasBudget) { mMayHaveWillChangeBudget = aHasBudget; }
 
   bool BuiltBlendContainer() { return mBuiltBlendContainer; }
   void SetBuiltBlendContainer(bool aBuilt) { mBuiltBlendContainer = aBuilt; }
 
+  /**
+   * Returns the set of flags indicating the properties of the frame that the
+   * compositor might care about for hit-testing purposes. Note that this function
+   * must be called during Gecko display list construction time (i.e while the
+   * frame tree is being traversed) because that is when the display list builder
+   * has the necessary state set up correctly.
+   */
   mozilla::gfx::CompositorHitTestInfo GetCompositorHitTestInfo(nsDisplayListBuilder* aBuilder);
 
 protected:
   static void DestroyAnonymousContent(nsPresContext* aPresContext,
                                       already_AddRefed<nsIContent>&& aContent);
 
   /**
    * Reparent this frame's view if it has one.
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4863,16 +4863,37 @@ nsDisplayEventReceiver::CreateWebRenderC
                                                 nsDisplayListBuilder* aDisplayListBuilder)
 {
   // This display item should never be getting created when building a display
   // list for WebRender consumption, so this function should never get called.
   MOZ_ASSERT(false);
   return true;
 }
 
+nsDisplayCompositorHitTestInfo::nsDisplayCompositorHitTestInfo(nsDisplayListBuilder* aBuilder,
+                                                               nsIFrame* aFrame,
+                                                               mozilla::gfx::CompositorHitTestInfo aHitTestInfo)
+  : nsDisplayEventReceiver(aBuilder, aFrame)
+  , mHitTestInfo(aHitTestInfo)
+{
+  MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
+  // We should never even create this display item if we're not building
+  // compositor hit-test info or if the computed hit info indicated the
+  // frame is invisible to hit-testing
+  MOZ_ASSERT(aBuilder->BuildCompositorHitTestInfo());
+  MOZ_ASSERT(mHitTestInfo != mozilla::gfx::CompositorHitTestInfo::eInvisibleToHitTest);
+
+  if (aBuilder->GetCurrentScrollbarFlags() != nsDisplayOwnLayerFlags::eNone) {
+    // In the case of scrollbar frames, we use the scrollbar's target scrollframe
+    // instead of the scrollframe with which the scrollbar actually moves.
+    MOZ_ASSERT(mHitTestInfo & CompositorHitTestInfo::eScrollbar);
+    mScrollTarget = Some(aBuilder->GetCurrentScrollbarTarget());
+  }
+}
+
 bool
 nsDisplayCompositorHitTestInfo::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                         const StackingContextHelper& aSc,
                                                         mozilla::layers::WebRenderLayerManager* aManager,
                                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   nsRect borderBox;
@@ -4897,20 +4918,23 @@ nsDisplayCompositorHitTestInfo::CreateWe
           borderBox + aDisplayListBuilder->ToReferenceFrame(mFrame),
           mFrame->PresContext()->AppUnitsPerDevPixel()));
 
   // XXX: eventually this scrollId computation and the SetHitTestInfo
   // call will get moved out into the WR display item iteration code so that
   // we don't need to do it as often, and so that we can do it for other
   // display item types as well (reducing the need for as many instances of
   // this display item).
-  FrameMetrics::ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
-  if (const ActiveScrolledRoot* asr = GetActiveScrolledRoot()) {
-    scrollId = asr->GetViewId();
-  }
+  FrameMetrics::ViewID scrollId = mScrollTarget.valueOrFrom(
+      [&]() -> FrameMetrics::ViewID {
+          if (const ActiveScrolledRoot* asr = GetActiveScrolledRoot()) {
+            return asr->GetViewId();
+          }
+          return FrameMetrics::NULL_SCROLL_ID;
+      });
 
   // Insert a transparent rectangle with the hit-test info
   aBuilder.SetHitTestInfo(scrollId, mHitTestInfo);
   aBuilder.PushRect(rect, rect, true, wr::ToColorF(gfx::Color()));
   aBuilder.ClearHitTestInfo();
 
   return true;
 }
@@ -6929,16 +6953,22 @@ nsDisplayOwnLayer::UpdateScrollData(mozi
                           : ScrollDirection::eHorizontal;
       aLayerData->SetScrollbarContainerDirection(dir);
       aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
     }
   }
   return ret;
 }
 
+void
+nsDisplayOwnLayer::WriteDebugInfo(std::stringstream& aStream)
+{
+  aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")", (int)mFlags, mScrollTarget).get();
+}
+
 nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
                                            nsIFrame* aFrame,
                                            nsSubDocumentFrame* aSubDocFrame,
                                            nsDisplayList* aList,
                                            nsDisplayOwnLayerFlags aFlags)
     : nsDisplayOwnLayer(aBuilder, aFrame, aList, aBuilder->CurrentActiveScrolledRoot(), aFlags)
     , mScrollParentId(aBuilder->GetCurrentScrollParentId())
     , mShouldFlatten(false)
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -4338,27 +4338,17 @@ public:
  * Similar to nsDisplayEventReceiver in that it is used for hit-testing. However
  * this gets built when we're doing widget painting and we need to send the
  * compositor some hit-test info for a frame. This is effectively a dummy item
  * whose sole purpose is to carry the hit-test info to the compositor.
  */
 class nsDisplayCompositorHitTestInfo : public nsDisplayEventReceiver {
 public:
   nsDisplayCompositorHitTestInfo(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-                                 mozilla::gfx::CompositorHitTestInfo aHitTestInfo)
-    : nsDisplayEventReceiver(aBuilder, aFrame)
-    , mHitTestInfo(aHitTestInfo)
-  {
-    MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
-    // We should never even create this display item if we're not building
-    // compositor hit-test info or if the computed hit info indicated the
-    // frame is invisible to hit-testing
-    MOZ_ASSERT(aBuilder->BuildCompositorHitTestInfo());
-    MOZ_ASSERT(mHitTestInfo != mozilla::gfx::CompositorHitTestInfo::eInvisibleToHitTest);
-  }
+                                 mozilla::gfx::CompositorHitTestInfo aHitTestInfo);
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayCompositorHitTestInfo()
   {
     MOZ_COUNT_DTOR(nsDisplayCompositorHitTestInfo);
   }
 #endif
 
@@ -4370,16 +4360,17 @@ public:
                                mozilla::layers::WebRenderLayerManager* aManager,
                                nsDisplayListBuilder* aDisplayListBuilder) override;
   void WriteDebugInfo(std::stringstream& aStream) override;
 
   NS_DISPLAY_DECL_NAME("CompositorHitTestInfo", TYPE_COMPOSITOR_HITTEST_INFO)
 
 private:
   mozilla::gfx::CompositorHitTestInfo mHitTestInfo;
+  mozilla::Maybe<mozilla::layers::FrameMetrics::ViewID> mScrollTarget;
 };
 
 /**
  * A display item that tracks event-sensitive regions which will be set
  * on the ContainerLayer that eventually contains this item.
  *
  * One of these is created for each stacking context and pseudo-stacking-context.
  * It accumulates regions for event targets contributed by the border-boxes of
@@ -5151,16 +5142,18 @@ public:
     return false;
   }
 
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override
   {
     return false;
   }
 
+  void WriteDebugInfo(std::stringstream& aStream) override;
+
   nsDisplayOwnLayerFlags GetFlags() { return mFlags; }
   bool IsScrollThumbLayer() const;
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
 protected:
   nsDisplayOwnLayerFlags mFlags;
   ViewID mScrollTarget;
   // If this nsDisplayOwnLayer represents a scroll thumb layer, mThumbData
   // stores information about the scroll thumb. Otherwise, mThumbData will be