@@ -2,6 +2,40 @@ use crate::*;
22
33use float_pigment_css:: num_traits:: Zero ;
44
5+ /// Computes the total space taken up by gaps in an axis given:
6+ /// - The size of each gap
7+ /// - The number of items (children or flex-lines) between which there are gaps
8+ #[ inline( always) ]
9+ fn sum_axis_gaps < L : LengthNum > ( gap : L , num_items : usize ) -> L {
10+ if num_items <= 1 {
11+ L :: zero ( )
12+ } else {
13+ gap. mul_i32 ( num_items as i32 - 1 )
14+ }
15+ }
16+
17+ #[ inline( always) ]
18+ fn main_gap < T : LayoutTreeNode > (
19+ style : & T :: Style ,
20+ dir : AxisDirection ,
21+ ) -> DefLength < T :: Length , T :: LengthCustom > {
22+ match dir {
23+ AxisDirection :: Horizontal => style. row_gap ( ) ,
24+ AxisDirection :: Vertical => style. column_gap ( ) ,
25+ }
26+ }
27+
28+ #[ inline( always) ]
29+ fn cross_gap < T : LayoutTreeNode > (
30+ style : & T :: Style ,
31+ dir : AxisDirection ,
32+ ) -> DefLength < T :: Length , T :: LengthCustom > {
33+ match dir {
34+ AxisDirection :: Horizontal => style. column_gap ( ) ,
35+ AxisDirection :: Vertical => style. row_gap ( ) ,
36+ }
37+ }
38+
539pub ( crate ) fn align_self < T : LayoutTreeNode > ( child : & T :: Style , parent : & T :: Style ) -> AlignSelf {
640 let s = child. align_self ( ) ;
741 if s == AlignSelf :: Auto {
@@ -335,15 +369,24 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
335369 } ) ;
336370 } else {
337371 let mut flex_items = & mut flex_items[ ..] ;
372+ let main_axis_gap = main_gap :: < T > ( style, dir)
373+ . resolve ( requested_inner_size. main_size ( dir) , node)
374+ . or_zero ( ) ;
338375 while !flex_items. is_empty ( ) {
339376 let mut line_length = T :: Length :: zero ( ) ;
340377 let index = flex_items
341378 . iter ( )
342379 . enumerate ( )
343- . find ( |( idx, child) | {
344- line_length += child. hypothetical_outer_size . main_size ( dir) ;
380+ . find ( |& ( idx, child) | {
381+ let gap_contribution = if idx == 0 {
382+ T :: Length :: zero ( )
383+ } else {
384+ main_axis_gap
385+ } ;
386+ line_length +=
387+ child. hypothetical_outer_size . main_size ( dir) + gap_contribution;
345388 match available_space. main_size ( dir) . val ( ) {
346- Some ( x) => line_length > x && * idx != 0 ,
389+ Some ( x) => line_length > x && idx != 0 ,
347390 None => false ,
348391 }
349392 } )
@@ -369,16 +412,23 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
369412
370413 let multi_flex_line = flex_lines. len ( ) > 1 ;
371414 for line in & mut flex_lines {
415+ let total_main_axis_gap = sum_axis_gaps (
416+ main_gap :: < T > ( style, dir)
417+ . resolve ( requested_inner_size. main_size ( dir) , node)
418+ . or_zero ( ) ,
419+ line. items . len ( ) ,
420+ ) ;
372421 // 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
373422 // items on the line. If the sum is less than the flex container’s inner main size,
374423 // use the flex grow factor for the rest of this algorithm; otherwise, use the
375424 // flex shrink factor.
376425
377- let used_flex_factor: T :: Length = length_sum (
378- line. items
379- . iter ( )
380- . map ( |child| child. hypothetical_outer_size . main_size ( dir) ) ,
381- ) ;
426+ let used_flex_factor: T :: Length = total_main_axis_gap
427+ + length_sum (
428+ line. items
429+ . iter ( )
430+ . map ( |child| child. hypothetical_outer_size . main_size ( dir) ) ,
431+ ) ;
382432 let growing = used_flex_factor < requested_inner_size. main_size ( dir) . or_zero ( ) ;
383433 let shrinking = !growing;
384434
@@ -469,14 +519,15 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
469519 // and subtract this from the flex container’s inner main size. For frozen items,
470520 // use their outer target main size; for other items, use their outer flex base size.
471521
472- let used_space: T :: Length = length_sum ( line. items . iter ( ) . map ( |child| {
473- child. margin . main_axis_sum ( dir)
474- + if child. frozen {
475- child. target_size . main_size ( dir)
476- } else {
477- child. flex_basis
478- }
479- } ) ) ;
522+ let used_space: T :: Length = total_main_axis_gap
523+ + length_sum ( line. items . iter ( ) . map ( |child| {
524+ child. margin . main_axis_sum ( dir)
525+ + if child. frozen {
526+ child. target_size . main_size ( dir)
527+ } else {
528+ child. flex_basis
529+ }
530+ } ) ) ;
480531 let initial_free_space = ( target_len - used_space) . or_zero ( ) ;
481532 let mut prev_free_space: Option < T :: Length > = None ;
482533
@@ -496,14 +547,15 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
496547 // value is less than the magnitude of the remaining free space, use this
497548 // as the remaining free space.
498549
499- let used_space: T :: Length = length_sum ( line. items . iter ( ) . map ( |child| {
500- child. margin . main_axis_sum ( dir)
501- + if child. frozen {
502- child. target_size . main_size ( dir)
503- } else {
504- child. flex_basis
505- }
506- } ) ) ;
550+ let used_space: T :: Length = total_main_axis_gap
551+ + length_sum ( line. items . iter ( ) . map ( |child| {
552+ child. margin . main_axis_sum ( dir)
553+ + if child. frozen {
554+ child. target_size . main_size ( dir)
555+ } else {
556+ child. flex_basis
557+ }
558+ } ) ) ;
507559
508560 let mut unfrozen: Vec < & mut FlexItem < T > > = line
509561 . items
@@ -518,12 +570,10 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
518570 ( flex_grow + child. flex_grow , flex_shrink + child. flex_shrink )
519571 } ) ;
520572 let free_space = if growing && sum_flex_grow < 1.0 {
521- initial_free_space
522- . mul_f32 ( sum_flex_grow)
573+ ( initial_free_space. mul_f32 ( sum_flex_grow) - total_main_axis_gap)
523574 . maybe_min ( target_len - used_space)
524575 } else if shrinking && sum_flex_shrink < 1.0 {
525- initial_free_space
526- . mul_f32 ( sum_flex_shrink)
576+ ( initial_free_space. mul_f32 ( sum_flex_shrink) - total_main_axis_gap)
527577 . maybe_max ( target_len - used_space)
528578 } else {
529579 ( target_len - used_space) . or_zero ( )
@@ -852,8 +902,14 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
852902 let requested_cross_size = requested_size. cross_size ( dir) . or_zero ( ) ;
853903 let min_inner_cross =
854904 self_min_max_limit. cross_size ( requested_cross_size, dir) - padding_border_cross;
905+ let total_cross_axis_gap = sum_axis_gaps (
906+ cross_gap :: < T > ( style, dir)
907+ . resolve ( requested_inner_size. main_size ( dir) , node)
908+ . or_zero ( ) ,
909+ flex_lines. len ( ) ,
910+ ) ;
855911 let line_total_cross: T :: Length =
856- length_sum ( flex_lines. iter ( ) . map ( |line| line. cross_size ) ) ;
912+ length_sum ( flex_lines. iter ( ) . map ( |line| line. cross_size ) ) + total_cross_axis_gap ;
857913
858914 if line_total_cross < min_inner_cross {
859915 let remaining = min_inner_cross - line_total_cross;
@@ -980,11 +1036,18 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
9801036 // 2. Align the items along the main-axis per justify-content.
9811037
9821038 for line in & mut flex_lines {
983- let used_space: T :: Length = length_sum (
984- line. items
985- . iter ( )
986- . map ( |child| child. outer_target_size . main_size ( dir) ) ,
1039+ let total_main_axis_gap = sum_axis_gaps (
1040+ main_gap :: < T > ( style, dir)
1041+ . resolve ( requested_inner_size. main_size ( dir) , node)
1042+ . or_zero ( ) ,
1043+ line. items . len ( ) ,
9871044 ) ;
1045+ let used_space: T :: Length = total_main_axis_gap
1046+ + length_sum (
1047+ line. items
1048+ . iter ( )
1049+ . map ( |child| child. outer_target_size . main_size ( dir) ) ,
1050+ ) ;
9881051 let free_space = inner_container_size. main_size ( dir) - used_space;
9891052 let mut num_auto_margins = 0 ;
9901053
@@ -1021,63 +1084,67 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
10211084 }
10221085 } else {
10231086 let num_items = line. items . len ( ) as i32 ;
1087+ let is_reversed = main_dir_rev == AxisReverse :: Reversed ;
10241088 for ( index, flex_child) in line. items . iter_mut ( ) . enumerate ( ) {
10251089 let is_first = index == 0 ;
1026- flex_child. extra_offset_main = match style. justify_content ( ) {
1027- JustifyContent :: FlexStart
1028- | JustifyContent :: Start
1029- | JustifyContent :: Baseline
1030- | JustifyContent :: Stretch => T :: Length :: zero ( ) ,
1031- JustifyContent :: Center => {
1032- if is_first {
1033- free_space. div_i32 ( 2 )
1034- } else {
1035- T :: Length :: zero ( )
1036- }
1037- }
1038- JustifyContent :: FlexEnd | JustifyContent :: End => {
1039- if is_first {
1040- free_space
1041- } else {
1042- T :: Length :: zero ( )
1043- }
1044- }
1045- JustifyContent :: Left => match main_dir_rev {
1046- AxisReverse :: NotReversed => T :: Length :: zero ( ) ,
1047- AxisReverse :: Reversed => {
1048- if is_first {
1090+ let gap = main_gap :: < T > ( style, dir)
1091+ . resolve ( requested_inner_size. main_size ( dir) , node)
1092+ . or_zero ( ) ;
1093+ flex_child. extra_offset_main = if is_first {
1094+ match style. justify_content ( ) {
1095+ JustifyContent :: Start
1096+ | JustifyContent :: Baseline
1097+ | JustifyContent :: Stretch => T :: Length :: zero ( ) ,
1098+ JustifyContent :: FlexStart => T :: Length :: zero ( ) ,
1099+ JustifyContent :: Center => free_space. div_i32 ( 2 ) ,
1100+ JustifyContent :: FlexEnd => free_space,
1101+ JustifyContent :: End => free_space,
1102+ JustifyContent :: Left => {
1103+ if is_reversed {
10491104 free_space
10501105 } else {
10511106 T :: Length :: zero ( )
10521107 }
10531108 }
1054- } ,
1055- JustifyContent :: Right => match main_dir_rev {
1056- AxisReverse :: NotReversed => {
1057- if is_first {
1109+ JustifyContent :: Right => {
1110+ if is_reversed {
1111+ T :: Length :: zero ( )
1112+ } else {
10581113 free_space
1114+ }
1115+ }
1116+ JustifyContent :: SpaceBetween => T :: Length :: zero ( ) ,
1117+ JustifyContent :: SpaceAround => {
1118+ if free_space >= T :: Length :: zero ( ) {
1119+ free_space. div_i32 ( num_items) . div_i32 ( 2 )
10591120 } else {
1060- T :: Length :: zero ( )
1121+ free_space . div_i32 ( 2 )
10611122 }
10621123 }
1063- AxisReverse :: Reversed => T :: Length :: zero ( ) ,
1064- } ,
1065- JustifyContent :: SpaceBetween => {
1066- if is_first {
1067- T :: Length :: zero ( )
1068- } else {
1069- free_space. div_i32 ( num_items - 1 )
1124+ JustifyContent :: SpaceEvenly => {
1125+ if free_space >= T :: Length :: zero ( ) {
1126+ free_space. div_i32 ( num_items + 1 )
1127+ } else {
1128+ free_space. div_i32 ( 2 )
1129+ }
10701130 }
10711131 }
1072- JustifyContent :: SpaceAround => {
1073- if is_first {
1074- free_space. div_i32 ( num_items) . div_i32 ( 2 )
1075- } else {
1076- free_space. div_i32 ( num_items)
1077- }
1132+ } else {
1133+ let free_space = free_space. max ( T :: Length :: zero ( ) ) ;
1134+ gap + match style. justify_content ( ) {
1135+ JustifyContent :: FlexStart
1136+ | JustifyContent :: Start
1137+ | JustifyContent :: Baseline
1138+ | JustifyContent :: Stretch => T :: Length :: zero ( ) ,
1139+ JustifyContent :: Center => T :: Length :: zero ( ) ,
1140+ JustifyContent :: FlexEnd | JustifyContent :: End => T :: Length :: zero ( ) ,
1141+ JustifyContent :: Left => T :: Length :: zero ( ) ,
1142+ JustifyContent :: Right => T :: Length :: zero ( ) ,
1143+ JustifyContent :: SpaceBetween => free_space. div_i32 ( num_items - 1 ) ,
1144+ JustifyContent :: SpaceAround => free_space. div_i32 ( num_items) ,
1145+ JustifyContent :: SpaceEvenly => free_space. div_i32 ( num_items + 1 ) ,
10781146 }
1079- JustifyContent :: SpaceEvenly => free_space. div_i32 ( num_items + 1 ) ,
1080- } ;
1147+ }
10811148 }
10821149 }
10831150 }
@@ -1162,45 +1229,56 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
11621229 }
11631230
11641231 // 16. Align all flex lines per align-content.
1165- let free_space =
1166- ( inner_container_size. cross_size ( dir) - total_cross_size) . max ( T :: Length :: zero ( ) ) ;
1232+
11671233 let num_lines = flex_lines. len ( ) as i32 ;
1234+ let gap = cross_gap :: < T > ( style, dir)
1235+ . resolve ( requested_inner_size. main_size ( dir) , node)
1236+ . or_zero ( ) ;
1237+ let total_cross_axis_gap = sum_axis_gaps ( gap, flex_lines. len ( ) ) ;
1238+ let free_space = ( inner_container_size. cross_size ( dir) - total_cross_size)
1239+ . max ( T :: Length :: zero ( ) )
1240+ + total_cross_axis_gap;
11681241 for ( index, line) in flex_lines. iter_mut ( ) . enumerate ( ) {
11691242 let is_first = index == 0 ;
1170- line. extra_offset_cross = match style. align_content ( ) {
1171- AlignContent :: FlexStart
1172- | AlignContent :: Start
1173- | AlignContent :: Normal
1174- | AlignContent :: Baseline => T :: Length :: zero ( ) ,
1175- AlignContent :: FlexEnd | AlignContent :: End => {
1176- if is_first {
1177- free_space
1178- } else {
1243+ line. extra_offset_cross = if is_first {
1244+ match style. align_content ( ) {
1245+ AlignContent :: Start | AlignContent :: Normal | AlignContent :: Baseline => {
11791246 T :: Length :: zero ( )
11801247 }
1181- }
1182- AlignContent :: Center => {
1183- if is_first {
1184- free_space. div_i32 ( 2 )
1185- } else {
1186- T :: Length :: zero ( )
1248+ AlignContent :: FlexStart => T :: Length :: zero ( ) ,
1249+ AlignContent :: End => free_space,
1250+ AlignContent :: FlexEnd => free_space,
1251+ AlignContent :: Center => free_space. div_i32 ( 2 ) ,
1252+ AlignContent :: Stretch => T :: Length :: zero ( ) ,
1253+ AlignContent :: SpaceBetween => T :: Length :: zero ( ) ,
1254+ AlignContent :: SpaceEvenly => {
1255+ if free_space >= T :: Length :: zero ( ) {
1256+ free_space. div_i32 ( num_lines + 1 )
1257+ } else {
1258+ free_space. div_i32 ( 2 )
1259+ }
11871260 }
1188- }
1189- AlignContent :: Stretch => T :: Length :: zero ( ) ,
1190- AlignContent :: SpaceBetween => {
1191- if is_first {
1192- T :: Length :: zero ( )
1193- } else {
1194- free_space. div_i32 ( num_lines - 1 )
1261+ AlignContent :: SpaceAround => {
1262+ if free_space >= T :: Length :: zero ( ) {
1263+ free_space. div_i32 ( num_lines) . div_i32 ( 2 )
1264+ } else {
1265+ free_space. div_i32 ( 2 )
1266+ }
11951267 }
11961268 }
1197- AlignContent :: SpaceEvenly => free_space. div_i32 ( num_lines + 1 ) ,
1198- AlignContent :: SpaceAround => {
1199- if is_first {
1200- free_space. div_i32 ( num_lines) . div_i32 ( 2 )
1201- } else {
1202- free_space. div_i32 ( num_lines)
1269+ } else {
1270+ gap + match style. align_content ( ) {
1271+ AlignContent :: Start | AlignContent :: Normal | AlignContent :: Baseline => {
1272+ T :: Length :: zero ( )
12031273 }
1274+ AlignContent :: FlexStart => T :: Length :: zero ( ) ,
1275+ AlignContent :: End => T :: Length :: zero ( ) ,
1276+ AlignContent :: FlexEnd => T :: Length :: zero ( ) ,
1277+ AlignContent :: Center => T :: Length :: zero ( ) ,
1278+ AlignContent :: Stretch => T :: Length :: zero ( ) ,
1279+ AlignContent :: SpaceBetween => free_space. div_i32 ( num_lines - 1 ) ,
1280+ AlignContent :: SpaceEvenly => free_space. div_i32 ( num_lines + 1 ) ,
1281+ AlignContent :: SpaceAround => free_space. div_i32 ( num_lines) ,
12041282 }
12051283 } ;
12061284 }
0 commit comments