diff options
author | Pu Xingyu <pu.stshine@gmail.com> | 2023-05-05 23:14:38 +0800 |
---|---|---|
committer | Pu Xingyu <pu.stshine@gmail.com> | 2023-05-10 19:06:52 +0800 |
commit | debcd30b21e86bc4e6597fd029e498e8668ef529 (patch) | |
tree | deba13d0f2d8aaaeecc303afbc1dce50c270a18f /components/layout_2020/flexbox/layout.rs | |
parent | f29834608aee21c1845737067c16f92adfb77f08 (diff) | |
download | servo-debcd30b21e86bc4e6597fd029e498e8668ef529.tar.gz servo-debcd30b21e86bc4e6597fd029e498e8668ef529.zip |
layout 2020: Implement justify-content in flexbox
Align the items along the main-axis per justify-content.
Diffstat (limited to 'components/layout_2020/flexbox/layout.rs')
-rw-r--r-- | components/layout_2020/flexbox/layout.rs | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index b6f450ac046..ff46826bd84 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -22,9 +22,11 @@ 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::flex_direction::computed_value::T as FlexDirection; use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap; +use style::properties::longhands::justify_content::computed_value::T as JustifyContent; use style::values::computed::length::Size; use style::values::computed::Length; use style::values::generics::flex::GenericFlexBasis as FlexBasis; +use style::values::CSSFloat; use style::Zero; // FIMXE: “Flex items […] `z-index` values other than `auto` create a stacking context @@ -45,6 +47,7 @@ struct FlexContext<'a> { main_start_cross_start_sides_are: MainStartCrossStart, container_definite_inner_size: FlexRelativeVec2<Option<Length>>, align_items: AlignItems, + justify_content: JustifyContent, } /// A flex item with some intermediate results @@ -259,6 +262,7 @@ fn layout<'context, 'boxes>( FlexWrap::WrapReverse => true, }; let align_items = containing_block.style.clone_align_items(); + let justify_content = containing_block.style.clone_justify_content(); let mut flex_context = FlexContext { layout_context, @@ -269,6 +273,7 @@ fn layout<'context, 'boxes>( container_is_single_line, flex_axis, align_items, + justify_content, main_start_cross_start_sides_are: MainStartCrossStart::from( flex_direction, flex_wrap_reverse, @@ -669,10 +674,37 @@ impl FlexLine<'_> { // Distribute any remaining free space // https://drafts.csswg.org/css-flexbox/#algo-main-align - let item_main_margins = self.resolve_auto_main_margins(remaining_free_space); + let (item_main_margins, free_space_distributed) = + self.resolve_auto_main_margins(remaining_free_space); - // FIXME: “Align the items along the main-axis per justify-content.” - // For now we hard-code `justify-content` to `flex-start`. + // Align the items along the main-axis per justify-content. + let item_count = self.items.len(); + let main_start_position = if free_space_distributed { + Length::zero() + } else { + match flex_context.justify_content { + JustifyContent::FlexEnd => remaining_free_space, + JustifyContent::Center => remaining_free_space / 2.0, + JustifyContent::SpaceAround => remaining_free_space / (item_count * 2) as CSSFloat, + _ => Length::zero(), + } + }; + + let item_main_interval = if free_space_distributed { + Length::zero() + } else { + match flex_context.justify_content { + JustifyContent::SpaceBetween => { + if item_count > 1 { + remaining_free_space / (item_count - 1) as CSSFloat + } else { + Length::zero() + } + }, + JustifyContent::SpaceAround => remaining_free_space / item_count as CSSFloat, + _ => Length::zero(), + } + }; // https://drafts.csswg.org/css-flexbox/#algo-cross-margins let item_cross_margins = self.items.iter().zip(&item_used_cross_sizes).map( @@ -697,8 +729,12 @@ impl FlexLine<'_> { ) .collect::<Vec<_>>(); // https://drafts.csswg.org/css-flexbox/#algo-main-align - let items_content_main_start_positions = - self.align_along_main_axis(&item_used_main_sizes, &item_margins); + let items_content_main_start_positions = self.align_along_main_axis( + &item_used_main_sizes, + &item_margins, + main_start_position, + item_main_interval, + ); // https://drafts.csswg.org/css-flexbox/#algo-cross-align let item_content_cross_start_posititons = self @@ -1029,11 +1065,12 @@ impl<'items> FlexLine<'items> { } // Return the main-start and main-end margin of each item in the line, - // with `auto` values resolved. + // with `auto` values resolved, + // and return whether free space has been distributed. fn resolve_auto_main_margins( &self, remaining_free_space: Length, - ) -> impl Iterator<Item = (Length, Length)> + '_ { + ) -> (impl Iterator<Item = (Length, Length)> + '_, bool) { let each_auto_margin = if remaining_free_space > Length::zero() { let auto_margins_count = self .items @@ -1050,12 +1087,15 @@ impl<'items> FlexLine<'items> { } else { Length::zero() }; - self.items.iter().map(move |item| { - ( - item.margin.main_start.auto_is(|| each_auto_margin), - item.margin.main_end.auto_is(|| each_auto_margin), - ) - }) + ( + self.items.iter().map(move |item| { + ( + item.margin.main_start.auto_is(|| each_auto_margin), + item.margin.main_end.auto_is(|| each_auto_margin), + ) + }), + each_auto_margin > Length::zero(), + ) } /// Return the coordinate of the main-start side of the content area of each item @@ -1063,11 +1103,11 @@ impl<'items> FlexLine<'items> { &'a self, item_used_main_sizes: &'a [Length], item_margins: &'a [FlexRelativeSides<Length>], + main_start_position: Length, + item_main_interval: Length, ) -> impl Iterator<Item = Length> + 'a { // “Align the items along the main-axis” - // FIXME: “per justify-content.” - // For now we hard-code the behavior for `justify-content: flex-start`. - let mut main_position_cursor = Length::zero(); + let mut main_position_cursor = main_start_position; self.items .iter() .zip(item_used_main_sizes) @@ -1079,7 +1119,8 @@ impl<'items> FlexLine<'items> { main_position_cursor += main_content_size + item.padding.main_end + item.border.main_end + - margin.main_end; + margin.main_end + + item_main_interval; content_main_start_position }) } |