From f963f2731dbbe583e409257f5338e2ae7567005e Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Sat, 14 Jun 2025 11:24:10 +0200 Subject: [PATCH] layout: Properly handle intrinsic min/max block sizes on replaced element (#37457) This change aligns Servo with both Blink and WebKit in common cases. When the `aspect-ratio` property is set to a different value than the natural ratio, then Blink and WebKit disagree, we match Blink. Gecko doesn't support intrinsic min/max block sizes at all. Note this patch doesn't fix the intrinsic contributions, they will need to be addressed in a follow-up patch. Testing: Covered by WPT Fixes: #37433 Signed-off-by: Oriol Brufau --- components/layout/replaced.rs | 95 ++++++++++--------- tests/wpt/meta/MANIFEST.json | 26 +++++ ...keyword-sizes-on-replaced-element.html.ini | 24 ----- .../replaced-element-047.tentative.html | 30 ++++++ .../replaced-element-048.tentative.html | 30 ++++++ 5 files changed, 136 insertions(+), 69 deletions(-) delete mode 100644 tests/wpt/meta/css/css-sizing/keyword-sizes-on-replaced-element.html.ini create mode 100644 tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-047.tentative.html create mode 100644 tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-048.tentative.html diff --git a/components/layout/replaced.rs b/components/layout/replaced.rs index 9ae886bf0ed..8bd1da619ee 100644 --- a/components/layout/replaced.rs +++ b/components/layout/replaced.rs @@ -509,55 +509,60 @@ impl ReplacedContents { .to_definite() .map(|block_size| Au::zero().max(block_size - pbm_sums.block)); + let resolve_inline_size = |get_block_size: &dyn Fn() -> SizeConstraint| { + let get_inline_content_size = || { + self.content_size( + Direction::Inline, + preferred_aspect_ratio, + get_block_size, + &get_inline_fallback_size, + ) + .into() + }; + sizes.inline.resolve( + Direction::Inline, + automatic_size.inline, + Au::zero, + Some(inline_stretch_size), + get_inline_content_size, + false, /* is_table */ + ) + }; + let resolve_block_size = |get_inline_size: &dyn Fn() -> SizeConstraint| { + let get_block_content_size = || -> ContentSizes { + self.content_size( + Direction::Block, + preferred_aspect_ratio, + get_inline_size, + &get_block_fallback_size, + ) + .into() + }; + sizes.block.resolve( + Direction::Block, + automatic_size.block, + Au::zero, + block_stretch_size, + get_block_content_size, + false, /* is_table */ + ) + }; + // First, compute the inline size. Intrinsic values depend on the block sizing properties // through the aspect ratio, but these can also be intrinsic and depend on the inline size. - // Therefore, we tentatively treat intrinsic block sizing properties as their initial value. - let get_inline_content_size = || { - let get_block_size = || { - sizes - .block - .resolve_extrinsic(automatic_size.block, Au::zero(), block_stretch_size) - }; - self.content_size( - Direction::Inline, - preferred_aspect_ratio, - &get_block_size, - &get_inline_fallback_size, - ) - .into() - }; - let inline_size = sizes.inline.resolve( - Direction::Inline, - automatic_size.inline, - Au::zero, - Some(inline_stretch_size), - get_inline_content_size, - false, /* is_table */ - ); - - // Now we can compute the block size, using the inline size from above. - let get_block_content_size = || -> ContentSizes { - let get_inline_size = || SizeConstraint::Definite(inline_size); - self.content_size( - Direction::Block, - preferred_aspect_ratio, - &get_inline_size, - &get_block_fallback_size, - ) - .into() - }; - let block_size = sizes.block.resolve( - Direction::Block, - automatic_size.block, - Au::zero, - block_stretch_size, - get_block_content_size, - false, /* is_table */ - ); - + // Therefore, when there is an aspect ratio, we may need to: + // 1. Tentatively resolve the inline size, ignoring block sizing properties. + // 2. Tentatively resolve the block size, resolving intrinsic keywords by transferring (1). + // 3. Resolve the final inline size, resolving intrinsic keywords by transferring (2). + // 4. Resolve the final block size, resolving intrinsic keywords by transferring (3). + let inline_size = resolve_inline_size(&|| { + SizeConstraint::Definite(resolve_block_size(&|| { + SizeConstraint::Definite(resolve_inline_size(&|| SizeConstraint::default())) + })) + }); LogicalVec2 { inline: inline_size, - block: block_size, + block: resolve_block_size(&|| SizeConstraint::Definite(inline_size)), } } diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index 02330f7982a..0986fe9cc09 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -249947,6 +249947,32 @@ {} ] ], + "replaced-element-047.tentative.html": [ + "ec0d6394088436ce3caa0b5d990c2b2fe017f583", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "replaced-element-048.tentative.html": [ + "66057fbdd4df4062e48f81de9417b7cc89fe54f1", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "replaced-element-dynamic-aspect-ratio.html": [ "d4b83d3673cbfba940baec1c88f3e6630c760eb4", [ diff --git a/tests/wpt/meta/css/css-sizing/keyword-sizes-on-replaced-element.html.ini b/tests/wpt/meta/css/css-sizing/keyword-sizes-on-replaced-element.html.ini deleted file mode 100644 index 331df3de9be..00000000000 --- a/tests/wpt/meta/css/css-sizing/keyword-sizes-on-replaced-element.html.ini +++ /dev/null @@ -1,24 +0,0 @@ -[keyword-sizes-on-replaced-element.html] - [.test 68] - expected: FAIL - - [.test 69] - expected: FAIL - - [.test 71] - expected: FAIL - - [.test 75] - expected: FAIL - - [.test 77] - expected: FAIL - - [.test 78] - expected: FAIL - - [.test 80] - expected: FAIL - - [.test 84] - expected: FAIL diff --git a/tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-047.tentative.html b/tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-047.tentative.html new file mode 100644 index 00000000000..ec0d6394088 --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-047.tentative.html @@ -0,0 +1,30 @@ + + + + + + + + + + +

Test passes if there is a filled green square and no red.

+ +
+ diff --git a/tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-048.tentative.html b/tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-048.tentative.html new file mode 100644 index 00000000000..66057fbdd4d --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/aspect-ratio/replaced-element-048.tentative.html @@ -0,0 +1,30 @@ + + + + + + + + + + +

Test passes if there is a filled green square and no red.

+ +
+