commit 7f33a0cc184f6372c66281499063bda0f42f9c83
parent 0d058aecce6ee7d22144d2f67b0e8c66ebb02103
Author: Hiroyuki Ikezoe <hikezoe.birchill@mozilla.com>
Date: Thu, 6 Nov 2025 23:03:27 +0000
Bug 1916028 - Do not propagate ancestor's pointer-events property in nsDisplayBuilder::mCompositorHitTestInfo. r=tnikkel
Rather check pointer-events proeprty in nsIFrame::GetCompositorHitTestInfo
because pointer-events property is inherited but `pointer-events: auto` cancels
out the inherited `pointer-events: none`.
Differential Revision: https://phabricator.services.mozilla.com/D226999
Diffstat:
6 files changed, 87 insertions(+), 13 deletions(-)
diff --git a/gfx/layers/apz/test/mochitest/helper_hittest_bug1916028.html b/gfx/layers/apz/test/mochitest/helper_hittest_bug1916028.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Hit-testing on a `pointer-events: auto` element in a `pointer-events: none` ancestor</title>
+ <script type="application/javascript" src="apz_test_utils.js"></script>
+ <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <meta name="viewport" content="width=device-width"/>
+<style>
+body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ touch-action: none;
+ pointer-events: none;
+}
+div {
+ font-size: 40px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100vw;
+ height: 100vh;
+}
+</style>
+</head>
+<body>
+<div style="pointer-events: auto;"></div>
+<script type="application/javascript">
+
+async function test() {
+ const config = getHitTestConfig();
+ const utils = config.utils;
+
+ checkHitResult(hitTest(centerOf(document.body)),
+ APZHitResultFlags.VISIBLE |
+ APZHitResultFlags.PAN_X_DISABLED |
+ APZHitResultFlags.PAN_Y_DISABLED |
+ APZHitResultFlags.PINCH_ZOOM_DISABLED |
+ APZHitResultFlags.DOUBLE_TAP_ZOOM_DISABLED,
+ utils.getViewId(document.scrollingElement),
+ utils.getLayersId(),
+ "pointer-events: auto");
+}
+
+waitUntilApzStable()
+.then(test)
+.then(subtestDone, subtestFailed);
+
+</script>
+</html>
diff --git a/gfx/layers/apz/test/mochitest/test_group_hittest-3.html b/gfx/layers/apz/test/mochitest/test_group_hittest-3.html
@@ -35,7 +35,8 @@ var subtests = [
{file: "helper_hittest_iframe_perspective-3.html", prefs},
{file: "helper_hittest_iframe_perspective-4.html", prefs},
{file: "helper_hittest_iframe_opacity_zero.html", prefs},
- {file: "helper_hittest_svgfilter_bug1934434.html", prefs}
+ {file: "helper_hittest_svgfilter_bug1934434.html", prefs},
+ {file: "helper_hittest_bug1916028.html", prefs},
];
if (isApzEnabled()) {
diff --git a/layout/generic/ScrollContainerFrame.cpp b/layout/generic/ScrollContainerFrame.cpp
@@ -4012,14 +4012,17 @@ void ScrollContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// of the scroll frame, the scrolled content is always hit, even
// if we are checkerboarding.
CompositorHitTestInfo info =
- mScrolledFrame->GetCompositorHitTestInfo(aBuilder);
+ mScrolledFrame->GetCompositorHitTestInfoWithoutPointerEvents(
+ aBuilder);
- if (info != CompositorHitTestInvisibleToHit) {
+ if (mScrolledFrame->Style()->PointerEvents() !=
+ StylePointerEvents::None &&
+ info != CompositorHitTestInvisibleToHit) {
auto* hitInfo =
MakeDisplayItemWithIndex<nsDisplayCompositorHitTestInfo>(
aBuilder, mScrolledFrame, 1);
if (hitInfo) {
- aBuilder->SetCompositorHitTestInfo(info);
+ aBuilder->SetInheritedCompositorHitTestInfo(info);
set.BorderBackground()->AppendToTop(hitInfo);
}
}
@@ -4211,7 +4214,7 @@ void ScrollContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder, mScrolledFrame, 1, area, info);
if (hitInfo) {
AppendInternalItemToTop(set, hitInfo, Some(zIndex));
- aBuilder->SetCompositorHitTestInfo(info);
+ aBuilder->SetInheritedCompositorHitTestInfo(info);
}
}
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
@@ -2910,8 +2910,9 @@ static void UpdateCurrentHitTestInfo(nsDisplayListBuilder* aBuilder,
CheckForApzAwareEventHandlers(aBuilder, aFrame);
- const CompositorHitTestInfo info = aFrame->GetCompositorHitTestInfo(aBuilder);
- aBuilder->SetCompositorHitTestInfo(info);
+ const CompositorHitTestInfo info =
+ aFrame->GetCompositorHitTestInfoWithoutPointerEvents(aBuilder);
+ aBuilder->SetInheritedCompositorHitTestInfo(info);
}
/**
@@ -12022,6 +12023,16 @@ nsRect nsIFrame::GetCompositorHitTestArea(nsDisplayListBuilder* aBuilder) {
CompositorHitTestInfo nsIFrame::GetCompositorHitTestInfo(
nsDisplayListBuilder* aBuilder) {
CompositorHitTestInfo result = CompositorHitTestInvisibleToHit;
+ if (Style()->PointerEvents() == StylePointerEvents::None) {
+ return result;
+ }
+ return GetCompositorHitTestInfoWithoutPointerEvents(aBuilder);
+}
+
+CompositorHitTestInfo nsIFrame::GetCompositorHitTestInfoWithoutPointerEvents(
+ nsDisplayListBuilder* aBuilder) {
+ CompositorHitTestInfo result = CompositorHitTestInvisibleToHit;
+
if (aBuilder->IsInsidePointerEventsNoneDoc() ||
aBuilder->IsInViewTransitionCapture()) {
// Somewhere up the parent document chain is a subdocument with pointer-
@@ -12034,9 +12045,6 @@ CompositorHitTestInfo nsIFrame::GetCompositorHitTestInfo(
// frames, are the event targets for any regions viewport frames may cover.
return result;
}
- if (Style()->PointerEvents() == StylePointerEvents::None) {
- return result;
- }
if (!StyleVisibility()->IsVisible()) {
return result;
}
@@ -12076,7 +12084,8 @@ CompositorHitTestInfo nsIFrame::GetCompositorHitTestInfo(
// that code, but woven into the top-down recursive display list building
// process.
CompositorHitTestInfo inheritedTouchAction =
- aBuilder->GetCompositorHitTestInfo() & CompositorHitTestTouchActionMask;
+ aBuilder->GetInheritedCompositorHitTestInfo() &
+ CompositorHitTestTouchActionMask;
nsIFrame* touchActionFrame = this;
if (ScrollContainerFrame* scrollContainerFrame =
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
@@ -5199,6 +5199,15 @@ class nsIFrame : public nsQueryFrame {
nsDisplayListBuilder* aBuilder);
/**
+ * Similar to GetCompositorHitTestInfo but this function doesn't consider
+ * pointer-events style.
+ * This function should be used only for
+ * nsDisplayBuilder::SetInheritedCompositorHitTestInfo.
+ */
+ mozilla::gfx::CompositorHitTestInfo
+ GetCompositorHitTestInfoWithoutPointerEvents(nsDisplayListBuilder* aBuilder);
+
+ /**
* Copies aWM to mWritingMode on 'this' and all its ancestors.
*/
inline void PropagateWritingModeToSelfAndAncestors(mozilla::WritingMode aWM);
diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h
@@ -619,11 +619,12 @@ class nsDisplayListBuilder {
mAllowMergingAndFlattening = aAllow;
}
- void SetCompositorHitTestInfo(const gfx::CompositorHitTestInfo& aInfo) {
+ void SetInheritedCompositorHitTestInfo(
+ const gfx::CompositorHitTestInfo& aInfo) {
mCompositorHitTestInfo = aInfo;
}
- const gfx::CompositorHitTestInfo& GetCompositorHitTestInfo() const {
+ const gfx::CompositorHitTestInfo& GetInheritedCompositorHitTestInfo() const {
return mCompositorHitTestInfo;
}