Skip to content

Commit c0f5641

Browse files
committed
fix(layout): flex gap calculation
1 parent d1200c5 commit c0f5641

File tree

3 files changed

+141
-37
lines changed

3 files changed

+141
-37
lines changed

float-pigment-css/src/typing.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,6 @@ pub struct FeatureTag {
17931793
#[cfg_attr(debug_assertions, derive(CompatibilityEnumCheck))]
17941794
pub enum Gap {
17951795
Normal,
1796-
#[resolve_font_size(Length::resolve_em_and_ratio)]
1796+
#[resolve_font_size(Length::resolve_em)]
17971797
Length(Length),
17981798
}

float-pigment-forest/tests/custom/css_flexbox/gap.rs

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ fn gap() {
1616
fn column_gap_in_flex_row_box() {
1717
assert_xml!(
1818
r#"
19-
<div style="display: flex; width: 100px; column-gap: 10px; flex-wrap: wrap;">
20-
<div style="width: 100px; height: 30px; flex-shrink: 0" expect_width="100"></div>
21-
<div style="width: 100px; height: 30px; flex-shrink: 0" expect_width="100" expect_top="40"></div>
19+
<div style="display: flex; flex-direction: row; width: 100px; height: 100px; column-gap: 10px;">
20+
<div style="width: 20px; height: 20px;" expect_left="0"></div>
21+
<div style="width: 20px; height: 20px;" expect_left="30"></div>
2222
</div>
2323
"#
2424
)
2525
}
2626

2727
#[test]
28-
fn row_gap_in_flex_row_box() {
28+
fn column_gap_with_percentage_in_flex_row_box() {
2929
assert_xml!(
3030
r#"
31-
<div style="display: flex; width: 100px; row-gap: 10px;">
32-
<div style="height: 10px; flex: 1" expect_width="45"></div>
33-
<div style="height: 10px; flex: 1" expect_width="45" expect_left="55"></div>
31+
<div style="display: flex; flex-direction: row; width: 200px; height: 100px; column-gap: 10%; align-items: flex-start">
32+
<div style="width: 20px; height: 20px;" expect_left="0"></div>
33+
<div style="width: 20px; height: 20px;" expect_left="40"></div>
3434
</div>
3535
"#
3636
)
@@ -40,9 +40,75 @@ fn row_gap_in_flex_row_box() {
4040
fn column_gap_in_flex_column_box() {
4141
assert_xml!(
4242
r#"
43-
<div style="display: flex; flex-direction: column; width: 100px; height: 50px; column-gap: 10px; flex-wrap: wrap; align-content: flex-start">
44-
<div style="width: 30px; height: 30px; flex-shrink: 0" expect_height="30"></div>
45-
<div style="width: 30px; height: 30px; flex-shrink: 0" expect_height="30" expect_left="40"></div>
43+
<div style="display: flex; flex-direction: column; width: 100px; height: 20px; column-gap: 10px; flex-wrap: wrap;">
44+
<div style="width: 20px; height: 20px;" expect_left="0"></div>
45+
<div style="width: 20px; height: 20px;" expect_left="55"></div>
46+
</div>
47+
"#
48+
)
49+
}
50+
51+
#[test]
52+
fn column_gap_in_flex_column_box_with_align_content_flex_start() {
53+
assert_xml!(
54+
r#"
55+
<div style="display: flex; flex-direction: column; width: 100px; height: 20px; column-gap: 10px; flex-wrap: wrap; align-content: flex-start">
56+
<div style="width: 20px; height: 20px;" expect_left="0"></div>
57+
<div style="width: 20px; height: 20px;" expect_left="30"></div>
58+
</div>
59+
"#
60+
)
61+
}
62+
63+
#[test]
64+
fn column_gap_with_percentage_in_flex_column_box_with_align_content_flex_start() {
65+
assert_xml!(
66+
r#"
67+
<div style="display: flex; flex-direction: column; width: 100px; height: 20px; column-gap: 10%; flex-wrap: wrap; align-content: flex-start">
68+
<div style="width: 20px; height: 20px; flex-shrink: 0" expect_left="0"></div>
69+
<div style="width: 20px; height: 20px; flex-shrink: 0" expect_left="30"></div>
70+
</div>
71+
"#
72+
)
73+
}
74+
75+
#[test]
76+
fn row_gap_in_flex_row_box() {
77+
assert_xml!(
78+
r#"
79+
<div style="display: flex; flex-direction:row; width: 100px; height: 100px; row-gap: 10px; flex-wrap: wrap;">
80+
<div style="height: 10px; width: 50px;" expect_left="0" expect_top="0"></div>
81+
<div style="height: 10px; width: 50px;" expect_left="50" expect_top="0"></div>
82+
<div style="height: 10px; width: 50px;" expect_left="0" expect_top="55"></div>
83+
<div style="height: 10px; width: 50px;" expect_left="50" expect_top="55"></div>
84+
</div>
85+
"#
86+
)
87+
}
88+
89+
#[test]
90+
fn row_gap_in_flex_row_box_with_align_content_flex_start() {
91+
assert_xml!(
92+
r#"
93+
<div style="display: flex; flex-direction:row; width: 100px; height: 100px; row-gap: 10px; flex-wrap: wrap; align-content: flex-start;">
94+
<div style="height: 10px; width: 50px;" expect_left="0"></div>
95+
<div style="height: 10px; width: 50px;" expect_left="50"></div>
96+
<div style="height: 10px; width: 50px;" expect_left="0" expect_top="20"></div>
97+
<div style="height: 10px; width: 50px;" expect_left="50" expect_top="20"></div>
98+
</div>
99+
"#
100+
)
101+
}
102+
103+
#[test]
104+
fn row_gap_with_percentage_in_flex_row_box_with_align_content_flex_start() {
105+
assert_xml!(
106+
r#"
107+
<div style="display: flex; flex-direction:row; width: 100px; height: 100px; row-gap: 10%; flex-wrap: wrap; align-content: flex-start;">
108+
<div style="height: 10px; width: 50px;" expect_left="0"></div>
109+
<div style="height: 10px; width: 50px;" expect_left="50"></div>
110+
<div style="height: 10px; width: 50px;" expect_left="0" expect_top="20"></div>
111+
<div style="height: 10px; width: 50px;" expect_left="50" expect_top="20"></div>
46112
</div>
47113
"#
48114
)
@@ -53,8 +119,20 @@ fn row_gap_in_flex_column_box() {
53119
assert_xml!(
54120
r#"
55121
<div style="display: flex; flex-direction: column; width: 100px; height: 100px; row-gap: 10px;">
56-
<div style="width: 100px; height: 30px;" expect_width="100"></div>
57-
<div style="width: 100px; height: 30px;" expect_width="100" expect_top="40"></div>
122+
<div style="width: 100px; height: 30px;"></div>
123+
<div style="width: 100px; height: 30px;"expect_top="40"></div>
124+
</div>
125+
"#
126+
)
127+
}
128+
129+
#[test]
130+
fn row_gap_with_percentage_in_flex_column_box() {
131+
assert_xml!(
132+
r#"
133+
<div style="display: flex; flex-direction: column; width: 100px; height: 100px; row-gap: 10%;">
134+
<div style="width: 100px; height: 30px;"></div>
135+
<div style="width: 100px; height: 30px;"expect_top="40"></div>
58136
</div>
59137
"#
60138
)

float-pigment-layout/src/algo/flex_box.rs

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,50 @@ fn sum_axis_gaps<L: LengthNum>(gap: L, num_items: usize) -> L {
1414
}
1515
}
1616

17+
#[inline(always)]
18+
fn resolve_row_gap<T: LayoutTreeNode>(
19+
style: &T::Style,
20+
node: &T,
21+
inner_size: &Normalized<OptionSize<T::Length>>,
22+
) -> T::Length {
23+
style.row_gap().resolve(inner_size.height, node).or_zero()
24+
}
25+
26+
#[inline(always)]
27+
fn resolve_column_gap<T: LayoutTreeNode>(
28+
style: &T::Style,
29+
node: &T,
30+
inner_size: &Normalized<OptionSize<T::Length>>,
31+
) -> T::Length {
32+
style.column_gap().resolve(inner_size.width, node).or_zero()
33+
}
34+
35+
#[inline(always)]
36+
fn main_axis_gap<T: LayoutTreeNode>(
37+
dir: AxisDirection,
38+
style: &T::Style,
39+
node: &T,
40+
inner_size: &Normalized<OptionSize<T::Length>>,
41+
) -> T::Length {
42+
match dir {
43+
AxisDirection::Horizontal => resolve_column_gap(style, node, inner_size),
44+
AxisDirection::Vertical => resolve_row_gap(style, node, inner_size),
45+
}
46+
}
47+
48+
#[inline(always)]
49+
fn cross_axis_gap<T: LayoutTreeNode>(
50+
dir: AxisDirection,
51+
style: &T::Style,
52+
node: &T,
53+
inner_size: &Normalized<OptionSize<T::Length>>,
54+
) -> T::Length {
55+
match dir {
56+
AxisDirection::Horizontal => resolve_row_gap(style, node, inner_size),
57+
AxisDirection::Vertical => resolve_column_gap(style, node, inner_size),
58+
}
59+
}
60+
1761
pub(crate) fn align_self<T: LayoutTreeNode>(child: &T::Style, parent: &T::Style) -> AlignSelf {
1862
let s = child.align_self();
1963
if s == AlignSelf::Auto {
@@ -347,10 +391,7 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
347391
});
348392
} else {
349393
let mut flex_items = &mut flex_items[..];
350-
let main_axis_gap = style
351-
.row_gap()
352-
.resolve(requested_inner_size.main_size(dir), node)
353-
.or_zero();
394+
let main_axis_gap = main_axis_gap::<T>(dir, style, node, &requested_inner_size);
354395
while !flex_items.is_empty() {
355396
let mut line_length = T::Length::zero();
356397
let index = flex_items
@@ -392,10 +433,7 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
392433
let multi_flex_line = flex_lines.len() > 1;
393434
for line in &mut flex_lines {
394435
let total_main_axis_gap = sum_axis_gaps(
395-
style
396-
.row_gap()
397-
.resolve(requested_inner_size.main_size(dir), node)
398-
.or_zero(),
436+
main_axis_gap::<T>(dir, style, node, &requested_inner_size),
399437
line.items.len(),
400438
);
401439
// 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
@@ -883,10 +921,7 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
883921
let min_inner_cross =
884922
self_min_max_limit.cross_size(requested_cross_size, dir) - padding_border_cross;
885923
let total_cross_axis_gap = sum_axis_gaps(
886-
style
887-
.column_gap()
888-
.resolve(requested_inner_size.main_size(dir), node)
889-
.or_zero(),
924+
cross_axis_gap::<T>(dir, style, node, &requested_inner_size),
890925
flex_lines.len(),
891926
);
892927
let line_total_cross: T::Length =
@@ -1018,10 +1053,7 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
10181053

10191054
for line in &mut flex_lines {
10201055
let total_main_axis_gap = sum_axis_gaps(
1021-
style
1022-
.row_gap()
1023-
.resolve(requested_inner_size.main_size(dir), node)
1024-
.or_zero(),
1056+
main_axis_gap::<T>(dir, style, node, &requested_inner_size),
10251057
line.items.len(),
10261058
);
10271059
let used_space: T::Length = total_main_axis_gap
@@ -1069,10 +1101,7 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
10691101
let is_reversed = main_dir_rev == AxisReverse::Reversed;
10701102
for (index, flex_child) in line.items.iter_mut().enumerate() {
10711103
let is_first = index == 0;
1072-
let gap = style
1073-
.row_gap()
1074-
.resolve(requested_inner_size.main_size(dir), node)
1075-
.or_zero();
1104+
let gap = main_axis_gap::<T>(dir, style, node, &requested_inner_size);
10761105
flex_child.extra_offset_main = if is_first {
10771106
match style.justify_content() {
10781107
JustifyContent::Start
@@ -1214,10 +1243,7 @@ impl<T: LayoutTreeNode> FlexBox<T> for LayoutUnit<T> {
12141243
// 16. Align all flex lines per align-content.
12151244

12161245
let num_lines = flex_lines.len() as i32;
1217-
let gap = style
1218-
.column_gap()
1219-
.resolve(requested_inner_size.main_size(dir), node)
1220-
.or_zero();
1246+
let gap = cross_axis_gap::<T>(dir, style, node, &requested_inner_size);
12211247
let total_cross_axis_gap = sum_axis_gaps(gap, flex_lines.len());
12221248
let free_space = (inner_container_size.cross_size(dir) - total_cross_size)
12231249
.max(T::Length::zero())

0 commit comments

Comments
 (0)