mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: Support min/max cross keywords sizes in flexbox (#35860)
Adds support for min-content, max-content, fit-content and stretch on the min and max cross size properties of a flex item. With one exception: when resolving the main sizes, transferred cross minimums and maximums will still ignore keywords. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
56da4ad959
commit
c6527c4118
7 changed files with 79 additions and 214 deletions
|
@ -62,9 +62,7 @@ struct FlexContext<'a> {
|
|||
/// A flex item with some intermediate results
|
||||
struct FlexItem<'a> {
|
||||
box_: &'a FlexItemBox,
|
||||
content_cross_size: Size<Au>,
|
||||
content_min_size: FlexRelativeVec2<Au>,
|
||||
content_max_size: FlexRelativeVec2<Option<Au>>,
|
||||
content_cross_sizes: Sizes,
|
||||
padding: FlexRelativeSides<Au>,
|
||||
border: FlexRelativeSides<Au>,
|
||||
margin: FlexRelativeSides<AuOrAuto>,
|
||||
|
@ -84,6 +82,14 @@ struct FlexItem<'a> {
|
|||
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
||||
hypothetical_main_size: Au,
|
||||
|
||||
/// The used min main size of the flex item.
|
||||
/// <https://drafts.csswg.org/css-flexbox/#min-main-size-property>
|
||||
content_min_main_size: Au,
|
||||
|
||||
/// The used max main size of the flex item.
|
||||
/// <https://drafts.csswg.org/css-flexbox/#max-main-size-property>
|
||||
content_max_main_size: Option<Au>,
|
||||
|
||||
/// This is `align-self`, defaulting to `align-items` if `auto`
|
||||
align_self: AlignItems,
|
||||
|
||||
|
@ -1222,9 +1228,10 @@ impl<'a> FlexItem<'a> {
|
|||
|
||||
Self {
|
||||
box_,
|
||||
content_cross_size: flex_relative_content_box_size.cross,
|
||||
content_min_size: flex_relative_content_min_size,
|
||||
content_max_size: flex_relative_content_max_size,
|
||||
content_cross_sizes: match config.flex_axis {
|
||||
FlexAxis::Row => content_box_sizes.block,
|
||||
FlexAxis::Column => content_box_sizes.inline,
|
||||
},
|
||||
padding,
|
||||
border,
|
||||
margin,
|
||||
|
@ -1232,6 +1239,8 @@ impl<'a> FlexItem<'a> {
|
|||
flex_base_size,
|
||||
flex_base_size_is_definite,
|
||||
hypothetical_main_size,
|
||||
content_min_main_size: flex_relative_content_min_size.main,
|
||||
content_max_main_size: flex_relative_content_max_size.main,
|
||||
align_self,
|
||||
depends_on_block_constraints,
|
||||
preferred_aspect_ratio,
|
||||
|
@ -1242,7 +1251,7 @@ impl<'a> FlexItem<'a> {
|
|||
// Note this returns false for a `stretch` size, because that stretches to the
|
||||
// containing block, not to the flex line.
|
||||
// To be discussed in https://github.com/w3c/csswg-drafts/issues/11784.
|
||||
self.content_cross_size.is_initial() &&
|
||||
self.content_cross_sizes.preferred.is_initial() &&
|
||||
item_with_auto_cross_size_stretches_to_line_size(self.align_self, &self.margin)
|
||||
}
|
||||
}
|
||||
|
@ -1562,8 +1571,8 @@ impl InitialFlexLineLayout<'_> {
|
|||
let violation = |item: &FlexibleLengthResolutionItem| {
|
||||
let size = item.target_main_size.get();
|
||||
let clamped = size.clamp_between_extremums(
|
||||
item.item.content_min_size.main,
|
||||
item.item.content_max_size.main,
|
||||
item.item.content_min_main_size,
|
||||
item.item.content_max_main_size,
|
||||
);
|
||||
clamped - size
|
||||
};
|
||||
|
@ -1588,7 +1597,7 @@ impl InitialFlexLineLayout<'_> {
|
|||
// it’s a min violation.”
|
||||
for item in items.iter() {
|
||||
if violation(item) > Au::zero() {
|
||||
item.target_main_size.set(item.item.content_min_size.main);
|
||||
item.target_main_size.set(item.item.content_min_main_size);
|
||||
item.frozen.set(true);
|
||||
frozen_count += 1;
|
||||
}
|
||||
|
@ -1601,7 +1610,7 @@ impl InitialFlexLineLayout<'_> {
|
|||
// it’s a max violation.”
|
||||
for item in items.iter() {
|
||||
if violation(item) < Au::zero() {
|
||||
let Some(max_size) = item.item.content_max_size.main else {
|
||||
let Some(max_size) = item.item.content_max_main_size else {
|
||||
unreachable!()
|
||||
};
|
||||
item.target_main_size.set(max_size);
|
||||
|
@ -1697,9 +1706,21 @@ impl InitialFlexLineLayout<'_> {
|
|||
for item in self.items.iter_mut() {
|
||||
let stretches = item.item.stretches_to_line();
|
||||
let used_cross_size = if stretches {
|
||||
(final_line_cross_size - item.item.pbm_auto_is_zero.cross).clamp_between_extremums(
|
||||
item.item.content_min_size.cross,
|
||||
item.item.content_max_size.cross,
|
||||
let (axis, content_size) = match flex_context.config.flex_axis {
|
||||
FlexAxis::Row => (Direction::Block, item.layout_result.content_size.block),
|
||||
FlexAxis::Column => (Direction::Inline, item.layout_result.content_size.inline),
|
||||
};
|
||||
item.item.content_cross_sizes.resolve(
|
||||
axis,
|
||||
Size::Stretch,
|
||||
Au::zero(),
|
||||
Some(final_line_cross_size - item.item.pbm_auto_is_zero.cross),
|
||||
|| content_size.into(),
|
||||
// Tables have a special sizing in the block axis in that handles collapsed rows,
|
||||
// but it would prevent stretching. So we only recognize tables in the inline axis.
|
||||
// The interaction of collapsed table tracks and the flexbox algorithms is unclear,
|
||||
// see https://github.com/w3c/csswg-drafts/issues/11408.
|
||||
item.item.is_table() && axis == Direction::Inline,
|
||||
)
|
||||
} else {
|
||||
item.layout_result.hypothetical_cross_size
|
||||
|
@ -1909,11 +1930,10 @@ impl FlexItem<'_> {
|
|||
.block
|
||||
.to_definite()
|
||||
.map(|size| Au::zero().max(size - self.pbm_auto_is_zero.cross));
|
||||
SizeConstraint::new(
|
||||
self.content_cross_size
|
||||
.maybe_resolve_extrinsic(stretch_size),
|
||||
self.content_min_size.cross,
|
||||
self.content_max_size.cross,
|
||||
self.content_cross_sizes.resolve_extrinsic(
|
||||
Size::FitContent,
|
||||
Au::zero(),
|
||||
stretch_size,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
@ -1931,7 +1951,7 @@ impl FlexItem<'_> {
|
|||
};
|
||||
let stretch_size =
|
||||
Au::zero().max(containing_block.size.inline - self.pbm_auto_is_zero.cross);
|
||||
let content_size = LazyCell::new(|| {
|
||||
let get_content_size = || {
|
||||
let constraint_space = ConstraintSpace::new(
|
||||
SizeConstraint::Definite(used_main_size),
|
||||
item_writing_mode,
|
||||
|
@ -1940,13 +1960,15 @@ impl FlexItem<'_> {
|
|||
independent_formatting_context
|
||||
.inline_content_sizes(flex_context.layout_context, &constraint_space)
|
||||
.sizes
|
||||
});
|
||||
self.content_cross_size
|
||||
.resolve_for_preferred(automatic_size, Some(stretch_size), &content_size)
|
||||
.clamp_between_extremums(
|
||||
self.content_min_size.cross,
|
||||
self.content_max_size.cross,
|
||||
)
|
||||
};
|
||||
self.content_cross_sizes.resolve(
|
||||
Direction::Inline,
|
||||
automatic_size,
|
||||
Au::zero(),
|
||||
Some(stretch_size),
|
||||
get_content_size,
|
||||
self.is_table(),
|
||||
)
|
||||
});
|
||||
// The main size of a flex item is considered to be definite if its flex basis is definite
|
||||
// or the flex container has a definite main size.
|
||||
|
@ -1968,8 +1990,16 @@ impl FlexItem<'_> {
|
|||
let item_style = independent_formatting_context.style();
|
||||
match &independent_formatting_context.contents {
|
||||
IndependentFormattingContextContents::Replaced(replaced) => {
|
||||
let min_size = flex_axis.vec2_to_flow_relative(self.content_min_size);
|
||||
let max_size = flex_axis.vec2_to_flow_relative(self.content_max_size);
|
||||
let min_size = flex_axis.vec2_to_flow_relative(FlexRelativeVec2 {
|
||||
main: Size::Numeric(self.content_min_main_size),
|
||||
cross: self.content_cross_sizes.min,
|
||||
});
|
||||
let max_size = flex_axis.vec2_to_flow_relative(FlexRelativeVec2 {
|
||||
main: self
|
||||
.content_max_main_size
|
||||
.map_or(Size::Initial, Size::Numeric),
|
||||
cross: self.content_cross_sizes.max,
|
||||
});
|
||||
let size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
|
||||
containing_block,
|
||||
item_style,
|
||||
|
@ -1979,13 +2009,13 @@ impl FlexItem<'_> {
|
|||
block_size
|
||||
.to_definite()
|
||||
.map_or(Size::Initial, Size::Numeric),
|
||||
Size::Numeric(min_size.block),
|
||||
max_size.block.map_or(Size::Initial, Size::Numeric),
|
||||
min_size.block,
|
||||
max_size.block,
|
||||
),
|
||||
inline: &Sizes::new(
|
||||
Size::Numeric(inline_size),
|
||||
Size::Numeric(min_size.inline),
|
||||
max_size.inline.map_or(Size::Initial, Size::Numeric),
|
||||
min_size.inline,
|
||||
max_size.inline,
|
||||
),
|
||||
},
|
||||
Size::FitContent.into(),
|
||||
|
@ -2043,13 +2073,14 @@ impl FlexItem<'_> {
|
|||
.block
|
||||
.to_definite()
|
||||
.map(|size| Au::zero().max(size - self.pbm_auto_is_zero.cross));
|
||||
let content_size = LazyCell::new(|| content_block_size.into());
|
||||
self.content_cross_size
|
||||
.resolve_for_preferred(Size::FitContent, stretch_size, &content_size)
|
||||
.clamp_between_extremums(
|
||||
self.content_min_size.cross,
|
||||
self.content_max_size.cross,
|
||||
)
|
||||
self.content_cross_sizes.resolve(
|
||||
Direction::Block,
|
||||
Size::FitContent,
|
||||
Au::zero(),
|
||||
stretch_size,
|
||||
|| content_block_size.into(),
|
||||
self.is_table(),
|
||||
)
|
||||
};
|
||||
|
||||
let item_as_containing_block = ContainingBlock {
|
||||
|
@ -2278,6 +2309,14 @@ impl FlexItem<'_> {
|
|||
};
|
||||
outer_cross_start + margin.cross_start + self.border.cross_start + self.padding.cross_start
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_table(&self) -> bool {
|
||||
match &self.box_.independent_formatting_context.contents {
|
||||
IndependentFormattingContextContents::NonReplaced(content) => content.is_table(),
|
||||
IndependentFormattingContextContents::Replaced(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FlexItemBox {
|
||||
|
|
|
@ -53,24 +53,6 @@
|
|||
[.test 27]
|
||||
expected: FAIL
|
||||
|
||||
[.test 31]
|
||||
expected: FAIL
|
||||
|
||||
[.test 32]
|
||||
expected: FAIL
|
||||
|
||||
[.test 33]
|
||||
expected: FAIL
|
||||
|
||||
[.test 34]
|
||||
expected: FAIL
|
||||
|
||||
[.test 35]
|
||||
expected: FAIL
|
||||
|
||||
[.test 36]
|
||||
expected: FAIL
|
||||
|
||||
[.test 40]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -88,39 +70,3 @@
|
|||
|
||||
[.test 45]
|
||||
expected: FAIL
|
||||
|
||||
[.test 49]
|
||||
expected: FAIL
|
||||
|
||||
[.test 50]
|
||||
expected: FAIL
|
||||
|
||||
[.test 51]
|
||||
expected: FAIL
|
||||
|
||||
[.test 52]
|
||||
expected: FAIL
|
||||
|
||||
[.test 53]
|
||||
expected: FAIL
|
||||
|
||||
[.test 54]
|
||||
expected: FAIL
|
||||
|
||||
[.test 69]
|
||||
expected: FAIL
|
||||
|
||||
[.test 70]
|
||||
expected: FAIL
|
||||
|
||||
[.test 71]
|
||||
expected: FAIL
|
||||
|
||||
[.test 72]
|
||||
expected: FAIL
|
||||
|
||||
[.test 73]
|
||||
expected: FAIL
|
||||
|
||||
[.test 74]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,58 +1,4 @@
|
|||
[keyword-sizes-on-flex-item-002.html]
|
||||
[.test 10]
|
||||
expected: FAIL
|
||||
|
||||
[.test 11]
|
||||
expected: FAIL
|
||||
|
||||
[.test 12]
|
||||
expected: FAIL
|
||||
|
||||
[.test 13]
|
||||
expected: FAIL
|
||||
|
||||
[.test 14]
|
||||
expected: FAIL
|
||||
|
||||
[.test 15]
|
||||
expected: FAIL
|
||||
|
||||
[.test 16]
|
||||
expected: FAIL
|
||||
|
||||
[.test 17]
|
||||
expected: FAIL
|
||||
|
||||
[.test 18]
|
||||
expected: FAIL
|
||||
|
||||
[.test 19]
|
||||
expected: FAIL
|
||||
|
||||
[.test 20]
|
||||
expected: FAIL
|
||||
|
||||
[.test 21]
|
||||
expected: FAIL
|
||||
|
||||
[.test 22]
|
||||
expected: FAIL
|
||||
|
||||
[.test 23]
|
||||
expected: FAIL
|
||||
|
||||
[.test 24]
|
||||
expected: FAIL
|
||||
|
||||
[.test 25]
|
||||
expected: FAIL
|
||||
|
||||
[.test 26]
|
||||
expected: FAIL
|
||||
|
||||
[.test 27]
|
||||
expected: FAIL
|
||||
|
||||
[.test 31]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -71,24 +17,6 @@
|
|||
[.test 36]
|
||||
expected: FAIL
|
||||
|
||||
[.test 40]
|
||||
expected: FAIL
|
||||
|
||||
[.test 41]
|
||||
expected: FAIL
|
||||
|
||||
[.test 42]
|
||||
expected: FAIL
|
||||
|
||||
[.test 43]
|
||||
expected: FAIL
|
||||
|
||||
[.test 44]
|
||||
expected: FAIL
|
||||
|
||||
[.test 45]
|
||||
expected: FAIL
|
||||
|
||||
[.test 49]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,24 +2,12 @@
|
|||
[[data-expected-height\] 8]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 19]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 22]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\]:not([skip-second-pass\]) 31]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\]:not([skip-second-pass\]) 42]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\]:not([skip-second-pass\]) 44]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\]:not([skip-second-pass\]) 45]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,24 +2,12 @@
|
|||
[[data-expected-width\] 8]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 20]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 22]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\]:not([skip-second-pass\]) 31]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\]:not([skip-second-pass\]) 43]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\]:not([skip-second-pass\]) 44]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\]:not([skip-second-pass\]) 45]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,29 +2,17 @@
|
|||
[[data-expected-height\] 8]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 19]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 20]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 22]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 31]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 42]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 43]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 44]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-height\] 45]
|
||||
expected: FAIL
|
||||
|
|
|
@ -5,12 +5,6 @@
|
|||
[[data-expected-width\] 19]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 20]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 21]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 22]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -20,11 +14,5 @@
|
|||
[[data-expected-width\] 42]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 43]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 44]
|
||||
expected: FAIL
|
||||
|
||||
[[data-expected-width\] 45]
|
||||
expected: FAIL
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue