tor-browser

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

commit d92b01bce062eb01a32599393d62fc625652f725
parent cfcfba76dec6d8785a9d50903d3f0d95d2aea206
Author: David Shin <dshin@mozilla.com>
Date:   Fri,  7 Nov 2025 17:57:07 +0000

Bug 1996832: Check margin rect of abspos frame for overflowing. r=layout-anchor-positioning-reviewers,layout-reviewers,emilio

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

Diffstat:
Mlayout/base/AnchorPositioningUtils.cpp | 38+++++++++++++++++++++++++++++++++-----
Mlayout/base/AnchorPositioningUtils.h | 22+++++++++++++++++++---
Mlayout/base/PresShell.cpp | 11+++++------
Mlayout/generic/AbsoluteContainingBlock.cpp | 5+++--
4 files changed, 60 insertions(+), 16 deletions(-)

diff --git a/layout/base/AnchorPositioningUtils.cpp b/layout/base/AnchorPositioningUtils.cpp @@ -822,12 +822,40 @@ const nsIFrame* AnchorPositioningUtils::GetAnchorPosImplicitAnchor( : pseudoRootFrame->GetParent(); } +AnchorPositioningUtils::ContainingBlockInfo +AnchorPositioningUtils::ContainingBlockInfo::ExplicitCBFrameSize( + const nsRect& aContainingBlockRect) { + // TODO(dshin, bug 1989292): Ideally, this takes both local containing rect + + // scrollable containing rect, and one is picked here. + return ContainingBlockInfo{aContainingBlockRect}; +} + +AnchorPositioningUtils::ContainingBlockInfo +AnchorPositioningUtils::ContainingBlockInfo::UseCBFrameSize( + const nsIFrame* aPositioned) { + // TODO(dshin, bug 1989292): This just gets local containing block. + const auto* cb = aPositioned->GetParent(); + MOZ_ASSERT(cb); + if (cb->Style()->GetPseudoType() == PseudoStyleType::scrolledContent) { + cb = aPositioned->GetParent(); + } + return ContainingBlockInfo{cb->GetPaddingRectRelativeToSelf()}; +} + bool AnchorPositioningUtils::FitsInContainingBlock( - const nsRect& aOverflowCheckRect, - const nsRect& aOriginalContainingBlockSize, const nsRect& aRect) { - return aOverflowCheckRect.Intersect(aOriginalContainingBlockSize) - .Union(aOriginalContainingBlockSize) - .Contains(aRect); + const ContainingBlockInfo& aContainingBlockInfo, + const nsIFrame* aPositioned, const AnchorPosReferenceData* aReferenceData) { + MOZ_ASSERT(aPositioned->GetProperty(nsIFrame::AnchorPosReferences()) == + aReferenceData); + const auto originalContainingBlockRect = + aContainingBlockInfo.GetContainingBlockRect(); + const auto overflowCheckRect = aReferenceData->mContainingBlockRect - + aReferenceData->mDefaultScrollShift; + const auto rect = aPositioned->GetMarginRect(); + + return overflowCheckRect.Intersect(originalContainingBlockRect) + .Union(originalContainingBlockRect) + .Contains(rect); } } // namespace mozilla diff --git a/layout/base/AnchorPositioningUtils.h b/layout/base/AnchorPositioningUtils.h @@ -291,9 +291,25 @@ struct AnchorPositioningUtils { PhysicalAxes aAxes, const nsIFrame* aPositioned, const AnchorPosDefaultAnchorCache& aDefaultAnchorCache); - static bool FitsInContainingBlock(const nsRect& aOverflowCheckRect, - const nsRect& aOriginalContainingBlockSize, - const nsRect& aRect); + struct ContainingBlockInfo { + // Provide an explicit containing block size, for during reflow when + // its `mRect` has not yet been set. + static ContainingBlockInfo ExplicitCBFrameSize( + const nsRect& aContainingBlockRect); + // Provide the positioned frame, to query its containing block rect. + static ContainingBlockInfo UseCBFrameSize(const nsIFrame* aPositioned); + + nsRect GetContainingBlockRect() const { return mRect; } + + private: + explicit ContainingBlockInfo(const nsRect& aRect) : mRect{aRect} {} + nsRect mRect; + }; + + static bool FitsInContainingBlock( + const ContainingBlockInfo& aContainingBlockInfo, + const nsIFrame* aPositioned, + const AnchorPosReferenceData* aReferenceData); }; } // namespace mozilla diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp @@ -11901,7 +11901,7 @@ static Maybe<FindScrollCompensatedAnchorResult> FindScrollCompensatedAnchor( return Nothing{}; } -static bool CheckOverflow(nsIFrame* aPositioned, const nsPoint& aOffset, +static bool CheckOverflow(nsIFrame* aPositioned, const AnchorPosReferenceData& aData) { const auto* stylePos = aPositioned->StylePosition(); const auto hasFallbacks = !stylePos->mPositionTryFallbacks._0.IsEmpty(); @@ -11910,11 +11910,10 @@ static bool CheckOverflow(nsIFrame* aPositioned, const nsPoint& aOffset, if (!hasFallbacks && !visibilityDependsOnOverflow) { return false; } - const auto* cb = aPositioned->GetParent(); - MOZ_ASSERT(cb); const auto overflows = !AnchorPositioningUtils::FitsInContainingBlock( - aData.mContainingBlockRect - aOffset, cb->GetPaddingRect(), - aPositioned->GetRect()); + AnchorPositioningUtils::ContainingBlockInfo{ + static_cast<const nsIFrame*>(aPositioned->GetParent())}, + aPositioned, &aData); aPositioned->AddOrRemoveStateBits(NS_FRAME_POSITION_VISIBILITY_HIDDEN, visibilityDependsOnOverflow && overflows); return hasFallbacks && overflows; @@ -11958,7 +11957,7 @@ void PresShell::UpdateAnchorPosForScroll( nsContainerFrame::PlaceFrameView(positioned); positioned->GetParent()->UpdateOverflow(); referenceData.mDefaultScrollShift = offset; - if (CheckOverflow(positioned, offset, referenceData)) { + if (CheckOverflow(positioned, referenceData)) { #ifdef ACCESSIBILITY if (nsAccessibilityService* accService = GetAccService()) { accService->NotifyAnchorPositionedScrollUpdate(this, positioned); diff --git a/layout/generic/AbsoluteContainingBlock.cpp b/layout/generic/AbsoluteContainingBlock.cpp @@ -1439,8 +1439,9 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( aAnchorPosResolutionCache->mReferenceData->mContainingBlockRect = overflowCheckRect; return AnchorPositioningUtils::FitsInContainingBlock( - overflowCheckRect, aOriginalContainingBlockRect, - aKidFrame->GetRect()); + AnchorPositioningUtils::ContainingBlockInfo::ExplicitCBFrameSize( + aOriginalContainingBlockRect), + aKidFrame, aAnchorPosResolutionCache->mReferenceData); } return overflowCheckRect.Contains(aKidFrame->GetRect()); }();