tor-browser

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

commit 022385323b3fa5c63ef015a5cf9dbb94063e3a83
parent c85f102c6f7713484396721c12b3afc215de097f
Author: David Shin <dshin@mozilla.com>
Date:   Fri,  7 Nov 2025 17:57:08 +0000

Bug 1996832: Take abs-cb being scrolled into account when testing abspos frame overflowing. r=layout-anchor-positioning-reviewers,layout-reviewers,emilio

Abspos frames are positioned against the scrolled frame, which is moved as a
whole to achieve scrolling. Not considering this offset will cause the
overflow check to behave as if the abspos frame never moves.

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

Diffstat:
Mlayout/base/AnchorPositioningUtils.cpp | 11++++++++++-
Mlayout/base/PresShell.cpp | 55+++++++++++++++++++++++++++++--------------------------
2 files changed, 39 insertions(+), 27 deletions(-)

diff --git a/layout/base/AnchorPositioningUtils.cpp b/layout/base/AnchorPositioningUtils.cpp @@ -851,7 +851,16 @@ bool AnchorPositioningUtils::FitsInContainingBlock( aContainingBlockInfo.GetContainingBlockRect(); const auto overflowCheckRect = aReferenceData->mContainingBlockRect - aReferenceData->mDefaultScrollShift; - const auto rect = aPositioned->GetMarginRect(); + const auto rect = [&]() { + auto rect = aPositioned->GetMarginRect(); + const auto* cb = aPositioned->GetParent(); + if (cb->Style()->GetPseudoType() != PseudoStyleType::scrolledContent) { + return rect; + } + const ScrollContainerFrame* scrollContainer = + do_QueryFrame(cb->GetParent()); + return rect - scrollContainer->GetScrollPosition(); + }(); return overflowCheckRect.Intersect(originalContainingBlockRect) .Union(originalContainingBlockRect) diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp @@ -11831,31 +11831,23 @@ static nsTArray<AffectedAnchorGroup> FindAnchorsAffectedByScroll( return affectedAnchors; } -struct FindScrollCompensatedAnchorResult { - const AffectedAnchor& mAnchorInfo; - AnchorPosReferenceData& mReferenceData; -}; - // Given a list of anchors affected by scrolling, find one that the given // positioned frame need to compensate scroll for. -static Maybe<FindScrollCompensatedAnchorResult> FindScrollCompensatedAnchor( +static Maybe<const AffectedAnchor&> FindScrollCompensatedAnchor( const PresShell* aPresShell, const nsTArray<AffectedAnchorGroup>& aAffectedAnchors, - const nsIFrame* aPositioned) { + const nsIFrame* aPositioned, const AnchorPosReferenceData& aReferenceData) { MOZ_ASSERT(aPositioned->IsAbsolutelyPositioned(), "Anchor positioned frame is not absolutely positioned?"); - auto* referencedAnchors = - aPositioned->GetProperty(nsIFrame::AnchorPosReferences()); - if (!referencedAnchors || referencedAnchors->IsEmpty()) { + if (aReferenceData.IsEmpty()) { return Nothing{}; } - if (!referencedAnchors->mDefaultAnchorName) { + if (!aReferenceData.mDefaultAnchorName) { return Nothing{}; } - const auto compensatingForScroll = - referencedAnchors->CompensatingForScrollAxes(); + const auto compensatingForScroll = aReferenceData.CompensatingForScrollAxes(); if (compensatingForScroll.isEmpty()) { return Nothing{}; } @@ -11895,7 +11887,7 @@ static Maybe<FindScrollCompensatedAnchorResult> FindScrollCompensatedAnchor( break; } const auto& info = anchors.ElementAt(idx); - return Some(FindScrollCompensatedAnchorResult{info, *referencedAnchors}); + return SomeRef(info); } return Nothing{}; @@ -11911,8 +11903,7 @@ static bool CheckOverflow(nsIFrame* aPositioned, return false; } const auto overflows = !AnchorPositioningUtils::FitsInContainingBlock( - AnchorPositioningUtils::ContainingBlockInfo{ - static_cast<const nsIFrame*>(aPositioned->GetParent())}, + AnchorPositioningUtils::ContainingBlockInfo::UseCBFrameSize(aPositioned), aPositioned, &aData); aPositioned->AddOrRemoveStateBits(NS_FRAME_POSITION_VISIBILITY_HIDDEN, visibilityDependsOnOverflow && overflows); @@ -11940,24 +11931,36 @@ void PresShell::UpdateAnchorPosForScroll( // Now, update all affected positioned elements' scroll offsets. for (auto* positioned : mAnchorPosPositioned) { - const auto scrollDependency = - FindScrollCompensatedAnchor(this, affectedAnchors, positioned); - if (!scrollDependency) { + auto* referenceData = + positioned->GetProperty(nsIFrame::AnchorPosReferences()); + if (!referenceData) { continue; } - const auto& info = scrollDependency->mAnchorInfo; - auto& referenceData = scrollDependency->mReferenceData; - const auto offset = AnchorPositioningUtils::GetScrollOffsetFor( - referenceData.CompensatingForScrollAxes(), positioned, info); - if (referenceData.mDefaultScrollShift != offset) { + const auto scrollDependency = FindScrollCompensatedAnchor( + this, affectedAnchors, positioned, *referenceData); + const bool offsetChanged = [&]() { + if (!scrollDependency) { + return false; + } + const auto offset = AnchorPositioningUtils::GetScrollOffsetFor( + referenceData->CompensatingForScrollAxes(), positioned, + *scrollDependency); + if (referenceData->mDefaultScrollShift == offset) { + return false; + } positioned->SetPosition(positioned->GetNormalPosition() - offset); // Update positioned frame's overflow, then the absolute containing // block's. positioned->UpdateOverflow(); nsContainerFrame::PlaceFrameView(positioned); positioned->GetParent()->UpdateOverflow(); - referenceData.mDefaultScrollShift = offset; - if (CheckOverflow(positioned, referenceData)) { + referenceData->mDefaultScrollShift = offset; + return true; + }(); + const bool cbScrolls = + positioned->GetParent() == aScrollContainer->GetScrolledFrame(); + if (offsetChanged || cbScrolls) { + if (CheckOverflow(positioned, *referenceData)) { #ifdef ACCESSIBILITY if (nsAccessibilityService* accService = GetAccService()) { accService->NotifyAnchorPositionedScrollUpdate(this, positioned);