WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-264043-20260513105821.patch (text/plain), 11.21 KB, created by
alan
on 2026-05-13 10:58:22 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
alan
Created:
2026-05-13 10:58:22 PDT
Size:
11.21 KB
patch
obsolete
>From 1d007865480c855a04cbc7bee5810f0aa8afc5c2 Mon Sep 17 00:00:00 2001 >From: Alan Baradlay <zalan@apple.com> >Date: Wed, 13 May 2026 07:54:40 -0700 >Subject: [PATCH] position: absolute parent breaks flex child aspect-ratio > 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. > >The flex algorithm checks hasDefiniteCrossSizeForFlexItem to decide if it can >tell a stretched flex item what its cross size should be. This check only >recognized fixed heights (height: 200px) and resolvable percentages. It missed >the out-of-flow case where height is auto but both cross-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 - returns true >when the element is out-of-flow with auto height and both block-axis insets >non-auto. Used in hasDefiniteCrossSizeForFlexItem, innerCrossSizeForFlexItem, >and availableLogicalHeightForPercentageComputation (replacing an inline lambda >that checked the same condition). > >* 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::RenderFlexibleBox::hasDefiniteCrossSizeForFlexItem): >(WebCore::RenderFlexibleBox::innerCrossSizeForFlexItem): >* LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-expected.html: Added. >* LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001-ref.html: Added. >* LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/flex-abspos-inset-cross-size-001.html: Added. >--- > Source/WebCore/rendering/RenderBlock.cpp | 15 +-------- > Source/WebCore/rendering/RenderBox.cpp | 7 ++++ > Source/WebCore/rendering/RenderBox.h | 1 + > .../WebCore/rendering/RenderFlexibleBox.cpp | 12 +++++-- > ...-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 +++++++++++++++++++ > 7 files changed, 107 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 > >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..684b82900a6c 100644 >--- a/Source/WebCore/rendering/RenderFlexibleBox.cpp >+++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp >@@ -1419,7 +1419,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 (hasFullyConstrainedLogicalHeight()) >+ return true; > } > return false; > } >@@ -2331,12 +2336,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 (hasFullyConstrainedLogicalHeight()) >+ 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>
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