Implement gaps in flexbox layout (#32891)

As per https://drafts.csswg.org/css-align/#gaps

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Oriol Brufau 2024-07-31 09:25:54 +02:00 committed by GitHub
parent f86493cd7e
commit ca6169990e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 44 additions and 46 deletions

View file

@ -19,6 +19,7 @@ use style::properties::ComputedValues;
use style::values::computed::length::Size; use style::values::computed::length::Size;
use style::values::computed::Length; use style::values::computed::Length;
use style::values::generics::flex::GenericFlexBasis as FlexBasis; use style::values::generics::flex::GenericFlexBasis as FlexBasis;
use style::values::generics::length::LengthPercentageOrNormal;
use style::values::specified::align::AlignFlags; use style::values::specified::align::AlignFlags;
use style::Zero; use style::Zero;
@ -299,16 +300,37 @@ impl FlexContainer {
}, },
}; };
let row_gap = container_style.clone_row_gap();
let column_gap = container_style.clone_column_gap();
let (cross_gap, main_gap) = match flex_context.flex_axis {
FlexAxis::Row => (row_gap, column_gap),
FlexAxis::Column => (column_gap, row_gap),
};
let cross_gap = match cross_gap {
LengthPercentageOrNormal::LengthPercentage(length_percent) => length_percent
.maybe_to_used_value(flex_context.container_definite_inner_size.cross)
.unwrap_or_default(),
LengthPercentageOrNormal::Normal => Au::zero(),
};
let main_gap = match main_gap {
LengthPercentageOrNormal::LengthPercentage(length_percent) => length_percent
.maybe_to_used_value(flex_context.container_definite_inner_size.main)
.unwrap_or_default(),
LengthPercentageOrNormal::Normal => Au::zero(),
};
// “Resolve the flexible lengths of all the flex items to find their *used main size*.” // “Resolve the flexible lengths of all the flex items to find their *used main size*.”
// https://drafts.csswg.org/css-flexbox/#algo-flex // https://drafts.csswg.org/css-flexbox/#algo-flex
let flex_lines = collect_flex_lines( let flex_lines = collect_flex_lines(
&mut flex_context, &mut flex_context,
container_main_size, container_main_size,
&mut flex_items, &mut flex_items,
|flex_context, mut line| line.layout(flex_context, container_main_size), main_gap,
); );
let content_cross_size = flex_lines.iter().map(|line| line.cross_size).sum(); let line_count = flex_lines.len();
let content_cross_size = flex_lines.iter().map(|line| line.cross_size).sum::<Au>() +
cross_gap * (line_count as i32 - 1);
// https://drafts.csswg.org/css-flexbox/#algo-cross-container // https://drafts.csswg.org/css-flexbox/#algo-cross-container
let container_cross_size = flex_context let container_cross_size = flex_context
@ -322,9 +344,8 @@ impl FlexContainer {
// https://drafts.csswg.org/css-flexbox/#algo-line-align // https://drafts.csswg.org/css-flexbox/#algo-line-align
// Align all flex lines per `align-content`. // Align all flex lines per `align-content`.
let line_count = flex_lines.len();
let mut cross_start_position_cursor = Au::zero(); let mut cross_start_position_cursor = Au::zero();
let mut line_interval = Au::zero(); let mut line_interval = cross_gap;
if let Some(cross_size) = flex_context.container_definite_inner_size.cross { if let Some(cross_size) = flex_context.container_definite_inner_size.cross {
let free_space = cross_size - content_cross_size; let free_space = cross_size - content_cross_size;
@ -391,8 +412,7 @@ impl FlexContainer {
_ => Au::zero(), _ => Au::zero(),
}; };
// TODO: Implement gap property line_interval += match resolved_align_content {
line_interval = /*gap + */ match resolved_align_content {
AlignFlags::START => Au::zero(), AlignFlags::START => Au::zero(),
AlignFlags::FLEX_START => Au::zero(), AlignFlags::FLEX_START => Au::zero(),
AlignFlags::END => Au::zero(), AlignFlags::END => Au::zero(),
@ -791,17 +811,17 @@ fn collect_flex_lines<'items>(
flex_context: &mut FlexContext, flex_context: &mut FlexContext,
container_main_size: Au, container_main_size: Au,
mut items: &'items mut [FlexItem<'items>], mut items: &'items mut [FlexItem<'items>],
mut each: impl FnMut(&mut FlexContext, FlexLine<'items>) -> FlexLineLayoutResult, main_gap: Au,
) -> Vec<FlexLineLayoutResult> { ) -> Vec<FlexLineLayoutResult> {
if flex_context.container_is_single_line { if flex_context.container_is_single_line {
let line = FlexLine { let mut line = FlexLine {
outer_hypothetical_main_sizes_sum: items outer_hypothetical_main_sizes_sum: items
.iter() .iter()
.map(|item| item.hypothetical_main_size + item.pbm_auto_is_zero.main) .map(|item| item.hypothetical_main_size + item.pbm_auto_is_zero.main)
.sum(), .sum(),
items, items,
}; };
vec![each(flex_context, line)] vec![line.layout(flex_context, container_main_size, main_gap)]
} else { } else {
let mut lines = Vec::new(); let mut lines = Vec::new();
let mut line_size_so_far = Au::zero(); let mut line_size_so_far = Au::zero();
@ -809,7 +829,10 @@ fn collect_flex_lines<'items>(
let mut index = 0; let mut index = 0;
while let Some(item) = items.get(index) { while let Some(item) = items.get(index) {
let item_size = item.hypothetical_main_size + item.pbm_auto_is_zero.main; let item_size = item.hypothetical_main_size + item.pbm_auto_is_zero.main;
let line_size_would_be = line_size_so_far + item_size; let mut line_size_would_be = line_size_so_far + item_size;
if !line_so_far_is_empty {
line_size_would_be += main_gap;
}
let item_fits = line_size_would_be <= container_main_size; let item_fits = line_size_would_be <= container_main_size;
if item_fits || line_so_far_is_empty { if item_fits || line_so_far_is_empty {
line_size_so_far = line_size_would_be; line_size_so_far = line_size_would_be;
@ -818,23 +841,23 @@ fn collect_flex_lines<'items>(
} else { } else {
// We found something that doesnt fit. This line ends *before* this item. // We found something that doesnt fit. This line ends *before* this item.
let (line_items, rest) = items.split_at_mut(index); let (line_items, rest) = items.split_at_mut(index);
let line = FlexLine { let mut line = FlexLine {
items: line_items, items: line_items,
outer_hypothetical_main_sizes_sum: line_size_so_far, outer_hypothetical_main_sizes_sum: line_size_so_far,
}; };
items = rest; items = rest;
lines.push(each(flex_context, line)); lines.push(line.layout(flex_context, container_main_size, main_gap));
// The next line has this item. // The next line has this item.
line_size_so_far = item_size; line_size_so_far = item_size;
index = 1; index = 1;
} }
} }
// The last line is added even without finding an item that doesnt fit // The last line is added even without finding an item that doesnt fit
let line = FlexLine { let mut line = FlexLine {
items, items,
outer_hypothetical_main_sizes_sum: line_size_so_far, outer_hypothetical_main_sizes_sum: line_size_so_far,
}; };
lines.push(each(flex_context, line)); lines.push(line.layout(flex_context, container_main_size, main_gap));
lines lines
} }
} }
@ -844,9 +867,11 @@ impl FlexLine<'_> {
&mut self, &mut self,
flex_context: &mut FlexContext, flex_context: &mut FlexContext,
container_main_size: Au, container_main_size: Au,
main_gap: Au,
) -> FlexLineLayoutResult { ) -> FlexLineLayoutResult {
let item_count = self.items.len();
let (item_used_main_sizes, mut free_space) = let (item_used_main_sizes, mut free_space) =
self.resolve_flexible_lengths(container_main_size); self.resolve_flexible_lengths(container_main_size - main_gap * (item_count as i32 - 1));
// https://drafts.csswg.org/css-flexbox/#algo-cross-item // https://drafts.csswg.org/css-flexbox/#algo-cross-item
let mut item_layout_results = self let mut item_layout_results = self
@ -873,7 +898,6 @@ impl FlexLine<'_> {
// Determine the used cross size of each flex item // Determine the used cross size of each flex item
// https://drafts.csswg.org/css-flexbox/#algo-stretch // https://drafts.csswg.org/css-flexbox/#algo-stretch
let item_count = self.items.len();
let mut shared_alignment_baseline = None; let mut shared_alignment_baseline = None;
let mut item_used_cross_sizes = Vec::with_capacity(item_count); let mut item_used_cross_sizes = Vec::with_capacity(item_count);
let mut item_cross_margins = Vec::with_capacity(item_count); let mut item_cross_margins = Vec::with_capacity(item_count);
@ -999,8 +1023,7 @@ impl FlexLine<'_> {
_ => Au::zero(), _ => Au::zero(),
}; };
// TODO: Implement gap property let item_main_interval = match resolved_justify_content {
let item_main_interval = /*gap + */ match resolved_justify_content {
AlignFlags::START => Au::zero(), AlignFlags::START => Au::zero(),
AlignFlags::FLEX_START => Au::zero(), AlignFlags::FLEX_START => Au::zero(),
AlignFlags::END => Au::zero(), AlignFlags::END => Au::zero(),
@ -1014,6 +1037,7 @@ impl FlexLine<'_> {
// TODO: Implement all alignments. Note: not all alignment values are valid for content distribution // TODO: Implement all alignments. Note: not all alignment values are valid for content distribution
_ => Au::zero(), _ => Au::zero(),
}; };
let item_main_interval = item_main_interval + main_gap;
let mut all_baselines = Baselines::default(); let mut all_baselines = Baselines::default();
let mut main_position_cursor = main_start_position; let mut main_position_cursor = main_start_position;

View file

@ -5,12 +5,6 @@
[.target > * 7] [.target > * 7]
expected: FAIL expected: FAIL
[.target > * 9]
expected: FAIL
[.target > * 11]
expected: FAIL
[.target > * 13] [.target > * 13]
expected: FAIL expected: FAIL

View file

@ -1,2 +0,0 @@
[flexbox-column-row-gap-003.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[flexbox-gap-position-absolute.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-001-lr.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-001-ltr.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-001-rl.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-001-rtl.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-004-lr.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-004-ltr.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-004-rl.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-004-rtl.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-011.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[gap-013.html]
expected: FAIL