layout: Fix intrinsic contributions of anonymous blocks (#34719)

In order to compute the inline min-content and max-content contributions
of an anonymous block, we were finding its min-content and max-content
inline size with a SizeConstraint coming from the block size of the box.

However, anonymous blocks do not establish a containing block for their
contents, so this patch uses a SizeConstraint from the block size of the
containing block.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2024-12-21 22:42:21 -08:00 committed by GitHub
parent 1157fa28b3
commit 09408ae10b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 91 additions and 22 deletions

View file

@ -412,6 +412,7 @@ fn compute_inline_content_sizes_for_block_level_boxes(
&LogicalVec2::zero(),
false, /* auto_block_size_stretches_to_containing_block */
false, /* is_table */
!matches!(base.style.pseudo(), Some(PseudoElement::ServoAnonymousBox)),
|_| None, /* TODO: support preferred aspect ratios on non-replaced boxes */
|constraint_space| {
base.inline_content_sizes(layout_context, constraint_space, contents)

View file

@ -216,6 +216,7 @@ impl IndependentFormattingContext {
auto_minimum,
auto_block_size_stretches_to_containing_block,
is_table,
true, /* establishes_containing_block */
|padding_border_sums| self.preferred_aspect_ratio(padding_border_sums),
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
)

View file

@ -871,6 +871,14 @@ impl SizeConstraint {
}
}
impl From<AuOrAuto> for SizeConstraint {
fn from(size: AuOrAuto) -> Self {
size.non_auto()
.map(SizeConstraint::Definite)
.unwrap_or_default()
}
}
#[derive(Clone, Default)]
pub(crate) struct Sizes {
/// <https://drafts.csswg.org/css-sizing-3/#preferred-size-properties>

View file

@ -109,12 +109,14 @@ impl From<Au> for ContentSizes {
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn outer_inline(
style: &ComputedValues,
containing_block: &IndefiniteContainingBlock,
auto_minimum: &LogicalVec2<Au>,
auto_block_size_stretches_to_containing_block: bool,
is_table: bool,
establishes_containing_block: bool,
get_preferred_aspect_ratio: impl FnOnce(&LogicalVec2<Au>) -> Option<AspectRatio>,
get_content_size: impl FnOnce(&ConstraintSpace) -> InlineContentSizesResult,
) -> InlineContentSizesResult {
@ -129,6 +131,7 @@ pub(crate) fn outer_inline(
inline: pbm.padding_border_sums.inline + margin.inline_sum(),
};
let content_size = LazyCell::new(|| {
let constraint_space = if establishes_containing_block {
let available_block_size = containing_block
.size
.block
@ -142,7 +145,7 @@ pub(crate) fn outer_inline(
} else {
Size::FitContent
};
get_content_size(&ConstraintSpace::new(
ConstraintSpace::new(
content_box_sizes.block.resolve_extrinsic(
automatic_size,
auto_minimum.block,
@ -150,7 +153,18 @@ pub(crate) fn outer_inline(
),
style.writing_mode,
get_preferred_aspect_ratio(&pbm.padding_border_sums),
))
)
} else {
// This assumes that there is no preferred aspect ratio, or that there is no
// block size constraint to be transferred so the ratio is irrelevant.
// We only get into here for anonymous blocks, for which the assumption holds.
ConstraintSpace::new(
containing_block.size.block.into(),
containing_block.writing_mode,
None,
)
};
get_content_size(&constraint_space)
});
let resolve_non_initial = |inline_size| {
Some(match inline_size {

View file

@ -81587,6 +81587,19 @@
{}
]
],
"intrinsic-size-with-anonymous-block.html": [
"5ddcefbbe1d8e133a80a06e6fb6c3115e886bd89",
[
null,
[
[
"/css/CSS2/reference/ref-filled-green-100px-square.xht",
"=="
]
],
{}
]
],
"intrinsic-size-with-negative-margins.html": [
"93dfc3dfd770be960eec71bc00082a04e7385e97",
[

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<title>Intrinsic size of an atomic inline with an anonymous block</title>
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#inlineblock-width">
<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width">
<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#anonymous-block-level">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<meta name="assert" content="
#test contains both inline-level contents (the canvas) and block-level (the <p>).
Then the canvas is wrapped inside an anonymous block, but it still resolves its percentage against #test.
So the canvas is 100px tall, and thus 100px wide because of its aspect ratio.
Therefore #test is 100px wide too.
">
<style>
#test {
display: inline-block;
height: 100px;
background: green;
}
#test > canvas {
height: 100%;
background: red;
position: relative;
z-index: -1;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div id="test">
<canvas width="10" height="10"></canvas>
<p></p>
</div>