commit bf0542d5275f3b66542f13a55e8fea141450cf2a
parent e34292a5fd10a52530f19d4d0f21d50e4013e2fa
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Thu, 2 Oct 2025 17:43:50 +0000
Bug 1992124 - Ignore invalid @position-try rules. r=layout-anchor-positioning-reviewers,layout-reviewers,dshin
Tested as part of bug 1992124.
Differential Revision: https://phabricator.services.mozilla.com/D267230
Diffstat:
1 file changed, 48 insertions(+), 23 deletions(-)
diff --git a/layout/generic/AbsoluteContainingBlock.cpp b/layout/generic/AbsoluteContainingBlock.cpp
@@ -893,13 +893,47 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
}
}
}
- do {
- const StylePositionTryFallbacksItem* currentFallback = nullptr;
- RefPtr<ComputedStyle> currentFallbackStyle;
- if (currentFallbackIndex) {
- currentFallback = &fallbacks[*currentFallbackIndex];
+ const StylePositionTryFallbacksItem* currentFallback = nullptr;
+ RefPtr<ComputedStyle> currentFallbackStyle;
+
+ auto TryAdvanceFallback = [&]() -> bool {
+ if (fallbacks.IsEmpty()) {
+ return false;
+ }
+ uint32_t nextFallbackIndex =
+ currentFallbackIndex ? *currentFallbackIndex + 1 : 0;
+ if (nextFallbackIndex >= fallbacks.Length()) {
+ return false;
+ }
+ const StylePositionTryFallbacksItem* nextFallback;
+ RefPtr<ComputedStyle> nextFallbackStyle;
+ while (true) {
+ nextFallback = &fallbacks[nextFallbackIndex];
+ if (nextFallback->IsIdentAndOrTactic()) {
+ auto* ident = nextFallback->AsIdentAndOrTactic().ident.AsAtom();
+ if (!ident->IsEmpty()) {
+ nextFallbackStyle = aPresContext->StyleSet()->ResolvePositionTry(
+ *aKidFrame->GetContent()->AsElement(), *aKidFrame->Style(),
+ ident);
+ if (!nextFallbackStyle) {
+ // No @position-try rule for this name was found, per spec we should
+ // skip it.
+ nextFallbackIndex++;
+ if (nextFallbackIndex >= fallbacks.Length()) {
+ return false;
+ }
+ }
+ }
+ }
+ break;
}
+ currentFallbackIndex = Some(nextFallbackIndex);
+ currentFallback = nextFallback;
+ currentFallbackStyle = std::move(nextFallbackStyle);
+ return true;
+ };
+ do {
const nsRect usedCb = [&] {
if (isGrid) {
// TODO(emilio): how does position-area interact with grid?
@@ -911,14 +945,8 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
if (currentFallback) {
if (currentFallback->IsIdentAndOrTactic()) {
const auto& item = currentFallback->AsIdentAndOrTactic();
- if (!item.ident.AsAtom()->IsEmpty()) {
- currentFallbackStyle = aPresContext->StyleSet()->ResolvePositionTry(
- *aKidFrame->GetContent()->AsElement(), *aKidFrame->Style(),
- item.ident.AsAtom());
- if (currentFallbackStyle) {
- positionArea =
- currentFallbackStyle->StylePosition()->mPositionArea;
- }
+ if (currentFallbackStyle) {
+ positionArea = currentFallbackStyle->StylePosition()->mPositionArea;
}
tactic = &item.try_tactic;
} else {
@@ -1159,21 +1187,18 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame(
aKidFrame->DidReflow(aPresContext, &kidReflowInput);
- if (fallbacks.IsEmpty() ||
- (currentFallbackIndex &&
- *currentFallbackIndex >= fallbacks.Length() - 1) ||
- (usedCb.Contains(aKidFrame->GetRect()) && aStatus.IsComplete())) {
- // If there are no further fallbacks, or we don't overflow, we're done.
+ if (usedCb.Contains(aKidFrame->GetRect()) && aStatus.IsComplete()) {
+ // We don't overflow our CB, no further fallback needed.
+ break;
+ }
+
+ if (!TryAdvanceFallback()) {
+ // If there are no further fallbacks, we're done.
break;
}
// Try with the next fallback.
aKidFrame->AddStateBits(NS_FRAME_IS_DIRTY);
- if (currentFallbackIndex) {
- (*currentFallbackIndex)++;
- } else {
- currentFallbackIndex.emplace(0);
- }
aStatus.Reset();
} while (true);