Flexbox: add align-self: stretch

This commit is contained in:
Simon Sapin 2020-06-23 00:30:58 +02:00
parent 01905923db
commit 3e13b3be80

View file

@ -603,17 +603,11 @@ impl FlexLine<'_> {
.items .items
.iter_mut() .iter_mut()
.zip(&item_used_main_sizes) .zip(&item_used_main_sizes)
.map(|(item, &used_main_size)| item.layout(used_main_size, flex_context)) .map(|(item, &used_main_size)| item.layout(used_main_size, flex_context, None))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let hypothetical_cross_sizes = || {
item_layout_results
.iter()
.map(|item_result| item_result.hypothetical_cross_size)
};
// https://drafts.csswg.org/css-flexbox/#algo-cross-line // https://drafts.csswg.org/css-flexbox/#algo-cross-line
let line_cross_size = self.cross_size(hypothetical_cross_sizes(), &flex_context); let line_cross_size = self.cross_size(&item_layout_results, &flex_context);
let line_size = FlexRelativeVec2 { let line_size = FlexRelativeVec2 {
main: container_main_size, main: container_main_size,
cross: line_cross_size, cross: line_cross_size,
@ -629,8 +623,34 @@ 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
// FIXME: Handle `align-self: stretch` // FIXME: For now we hard-code the behavior for `align-self: stretch`
let item_used_cross_sizes = hypothetical_cross_sizes().collect::<Vec<_>>(); let (item_used_cross_sizes, item_fragments): (Vec<_>, Vec<_>) = self
.items
.iter_mut()
.zip(item_layout_results)
.zip(&item_used_main_sizes)
.map(|((item, item_result), &used_main_size)| {
let has_stretch_auto = true; // FIXME: use the property
let cross_size = if has_stretch_auto &&
item.content_box_size.cross.is_auto() &&
!(item.margin.cross_start.is_auto() || item.margin.cross_end.is_auto())
{
(line_cross_size - item.pbm_auto_is_zero.cross).clamp_between_extremums(
item.content_min_size.cross,
item.content_max_size.cross,
)
} else {
item_result.hypothetical_cross_size
};
let fragments = if has_stretch_auto {
item.layout(used_main_size, flex_context, Some(cross_size))
.fragments
} else {
item_result.fragments
};
(cross_size, fragments)
})
.unzip();
// Distribute any remaining free space // Distribute any remaining free space
// https://drafts.csswg.org/css-flexbox/#algo-main-align // https://drafts.csswg.org/css-flexbox/#algo-main-align
@ -675,7 +695,7 @@ impl FlexLine<'_> {
let item_fragments = self let item_fragments = self
.items .items
.iter() .iter()
.zip(item_layout_results) .zip(item_fragments)
.zip( .zip(
item_used_main_sizes item_used_main_sizes
.iter() .iter()
@ -689,14 +709,14 @@ impl FlexLine<'_> {
.map(|(size, start_corner)| FlexRelativeRect { size, start_corner }), .map(|(size, start_corner)| FlexRelativeRect { size, start_corner }),
) )
.zip(&item_margins) .zip(&item_margins)
.map(|(((item, item_layout_result), content_rect), margin)| { .map(|(((item, fragments), content_rect), margin)| {
let content_rect = flex_context.rect_to_flow_relative(line_size, content_rect); let content_rect = flex_context.rect_to_flow_relative(line_size, content_rect);
let margin = flex_context.sides_to_flow_relative(*margin); let margin = flex_context.sides_to_flow_relative(*margin);
let collapsed_margin = CollapsedBlockMargins::from_margin(&margin); let collapsed_margin = CollapsedBlockMargins::from_margin(&margin);
BoxFragment::new( BoxFragment::new(
item.box_.tag(), item.box_.tag(),
item.box_.style().clone(), item.box_.style().clone(),
item_layout_result.fragments, fragments,
content_rect, content_rect,
flex_context.sides_to_flow_relative(item.padding), flex_context.sides_to_flow_relative(item.padding),
flex_context.sides_to_flow_relative(item.border), flex_context.sides_to_flow_relative(item.border),
@ -873,6 +893,7 @@ impl<'a> FlexItem<'a> {
&mut self, &mut self,
used_main_size: Length, used_main_size: Length,
flex_context: &mut FlexContext, flex_context: &mut FlexContext,
used_cross_size_override: Option<Length>,
) -> FlexItemLayoutResult { ) -> FlexItemLayoutResult {
match flex_context.flex_axis { match flex_context.flex_axis {
FlexAxis::Row => { FlexAxis::Row => {
@ -904,9 +925,13 @@ impl<'a> FlexItem<'a> {
} }
}, },
IndependentFormattingContext::NonReplaced(non_replaced) => { IndependentFormattingContext::NonReplaced(non_replaced) => {
let block_size = match used_cross_size_override {
Some(s) => LengthOrAuto::LengthPercentage(s),
None => self.content_box_size.cross,
};
let item_as_containing_block = ContainingBlock { let item_as_containing_block = ContainingBlock {
inline_size: used_main_size, inline_size: used_main_size,
block_size: self.content_box_size.cross, block_size,
style: &non_replaced.style, style: &non_replaced.style,
}; };
let IndependentLayout { let IndependentLayout {
@ -938,7 +963,7 @@ impl<'items> FlexLine<'items> {
/// https://drafts.csswg.org/css-flexbox/#algo-cross-line /// https://drafts.csswg.org/css-flexbox/#algo-cross-line
fn cross_size( fn cross_size(
&self, &self,
hypothetical_cross_sizes: impl Iterator<Item = Length>, item_layout_results: &[FlexItemLayoutResult],
flex_context: &FlexContext, flex_context: &FlexContext,
) -> Length { ) -> Length {
if flex_context.container_is_single_line { if flex_context.container_is_single_line {
@ -946,9 +971,13 @@ impl<'items> FlexLine<'items> {
return size; return size;
} }
} }
let outer_hypothetical_cross_sizes = hypothetical_cross_sizes let outer_hypothetical_cross_sizes =
.zip(&*self.items) item_layout_results
.map(|(hypothetical, item)| hypothetical + item.pbm_auto_is_zero.cross); .iter()
.zip(&*self.items)
.map(|(item_result, item)| {
item_result.hypothetical_cross_size + item.pbm_auto_is_zero.cross
});
// FIXME: add support for `align-self: baseline` // FIXME: add support for `align-self: baseline`
// and computing the baseline of flex items. // and computing the baseline of flex items.
// https://drafts.csswg.org/css-flexbox/#baseline-participation // https://drafts.csswg.org/css-flexbox/#baseline-participation
@ -1083,7 +1112,7 @@ impl FlexItem<'_> {
Length::zero() Length::zero()
} else { } else {
// FIXME: “Align all flex items along the cross-axis per `align-self`” // FIXME: “Align all flex items along the cross-axis per `align-self`”
// For now we hard-code the behavior of `flex-start`: // For now we hard-code the behavior of `stretch`:
Length::zero() Length::zero()
}; };
outer_cross_start + margin.cross_start + self.border.cross_start + self.padding.cross_start outer_cross_start + margin.cross_start + self.border.cross_start + self.padding.cross_start