From 41c2422a662926ea4b4ccc3ba6c3fd7e071586f5 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Mon, 24 Feb 2025 14:51:08 +0100 Subject: [PATCH] layout: Ignore indefinite `stretch` on min and max sizing properties (#35630) We were always treating an indefinite `stretch` as the automatic size. This instead treats it as `0px` on min sizing properties, and as `none` on max sizing properties, aligning with Blink and this recent CSSWG resolution: https://github.com/w3c/csswg-drafts/issues/11006 Signed-off-by: Oriol Brufau --- components/layout_2020/flexbox/layout.rs | 45 +++++----- components/layout_2020/flow/mod.rs | 20 ++--- components/layout_2020/geom.rs | 87 ++++++++++++------- components/layout_2020/positioned.rs | 2 +- components/layout_2020/replaced.rs | 4 +- tests/wpt/meta/MANIFEST.json | 10 +-- .../keyword-sizes-on-flex-item-001.html.ini | 21 +++-- .../keyword-sizes-on-flex-item-002.html.ini | 12 +-- .../css-sizing/stretch/indefinite-2.html.ini | 3 - .../css-sizing/stretch/indefinite-3.html.ini | 3 - .../keyword-sizes-on-flex-item-001.html | 34 +++++--- .../keyword-sizes-on-flex-item-002.html | 38 +++++--- .../keyword-sizes-on-floated-element.html | 45 +++++++--- .../keyword-sizes-on-inline-block.html | 33 +++++-- .../keyword-sizes-on-replaced-element.html | 54 +++++++++--- 15 files changed, 266 insertions(+), 145 deletions(-) delete mode 100644 tests/wpt/meta/css/css-sizing/stretch/indefinite-2.html.ini delete mode 100644 tests/wpt/meta/css/css-sizing/stretch/indefinite-3.html.ini diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index c80d1739eb5..c5cbb412496 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -2753,14 +2753,11 @@ impl FlexItemBox { } }); - let flex_base_size = if let Some(container_size) = container_definite_inner_size.main { - let stretch_size = Au::zero().max(container_size - pbm_auto_is_zero.main); - used_flex_basis.resolve(Size::MaxContent, stretch_size, &content_size) - } else if matches!(used_flex_basis, Size::Stretch | Size::FitContent) { - content_size.max_content - } else { - used_flex_basis.resolve(Size::MaxContent, Au::zero(), &content_size) - }; + let stretch_size = container_definite_inner_size + .main + .map(|container_size| Au::zero().max(container_size - pbm_auto_is_zero.main)); + let flex_base_size = + used_flex_basis.resolve_for_preferred(Size::MaxContent, stretch_size, &content_size); (flex_base_size, flex_base_size_is_definite) } @@ -2849,7 +2846,7 @@ impl FlexItemBox { }); content_box_size .inline - .resolve(initial_behavior, stretch_size, &content_size) + .resolve_for_preferred(initial_behavior, Some(stretch_size), &content_size) .clamp_between_extremums(min_size.inline, max_size.inline) }; let item_as_containing_block = ContainingBlock { @@ -2891,31 +2888,31 @@ impl FlexItemBox { }); content_block_size }; - let content_block_size = LazyCell::new(|| ContentSizes::from(content_block_size())); match intrinsic_sizing_mode { IntrinsicSizingMode::Contribution => { - let stretch_size = flex_context - .containing_block - .size - .block - .to_definite() - .map(|block_size| { - block_size - - padding_border_margin.padding_border_sums.block - - padding_border_margin.margin.block_start.auto_is(Au::zero) - - padding_border_margin.margin.block_end.auto_is(Au::zero) - }) - .unwrap_or_else(|| content_block_size.max_content); + let stretch_size = + flex_context.containing_block.size.block.to_definite().map( + |block_size| { + block_size - + padding_border_margin.padding_border_sums.block - + padding_border_margin.margin.block_start.auto_is(Au::zero) - + padding_border_margin.margin.block_end.auto_is(Au::zero) + }, + ); let inner_block_size = content_box_size .block - .resolve(Size::FitContent, stretch_size, &content_block_size) + .resolve_for_preferred( + Size::FitContent, + stretch_size, + &LazyCell::new(|| ContentSizes::from(content_block_size())), + ) .clamp_between_extremums(min_size.block, max_size.block); inner_block_size + padding_border_margin.padding_border_sums.block + padding_border_margin.margin.block_start.auto_is(Au::zero) + padding_border_margin.margin.block_end.auto_is(Au::zero) }, - IntrinsicSizingMode::Size => content_block_size.max_content, + IntrinsicSizingMode::Size => content_block_size(), } }, } diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 1061ad8ac88..09561114cda 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -171,7 +171,7 @@ impl BlockLevelBox { Direction::Inline, Size::Stretch, Au::zero(), - available_inline_size, + Some(available_inline_size), get_inline_content_sizes, false, /* is_table */ ); @@ -996,7 +996,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( Direction::Block, Size::FitContent, Au::zero(), - available_block_size.unwrap_or(content_block_size), + available_block_size, || content_block_size.into(), false, /* is_table */ ); @@ -1117,7 +1117,7 @@ impl IndependentNonReplacedContents { Direction::Block, Size::FitContent, Au::zero(), - available_block_size.unwrap_or(layout.content_block_size), + available_block_size, || layout.content_block_size.into(), layout_style.is_table(), ); @@ -1251,7 +1251,7 @@ impl IndependentNonReplacedContents { Direction::Inline, automatic_inline_size, Au::zero(), - stretch_size, + Some(stretch_size), get_inline_content_sizes, is_table, ) @@ -1262,7 +1262,7 @@ impl IndependentNonReplacedContents { Direction::Block, Size::FitContent, Au::zero(), - available_block_size.unwrap_or(layout.content_block_size), + available_block_size, || layout.content_block_size.into(), is_table, ) @@ -1699,7 +1699,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( Direction::Inline, automatic_inline_size, Au::zero(), - available_inline_size, + Some(available_inline_size), get_inline_content_sizes, is_table, ); @@ -2175,12 +2175,12 @@ impl IndependentFormattingContext { IndependentFormattingContextContents::NonReplaced(non_replaced) => { let writing_mode = self.style().writing_mode; let available_inline_size = - (containing_block.size.inline - pbm_sums.inline_sum()).max(Au::zero()); + Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum()); let available_block_size = containing_block .size .block .to_definite() - .map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero())); + .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum())); let tentative_block_size = content_box_sizes_and_pbm .content_box_sizes .block @@ -2201,7 +2201,7 @@ impl IndependentFormattingContext { Direction::Inline, Size::FitContent, Au::zero(), - available_inline_size, + Some(available_inline_size), get_content_size, is_table, ); @@ -2232,7 +2232,7 @@ impl IndependentFormattingContext { Direction::Block, Size::FitContent, Au::zero(), - available_block_size.unwrap_or(independent_layout.content_block_size), + available_block_size, || independent_layout.content_block_size.into(), is_table, ); diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index 0f367cc0fe5..80898c31090 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -7,7 +7,7 @@ use std::convert::From; use std::fmt; use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; -use app_units::Au; +use app_units::{Au, MAX_AU}; use style::logical_geometry::{BlockFlowDirection, Direction, InlineBaseDirection, WritingMode}; use style::values::computed::{ CSSPixelLength, LengthPercentage, MaxSize as StyleMaxSize, Percentage, Size as StyleSize, @@ -779,39 +779,65 @@ impl LogicalVec2> { } impl Size { - /// Resolves any size into a numerical value. + /// Resolves a preferred size into a numerical value. + /// #[inline] - pub(crate) fn resolve ContentSizes>( + pub(crate) fn resolve_for_preferred ContentSizes>( &self, - initial_behavior: Self, - stretch_size: Au, + automatic_size: Size, + stretch_size: Option, content_size: &LazyCell, ) -> Au { - if self.is_initial() { - assert!(!initial_behavior.is_initial()); - initial_behavior.resolve_non_initial(stretch_size, content_size) - } else { - self.resolve_non_initial(stretch_size, content_size) + match self { + Self::Initial => { + assert!(!automatic_size.is_initial()); + automatic_size.resolve_for_preferred(automatic_size, stretch_size, content_size) + }, + Self::MinContent => content_size.min_content, + Self::MaxContent => content_size.max_content, + Self::FitContent => { + content_size.shrink_to_fit(stretch_size.unwrap_or_else(|| content_size.max_content)) + }, + Self::Stretch => stretch_size.unwrap_or_else(|| content_size.max_content), + Self::Numeric(numeric) => *numeric, } - .unwrap() } - /// Resolves a non-initial size into a numerical value. - /// Returns `None` if the size is the initial one. + /// Resolves a minimum size into a numerical value. + /// #[inline] - pub(crate) fn resolve_non_initial ContentSizes>( + pub(crate) fn resolve_for_min ContentSizes>( &self, - stretch_size: Au, + automatic_minimum_size: Au, + stretch_size: Option, + content_size: &LazyCell, + ) -> Au { + match self { + Self::Initial => automatic_minimum_size, + Self::MinContent => content_size.min_content, + Self::MaxContent => content_size.max_content, + Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or_default()), + Self::Stretch => stretch_size.unwrap_or_default(), + Self::Numeric(numeric) => *numeric, + } + } + + /// Resolves a maximum size into a numerical value. + /// + #[inline] + pub(crate) fn resolve_for_max ContentSizes>( + &self, + stretch_size: Option, content_size: &LazyCell, ) -> Option { - match self { - Self::Initial => None, - Self::MinContent => Some(content_size.min_content), - Self::MaxContent => Some(content_size.max_content), - Self::FitContent => Some(content_size.shrink_to_fit(stretch_size)), - Self::Stretch => Some(stretch_size), - Self::Numeric(numeric) => Some(*numeric), - } + Some(match self { + Self::Initial => return None, + Self::MinContent => content_size.min_content, + Self::MaxContent => content_size.max_content, + Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or(MAX_AU)), + Self::Stretch => return stretch_size, + Self::Numeric(numeric) => *numeric, + }) } /// Tries to resolve an extrinsic size into a numerical value. @@ -915,7 +941,7 @@ impl Sizes { axis: Direction, automatic_size: Size, automatic_minimum_size: Au, - stretch_size: Au, + stretch_size: Option, get_content_size: impl FnOnce() -> ContentSizes, is_table: bool, ) -> Au { @@ -937,7 +963,7 @@ impl Sizes { axis: Direction, automatic_size: Size, automatic_minimum_size: Au, - stretch_size: Au, + stretch_size: Option, get_content_size: impl FnOnce() -> ContentSizes, is_table: bool, ) -> (Au, Au, Option) { @@ -953,13 +979,12 @@ impl Sizes { return (content_size.max_content, content_size.min_content, None); } - let preferred = self - .preferred - .resolve(automatic_size, stretch_size, &content_size); + let preferred = + self.preferred + .resolve_for_preferred(automatic_size, stretch_size, &content_size); let mut min = self .min - .resolve_non_initial(stretch_size, &content_size) - .unwrap_or(automatic_minimum_size); + .resolve_for_min(automatic_minimum_size, stretch_size, &content_size); if is_table { // In addition to the specified minimum, the inline size of a table is forced to be // at least as big as its min-content size. @@ -968,7 +993,7 @@ impl Sizes { // This is being discussed in https://github.com/w3c/csswg-drafts/issues/11408 min.max_assign(content_size.min_content); } - let max = self.max.resolve_non_initial(stretch_size, &content_size); + let max = self.max.resolve_for_max(stretch_size, &content_size); (preferred, min, max) } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index b94294fd7ac..8767f042700 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -822,7 +822,7 @@ impl AbsoluteAxisSolver<'_> { self.axis, initial_behavior, Au::zero(), - stretch_size, + Some(stretch_size), get_content_size, self.is_table, )) diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index b00633d6a13..b4ee3fd4a51 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -536,7 +536,7 @@ impl ReplacedContents { Direction::Inline, automatic_size.inline, Au::zero(), - inline_stretch_size, + Some(inline_stretch_size), get_inline_content_size, false, /* is_table */ ); @@ -565,7 +565,7 @@ impl ReplacedContents { Direction::Block, automatic_size.block, Au::zero(), - block_stretch_size.unwrap_or_else(|| block_content_size.max_content), + block_stretch_size, || *block_content_size, false, /* is_table */ ); diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index df899924f72..5dfd071b218 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -592760,35 +592760,35 @@ ] ], "keyword-sizes-on-flex-item-001.html": [ - "5989de812e6a17bb4fa2f9ea5df634a3bfbaaccc", + "04c4bddbbd19c3a2942e56d54dba9a3f4a3dd44e", [ null, {} ] ], "keyword-sizes-on-flex-item-002.html": [ - "4a8cf76b253d2302da59c4020d370f870fa4a0c7", + "73c6cb0c3d50b37488ed1d2a4cdaa8e434b0093d", [ null, {} ] ], "keyword-sizes-on-floated-element.html": [ - "e3da8bee7eb7b613e457d00eb88a677c35698d08", + "44f75194794f0495febeecf02418fa5d023db35e", [ null, {} ] ], "keyword-sizes-on-inline-block.html": [ - "519081349c61e63da5f0a261da74dc985afb7c49", + "e80df2343843220c97d6c760fcf595a7e9c4936a", [ null, {} ] ], "keyword-sizes-on-replaced-element.html": [ - "8863ef491570c4d194bbb4b1d03a6e12367d4ff3", + "497f87ca5fca68e6423c6aba94a34d3de938c1b1", [ null, {} diff --git a/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-001.html.ini b/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-001.html.ini index 7ee274d3a4a..71d18a9e17e 100644 --- a/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-001.html.ini +++ b/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-001.html.ini @@ -125,20 +125,29 @@ [.test 59] expected: FAIL - [.test 60] + [.test 66] expected: FAIL - [.test 61] + [.test 67] expected: FAIL - [.test 62] + [.test 68] expected: FAIL - [.test 63] + [.test 69] expected: FAIL - [.test 64] + [.test 70] expected: FAIL - [.test 65] + [.test 71] + expected: FAIL + + [.test 72] + expected: FAIL + + [.test 73] + expected: FAIL + + [.test 74] expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-002.html.ini b/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-002.html.ini index 547bdd0ad7f..33c0021a067 100644 --- a/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-002.html.ini +++ b/tests/wpt/meta/css/css-sizing/keyword-sizes-on-flex-item-002.html.ini @@ -131,20 +131,20 @@ [.test 54] expected: FAIL - [.test 60] + [.test 69] expected: FAIL - [.test 61] + [.test 70] expected: FAIL - [.test 62] + [.test 71] expected: FAIL - [.test 63] + [.test 72] expected: FAIL - [.test 64] + [.test 73] expected: FAIL - [.test 65] + [.test 74] expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/stretch/indefinite-2.html.ini b/tests/wpt/meta/css/css-sizing/stretch/indefinite-2.html.ini deleted file mode 100644 index 05de804a562..00000000000 --- a/tests/wpt/meta/css/css-sizing/stretch/indefinite-2.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[indefinite-2.html] - [[data-expected-client-height\] 1] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/stretch/indefinite-3.html.ini b/tests/wpt/meta/css/css-sizing/stretch/indefinite-3.html.ini deleted file mode 100644 index 0534dc7600c..00000000000 --- a/tests/wpt/meta/css/css-sizing/stretch/indefinite-3.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[indefinite-3.html] - [[data-expected-client-height\] 1] - expected: FAIL diff --git a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-001.html b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-001.html index 5989de812e6..04c4bddbbd1 100644 --- a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-001.html +++ b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-001.html @@ -129,20 +129,34 @@
-
-
X X
-
XXX XXX
-
XXXXX XXXXX
+
X X
+
XXX XXX
+
XXXXX XXXXX
-
X X
-
XXX XXX
-
XXXXX XXXXX
+
X X
+
XXX XXX
+
XXXXX XXXXX
-
X X
-
XXX XXX
-
XXXXX XXXXX
+
X X
+
XXX XXX
+
XXXXX XXXXX
+
+ + +
+
X X
+
XXX XXX
+
XXXXX XXXXX
+ +
X X
+
XXX XXX
+
XXXXX XXXXX
+ +
X X
+
XXX XXX
+
XXXXX XXXXX
diff --git a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-002.html b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-002.html index 4a8cf76b253..73c6cb0c3d5 100644 --- a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-002.html +++ b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-flex-item-002.html @@ -10,8 +10,10 @@