layout_2020: Implement align-content in flexbox

Align all flex lines per `align-content`.
This commit is contained in:
Pu Xingyu 2023-05-11 00:38:38 +08:00
parent 03574d8191
commit 4a65dd0425
2 changed files with 36 additions and 10 deletions

View file

@ -17,6 +17,7 @@ use crate::style_ext::ComputedValuesExt;
use crate::ContainingBlock; use crate::ContainingBlock;
use atomic_refcell::AtomicRefMut; use atomic_refcell::AtomicRefMut;
use std::cell::Cell; use std::cell::Cell;
use style::properties::longhands::align_content::computed_value::T as AlignContent;
use style::properties::longhands::align_items::computed_value::T as AlignItems; use style::properties::longhands::align_items::computed_value::T as AlignItems;
use style::properties::longhands::align_self::computed_value::T as AlignSelf; use style::properties::longhands::align_self::computed_value::T as AlignSelf;
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing; use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
@ -46,6 +47,7 @@ struct FlexContext<'a> {
flex_axis: FlexAxis, flex_axis: FlexAxis,
main_start_cross_start_sides_are: MainStartCrossStart, main_start_cross_start_sides_are: MainStartCrossStart,
container_definite_inner_size: FlexRelativeVec2<Option<Length>>, container_definite_inner_size: FlexRelativeVec2<Option<Length>>,
align_content: AlignContent,
align_items: AlignItems, align_items: AlignItems,
justify_content: JustifyContent, justify_content: JustifyContent,
} }
@ -261,6 +263,7 @@ fn layout<'context, 'boxes>(
FlexWrap::Nowrap | FlexWrap::Wrap => false, FlexWrap::Nowrap | FlexWrap::Wrap => false,
FlexWrap::WrapReverse => true, FlexWrap::WrapReverse => true,
}; };
let align_content = containing_block.style.clone_align_content();
let align_items = containing_block.style.clone_align_items(); let align_items = containing_block.style.clone_align_items();
let justify_content = containing_block.style.clone_justify_content(); let justify_content = containing_block.style.clone_justify_content();
@ -272,6 +275,7 @@ fn layout<'context, 'boxes>(
container_max_cross_size, container_max_cross_size,
container_is_single_line, container_is_single_line,
flex_axis, flex_axis,
align_content,
align_items, align_items,
justify_content, justify_content,
main_start_cross_start_sides_are: MainStartCrossStart::from( main_start_cross_start_sides_are: MainStartCrossStart::from(
@ -315,30 +319,51 @@ fn layout<'context, 'boxes>(
|flex_context, mut line| line.layout(flex_context, container_main_size), |flex_context, mut line| line.layout(flex_context, container_main_size),
); );
let content_cross_size = flex_lines
.iter()
.map(|line| line.cross_size)
.sum::<Length>();
// 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
.container_definite_inner_size .container_definite_inner_size
.cross .cross
.unwrap_or_else(|| { .unwrap_or(content_cross_size)
flex_lines
.iter()
.map(|line| line.cross_size)
.sum::<Length>()
})
.clamp_between_extremums( .clamp_between_extremums(
flex_context.container_min_cross_size, flex_context.container_min_cross_size,
flex_context.container_max_cross_size, flex_context.container_max_cross_size,
); );
// 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`.
let line_count = flex_lines.len();
let mut cross_start_position_cursor = Length::zero(); let mut cross_start_position_cursor = Length::zero();
let line_interval = match flex_context.container_definite_inner_size.cross {
Some(cross_size) if line_count >= 2 => {
let free_space = cross_size - content_cross_size;
cross_start_position_cursor = match flex_context.align_content {
AlignContent::Center => free_space / 2.0,
AlignContent::SpaceAround => free_space / (line_count * 2) as CSSFloat,
AlignContent::FlexEnd => free_space,
_ => Length::zero(),
};
match flex_context.align_content {
AlignContent::SpaceBetween => free_space / (line_count - 1) as CSSFloat,
AlignContent::SpaceAround => free_space / line_count as CSSFloat,
_ => Length::zero(),
}
},
_ => Length::zero(),
};
let line_cross_start_positions = flex_lines let line_cross_start_positions = flex_lines
.iter() .iter()
.map(|line| { .map(|line| {
// FIXME: “Align all flex lines per `align-content`.”
// For now we hard-code the behavior of `align-content: flex-start`.
let cross_start = cross_start_position_cursor; let cross_start = cross_start_position_cursor;
let cross_end = cross_start + line.cross_size; let cross_end = cross_start + line.cross_size + line_interval;
cross_start_position_cursor = cross_end; cross_start_position_cursor = cross_end;
cross_start cross_start
}) })

View file

@ -134,7 +134,8 @@ ${helpers.single_keyword(
${helpers.single_keyword( ${helpers.single_keyword(
"align-content", "align-content",
"stretch flex-start flex-end center space-between space-around", "stretch flex-start flex-end center space-between space-around",
engines="servo-2013", engines="servo-2013 servo-2020",
servo_2020_pref="layout.flexbox.enabled",
extra_prefixes="webkit", extra_prefixes="webkit",
spec="https://drafts.csswg.org/css-align/#propdef-align-content", spec="https://drafts.csswg.org/css-align/#propdef-align-content",
animation_value_type="discrete", animation_value_type="discrete",