tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Agfx/layers/apz/test/mochitest/helper_hittest_bug1916028.html | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Mgfx/layers/apz/test/mochitest/test_group_hittest-3.html | 3++-
Mlayout/generic/ScrollContainerFrame.cpp | 11+++++++----
Mlayout/generic/nsIFrame.cpp | 21+++++++++++++++------
Mlayout/generic/nsIFrame.h | 9+++++++++
Mlayout/painting/nsDisplayList.h | 5+++--
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; }