Bug 1418387 - Add CompositorHitTestInfo bits for scrollbars. r?mstange
MozReview-Commit-ID: KTfpXoESOxF
--- 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