layout: Partial support for sizing keywords on flex items (#35469)

* Add tests for sizing keywords on flex items

Signed-off-by: Oriol Brufau <obrufau@igalia.com>

* layout: Partial support for sizing keywords on flex items

When a flex item has `flex-basis: auto`, the used `flex-basis` is the
value of the main size property. In that case, if the main size property
was set to keyword, we were always assuming it was `auto`. Now we handle
non-`auto` keywords correctly.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>

---------

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-02-17 18:51:10 +01:00 committed by GitHub
parent 5fa14c97bd
commit c2224d5afc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 639 additions and 52 deletions

View file

@ -42,8 +42,7 @@ use crate::sizing::{
ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, IntrinsicSizingMode,
};
use crate::style_ext::{
AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, LayoutStyle,
PaddingBorderMargin,
AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin,
};
use crate::{
ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock,
@ -1119,17 +1118,19 @@ impl<'a> FlexItem<'a> {
config.flex_axis,
);
let ContentBoxSizesAndPBMDeprecated {
content_box_size,
content_min_box_size,
content_max_box_size,
let ContentBoxSizesAndPBM {
content_box_sizes,
pbm,
depends_on_block_constraints,
} = box_
.independent_formatting_context
.layout_style()
.content_box_sizes_and_padding_border_margin(&containing_block.into())
.into();
.content_box_sizes_and_padding_border_margin(&containing_block.into());
// TODO(#32853): handle size keywords.
let content_box_size = content_box_sizes.map(|size| size.preferred.to_auto_or());
let content_min_box_size = content_box_sizes.map(|size| size.min.to_auto_or());
let content_max_box_size = content_box_sizes.map(|size| size.max.to_numeric());
let preferred_aspect_ratio = box_
.independent_formatting_context
@ -1189,8 +1190,7 @@ impl<'a> FlexItem<'a> {
.container_inner_size_constraint
.map(|size| size.to_definite()),
cross_axis_is_item_block_axis,
flex_relative_content_box_size
.map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)),
flex_context.vec2_to_flex_relative(content_box_sizes.map(|size| size.preferred)),
flex_relative_content_min_size,
flex_relative_content_max_size,
preferred_aspect_ratio,
@ -2270,17 +2270,20 @@ impl FlexItemBox {
let cross_axis_is_item_block_axis =
cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis);
let ContentBoxSizesAndPBMDeprecated {
content_box_size,
content_min_box_size,
content_max_box_size,
let ContentBoxSizesAndPBM {
content_box_sizes,
pbm,
..
} = self
.independent_formatting_context
.layout_style()
.content_box_sizes_and_padding_border_margin(containing_block)
.into();
.content_box_sizes_and_padding_border_margin(containing_block);
// TODO(#32853): handle size keywords.
let content_box_size = content_box_sizes.map(|size| size.preferred.to_auto_or());
let content_min_box_size = content_box_sizes.map(|size| size.min.to_auto_or());
let content_max_box_size = content_box_sizes.map(|size| size.max.to_numeric());
let preferred_aspect_ratio = self
.independent_formatting_context
.preferred_aspect_ratio(&pbm.padding_border_sums);
@ -2376,7 +2379,8 @@ impl FlexItemBox {
},
};
let content_box_size = flex_axis.vec2_to_flex_relative(content_box_size);
let content_box_size =
flex_axis.vec2_to_flex_relative(content_box_sizes.map(|size| size.preferred));
let content_min_size_no_auto = flex_axis.vec2_to_flex_relative(content_min_size_no_auto);
let content_max_size = flex_axis.vec2_to_flex_relative(content_max_box_size);
@ -2388,7 +2392,7 @@ impl FlexItemBox {
.flex_axis
.vec2_to_flex_relative(containing_block.size.map(|v| v.non_auto())),
cross_axis_is_item_block_axis,
content_box_size.map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)),
content_box_size,
content_min_size_no_auto,
content_max_size,
preferred_aspect_ratio,

View file

@ -202,28 +202,6 @@ pub(crate) struct ContentBoxSizesAndPBM {
pub depends_on_block_constraints: bool,
}
impl From<ContentBoxSizesAndPBM> for ContentBoxSizesAndPBMDeprecated {
fn from(sizes: ContentBoxSizesAndPBM) -> Self {
Self {
content_box_size: sizes
.content_box_sizes
.map(|size| size.preferred.to_auto_or()),
content_min_box_size: sizes.content_box_sizes.map(|size| size.min.to_auto_or()),
content_max_box_size: sizes.content_box_sizes.map(|size| size.max.to_numeric()),
pbm: sizes.pbm.clone(),
depends_on_block_constraints: sizes.depends_on_block_constraints,
}
}
}
pub(crate) struct ContentBoxSizesAndPBMDeprecated {
pub content_box_size: LogicalVec2<AuOrAuto>,
pub content_min_box_size: LogicalVec2<AuOrAuto>,
pub content_max_box_size: LogicalVec2<Option<Au>>,
pub pbm: PaddingBorderMargin,
pub depends_on_block_constraints: bool,
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) struct BorderStyleColor {
pub style: BorderStyle,

View file

@ -592759,6 +592759,20 @@
{}
]
],
"keyword-sizes-on-flex-item-001.html": [
"5989de812e6a17bb4fa2f9ea5df634a3bfbaaccc",
[
null,
{}
]
],
"keyword-sizes-on-flex-item-002.html": [
"4a8cf76b253d2302da59c4020d370f870fa4a0c7",
[
null,
{}
]
],
"keyword-sizes-on-floated-element.html": [
"e3da8bee7eb7b613e457d00eb88a677c35698d08",
[

View file

@ -0,0 +1,147 @@
[keyword-sizes-on-flex-item-001.html]
[.test 10]
expected: FAIL
[.test 11]
expected: FAIL
[.test 12]
expected: FAIL
[.test 13]
expected: FAIL
[.test 14]
expected: FAIL
[.test 15]
expected: FAIL
[.test 16]
expected: FAIL
[.test 17]
expected: FAIL
[.test 18]
expected: FAIL
[.test 19]
expected: FAIL
[.test 20]
expected: FAIL
[.test 21]
expected: FAIL
[.test 22]
expected: FAIL
[.test 23]
expected: FAIL
[.test 24]
expected: FAIL
[.test 25]
expected: FAIL
[.test 26]
expected: FAIL
[.test 27]
expected: FAIL
[.test 28]
expected: FAIL
[.test 29]
expected: FAIL
[.test 30]
expected: FAIL
[.test 31]
expected: FAIL
[.test 32]
expected: FAIL
[.test 33]
expected: FAIL
[.test 34]
expected: FAIL
[.test 35]
expected: FAIL
[.test 36]
expected: FAIL
[.test 39]
expected: FAIL
[.test 40]
expected: FAIL
[.test 41]
expected: FAIL
[.test 42]
expected: FAIL
[.test 43]
expected: FAIL
[.test 44]
expected: FAIL
[.test 45]
expected: FAIL
[.test 49]
expected: FAIL
[.test 50]
expected: FAIL
[.test 51]
expected: FAIL
[.test 52]
expected: FAIL
[.test 53]
expected: FAIL
[.test 54]
expected: FAIL
[.test 57]
expected: FAIL
[.test 58]
expected: FAIL
[.test 59]
expected: FAIL
[.test 60]
expected: FAIL
[.test 61]
expected: FAIL
[.test 62]
expected: FAIL
[.test 63]
expected: FAIL
[.test 64]
expected: FAIL
[.test 65]
expected: FAIL

View file

@ -0,0 +1,150 @@
[keyword-sizes-on-flex-item-002.html]
[.test 1]
expected: FAIL
[.test 2]
expected: FAIL
[.test 3]
expected: FAIL
[.test 4]
expected: FAIL
[.test 6]
expected: FAIL
[.test 7]
expected: FAIL
[.test 8]
expected: FAIL
[.test 9]
expected: FAIL
[.test 10]
expected: FAIL
[.test 11]
expected: FAIL
[.test 12]
expected: FAIL
[.test 13]
expected: FAIL
[.test 14]
expected: FAIL
[.test 15]
expected: FAIL
[.test 16]
expected: FAIL
[.test 17]
expected: FAIL
[.test 18]
expected: FAIL
[.test 19]
expected: FAIL
[.test 20]
expected: FAIL
[.test 21]
expected: FAIL
[.test 22]
expected: FAIL
[.test 23]
expected: FAIL
[.test 24]
expected: FAIL
[.test 25]
expected: FAIL
[.test 26]
expected: FAIL
[.test 27]
expected: FAIL
[.test 31]
expected: FAIL
[.test 32]
expected: FAIL
[.test 33]
expected: FAIL
[.test 34]
expected: FAIL
[.test 35]
expected: FAIL
[.test 36]
expected: FAIL
[.test 40]
expected: FAIL
[.test 41]
expected: FAIL
[.test 42]
expected: FAIL
[.test 43]
expected: FAIL
[.test 44]
expected: FAIL
[.test 45]
expected: FAIL
[.test 49]
expected: FAIL
[.test 50]
expected: FAIL
[.test 51]
expected: FAIL
[.test 52]
expected: FAIL
[.test 53]
expected: FAIL
[.test 54]
expected: FAIL
[.test 60]
expected: FAIL
[.test 61]
expected: FAIL
[.test 62]
expected: FAIL
[.test 63]
expected: FAIL
[.test 64]
expected: FAIL
[.test 65]
expected: FAIL

View file

@ -2,9 +2,6 @@
[[data-expected-height\] 8]
expected: FAIL
[[data-expected-height\] 20]
expected: FAIL
[[data-expected-height\] 21]
expected: FAIL
@ -14,9 +11,6 @@
[[data-expected-height\] 31]
expected: FAIL
[[data-expected-height\] 43]
expected: FAIL
[[data-expected-height\] 44]
expected: FAIL

View file

@ -2,9 +2,6 @@
[[data-expected-width\] 8]
expected: FAIL
[[data-expected-width\] 19]
expected: FAIL
[[data-expected-width\] 21]
expected: FAIL
@ -14,9 +11,6 @@
[[data-expected-width\] 31]
expected: FAIL
[[data-expected-width\] 42]
expected: FAIL
[[data-expected-width\] 44]
expected: FAIL

View file

@ -0,0 +1,153 @@
<!DOCTYPE html>
<title>Keyword sizes on flex item: row container</title>
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#sizing-values">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#sizing-values">
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/11006">
<meta assert="The various keyword sizes work as expected on flex items.">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
.wrapper {
display: flex;
flex-direction: row;
}
.test {
flex: none;
margin: 5px;
border: 3px solid;
padding: 2px;
font: 20px/1 Ahem;
}
/* Set the preferred size to small amount, to test that the min size works */
.test.min-width { width: 0px }
.test.min-height { height: 0px }
/* Set the preferred size to big amount, to test that the max size works */
.test.max-width { width: 500px }
.test.max-height { height: 500px }
/* stretch isn't widely supported, fall back to vendor-prefixed alternatives */
.width.stretch { width: -moz-available; width: -webkit-fill-available; width: stretch }
.min-width.stretch { min-width: -moz-available; min-width: -webkit-fill-available; min-width: stretch }
.max-width.stretch { max-width: -moz-available; max-width: -webkit-fill-available; max-width: stretch }
.height.stretch { height: -moz-available; height: -webkit-fill-available; height: stretch }
.min-height.stretch { min-height: -moz-available; min-height: -webkit-fill-available; min-height: stretch }
.max-height.stretch { max-height: -moz-available; max-height: -webkit-fill-available; max-height: stretch }
</style>
<div id="log"></div>
<!-- Intrinsic keywords -->
<div class="wrapper" style="width: 100px; height: 100px">
<div class="test width" style="width: min-content" data-expected-width="30">X X</div>
<div class="test width" style="width: fit-content" data-expected-width="70">X X</div>
<div class="test width" style="width: max-content" data-expected-width="70">X X</div>
<div class="test width" style="width: min-content" data-expected-width="70">XXX XXX</div>
<div class="test width" style="width: fit-content" data-expected-width="90">XXX XXX</div>
<div class="test width" style="width: max-content" data-expected-width="150">XXX XXX</div>
<div class="test width" style="width: min-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test width" style="width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test width" style="width: max-content" data-expected-width="230">XXXXX XXXXX</div>
<br>
<div class="test min-width" style="min-width: min-content" data-expected-width="30">X X</div>
<div class="test min-width" style="min-width: fit-content" data-expected-width="70">X X</div>
<div class="test min-width" style="min-width: max-content" data-expected-width="70">X X</div>
<div class="test min-width" style="min-width: min-content" data-expected-width="70">XXX XXX</div>
<div class="test min-width" style="min-width: fit-content" data-expected-width="90">XXX XXX</div>
<div class="test min-width" style="min-width: max-content" data-expected-width="150">XXX XXX</div>
<div class="test min-width" style="min-width: min-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test min-width" style="min-width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test min-width" style="min-width: max-content" data-expected-width="230">XXXXX XXXXX</div>
<br>
<div class="test max-width" style="max-width: min-content" data-expected-width="30">X X</div>
<div class="test max-width" style="max-width: fit-content" data-expected-width="70">X X</div>
<div class="test max-width" style="max-width: max-content" data-expected-width="70">X X</div>
<div class="test max-width" style="max-width: min-content" data-expected-width="70">XXX XXX</div>
<div class="test max-width" style="max-width: fit-content" data-expected-width="90">XXX XXX</div>
<div class="test max-width" style="max-width: max-content" data-expected-width="150">XXX XXX</div>
<div class="test max-width" style="max-width: min-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test max-width" style="max-width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test max-width" style="max-width: max-content" data-expected-width="230">XXXXX XXXXX</div>
<br>
<div class="test height" style="height: min-content" data-expected-height="30">X X</div>
<div class="test height" style="height: fit-content" data-expected-height="30">X X</div>
<div class="test height" style="height: max-content" data-expected-height="30">X X</div>
<div class="test min-height" style="min-height: min-content" data-expected-height="30">X X</div>
<div class="test min-height" style="min-height: fit-content" data-expected-height="30">X X</div>
<div class="test min-height" style="min-height: max-content" data-expected-height="30">X X</div>
<div class="test max-height" style="max-height: min-content" data-expected-height="30">X X</div>
<div class="test max-height" style="max-height: fit-content" data-expected-height="30">X X</div>
<div class="test max-height" style="max-height: max-content" data-expected-height="30">X X</div>
</div>
<!-- Definite stretch -->
<div class="wrapper" style="width: 100px; height: 100px">
<div class="test width stretch" data-expected-width="90">X X</div>
<div class="test width stretch" data-expected-width="90">XXX XXX</div>
<div class="test width stretch" data-expected-width="90">XXXXX XXXXX</div>
<div class="test min-width stretch" data-expected-width="90">X X</div>
<div class="test min-width stretch" data-expected-width="90">XXX XXX</div>
<div class="test min-width stretch" data-expected-width="90">XXXXX XXXXX</div>
<div class="test max-width stretch" data-expected-width="90">X X</div>
<div class="test max-width stretch" data-expected-width="90">XXX XXX</div>
<div class="test max-width stretch" data-expected-width="90">XXXXX XXXXX</div>
<div class="test height stretch" data-expected-height="90">X X</div>
<div class="test height stretch" data-expected-height="90">XXX XXX<</div>
<div class="test height stretch" data-expected-height="90">XXXXX XXXXX</div>
<div class="test min-height stretch" data-expected-height="90">X X</div>
<div class="test min-height stretch" data-expected-height="90">XXX XXX</div>
<div class="test min-height stretch" data-expected-height="90">XXXXX XXXXX</div>
<div class="test max-height stretch" data-expected-height="90">X X</div>
<div class="test max-height stretch" data-expected-height="90">XXX XXX</div>
<div class="test max-height stretch" data-expected-height="90">XXXXX XXXXX</div>
</div>
<!-- Stretch sizes can't result in a negative content size -->
<div class="wrapper" style="width: 0px; height: 0px">
<div class="test width min-width max-width stretch" data-expected-width="10"></div>
<div class="test height min-height max-height stretch" data-expected-height="10"></div>
</div>
<!-- Indefinite stretch -->
<div class="wrapper" style="width: 100px; max-height: 100px">
<div class="test height stretch indefinite" data-expected-height="30">X X</div>
<div class="test height stretch indefinite" data-expected-height="30">XXX XXX</div>
<div class="test height stretch indefinite" data-expected-height="30">XXXXX XXXXX</div>
<div class="test min-height stretch indefinite" data-expected-height="30">X X</div>
<div class="test min-height stretch indefinite" data-expected-height="30">XXX XXX</div>
<div class="test min-height stretch indefinite" data-expected-height="30">XXXXX XXXXX</div>
<div class="test max-height stretch indefinite" data-expected-height="30">X X</div>
<div class="test max-height stretch indefinite" data-expected-height="30">XXX XXX</div>
<div class="test max-height stretch indefinite" data-expected-height="30">XXXXX XXXXX</div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.fonts.ready.then(() => checkLayout(".test"));
</script>

View file

@ -0,0 +1,153 @@
<!DOCTYPE html>
<title>Keyword sizes on flex item: column container</title>
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#sizing-values">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#sizing-values">
<link rel="help" href="https://drafts.csswg.org/css-flexbox-1/">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/11006">
<meta assert="The various keyword sizes work as expected on flex items.">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
.wrapper {
display: flex;
flex-direction: column;
}
.test {
flex: none;
margin: 5px;
border: 3px solid;
padding: 2px;
font: 20px/1 Ahem;
}
/* Set the preferred size to small amount, to test that the min size works */
.test.min-width { width: 0px }
.test.min-height { height: 0px }
/* Set the preferred size to big amount, to test that the max size works */
.test.max-width { width: 500px }
.test.max-height { height: 500px }
/* stretch isn't widely supported, fall back to vendor-prefixed alternatives */
.width.stretch { width: -moz-available; width: -webkit-fill-available; width: stretch }
.min-width.stretch { min-width: -moz-available; min-width: -webkit-fill-available; min-width: stretch }
.max-width.stretch { max-width: -moz-available; max-width: -webkit-fill-available; max-width: stretch }
.height.stretch { height: -moz-available; height: -webkit-fill-available; height: stretch }
.min-height.stretch { min-height: -moz-available; min-height: -webkit-fill-available; min-height: stretch }
.max-height.stretch { max-height: -moz-available; max-height: -webkit-fill-available; max-height: stretch }
</style>
<div id="log"></div>
<!-- Intrinsic keywords -->
<div class="wrapper" style="width: 100px; height: 100px">
<div class="test width" style="width: min-content" data-expected-width="30">X X</div>
<div class="test width" style="width: fit-content" data-expected-width="70">X X</div>
<div class="test width" style="width: max-content" data-expected-width="70">X X</div>
<div class="test width" style="width: min-content" data-expected-width="70">XXX XXX</div>
<div class="test width" style="width: fit-content" data-expected-width="90">XXX XXX</div>
<div class="test width" style="width: max-content" data-expected-width="150">XXX XXX</div>
<div class="test width" style="width: min-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test width" style="width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test width" style="width: max-content" data-expected-width="230">XXXXX XXXXX</div>
<br>
<div class="test min-width" style="min-width: min-content" data-expected-width="30">X X</div>
<div class="test min-width" style="min-width: fit-content" data-expected-width="70">X X</div>
<div class="test min-width" style="min-width: max-content" data-expected-width="70">X X</div>
<div class="test min-width" style="min-width: min-content" data-expected-width="70">XXX XXX</div>
<div class="test min-width" style="min-width: fit-content" data-expected-width="90">XXX XXX</div>
<div class="test min-width" style="min-width: max-content" data-expected-width="150">XXX XXX</div>
<div class="test min-width" style="min-width: min-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test min-width" style="min-width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test min-width" style="min-width: max-content" data-expected-width="230">XXXXX XXXXX</div>
<br>
<div class="test max-width" style="max-width: min-content" data-expected-width="30">X X</div>
<div class="test max-width" style="max-width: fit-content" data-expected-width="70">X X</div>
<div class="test max-width" style="max-width: max-content" data-expected-width="70">X X</div>
<div class="test max-width" style="max-width: min-content" data-expected-width="70">XXX XXX</div>
<div class="test max-width" style="max-width: fit-content" data-expected-width="90">XXX XXX</div>
<div class="test max-width" style="max-width: max-content" data-expected-width="150">XXX XXX</div>
<div class="test max-width" style="max-width: min-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test max-width" style="max-width: fit-content" data-expected-width="110">XXXXX XXXXX</div>
<div class="test max-width" style="max-width: max-content" data-expected-width="230">XXXXX XXXXX</div>
<br>
<div class="test height" style="height: min-content" data-expected-height="30">X X</div>
<div class="test height" style="height: fit-content" data-expected-height="30">X X</div>
<div class="test height" style="height: max-content" data-expected-height="30">X X</div>
<div class="test min-height" style="min-height: min-content" data-expected-height="30">X X</div>
<div class="test min-height" style="min-height: fit-content" data-expected-height="30">X X</div>
<div class="test min-height" style="min-height: max-content" data-expected-height="30">X X</div>
<div class="test max-height" style="max-height: min-content" data-expected-height="30">X X</div>
<div class="test max-height" style="max-height: fit-content" data-expected-height="30">X X</div>
<div class="test max-height" style="max-height: max-content" data-expected-height="30">X X</div>
</div>
<!-- Definite stretch -->
<div class="wrapper" style="width: 100px; height: 100px">
<div class="test width stretch" data-expected-width="90">X X</div>
<div class="test width stretch" data-expected-width="90">XXX XXX</div>
<div class="test width stretch" data-expected-width="90">XXXXX XXXXX</div>
<div class="test min-width stretch" data-expected-width="90">X X</div>
<div class="test min-width stretch" data-expected-width="90">XXX XXX</div>
<div class="test min-width stretch" data-expected-width="90">XXXXX XXXXX</div>
<div class="test max-width stretch" data-expected-width="90">X X</div>
<div class="test max-width stretch" data-expected-width="90">XXX XXX</div>
<div class="test max-width stretch" data-expected-width="90">XXXXX XXXXX</div>
<div class="test height stretch" data-expected-height="90">X X</div>
<div class="test height stretch" data-expected-height="90">XXX XXX<</div>
<div class="test height stretch" data-expected-height="90">XXXXX XXXXX</div>
<div class="test min-height stretch" data-expected-height="90">X X</div>
<div class="test min-height stretch" data-expected-height="90">XXX XXX</div>
<div class="test min-height stretch" data-expected-height="90">XXXXX XXXXX</div>
<div class="test max-height stretch" data-expected-height="90">X X</div>
<div class="test max-height stretch" data-expected-height="90">XXX XXX</div>
<div class="test max-height stretch" data-expected-height="90">XXXXX XXXXX</div>
</div>
<!-- Stretch sizes can't result in a negative content size -->
<div class="wrapper" style="width: 0px; height: 0px">
<div class="test width min-width max-width stretch" data-expected-width="10"></div>
<div class="test height min-height max-height stretch" data-expected-height="10"></div>
</div>
<!-- Indefinite stretch -->
<div class="wrapper" style="width: 100px; max-height: 100px">
<div class="test height stretch indefinite" data-expected-height="30">X X</div>
<div class="test height stretch indefinite" data-expected-height="50">XXX XXX</div>
<div class="test height stretch indefinite" data-expected-height="50">XXXXX XXXXX</div>
<div class="test min-height stretch indefinite" data-expected-height="30">X X</div>
<div class="test min-height stretch indefinite" data-expected-height="50">XXX XXX</div>
<div class="test min-height stretch indefinite" data-expected-height="50">XXXXX XXXXX</div>
<div class="test max-height stretch indefinite" data-expected-height="30">X X</div>
<div class="test max-height stretch indefinite" data-expected-height="50">XXX XXX</div>
<div class="test max-height stretch indefinite" data-expected-height="50">XXXXX XXXXX</div>
</div>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
document.fonts.ready.then(() => checkLayout(".test"));
</script>