WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
[fast-cq]Patch
bug-264043-20260513145408.patch (text/plain), 18.48 KB, created by
alan
on 2026-05-13 14:54:09 PDT
(
hide
)
Description:
[fast-cq]Patch
Filename:
MIME Type:
Creator:
alan
Created:
2026-05-13 14:54:09 PDT
Size:
18.48 KB
patch
obsolete
>From 4b6bb08f6adaa290d8ce0e5c28089bdabdf0f8c0 Mon Sep 17 00:00:00 2001 >From: Alan Baradlay <zalan@apple.com> >Date: Wed, 13 May 2026 14:34:18 -0700 >Subject: [PATCH] [Flex] position: absolute parent breaks flex child > aspect-ratios https://bugs.webkit.org/show_bug.cgi?id=264043 > >Reviewed by Antti Koivisto. > > <div style="height: 200px; position: relative"> > <div style="display: flex; position: absolute; top: 0; bottom: 0"> > <img src="1x1-green.png"> > </div> > </div> > >The image should be 200x200 (stretched to the flex container's height, then >width from 1:1 aspect ratio). Instead it was 1x200 - the image used its >intrinsic width because the flex algorithm didn't recognize the container's >height as definite. > >hasDefiniteCrossSizeForFlexItem only recognized fixed heights and resolvable >percentages. It missed the out-of-flow case where height is auto but both >block-axis insets are specified - CSS Sizing 3 section 3.2.1 says this makes >the size "fully constrained" and therefore definite. > >The fix adds hasFullyConstrainedLogicalHeight() on RenderBox and uses it in >hasDefiniteCrossSizeForFlexItem and innerCrossSizeForFlexItem. However, it >must be guarded: in nested flex layouts, the containing block may be a flex >item that hasn't been stretched yet (height is 0). The guard >canResolveFullyConstrainedLogicalHeight() checks that the containing block's >height is currently definite (via hasDefiniteLogicalHeight, which respects >flex phase flags through canUseFlexItemForPercentageResolution). > >Also extracts the inline lambda in availableLogicalHeightForPercentageComputation >to use the shared hasFullyConstrainedLogicalHeight() helper. > >* Source/WebCore/rendering/RenderBox.cpp: >(WebCore::RenderBox::hasFullyConstrainedLogicalHeight): >* Source/WebCore/rendering/RenderBox.h: >* Source/WebCore/rendering/RenderBlock.cpp: >(WebCore::RenderBlock::availableLogicalHeightForPercentageComputation): >* Source/WebCore/rendering/RenderFlexibleBox.cpp: >(WebCore::canResolveFullyConstrainedLogicalHeight): >(WebCore::RenderFlexibleBox::hasDefiniteCrossSizeForFlexItem): >(WebCore::RenderFlexibleBox::innerCrossSizeForFlexItem): >* LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001{,-ref,-expected}.html: Added. >* LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001{,-ref,-expected}.html: Added. >* LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002{,-ref,-expected}.html: Added. > >Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> >--- > Source/WebCore/rendering/RenderBlock.cpp | 15 +------ > Source/WebCore/rendering/RenderBox.cpp | 7 ++++ > Source/WebCore/rendering/RenderBox.h | 1 + > .../WebCore/rendering/RenderFlexibleBox.cpp | 23 ++++++++++- > ...-abspos-inset-cross-size-001-expected.html | 28 +++++++++++++ > .../flex-abspos-inset-cross-size-001-ref.html | 28 +++++++++++++ > .../flex-abspos-inset-cross-size-001.html | 32 +++++++++++++++ > ...flex-abspos-inset-nested-001-expected.html | 11 +++++ > .../flex-abspos-inset-nested-001-ref.html | 11 +++++ > .../flex-abspos-inset-nested-001.html | 40 +++++++++++++++++++ > ...flex-abspos-inset-nested-002-expected.html | 11 +++++ > .../flex-abspos-inset-nested-002-ref.html | 11 +++++ > .../flex-abspos-inset-nested-002.html | 39 ++++++++++++++++++ > 13 files changed, 241 insertions(+), 16 deletions(-) > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-expected.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-ref.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-expected.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-ref.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-expected.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-ref.html > create mode 100644 LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002.html > >diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp >index 235b279b85fc..4f72ae3b1a83 100644 >--- a/Source/WebCore/rendering/RenderBlock.cpp >+++ b/Source/WebCore/rendering/RenderBlock.cpp >@@ -3007,20 +3007,7 @@ std::optional<LayoutUnit> RenderBlock::availableLogicalHeightForPercentageComput > ); > } > >- auto isOutOfFlowPositionedWithDefiniteHeight = [&] { >- if (!isOutOfFlowPositioned()) >- return false; >- // Explicit lengths/percentages are definite (CSS Sizing 3, 3.2.1). >- if (style.logicalHeight().isSpecified()) >- return true; >- // Both insets + height:auto -> the constraint equation (CSS2 10.6.4) solves for >- // height from known values (containing block, insets, margins, borders, padding). >- // height:auto is the only non-specified case where this works. >- // Content-dependent values (fit-content, etc.) can't be resolved here - the child is asking for >- // the containig block's height to size itself, but the containing blokc needs the child's size first. >- return !style.logicalTop().isAuto() && !style.logicalBottom().isAuto() && style.logicalHeight().isAuto(); >- }; >- if (isOutOfFlowPositionedWithDefiniteHeight()) { >+ if (isOutOfFlowPositioned() && (style.logicalHeight().isSpecified() || hasFullyConstrainedLogicalHeight())) { > // Don't allow this to affect the block' size() member variable, since this > // can get called while the block is still laying out its kids. > return std::max(0_lu, computeLogicalHeight(logicalHeight(), 0_lu).extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight()); >diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp >index 96b1444a7bad..2c2f7897a37c 100644 >--- a/Source/WebCore/rendering/RenderBox.cpp >+++ b/Source/WebCore/rendering/RenderBox.cpp >@@ -5226,6 +5226,13 @@ bool RenderBox::shouldComputeLogicalHeightFromAspectRatio() const > return h.isAuto() || h.isIntrinsic() || isUnresolveableStretchSize(h) || (!isOutOfFlowPositioned() && h.isPercentOrCalculated() && !percentageLogicalHeightIsResolvable()); > } > >+bool RenderBox::hasFullyConstrainedLogicalHeight() const >+{ >+ // CSS Sizing 3 section 3.2.1: "If the size is being computed in a context where >+ // it is fully constrained (e.g., because both inset properties are specified), the resulting size is definite." >+ return isOutOfFlowPositioned() && style().logicalHeight().isAuto() && !style().logicalTop().isAuto() && !style().logicalBottom().isAuto(); >+} >+ > bool RenderBox::shouldComputeLogicalWidthFromAspectRatio() const > { > if (shouldIgnoreAspectRatio()) >diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h >index a59be426b61f..984b8dde9952 100644 >--- a/Source/WebCore/rendering/RenderBox.h >+++ b/Source/WebCore/rendering/RenderBox.h >@@ -642,6 +642,7 @@ public: > virtual FloatSize preferredAspectRatioAsSize() const; > > bool shouldComputeLogicalWidthFromAspectRatio() const; >+ bool hasFullyConstrainedLogicalHeight() const; > > protected: > RenderBox(Type, Element&, RenderStyle&&, OptionSet<TypeFlag> = { }, TypeSpecificFlags = { }); >diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp >index 754904d6c8e6..77e8ee5070be 100644 >--- a/Source/WebCore/rendering/RenderFlexibleBox.cpp >+++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp >@@ -1408,6 +1408,17 @@ bool RenderFlexibleBox::flexItemHasComputableAspectRatioAndCrossSizeIsConsidered > && (flexItemCrossSizeIsDefinite(flexItem, preferredCrossSizeLengthForFlexItem(flexItem)) || hasDefiniteCrossSizeForFlexItem(flexItem)); > } > >+static bool canResolveFullyConstrainedLogicalHeight(const RenderFlexibleBox& flexBox) >+{ >+ // The height is fully constrained by insets (CSS Sizing 3 section 3.2.1), but we can >+ // only resolve it if the containing block's height is itself definite right now. >+ // In nested flex layouts, the containing block may be a flex item that hasn't been >+ // stretched yet - its height is 0 at that point and computeLogicalHeight would give >+ // a wrong answer. This happens when the nested out-of-flow flex is laid out as part of the >+ // anector flex's main-axis sizing, before the stretch phase sets the final cross size. >+ return flexBox.hasFullyConstrainedLogicalHeight() && flexBox.containingBlock()->hasDefiniteLogicalHeight(); >+} >+ > bool RenderFlexibleBox::hasDefiniteCrossSizeForFlexItem(const RenderBox& flexItem) const > { > // 9.8 https://drafts.csswg.org/css-flexbox/#definite-sizes >@@ -1419,7 +1430,12 @@ bool RenderFlexibleBox::hasDefiniteCrossSizeForFlexItem(const RenderBox& flexIte > return true; > // This must be kept in sync with computeMainSizeFromAspectRatioUsing(). > auto& crossSize = isHorizontalFlow() ? style().height() : style().width(); >- return crossSize.isFixed() || (crossSize.isPercent() && availableLogicalHeightForPercentageComputation()); >+ if (crossSize.isFixed()) >+ return true; >+ if (crossSize.isPercent() && availableLogicalHeightForPercentageComputation()) >+ return true; >+ if (canResolveFullyConstrainedLogicalHeight(*this)) >+ return true; > } > return false; > } >@@ -2331,12 +2347,15 @@ LayoutUnit RenderFlexibleBox::innerCrossSizeForFlexItem(const RenderBox& flexIte > auto flexContainerInnerCrossSize = [&] { > auto isHorizontal = isHorizontalFlow(); > auto size = isHorizontal ? style().height() : style().width(); >- ASSERT(size.isFixed() || (size.isPercent() && availableLogicalHeightForPercentageComputation())); > auto innerCrossSize = LayoutUnit { }; > if (auto fixedSize = size.tryFixed()) > innerCrossSize = adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit { fixedSize->resolveZoom(style().usedZoomForLength()) }); > else if (size.isPercent()) > innerCrossSize = availableLogicalHeightForPercentageComputation().value_or(0_lu); >+ else if (canResolveFullyConstrainedLogicalHeight(*this)) >+ innerCrossSize = std::max(0_lu, computeLogicalHeight(logicalHeight(), 0_lu).extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight()); >+ else >+ ASSERT_NOT_REACHED(); > > auto maximumSize = isHorizontal ? style().maxHeight() : style().maxWidth(); > if (auto fixedMaximumSize = maximumSize.tryFixed()) >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-expected.html >new file mode 100644 >index 000000000000..503f28246459 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-expected.html >@@ -0,0 +1,28 @@ >+<!DOCTYPE html> >+<title>Reference</title> >+<style> >+.holder { >+ height: 200px; >+ position: relative; >+} >+ >+.flex { >+ display: flex; >+ height: 200px; >+} >+ >+img { >+ display: block; >+} >+</style> >+<p>Test passes if the two images below are the same size.</p> >+<div class="holder"> >+ <div class="flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+</div> >+<div class="holder"> >+ <div class="flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+</div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-ref.html >new file mode 100644 >index 000000000000..503f28246459 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-ref.html >@@ -0,0 +1,28 @@ >+<!DOCTYPE html> >+<title>Reference</title> >+<style> >+.holder { >+ height: 200px; >+ position: relative; >+} >+ >+.flex { >+ display: flex; >+ height: 200px; >+} >+ >+img { >+ display: block; >+} >+</style> >+<p>Test passes if the two images below are the same size.</p> >+<div class="holder"> >+ <div class="flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+</div> >+<div class="holder"> >+ <div class="flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+</div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001.html >new file mode 100644 >index 000000000000..70c58cebefd5 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001.html >@@ -0,0 +1,32 @@ >+<!DOCTYPE html> >+<title>Abspos flex container with inset-derived height provides definite cross size to flex items</title> >+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#definite-sizes"> >+<link rel="match" href="flex-abspos-inset-cross-size-001-ref.html"> >+<style> >+.holder { >+ height: 200px; >+ position: relative; >+} >+ >+.flex { >+ display: flex; >+ position: absolute; >+ top: 0; >+ bottom: 0; >+} >+ >+img { >+ display: block; >+} >+</style> >+<p>Test passes if the two images below are the same size.</p> >+<div class="holder"> >+ <div class="flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+</div> >+<div class="holder"> >+ <div class="flex" style="position: static; height: 200px;"> >+ <img src="../support/1x1-green.png"> >+ </div> >+</div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-expected.html >new file mode 100644 >index 000000000000..fe82ccb72803 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-expected.html >@@ -0,0 +1,11 @@ >+<!DOCTYPE html> >+<title>Reference</title> >+<style> >+.ref { >+ width: 200px; >+ height: 200px; >+ background: green; >+} >+</style> >+<p>Test passes if there is a 200x200 green square.</p> >+<div class="ref"></div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-ref.html >new file mode 100644 >index 000000000000..fe82ccb72803 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001-ref.html >@@ -0,0 +1,11 @@ >+<!DOCTYPE html> >+<title>Reference</title> >+<style> >+.ref { >+ width: 200px; >+ height: 200px; >+ background: green; >+} >+</style> >+<p>Test passes if there is a 200x200 green square.</p> >+<div class="ref"></div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001.html >new file mode 100644 >index 000000000000..e982207d46f0 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-001.html >@@ -0,0 +1,40 @@ >+<!DOCTYPE html> >+<title>Nested abspos flex with intermediate percentage-height containing block</title> >+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#definite-sizes"> >+<link rel="match" href="flex-abspos-inset-nested-001-ref.html"> >+<style> >+.outer-flex { >+ display: flex; >+ height: 200px; >+} >+ >+.flex-item { >+ width: 100%; >+} >+ >+.intermediate { >+ position: relative; >+ height: 100%; >+} >+ >+.inner-flex { >+ display: flex; >+ position: absolute; >+ top: 0; >+ bottom: 0; >+} >+ >+img { >+ display: block; >+} >+</style> >+<p>Test passes if there is a 200x200 green square.</p> >+<div class="outer-flex"> >+ <div class="flex-item"> >+ <div class="intermediate"> >+ <div class="inner-flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+ </div> >+ </div> >+</div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-expected.html >new file mode 100644 >index 000000000000..a3659012174a >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-expected.html >@@ -0,0 +1,11 @@ >+<!DOCTYPE html> >+<title>Reference</title> >+<style> >+.ref { >+ width: 300px; >+ height: 300px; >+ background: green; >+} >+</style> >+<p>Test passes if there is a 300x300 green square.</p> >+<div class="ref"></div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-ref.html >new file mode 100644 >index 000000000000..a3659012174a >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002-ref.html >@@ -0,0 +1,11 @@ >+<!DOCTYPE html> >+<title>Reference</title> >+<style> >+.ref { >+ width: 300px; >+ height: 300px; >+ background: green; >+} >+</style> >+<p>Test passes if there is a 300x300 green square.</p> >+<div class="ref"></div> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002.html >new file mode 100644 >index 000000000000..1e49eb5abbea >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-nested-002.html >@@ -0,0 +1,39 @@ >+<!DOCTYPE html> >+<title>Abspos flex inside a fixed-height intermediate block within an outer flex item</title> >+<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/#definite-sizes"> >+<link rel="match" href="flex-abspos-inset-nested-002-ref.html"> >+<style> >+.outer-flex { >+ display: flex; >+} >+ >+.flex-item { >+ width: 100%; >+} >+ >+.intermediate { >+ position: relative; >+ height: 300px; >+} >+ >+.inner-flex { >+ display: flex; >+ position: absolute; >+ top: 0; >+ bottom: 0; >+} >+ >+img { >+ display: block; >+} >+</style> >+<p>Test passes if there is a 300x300 green square.</p> >+<div class="outer-flex"> >+ <div class="flex-item"> >+ <div class="intermediate"> >+ <div class="inner-flex"> >+ <img src="../support/1x1-green.png"> >+ </div> >+ </div> >+ </div> >+</div>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 264043
:
479652
|
479656
| 479658