Fix min/max-content block size of replaced element (#34284)

The min-content and max-content sizes on the block axis depend on the
inline size. But when computing the SizeConstraint corresponding to the
inline axis, we were resolving the preferred inline size ignoring
intrinsic keywords. Now we will only ignore `auto`.

Also, this patch refactors the logic to compute the min-content and
max-content block sizes after fully resolving the inline size.
This avoids having to resolve the inline sizing properties twice.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2024-11-18 23:04:57 +01:00 committed by GitHub
parent 696c591d81
commit 8c689aac67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 67 additions and 28 deletions

View file

@ -538,7 +538,9 @@ impl ReplacedContent {
.non_auto()
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
// <https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes>
// 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 inline_content_size = LazyCell::new(|| {
let get_block_size = || {
let block_stretch_size = block_stretch_size.unwrap_or_else(get_block_fallback_size);
@ -563,20 +565,29 @@ impl ReplacedContent {
)
.into()
});
let preferred_inline =
box_size
.inline
.resolve(Size::FitContent, inline_stretch_size, &inline_content_size);
let min_inline = min_box_size
.inline
.resolve_non_initial(inline_stretch_size, &inline_content_size)
.unwrap_or_default();
let max_inline = max_box_size
.inline
.resolve_non_initial(inline_stretch_size, &inline_content_size);
let inline_size = preferred_inline.clamp_between_extremums(min_inline, max_inline);
// Now we can compute the block size, using the inline size from above.
let block_content_size = LazyCell::new(|| -> ContentSizes {
let get_inline_size = || {
SizeConstraint::new(
box_size
.inline
.maybe_resolve_extrinsic(Some(inline_stretch_size)),
min_box_size
.inline
.resolve_non_initial(inline_stretch_size, &inline_content_size)
.unwrap_or_default(),
max_box_size
.inline
.resolve_non_initial(inline_stretch_size, &inline_content_size),
)
if box_size.inline.is_initial() {
// TODO: do we really need to special-case `auto`?
// https://github.com/w3c/csswg-drafts/issues/11236
SizeConstraint::MinMax(min_inline, max_inline)
} else {
SizeConstraint::Definite(inline_size)
}
};
self.content_size(
Direction::Block,
@ -588,34 +599,22 @@ impl ReplacedContent {
});
let block_stretch_size =
block_stretch_size.unwrap_or_else(|| block_content_size.max_content);
// <https://drafts.csswg.org/css-sizing-3/#sizing-properties>
let preferred_inline =
box_size
.inline
.resolve(Size::FitContent, inline_stretch_size, &inline_content_size);
let preferred_block =
box_size
.block
.resolve(Size::FitContent, block_stretch_size, &block_content_size);
let min_inline = min_box_size
.inline
.resolve_non_initial(inline_stretch_size, &inline_content_size)
.unwrap_or_default();
let min_block = min_box_size
.block
.resolve_non_initial(block_stretch_size, &block_content_size)
.unwrap_or_default();
let max_inline = max_box_size
.inline
.resolve_non_initial(inline_stretch_size, &inline_content_size);
let max_block = max_box_size
.block
.resolve_non_initial(block_stretch_size, &block_content_size);
let block_size = preferred_block.clamp_between_extremums(min_block, max_block);
LogicalVec2 {
inline: preferred_inline.clamp_between_extremums(min_inline, max_inline),
block: preferred_block.clamp_between_extremums(min_block, max_block),
inline: inline_size,
block: block_size,
}
}
}

View file

@ -572214,6 +572214,13 @@
{}
]
],
"replaced-element-044.tentative.html": [
"58a4b9b76ff32010a82c49d1e5d42090d794a081",
[
null,
{}
]
],
"sign-function-aspect-ratio.html": [
"e5ba1a8321a42918cccee4ee164527fa25078e4f",
[

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS aspect-ratio: replaced element transferring intrinsic sizes</title>
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers">
<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/11236">
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
<meta name="assert" content="
The inline size resulting from an intrinsic keyword is transferred
to the block axis through aspect ratio.
Except if the inline size is `auto`, then we ignore the ratio and
just use the natural block size instead.
">
<style>
canvas { aspect-ratio: 1; height: auto; background: cyan; }
</style>
<canvas width="50" height="25" style="width: auto"
data-expected-width="50" data-expected-height="25"></canvas>
<canvas width="50" height="25" style="width: min-content"
data-expected-width="50" data-expected-height="50"></canvas>
<canvas width="50" height="25" style="width: fit-content"
data-expected-width="50" data-expected-height="50"></canvas>
<canvas width="50" height="25" style="width: max-content"
data-expected-width="50" data-expected-height="50"></canvas>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/check-layout-th.js"></script>
<script>
checkLayout("canvas");
</script>