diff options
author | Oriol Brufau <obrufau@igalia.com> | 2024-12-16 13:34:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-16 12:34:57 +0000 |
commit | eb82161a8ae503f3019098c3230e5b33b89ccb58 (patch) | |
tree | a2bfb7288326da4df789a5f85da5b91029f35a4a /components | |
parent | 6be403d8b46a6974ce79b52117339d10961047df (diff) | |
download | servo-eb82161a8ae503f3019098c3230e5b33b89ccb58.tar.gz servo-eb82161a8ae503f3019098c3230e5b33b89ccb58.zip |
Partial implementation of keyword sizes for block layout (#34568)
Adds support for min-content, max-content, fit-content and stretch,
for block-level elements that don't establish an independent formatting
context, and for block-level elements when there is no float.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Diffstat (limited to 'components')
-rw-r--r-- | components/layout_2020/flow/mod.rs | 159 |
1 files changed, 113 insertions, 46 deletions
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 0ff9da63274..e3a45b579b6 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -42,7 +42,8 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, Positioning use crate::replaced::ReplacedContents; use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; use crate::style_ext::{ - Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin, + Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, ContentBoxSizesAndPBMDeprecated, + PaddingBorderMargin, }; use crate::{ ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock, @@ -715,8 +716,7 @@ impl BlockLevelBox { layout_context, positioning_context, containing_block, - base.base_fragment_info, - &base.style, + base, contents, sequential_layout_state, collapsible_with_parent_start_margin, @@ -785,13 +785,17 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( layout_context: &LayoutContext, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, - mut base_fragment_info: BaseFragmentInfo, - style: &Arc<ComputedValues>, + base: &LayoutBoxBase, contents: &BlockContainer, mut sequential_layout_state: Option<&mut SequentialLayoutState>, collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>, ) -> BoxFragment { + let style = &base.style; let containing_block_writing_mode = containing_block.style.writing_mode; + let get_inline_content_sizes = |constraint_space: &ConstraintSpace| { + base.inline_content_sizes(layout_context, constraint_space, contents) + .sizes + }; let ContainingBlockPaddingAndBorder { containing_block: containing_block_for_children, pbm, @@ -799,7 +803,12 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( min_box_size, max_box_size, depends_on_block_constraints, - } = solve_containing_block_padding_and_border_for_in_flow_box(containing_block, style); + available_block_size, + } = solve_containing_block_padding_and_border_for_in_flow_box( + containing_block, + style, + get_inline_content_sizes, + ); let ResolvedMargins { margin, effective_margin_inline_start, @@ -933,10 +942,20 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( content_block_size += collapsible_margins_in_children.end.solve(); } - let block_size = box_size + let available_block_size = available_block_size.unwrap_or(content_block_size); + let block_content_sizes = LazyCell::new(|| content_block_size.into()); + let preferred_block_size = + box_size + .block + .resolve(Size::FitContent, available_block_size, &block_content_sizes); + let min_block_size = min_box_size + .block + .resolve_non_initial(available_block_size, &block_content_sizes) + .unwrap_or_default(); + let max_block_size = max_box_size .block - .auto_is(|| content_block_size) - .clamp_between_extremums(min_box_size.block, max_box_size.block); + .resolve_non_initial(available_block_size, &block_content_sizes); + let block_size = preferred_block_size.clamp_between_extremums(min_block_size, max_block_size); if let Some(ref mut sequential_layout_state) = sequential_layout_state { // Now that we're done laying out our children, we can restore the @@ -978,6 +997,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( }, }; + let mut base_fragment_info = base.base_fragment_info; if depends_on_block_constraints { base_fragment_info .flags @@ -1022,6 +1042,10 @@ impl IndependentNonReplacedContents { ); } + let get_inline_content_sizes = |constraint_space: &ConstraintSpace| { + base.inline_content_sizes(layout_context, constraint_space, self) + .sizes + }; let ContainingBlockPaddingAndBorder { containing_block: containing_block_for_children, pbm, @@ -1029,9 +1053,11 @@ impl IndependentNonReplacedContents { min_box_size, max_box_size, depends_on_block_constraints, + available_block_size, } = solve_containing_block_padding_and_border_for_in_flow_box( containing_block, &base.style, + get_inline_content_sizes, ); let layout = self.layout( @@ -1043,13 +1069,26 @@ impl IndependentNonReplacedContents { let (block_size, inline_size) = match layout.content_inline_size_for_table { Some(inline_size) => (layout.content_block_size, inline_size), - None => ( - box_size + None => { + let available_block_size = + available_block_size.unwrap_or(layout.content_block_size); + let block_content_sizes = LazyCell::new(|| layout.content_block_size.into()); + let preferred_block_size = box_size.block.resolve( + Size::FitContent, + available_block_size, + &block_content_sizes, + ); + let min_block_size = min_box_size .block - .auto_is(|| layout.content_block_size) - .clamp_between_extremums(min_box_size.block, max_box_size.block), - containing_block_for_children.size.inline, - ), + .resolve_non_initial(available_block_size, &block_content_sizes) + .unwrap_or_default(); + let max_block_size = max_box_size + .block + .resolve_non_initial(available_block_size, &block_content_sizes); + let block_size = + preferred_block_size.clamp_between_extremums(min_block_size, max_block_size); + (block_size, containing_block_for_children.size.inline) + }, }; let ResolvedMargins { @@ -1488,10 +1527,11 @@ impl ReplacedContents { struct ContainingBlockPaddingAndBorder<'a> { containing_block: ContainingBlock<'a>, pbm: PaddingBorderMargin, - box_size: LogicalVec2<AuOrAuto>, - min_box_size: LogicalVec2<Au>, - max_box_size: LogicalVec2<Option<Au>>, + box_size: LogicalVec2<Size<Au>>, + min_box_size: LogicalVec2<Size<Au>>, + max_box_size: LogicalVec2<Size<Au>>, depends_on_block_constraints: bool, + available_block_size: Option<Au>, } struct ResolvedMargins { @@ -1515,6 +1555,7 @@ struct ResolvedMargins { fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( containing_block: &ContainingBlock<'_>, style: &'a Arc<ComputedValues>, + get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes, ) -> ContainingBlockPaddingAndBorder<'a> { if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) { // <https://drafts.csswg.org/css2/#anonymous-block-level> @@ -1532,53 +1573,78 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( return ContainingBlockPaddingAndBorder { containing_block: containing_block_for_children, pbm: PaddingBorderMargin::zero(), - box_size: LogicalVec2 { - inline: AuOrAuto::Auto, - block: AuOrAuto::Auto, - }, + box_size: LogicalVec2::default(), min_box_size: LogicalVec2::default(), max_box_size: LogicalVec2::default(), depends_on_block_constraints: false, + // The available block size may actually be definite, but it should be irrelevant + // since the sizing properties are set to their initial value. + available_block_size: None, }; } - let ContentBoxSizesAndPBMDeprecated { + let ContentBoxSizesAndPBM { content_box_size, content_min_box_size, content_max_box_size, pbm, depends_on_block_constraints, - } = style - .content_box_sizes_and_padding_border_margin(&containing_block.into()) - .into(); - let content_min_box_size = content_min_box_size.auto_is(Au::zero); + } = style.content_box_sizes_and_padding_border_margin(&containing_block.into()); + + let margin = pbm.margin.auto_is(Au::zero); + let pbm_sums = pbm.padding + pbm.border + margin; + let writing_mode = style.writing_mode; + let available_inline_size = + Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum()); + let available_block_size = containing_block + .size + .block + .non_auto() + .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum())); + + // https://drafts.csswg.org/css2/#the-height-property + // https://drafts.csswg.org/css2/visudet.html#min-max-heights + let preferred_block_size = content_box_size + .block + .maybe_resolve_extrinsic(available_block_size); + let min_block_size = content_min_box_size + .block + .maybe_resolve_extrinsic(available_block_size) + .unwrap_or_default(); + let max_block_size = content_max_box_size + .block + .maybe_resolve_extrinsic(available_block_size); + let tentative_block_size = + SizeConstraint::new(preferred_block_size, min_block_size, max_block_size); // https://drafts.csswg.org/css2/#the-width-property // https://drafts.csswg.org/css2/visudet.html#min-max-widths - let inline_size = content_box_size + let inline_content_sizes = LazyCell::new(|| { + get_inline_content_sizes(&ConstraintSpace::new( + tentative_block_size, + writing_mode, + None, /* TODO: support preferred aspect ratios on non-replaced boxes */ + )) + }); + let preferred_inline_size = content_box_size.inline.resolve( + Size::Stretch, + available_inline_size, + &inline_content_sizes, + ); + let min_inline_size = content_min_box_size .inline - .auto_is(|| { - let margin_inline_start = pbm.margin.inline_start.auto_is(Au::zero); - let margin_inline_end = pbm.margin.inline_end.auto_is(Au::zero); - containing_block.size.inline - - pbm.padding_border_sums.inline - - margin_inline_start - - margin_inline_end - }) - .clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline); - - // https://drafts.csswg.org/css2/#the-height-property - // https://drafts.csswg.org/css2/visudet.html#min-max-heights - let mut block_size = content_box_size.block; - if let AuOrAuto::LengthPercentage(ref mut block_size) = block_size { - *block_size = block_size - .clamp_between_extremums(content_min_box_size.block, content_max_box_size.block); - } + .resolve_non_initial(available_inline_size, &inline_content_sizes) + .unwrap_or_default(); + let max_inline_size = content_max_box_size + .inline + .resolve_non_initial(available_inline_size, &inline_content_sizes); + let inline_size = + preferred_inline_size.clamp_between_extremums(min_inline_size, max_inline_size); let containing_block_for_children = ContainingBlock { size: ContainingBlockSize { inline: inline_size, - block: block_size, + block: tentative_block_size.to_auto_or(), }, style, }; @@ -1598,6 +1664,7 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>( min_box_size: content_min_box_size, max_box_size: content_max_box_size, depends_on_block_constraints, + available_block_size, } } |