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:
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());
}();