tor-browser

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

commit 537725a5c4aaa5e36df125f308024c54b1eb6fda
parent c709185f845a52a167ac5691f7d90ee95e6583bb
Author: Timothy Nikkel <tnikkel@gmail.com>
Date:   Wed, 26 Nov 2025 13:04:51 +0000

Bug 1988030. Adjust nsLayoutUtils::GetAsyncScrollableAncestorFrame to be CSS anchor pos aware. r=layout-reviewers,layout-anchor-positioning-reviewers,hiro,emilio

We want to assign the ASR of the anchor to the anchored content. That means we are changing the ASR chain so we need to adjust the functions that walk the async scrollable ancestors chain. In this patch we adjust nsLayoutUtils::GetAsyncScrollableAncestorFrame.

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

Diffstat:
Mlayout/base/AnchorPositioningUtils.cpp | 19+++++++++++++++++++
Mlayout/base/AnchorPositioningUtils.h | 6++++++
Mlayout/base/nsLayoutUtils.cpp | 24++++++++++++++++++++++++
3 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/layout/base/AnchorPositioningUtils.cpp b/layout/base/AnchorPositioningUtils.cpp @@ -874,4 +874,23 @@ bool AnchorPositioningUtils::FitsInContainingBlock( .Contains(rect); } +nsIFrame* AnchorPositioningUtils::GetAnchorThatFrameScrollsWith( + nsIFrame* aFrame) { + mozilla::PhysicalAxes axes = aFrame->GetAnchorPosCompensatingForScroll(); + // TODO for now we return the anchor if we are compensating in either axis. + // This is not fully spec compliant, bug 1988034 tracks this. + if (axes.isEmpty()) { + return nullptr; + } + + const auto* pos = aFrame->StylePosition(); + if (!pos->mPositionAnchor.IsIdent()) { + return nullptr; + } + + const nsAtom* defaultAnchorName = pos->mPositionAnchor.AsIdent().AsAtom(); + return const_cast<nsIFrame*>( + aFrame->PresShell()->GetAnchorPosAnchor(defaultAnchorName, aFrame)); +} + } // namespace mozilla diff --git a/layout/base/AnchorPositioningUtils.h b/layout/base/AnchorPositioningUtils.h @@ -309,6 +309,12 @@ struct AnchorPositioningUtils { const ContainingBlockInfo& aContainingBlockInfo, const nsIFrame* aPositioned, const AnchorPosReferenceData* aReferenceData); + + /** + * If aFrame is positioned using CSS anchor positioning, and it scrolls with + * its anchor this function returns the anchor. Otherwise null. + */ + static nsIFrame* GetAnchorThatFrameScrollsWith(nsIFrame* aFrame); }; } // namespace mozilla diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp @@ -10,6 +10,7 @@ #include <limits> #include "ActiveLayerTracker.h" +#include "AnchorPositioningUtils.h" #include "DisplayItemClip.h" #include "ImageContainer.h" #include "ImageOps.h" @@ -1362,6 +1363,29 @@ static nsIFrame* GetNearestScrollableOrOverflowClipFrame( } } } + + nsIFrame* anchor = nullptr; + // If the current frame also happens to be fixed then we want to check if it + // scrolls with its anchor before the special fixed behaviour below because + // scrolling with its anchor overrides that behaviour and is higher + // priority. + + // This needs to be a while loop because anchors can chain, and we don't + // want to consider each frame in this loop separately (as a potential + // scrollable ancestor) because they are all equivalent in the scrollable + // ancestor chain: they all scroll together. We are not walking up the async + // scrollable ancestor chain, but rather we are move sideways. And when we + // exit this loop we want to move up one because we haven't yet ascended + // (because of that same reason), and that moving up one will happen either + // via the special fixed pos behaviour below or the next iteration of the + // outer for loop. + if (aFlags & nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE) { + while ( + (anchor = AnchorPositioningUtils::GetAnchorThatFrameScrollsWith(f))) { + f = anchor; + } + } + if ((aFlags & nsLayoutUtils::SCROLLABLE_FIXEDPOS_FINDS_ROOT) && f->StyleDisplay()->mPosition == StylePositionProperty::Fixed && nsLayoutUtils::IsReallyFixedPos(f)) {