commit f9538b019e72db60784a50b613c4ed9bcd26a905
parent 89b86fad2fafb90dcd329d06999393dab29af58a
Author: Jonathan Kew <jkew@mozilla.com>
Date: Sat, 27 Dec 2025 15:37:20 +0000
Bug 1989059 - Account for position-try-order when choosing position fallback. r=layout-anchor-positioning-reviewers,layout-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D277556
Diffstat:
3 files changed, 59 insertions(+), 83 deletions(-)
diff --git a/layout/generic/AbsoluteContainingBlock.cpp b/layout/generic/AbsoluteContainingBlock.cpp
@@ -1176,8 +1176,10 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
AutoNoisyIndenter indent(nsBlockFrame::gNoisy);
#endif // DEBUG
+ const WritingMode outerWM = aReflowInput.GetWritingMode();
+ const WritingMode wm = aKidFrame->GetWritingMode();
+
const bool isGrid = aFlags.contains(AbsPosReflowFlag::IsGridContainerCB);
- // TODO(bug 1989059): position-try-order.
auto fallbacks =
aKidFrame->StylePosition()->mPositionTryFallbacks._0.AsSpan();
Maybe<uint32_t> currentFallbackIndex;
@@ -1185,6 +1187,31 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
RefPtr<ComputedStyle> currentFallbackStyle;
RefPtr<ComputedStyle> firstTryStyle;
Maybe<uint32_t> firstTryIndex;
+ // If non-'normal' position-try-order is in effect, we keep track of the
+ // index of the "best" option seen, and its size in the relevant axis, so
+ // that once all fallbacks have been considered we can reset to the one
+ // that provided the most space.
+ Maybe<uint32_t> bestIndex;
+ nscoord bestSize = -1;
+ // Flag to indicate that we've determined which fallback to use and should
+ // exit the loop.
+ bool finalizing = false;
+
+ auto tryOrder = aKidFrame->StylePosition()->mPositionTryOrder;
+ // If position-try-order is a logical value, resolve to physical using
+ // the containing block's writing mode.
+ switch (tryOrder) {
+ case StylePositionTryOrder::MostInlineSize:
+ tryOrder = outerWM.IsVertical() ? StylePositionTryOrder::MostHeight
+ : StylePositionTryOrder::MostWidth;
+ break;
+ case StylePositionTryOrder::MostBlockSize:
+ tryOrder = outerWM.IsVertical() ? StylePositionTryOrder::MostWidth
+ : StylePositionTryOrder::MostHeight;
+ break;
+ default:
+ break;
+ }
// Set the current fallback to the given index, or reset to the base position
// if Nothing() is passed.
@@ -1355,8 +1382,6 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
aAnchorPosResolutionCache->mReferenceData->mAdjustedContainingBlock =
cb.mFinalRect;
}
- const WritingMode outerWM = aReflowInput.GetWritingMode();
- const WritingMode wm = aKidFrame->GetWritingMode();
const LogicalSize cbSize(outerWM, cb.mFinalRect.Size());
ReflowInput::InitFlags initFlags;
@@ -1658,7 +1683,9 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
// containing-block, see:
// https://drafts.csswg.org/css-anchor-position-1/#fallback-apply
const auto fits = aStatus.IsComplete() && FitsInContainingBlock();
- if (fallbacks.IsEmpty() || fits) {
+ if (fallbacks.IsEmpty() || finalizing ||
+ (fits && (tryOrder == StylePositionTryOrder::Normal ||
+ currentFallbackIndex == firstTryIndex))) {
// We completed the reflow - Either we had a fallback that fit, or we
// didn't have any to try in the first place.
isOverflowingCB = !fits;
@@ -1669,9 +1696,36 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
break;
}
+ if (fits) {
+ auto imcbSize = cb.mFinalRect.Size();
+ imcbSize -= nsSize{insets.LeftRight(), insets.TopBottom()};
+ switch (tryOrder) {
+ case StylePositionTryOrder::MostWidth:
+ if (imcbSize.Width() > bestSize) {
+ bestSize = imcbSize.Width();
+ bestIndex = currentFallbackIndex;
+ }
+ break;
+ case StylePositionTryOrder::MostHeight:
+ if (imcbSize.Height() > bestSize) {
+ bestSize = imcbSize.Height();
+ bestIndex = currentFallbackIndex;
+ }
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("unexpected try-order value");
+ break;
+ }
+ }
+
if (!TryAdvanceFallback()) {
// If there are no further fallbacks, we're done.
- break;
+ if (bestSize >= 0) {
+ finalizing = true;
+ SeekFallbackTo(bestIndex);
+ } else {
+ break;
+ }
}
// Try with the next fallback.
diff --git a/testing/web-platform/meta/css/css-anchor-position/position-try-order-basic.html.ini b/testing/web-platform/meta/css/css-anchor-position/position-try-order-basic.html.ini
@@ -1,39 +0,0 @@
-[position-try-order-basic.html]
- [most-inline-size --right, --left | --left]
- expected: FAIL
-
- [most-width --right, --left | --left]
- expected: FAIL
-
- [most-block-size --bottom, --top | --top]
- expected: FAIL
-
- [most-height --bottom, --top | --top]
- expected: FAIL
-
- [most-inline-size --right, --left, --bottom, --top | --bottom]
- expected: FAIL
-
- [most-inline-size --right, --left, --top, --bottom | --top]
- expected: FAIL
-
- [most-block-size --bottom, --top, --right, --left | --right]
- expected: FAIL
-
- [most-block-size --bottom, --top, --left, --right | --left]
- expected: FAIL
-
- [most-block-size --bottom-sweep, --left-sweep | --left-sweep]
- expected: FAIL
-
- [most-inline-size --right-sweep, --left-sweep, --bottom-sweep, --top-sweep | --left-sweep]
- expected: FAIL
-
- [most-block-size --right-sweep, --left-sweep, --bottom-sweep, --top-sweep | --top-sweep]
- expected: FAIL
-
- [most-inline-size\n --right-sweep, --left-sweep, --bottom-sweep, --top-sweep,\n /* --right, --left, --bottom, --top */\n --bottom\n | --bottom]
- expected: FAIL
-
- [most-block-size\n --right-sweep, --left-sweep, --bottom-sweep, --top-sweep,\n /* --right, --left, --bottom, --top */\n --right\n | --right]
- expected: FAIL
diff --git a/testing/web-platform/meta/css/css-anchor-position/position-try-order-position-area.html.ini b/testing/web-platform/meta/css/css-anchor-position/position-try-order-position-area.html.ini
@@ -1,39 +0,0 @@
-[position-try-order-position-area.html]
- [most-inline-size --right, --left, --bottom, --top | --bottom]
- expected: FAIL
-
- [most-inline-size --right, --left, --top, --bottom | --top]
- expected: FAIL
-
- [most-block-size --bottom, --top, --right, --left | --right]
- expected: FAIL
-
- [most-block-size --bottom, --top, --left, --right | --left]
- expected: FAIL
-
- [most-inline-size --right-sweep, --left-sweep, --bottom-sweep, --top-sweep | --left-sweep]
- expected: FAIL
-
- [most-inline-size --right, --left | --left]
- expected: FAIL
-
- [most-width --right, --left | --left]
- expected: FAIL
-
- [most-block-size --bottom, --top | --top]
- expected: FAIL
-
- [most-height --bottom, --top | --top]
- expected: FAIL
-
- [most-block-size --bottom-sweep, --left-sweep | --left-sweep]
- expected: FAIL
-
- [most-block-size --right-sweep, --left-sweep, --bottom-sweep, --top-sweep | --top-sweep]
- expected: FAIL
-
- [most-inline-size\n --right-sweep, --left-sweep, --bottom-sweep, --top-sweep,\n /* --right, --left, --bottom, --top */\n --bottom\n | --bottom]
- expected: FAIL
-
- [most-block-size\n --right-sweep, --left-sweep, --bottom-sweep, --top-sweep,\n /* --right, --left, --bottom, --top */\n --right\n | --right]
- expected: FAIL