tor-browser

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

commit 11c894dcc1a23fb27edbb33f376f12d931e138a5
parent d552295c5c50937950dfd87d3b4f6279680526d0
Author: Botond Ballo <botond@mozilla.com>
Date:   Tue, 25 Nov 2025 02:48:11 +0000

Bug 2000753 - Ensure the sticky spatial node is created by the time WebRender display list building enters a sticky display item. r=mstange

The patch also relaxes assumptions made in ClipManager::SwitchItem
about an item's ASR chain, and its clip's ASR chain, overlapping,
as this was also observed not to hold in the fuzzer's testcase.

Differential Revision: https://phabricator.services.mozilla.com/D273732

Diffstat:
Mgfx/layers/wr/ClipManager.cpp | 36++++++++++++++++++++++--------------
Alayout/base/crashtests/2000753.html | 25+++++++++++++++++++++++++
Mlayout/base/crashtests/crashtests.list | 1+
3 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/gfx/layers/wr/ClipManager.cpp b/gfx/layers/wr/ClipManager.cpp @@ -191,6 +191,7 @@ wr::WrSpaceAndClipChain ClipManager::SwitchItem(nsDisplayListBuilder* aBuilder, } const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot(); DisplayItemType type = aItem->GetType(); + const ActiveScrolledRoot* stickyAsr = nullptr; if (type == DisplayItemType::TYPE_STICKY_POSITION) { // For sticky position items, the ASR is computed differently depending on // whether the item has a fixed descendant or not. But for WebRender @@ -199,6 +200,8 @@ wr::WrSpaceAndClipChain ClipManager::SwitchItem(nsDisplayListBuilder* aBuilder, // the sticky item. auto* sticky = static_cast<nsDisplayStickyPosition*>(aItem); asr = sticky->GetContainerASR(); + stickyAsr = ActiveScrolledRoot::GetStickyASRFromFrame(sticky->Frame()); + MOZ_ASSERT(stickyAsr); } CLIP_LOG("processing item %p (%s) asr %p clip %p, inherited = %p\n", aItem, @@ -250,20 +253,25 @@ wr::WrSpaceAndClipChain ClipManager::SwitchItem(nsDisplayListBuilder* aBuilder, clip = clip->mParent; } - // There are two ASR chains here that we need to be fully defined. One is the - // ASR chain pointed to by |asr|. The other is the - // ASR chain pointed to by clip->mASR. We pick the leafmost - // of these two chains because that one will include the other. Calling - // DefineSpatialNodes with this leafmost ASR will recursively define all the - // ASRs that we care about for this item, but will not actually push - // anything onto the WR stack. - const ActiveScrolledRoot* leafmostASR = asr; - if (clip) { - leafmostASR = ActiveScrolledRoot::PickDescendant(leafmostASR, clip->mASR); - } - Maybe<wr::WrSpatialId> leafmostId = - DefineSpatialNodes(aBuilder, leafmostASR, aItem); - (void)leafmostId; + // There are up to three ASR chains here that we need to be fully defined: + // 1. The ASR chain pointed to by |asr| + // 2. The ASR chain pointed to by clip->mASR + // 3. For a sticky item, the ASR chain pointed to by the item's sticky ASR. + // This one is needed so that when we create WebRender commands for the + // sticky item, we can give WebRender accurate information about the + // spatial node we're in. + // These chains will often be the same, or one will include the other, + // but we can't rely on that always being the case, so we make a + // DefineSpatialNodes call on all three. These calls will recursively + // define all the ASRs that we care about for this item, but will not + // actually push anything onto the WR stack. + (void)DefineSpatialNodes(aBuilder, asr, aItem); + if (clip && clip->mASR != asr) { + (void)DefineSpatialNodes(aBuilder, clip->mASR, aItem); + } + if (stickyAsr && stickyAsr != asr) { + (void)DefineSpatialNodes(aBuilder, stickyAsr, aItem); + } // Define all the clips in the item's clip chain, and obtain a clip chain id // for it. diff --git a/layout/base/crashtests/2000753.html b/layout/base/crashtests/2000753.html @@ -0,0 +1,25 @@ +<html> + <head> + <meta http-equiv="content-type" content="text/html; charset=windows-1252"> + <style> + #a { + position: sticky; + clip-path: polygon(93% 0%, 0.46em 0%, 9px 18446744073709551615px, 0em 35%); + } + #b { + position: sticky; + clip-path: polygon(93% 0%, 0.46em 0%, 9px 18446744073709551615px, 0em 35%); + } + #c { + position: sticky; + } + </style> + </head> + <body> + <time id="a"> + <time id="b"> + <img id="c" srcset="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAIAAABt+uBvAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wDGhYvCNVA1EIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAjklEQVR42u3QIQEAMAgAsHNNVspTgARY1BZh0ZWP3VcgSJAgQYIECRKEIEGCBAkSJEgQggQJEiRIkCBBCBIkSJAgQYIECUKQIEGCBAkSJAhBggQJEiRIkCAECRIkSJAgQYIEIUiQIEGCBAkShCBBggQJEiRIEIIECRIkSJAgQYIQJEiQIEGCBAlCkCBBdwaeugIthHvZ+AAAAABJRU5ErkJggg== 1x" align="right"> + </time> + </time> + </body> +</html> diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list @@ -568,4 +568,5 @@ load 1929445.html asserts(1-3) load 1931933.html load 1984507.html load 2000121.html +skip-if(debug) load 2000753.html load 2000991.html