Skip to content

Commit

Permalink
Fix resolving flexible lengths (WPT css/flexbox-multiline-min-max tes…
Browse files Browse the repository at this point in the history
…t) (#692)

* Port failing multiline-min-max tests from WPT

* Don't assume that we are flex-shrinking just because we are not flex-growing (we may be exactly sized)

* Don't double count margins when calculating free space when resolving
flexible lengths
  • Loading branch information
nicoburns authored Jul 16, 2024
1 parent 0ce2f3e commit 25571b5
Show file tree
Hide file tree
Showing 12 changed files with 2,231 additions and 11 deletions.
32 changes: 21 additions & 11 deletions src/compute/flexbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,6 @@ fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inp
// If container size is undefined, determine the container's main size
// and then re-resolve gaps based on newly determined size
debug_log!("determine_container_main_size");
let original_gap = constants.gap;
if let Some(inner_main_size) = constants.node_inner_size.main(constants.dir) {
let outer_main_size = inner_main_size + constants.content_box_inset.main_axis_sum(constants.dir);
constants.inner_container_size.set_main(constants.dir, inner_main_size);
Expand All @@ -285,7 +284,7 @@ fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inp
// 6. Resolve the flexible lengths of all the flex items to find their used main size.
debug_log!("resolve_flexible_lengths");
for line in &mut flex_lines {
resolve_flexible_lengths(line, &constants, original_gap);
resolve_flexible_lengths(line, &constants);
}

// 9.4. Cross Size Determination
Expand Down Expand Up @@ -1105,8 +1104,7 @@ fn determine_container_main_size(
///
/// # [9.7. Resolving Flexible Lengths](https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths)
#[inline]
fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, original_gap: Size<f32>) {
let total_original_main_axis_gap = sum_axis_gaps(original_gap.main(constants.dir), line.items.len());
fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants) {
let total_main_axis_gap = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len());

// 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
Expand All @@ -1116,9 +1114,10 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig

let total_hypothetical_outer_main_size =
line.items.iter().map(|child| child.hypothetical_outer_size.main(constants.dir)).sum::<f32>();
let used_flex_factor: f32 = total_original_main_axis_gap + total_hypothetical_outer_main_size;
let used_flex_factor: f32 = total_main_axis_gap + total_hypothetical_outer_main_size;
let growing = used_flex_factor < constants.node_inner_size.main(constants.dir).unwrap_or(0.0);
let shrinking = !growing;
let shrinking = used_flex_factor > constants.node_inner_size.main(constants.dir).unwrap_or(0.0);
let exactly_sized = !growing & !shrinking;

// 2. Size inflexible items. Freeze, setting its target main size to its hypothetical main size
// - Any item that has a flex factor of zero
Expand All @@ -1131,7 +1130,8 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig
let inner_target_size = child.hypothetical_inner_size.main(constants.dir);
child.target_size.set_main(constants.dir, inner_target_size);

if (child.flex_grow == 0.0 && child.flex_shrink == 0.0)
if exactly_sized
|| (child.flex_grow == 0.0 && child.flex_shrink == 0.0)
|| (growing && child.flex_basis > child.hypothetical_inner_size.main(constants.dir))
|| (shrinking && child.flex_basis < child.hypothetical_inner_size.main(constants.dir))
{
Expand All @@ -1141,6 +1141,10 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig
}
}

if exactly_sized {
return;
}

// 3. Calculate initial free space. Sum the outer sizes of all items on the line,
// and subtract this from the flex container’s inner main size. For frozen items,
// use their outer target main size; for other items, use their outer flex base size.
Expand All @@ -1150,8 +1154,11 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig
.items
.iter()
.map(|child| {
child.margin.main_axis_sum(constants.dir)
+ if child.frozen { child.outer_target_size.main(constants.dir) } else { child.flex_basis }
if child.frozen {
child.outer_target_size.main(constants.dir)
} else {
child.flex_basis + child.margin.main_axis_sum(constants.dir)
}
})
.sum::<f32>();

Expand All @@ -1178,8 +1185,11 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig
.items
.iter()
.map(|child| {
child.margin.main_axis_sum(constants.dir)
+ if child.frozen { child.outer_target_size.main(constants.dir) } else { child.flex_basis }
if child.frozen {
child.outer_target_size.main(constants.dir)
} else {
child.flex_basis + child.margin.main_axis_sum(constants.dir)
}
})
.sum::<f32>();

Expand Down
32 changes: 32 additions & 0 deletions test_fixtures/flex/multiline_min_max_12.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<meta name="wpt-test-port" value="css/css-flexbox/multiline-min-max.html" />
<meta name="wpt-subtest" value=".flexbox 8" />
<style type="text/css">
#test-root { background-color: grey; }
#test-root :nth-child(1) { background-color: blue; }
#test-root :nth-child(2) { background-color: yellow; }
#test-root :nth-child(3) { background-color: salmon; }
#test-root :nth-child(4) { background-color: lime; }
#test-root :nth-child(5) { background-color: red; }
#test-root :nth-child(6) { background-color: orange; }
#test-root :nth-child(7) { background-color: purple; }
</style>
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="box-sizing: content-box; display: flex; flex-wrap: wrap; width: 600px; background-color: grey; border: 5px solid black; height: 20px; position: relative;">
<div style="box-sizing: border-box; height: 10px; max-width: 300px; flex: 1 1 600px; padding-left: 10px;" data-w="300" data-x="0" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="300" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="400" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="500" data-y="0"></div>
</div>

</body>
</html>
32 changes: 32 additions & 0 deletions test_fixtures/flex/multiline_min_max_13.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<meta name="wpt-test-port" value="css/css-flexbox/multiline-min-max.html" />
<meta name="wpt-subtest" value=".flexbox 8" />
<style type="text/css">
#test-root { background-color: grey; }
#test-root :nth-child(1) { background-color: blue; }
#test-root :nth-child(2) { background-color: yellow; }
#test-root :nth-child(3) { background-color: salmon; }
#test-root :nth-child(4) { background-color: lime; }
#test-root :nth-child(5) { background-color: red; }
#test-root :nth-child(6) { background-color: orange; }
#test-root :nth-child(7) { background-color: purple; }
</style>
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="box-sizing: content-box; display: flex; flex-wrap: wrap; width: 600px; background-color: grey; border: 5px solid black; height: 20px; position: relative;">
<div style="box-sizing: border-box; height: 10px; max-width: 300px; flex: 1 1 600px; border-left: 10px solid red;" data-w="300" data-x="0" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="300" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="400" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="500" data-y="0"></div>
</div>

</body>
</html>
32 changes: 32 additions & 0 deletions test_fixtures/flex/multiline_min_max_14.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<meta name="wpt-test-port" value="css/css-flexbox/multiline-min-max.html" />
<meta name="wpt-subtest" value=".flexbox 8" />
<style type="text/css">
#test-root { background-color: grey; }
#test-root :nth-child(1) { background-color: blue; }
#test-root :nth-child(2) { background-color: yellow; }
#test-root :nth-child(3) { background-color: salmon; }
#test-root :nth-child(4) { background-color: lime; }
#test-root :nth-child(5) { background-color: red; }
#test-root :nth-child(6) { background-color: orange; }
#test-root :nth-child(7) { background-color: purple; }
</style>
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="box-sizing: content-box; display: flex; flex-wrap: wrap; width: 600px; background-color: grey; border: 5px solid black; height: 20px; position: relative;">
<div style="box-sizing: border-box; height: 10px; max-width: 300px; flex: 1 1 600px; margin-left: 10px;" data-w="300" data-x="10" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="145" data-x="310" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="145" data-x="455" data-y="0"></div>
<div style="box-sizing: border-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="600" data-x="0" data-y="10"></div>
</div>

</body>
</html>
32 changes: 32 additions & 0 deletions test_fixtures/flex/multiline_min_max_5.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<meta name="wpt-test-port" value="css/css-flexbox/multiline-min-max.html" />
<meta name="wpt-subtest" value=".flexbox 5" />
<style type="text/css">
#test-root { background-color: grey; }
#test-root :nth-child(1) { background-color: blue; }
#test-root :nth-child(2) { background-color: yellow; }
#test-root :nth-child(3) { background-color: salmon; }
#test-root :nth-child(4) { background-color: lime; }
#test-root :nth-child(5) { background-color: red; }
#test-root :nth-child(6) { background-color: orange; }
#test-root :nth-child(7) { background-color: purple; }
</style>
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="display: flex; flex-wrap: wrap; width: 600px; border: 5px solid black; height: 20px; position: relative; box-sizing: content-box;">
<div style="box-sizing: content-box; height: 10px; max-width: 300px; flex: 1 1 600px;" data-w="300" data-x="0" data-y="0"></div>
<div style="box-sizing: content-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="300" data-y="0"></div>
<div style="box-sizing: content-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="400" data-y="0"></div>
<div style="box-sizing: content-box; height: 10px; width: 100px; flex: 1 1 auto;" data-w="100" data-x="500" data-y="0"></div>
</div>

</body>
</html>
32 changes: 32 additions & 0 deletions test_fixtures/flex/multiline_min_max_8.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="../../scripts/gentest/test_helper.js"></script>
<link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
<meta name="wpt-test-port" value="css/css-flexbox/multiline-min-max.html" />
<meta name="wpt-subtest" value=".flexbox 8" />
<style type="text/css">
#test-root { background-color: grey; }
#test-root :nth-child(1) { background-color: blue; }
#test-root :nth-child(2) { background-color: yellow; }
#test-root :nth-child(3) { background-color: salmon; }
#test-root :nth-child(4) { background-color: lime; }
#test-root :nth-child(5) { background-color: red; }
#test-root :nth-child(6) { background-color: orange; }
#test-root :nth-child(7) { background-color: purple; }
</style>
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="display: flex; flex-wrap: wrap; width: 600px; background-color: grey; border: 5px solid black; height: 20px; position: relative; box-sizing: content-box;">
<div style="height: 10px; max-width: 300px; flex: 1 1 600px; margin-left: 10px;" data-w="300" data-x="10" data-y="0"></div>
<div style="height: 10px; width: 100px; flex: 1 1 auto;" data-w="145" data-x="310" data-y="0"></div>
<div style="height: 10px; width: 100px; flex: 1 1 auto;" data-w="145" data-x="455" data-y="0"></div>
<div style="height: 10px; width: 100px; flex: 1 1 auto;" data-w="600" data-x="0" data-y="10"></div>
</div>

</body>
</html>
5 changes: 5 additions & 0 deletions tests/generated/flex/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 25571b5

Please sign in to comment.