Bug 1418397 - Add dispatch-to-content hit info to WR hit-test for inactive scrollframes. r?mstange
MozReview-Commit-ID: F6HgYPRc9Bi
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3626,29 +3626,33 @@ ScrollFrameHelper::BuildDisplayList(nsDi
if (mWillBuildScrollableLayer && aBuilder->IsPaintingToWindow()) {
aBuilder->ForceLayerForScrollParent();
}
if (couldBuildLayer) {
// Make sure that APZ will dispatch events back to content so we can create
// a displayport for this frame. We'll add the item later on.
- nsDisplayLayerEventRegions* inactiveRegionItem = nullptr;
- if (aBuilder->IsPaintingToWindow() &&
- !mWillBuildScrollableLayer &&
- aBuilder->IsBuildingLayerEventRegions())
- {
- inactiveRegionItem = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, mScrolledFrame, 1);
- inactiveRegionItem->AddInactiveScrollPort(mScrolledFrame, mScrollPort + aBuilder->ToReferenceFrame(mOuter));
- }
-
- if (inactiveRegionItem) {
+ if (!mWillBuildScrollableLayer) {
int32_t zIndex =
MaxZIndexInListOfItemsContainedInFrame(scrolledContent.PositionedDescendants(), mOuter);
- AppendInternalItemToTop(scrolledContent, inactiveRegionItem, zIndex);
+ if (aBuilder->BuildCompositorHitTestInfo()) {
+ CompositorHitTestInfo info = CompositorHitTestInfo::eVisibleToHitTest
+ | CompositorHitTestInfo::eDispatchToContent;
+ nsDisplayCompositorHitTestInfo* hitInfo =
+ new (aBuilder) nsDisplayCompositorHitTestInfo(aBuilder, mScrolledFrame, info, 1);
+ hitInfo->SetArea(mScrollPort + aBuilder->ToReferenceFrame(mOuter));
+ AppendInternalItemToTop(scrolledContent, hitInfo, zIndex);
+ }
+ if (aBuilder->IsBuildingLayerEventRegions()) {
+ nsDisplayLayerEventRegions* inactiveRegionItem =
+ new (aBuilder) nsDisplayLayerEventRegions(aBuilder, mScrolledFrame, 1);
+ inactiveRegionItem->AddInactiveScrollPort(mScrolledFrame, mScrollPort + aBuilder->ToReferenceFrame(mOuter));
+ AppendInternalItemToTop(scrolledContent, inactiveRegionItem, zIndex);
+ }
}
if (aBuilder->ShouldBuildScrollInfoItemsForHoisting()) {
aBuilder->AppendNewScrollInfoItemForHoisting(
new (aBuilder) nsDisplayScrollInfoLayer(aBuilder, mScrolledFrame,
mOuter));
}
}
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4865,62 +4865,75 @@ nsDisplayEventReceiver::CreateWebRenderC
// 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)
+ mozilla::gfx::CompositorHitTestInfo aHitTestInfo,
+ uint32_t aIndex)
: nsDisplayEventReceiver(aBuilder, aFrame)
, mHitTestInfo(aHitTestInfo)
+ , mIndex(aIndex)
{
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());
}
}
+void
+nsDisplayCompositorHitTestInfo::SetArea(const nsRect& aArea)
+{
+ mArea = Some(aArea);
+}
+
bool
nsDisplayCompositorHitTestInfo::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder)
{
- nsRect borderBox;
- nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(mFrame);
- if (scrollFrame) {
- // If the frame is content of a scrollframe, then we need to pick up the
- // area corresponding to the overflow rect as well. Otherwise the parts of
- // the overflow that are not occupied by descendants get skipped and the
- // APZ code sends touch events to the content underneath instead.
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=1127773#c15.
- borderBox = mFrame->GetScrollableOverflowRect();
- } else {
- borderBox = nsRect(nsPoint(0, 0), mFrame->GetSize());
- }
-
- if (borderBox.IsEmpty()) {
- return true;
- }
-
+ if (mArea.isNothing()) {
+ nsRect borderBox;
+ nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(mFrame);
+ if (scrollFrame) {
+ // If the frame is content of a scrollframe, then we need to pick up the
+ // area corresponding to the overflow rect as well. Otherwise the parts of
+ // the overflow that are not occupied by descendants get skipped and the
+ // APZ code sends touch events to the content underneath instead.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1127773#c15.
+ borderBox = mFrame->GetScrollableOverflowRect();
+ } else {
+ borderBox = nsRect(nsPoint(0, 0), mFrame->GetSize());
+ }
+
+ if (borderBox.IsEmpty()) {
+ return true;
+ }
+
+ mArea = Some(borderBox + aDisplayListBuilder->ToReferenceFrame(mFrame));
+ }
+
+ MOZ_ASSERT(mArea.isSome());
wr::LayoutRect rect = aSc.ToRelativeLayoutRect(
LayoutDeviceRect::FromAppUnits(
- borderBox + aDisplayListBuilder->ToReferenceFrame(mFrame),
+ *mArea,
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 = mScrollTarget.valueOrFrom(
@@ -4940,16 +4953,34 @@ nsDisplayCompositorHitTestInfo::CreateWe
}
void
nsDisplayCompositorHitTestInfo::WriteDebugInfo(std::stringstream& aStream)
{
aStream << nsPrintfCString(" (hitTestInfo 0x%x)", (int)mHitTestInfo).get();
}
+uint32_t
+nsDisplayCompositorHitTestInfo::GetPerFrameKey() const
+{
+ return (mIndex << TYPE_BITS) | nsDisplayItem::GetPerFrameKey();
+}
+
+int32_t
+nsDisplayCompositorHitTestInfo::ZIndex() const
+{
+ return mOverrideZIndex ? *mOverrideZIndex : nsDisplayItem::ZIndex();
+}
+
+void
+nsDisplayCompositorHitTestInfo::SetOverrideZIndex(int32_t aZIndex)
+{
+ mOverrideZIndex = Some(aZIndex);
+}
+
void
nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame)
{
NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame),
"Reference frame mismatch");
CompositorHitTestInfo hitInfo =
aFrame->GetCompositorHitTestInfo(aBuilder);
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -4338,39 +4338,47 @@ 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);
+ mozilla::gfx::CompositorHitTestInfo aHitTestInfo,
+ uint32_t aIndex = 0);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayCompositorHitTestInfo()
{
MOZ_COUNT_DTOR(nsDisplayCompositorHitTestInfo);
}
#endif
mozilla::gfx::CompositorHitTestInfo HitTestInfo() const { return mHitTestInfo; }
+ void SetArea(const nsRect& aArea);
bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override;
void WriteDebugInfo(std::stringstream& aStream) override;
+ uint32_t GetPerFrameKey() const override;
+ int32_t ZIndex() const override;
+ void SetOverrideZIndex(int32_t aZIndex);
NS_DISPLAY_DECL_NAME("CompositorHitTestInfo", TYPE_COMPOSITOR_HITTEST_INFO)
private:
mozilla::gfx::CompositorHitTestInfo mHitTestInfo;
mozilla::Maybe<mozilla::layers::FrameMetrics::ViewID> mScrollTarget;
+ mozilla::Maybe<nsRect> mArea;
+ uint32_t mIndex;
+ mozilla::Maybe<int32_t> mOverrideZIndex;
};
/**
* 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