Implement keyword sizes for intrinsic contributions (#33854)

Correctly handle keyword sizes when computing the min-content or
max-content contribution of a box.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2024-10-26 11:15:19 +02:00 committed by GitHub
parent 831a65917a
commit faeb31d6c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 209 additions and 42 deletions

View file

@ -4,6 +4,7 @@
//! <https://drafts.csswg.org/css-sizing/>
use std::cell::LazyCell;
use std::ops::{Add, AddAssign};
use app_units::Au;
@ -11,7 +12,8 @@ use serde::Serialize;
use style::properties::ComputedValues;
use style::Zero;
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated};
use crate::geom::Size;
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
use crate::{AuOrAuto, IndefiniteContainingBlock, LogicalVec2};
#[derive(PartialEq)]
@ -120,52 +122,100 @@ pub(crate) fn outer_inline(
auto_block_size_stretches_to_containing_block: bool,
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> InlineContentSizesResult,
) -> InlineContentSizesResult {
let ContentBoxSizesAndPBMDeprecated {
let ContentBoxSizesAndPBM {
content_box_size,
content_min_box_size,
content_max_box_size,
pbm,
mut depends_on_block_constraints,
} = style
.content_box_sizes_and_padding_border_margin(containing_block)
.into();
let content_box_min_size = LogicalVec2 {
inline: content_min_box_size.inline.auto_is(|| auto_minimum.inline),
block: content_min_box_size.block.auto_is(|| auto_minimum.block),
};
} = style.content_box_sizes_and_padding_border_margin(containing_block);
let margin = pbm.margin.map(|v| v.auto_is(Au::zero));
let pbm_inline_sum = pbm.padding_border_sums.inline + margin.inline_sum();
let adjust = |v: Au| {
v.clamp_between_extremums(content_box_min_size.inline, content_max_box_size.inline) +
pbm_inline_sum
let pbm_sums = LogicalVec2 {
block: pbm.padding_border_sums.block + margin.block_sum(),
inline: pbm.padding_border_sums.inline + margin.inline_sum(),
};
match content_box_size.inline {
AuOrAuto::LengthPercentage(inline_size) => InlineContentSizesResult {
sizes: adjust(inline_size).into(),
depends_on_block_constraints: false,
},
AuOrAuto::Auto => {
let block_size = if content_box_size.block.is_auto() &&
auto_block_size_stretches_to_containing_block
{
depends_on_block_constraints = true;
let outer_block_size = containing_block.size.block;
outer_block_size.map(|v| v - pbm.padding_border_sums.block - margin.block_sum())
} else {
content_box_size.block
}
.map(|v| {
v.clamp_between_extremums(content_box_min_size.block, content_max_box_size.block)
});
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size);
let content_result = get_content_size(&containing_block_for_children);
InlineContentSizesResult {
sizes: content_result.sizes.map(adjust),
depends_on_block_constraints: content_result.depends_on_block_constraints &&
let content_size = LazyCell::new(|| {
let available_block_size = containing_block
.size
.block
.non_auto()
.map(|v| Au::zero().max(v - pbm_sums.block));
let block_size = if content_box_size.block.is_initial() &&
auto_block_size_stretches_to_containing_block
{
depends_on_block_constraints = true;
available_block_size
} else {
content_box_size
.block
.maybe_resolve_extrinsic(available_block_size)
}
.map(|block_size| {
let min_block_size = content_min_box_size
.block
.maybe_resolve_extrinsic(available_block_size)
.unwrap_or(auto_minimum.block);
let max_block_size = content_max_box_size
.block
.maybe_resolve_extrinsic(available_block_size);
block_size.clamp_between_extremums(min_block_size, max_block_size)
})
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
let containing_block_for_children =
IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size);
get_content_size(&containing_block_for_children)
});
let resolve_non_initial = |inline_size| {
Some(match inline_size {
Size::Initial => return None,
Size::Numeric(numeric) => (numeric, numeric, false),
Size::MinContent => (
content_size.sizes.min_content,
content_size.sizes.min_content,
content_size.depends_on_block_constraints,
),
Size::MaxContent => (
content_size.sizes.max_content,
content_size.sizes.max_content,
content_size.depends_on_block_constraints,
),
Size::Stretch | Size::FitContent => (
content_size.sizes.min_content,
content_size.sizes.max_content,
content_size.depends_on_block_constraints,
),
})
};
let (preferred_min_content, preferred_max_content, preferred_depends_on_block_constraints) =
resolve_non_initial(content_box_size.inline)
.unwrap_or_else(|| resolve_non_initial(Size::FitContent).unwrap());
let (min_min_content, min_max_content, min_depends_on_block_constraints) = resolve_non_initial(
content_min_box_size.inline,
)
.unwrap_or((auto_minimum.inline, auto_minimum.inline, false));
let (max_min_content, max_max_content, max_depends_on_block_constraints) =
resolve_non_initial(content_max_box_size.inline)
.map(|(min_content, max_content, depends_on_block_constraints)| {
(
Some(min_content),
Some(max_content),
depends_on_block_constraints,
}
)
})
.unwrap_or_default();
InlineContentSizesResult {
sizes: ContentSizes {
min_content: preferred_min_content
.clamp_between_extremums(min_min_content, max_min_content) +
pbm_sums.inline,
max_content: preferred_max_content
.clamp_between_extremums(min_max_content, max_max_content) +
pbm_sums.inline,
},
depends_on_block_constraints: depends_on_block_constraints &&
(preferred_depends_on_block_constraints ||
min_depends_on_block_constraints ||
max_depends_on_block_constraints),
}
}