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 <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-06-14 11:24:10 +02:00 committed by GitHub
parent a27f2bb84d
commit f963f2731d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 136 additions and 69 deletions

View file

@ -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)),
}
}