aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorOriol Brufau <obrufau@igalia.com>2024-12-16 13:34:57 +0100
committerGitHub <noreply@github.com>2024-12-16 12:34:57 +0000
commiteb82161a8ae503f3019098c3230e5b33b89ccb58 (patch)
treea2bfb7288326da4df789a5f85da5b91029f35a4a /components
parent6be403d8b46a6974ce79b52117339d10961047df (diff)
downloadservo-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.rs159
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,
}
}