commit 1b61767689e5fbbe68d7f751d1950b542c4e2901
parent e68d92a91aac8905aae22bb4a5d66f551448a8e6
Author: David Shin <dshin@mozilla.com>
Date: Thu, 18 Dec 2025 22:12:11 +0000
Bug 2004596: Modify containing block with both grid and position-area. r=layout-anchor-positioning-reviewers,layout-reviewers,emilio
Current position-area computation is spec-complaint so that it can handle
anchors outside of its containing block, so we can simply feed the result
of the grid adjusted containing block.
Differential Revision: https://phabricator.services.mozilla.com/D277052
Diffstat:
2 files changed, 56 insertions(+), 48 deletions(-)
diff --git a/layout/generic/AbsoluteContainingBlock.cpp b/layout/generic/AbsoluteContainingBlock.cpp
@@ -1210,54 +1210,68 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
aAnchorPosResolutionCache,
firstTryIndex == currentFallbackIndex);
auto cb = [&]() {
- if (aAnchorPosResolutionCache) {
- const auto defaultAnchorInfo =
- AnchorPositioningUtils::ResolveAnchorPosRect(
- aKidFrame, aDelegatingFrame, nullptr, false,
- aAnchorPosResolutionCache);
- if (defaultAnchorInfo) {
- auto positionArea = aKidFrame->StylePosition()->mPositionArea;
- if (!positionArea.IsNone()) {
- // Offset should be up to, but not including the containing block's
- // scroll offset.
- const auto offset = AnchorPositioningUtils::GetScrollOffsetFor(
- aAnchorPosResolutionCache->mReferenceData
- ->CompensatingForScrollAxes(),
- aKidFrame, aAnchorPosResolutionCache->mDefaultAnchorCache);
- // Imagine an abspos container with a scroller in it, and then an
- // anchor in it, where the anchor is visually in the middle of the
- // scrollport. Then, when the scroller moves such that the anchor's
- // left edge is on that of the scrollports, w.r.t. containing block,
- // the anchor is zero left offset horizontally. The position-area
- // grid needs to account for this.
- const auto scrolledAnchorRect = defaultAnchorInfo->mRect - offset;
- StylePositionArea resolvedPositionArea{};
- const auto scrolledAnchorCb = AnchorPositioningUtils::
- AdjustAbsoluteContainingBlockRectForPositionArea(
- scrolledAnchorRect + aOriginalContainingBlockRect.TopLeft(),
- aOriginalScrollableContainingBlockRect,
- aKidFrame->GetWritingMode(),
- aDelegatingFrame->GetWritingMode(), positionArea,
- &resolvedPositionArea);
- return ContainingBlockRect{
- offset, resolvedPositionArea,
- aOriginalScrollableContainingBlockRect,
- // Unscroll the CB by canceling out the previously applied
- // scroll offset (See above), the offset will be applied later.
- scrolledAnchorCb + offset};
- }
- return ContainingBlockRect{aOriginalScrollableContainingBlockRect};
+ // The current containing block, with ongoing modifications.
+ // Starts as a local containing block.
+ nsRect containingBlock = aOriginalContainingBlockRect;
+ const auto defaultAnchorInfo = [&]() -> Maybe<AnchorPosInfo> {
+ if (!aAnchorPosResolutionCache) {
+ return Nothing{};
}
+ return AnchorPositioningUtils::ResolveAnchorPosRect(
+ aKidFrame, aDelegatingFrame, nullptr, false,
+ aAnchorPosResolutionCache);
+ }();
+ if (defaultAnchorInfo) {
+ // Presence of a valid default anchor causes us to use the scrollable
+ // containing block.
+ // https://github.com/w3c/csswg-drafts/issues/12552#issuecomment-3210696721
+ containingBlock = aOriginalScrollableContainingBlockRect;
}
+ // https://drafts.csswg.org/css-position/#original-cb
+ // Handle grid-based adjustment first...
if (isGrid) {
- // TODO(emilio, bug 2004596): This adjustment is supposed to also
- // restrict the position-area rect above...
const auto border = aDelegatingFrame->GetUsedBorder();
const nsPoint borderShift{border.left, border.top};
// Shift in by border of the overall grid container.
- return ContainingBlockRect{nsGridContainerFrame::GridItemCB(aKidFrame) +
- borderShift};
+ containingBlock =
+ nsGridContainerFrame::GridItemCB(aKidFrame) + borderShift;
+ if (!defaultAnchorInfo) {
+ return ContainingBlockRect{containingBlock};
+ }
+ }
+ // ... Then the position-area based adjustment.
+ if (defaultAnchorInfo) {
+ auto positionArea = aKidFrame->StylePosition()->mPositionArea;
+ if (!positionArea.IsNone()) {
+ // Offset should be up to, but not including the containing block's
+ // scroll offset.
+ const auto offset = AnchorPositioningUtils::GetScrollOffsetFor(
+ aAnchorPosResolutionCache->mReferenceData
+ ->CompensatingForScrollAxes(),
+ aKidFrame, aAnchorPosResolutionCache->mDefaultAnchorCache);
+ // Imagine an abspos container with a scroller in it, and then an
+ // anchor in it, where the anchor is visually in the middle of the
+ // scrollport. Then, when the scroller moves such that the anchor's
+ // left edge is on that of the scrollports, w.r.t. containing block,
+ // the anchor is zero left offset horizontally. The position-area
+ // grid needs to account for this.
+ const auto scrolledAnchorRect = defaultAnchorInfo->mRect - offset;
+ StylePositionArea resolvedPositionArea{};
+ const auto scrolledAnchorCb = AnchorPositioningUtils::
+ AdjustAbsoluteContainingBlockRectForPositionArea(
+ scrolledAnchorRect + aOriginalContainingBlockRect.TopLeft(),
+ containingBlock, aKidFrame->GetWritingMode(),
+ aDelegatingFrame->GetWritingMode(), positionArea,
+ &resolvedPositionArea);
+ return ContainingBlockRect{
+ offset, resolvedPositionArea,
+ aOriginalScrollableContainingBlockRect,
+ // Unscroll the CB by canceling out the previously applied
+ // scroll offset (See above), the offset will be applied later.
+ scrolledAnchorCb + offset};
+ }
+ return ContainingBlockRect{containingBlock};
}
if (ViewportFrame* viewport = do_QueryFrame(aDelegatingFrame)) {
@@ -1269,7 +1283,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
dom::ViewTransition::SnapshotContainingBlockRect(
viewport->PresContext())};
}
- return ContainingBlockRect{aOriginalContainingBlockRect};
+ return ContainingBlockRect{containingBlock};
}();
if (aAnchorPosResolutionCache) {
const auto& originalCb = cb.mMaybeScrollableRect;
diff --git a/testing/web-platform/meta/css/css-anchor-position/position-area-in-grid.html.ini b/testing/web-platform/meta/css/css-anchor-position/position-area-in-grid.html.ini
@@ -1,6 +0,0 @@
-[position-area-in-grid.html]
- [Offsets for position-area: span-bottom span-left and insets: {"left":"auto","right":"auto","top":"auto","bottom":"auto"}]
- expected: FAIL
-
- [Offsets for position-area: span-bottom span-left and insets: {"left":"10px","right":"10px","top":"10px","bottom":"10px"}]
- expected: FAIL