Skip to content

Commit

Permalink
Fix flex line cross-size determination
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoburns committed Jul 16, 2024
1 parent e6255f7 commit 30d7c8f
Show file tree
Hide file tree
Showing 10 changed files with 827 additions and 38 deletions.
56 changes: 18 additions & 38 deletions src/compute/flexbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1412,34 +1412,11 @@ fn calculate_children_base_lines(
/// # [9.4. Cross Size Determination](https://www.w3.org/TR/css-flexbox-1/#cross-sizing)
///
/// - [**Calculate the cross size of each flex line**](https://www.w3.org/TR/css-flexbox-1/#algo-cross-line).
///
/// If the flex container is single-line and has a definite cross size, the cross size of the flex line is the flex container’s inner cross size.
///
/// Otherwise, for each flex line:
///
/// 1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose align-self is baseline, and whose cross-axis margins are both non-auto.
/// Find the largest of the distances between each item’s baseline and its hypothetical outer cross-start edge,
/// and the largest of the distances between each item’s baseline and its hypothetical outer cross-end edge, and sum these two values.
///
/// 2. Among all the items not collected by the previous step, find the largest outer hypothetical cross size.
///
/// 3. The used cross-size of the flex line is the largest of the numbers found in the previous two steps and zero.
///
/// If the flex container is single-line, then clamp the line’s cross-size to be within the container’s computed min and max cross sizes.
/// **Note that if CSS 2.1’s definition of min/max-width/height applied more generally, this behavior would fall out automatically**.
#[inline]
fn calculate_cross_size(flex_lines: &mut [FlexLine], node_size: Size<Option<f32>>, constants: &AlgoConstants) {
// Note: AlignContent::SpaceEvenly and AlignContent::SpaceAround behave like AlignContent::Stretch when there is only
// a single flex line in the container. See: https://www.w3.org/TR/css-flexbox-1/#align-content-property
// Also: align_content is ignored entirely (and thus behaves like Stretch) when `flex_wrap` is set to `nowrap`.
if flex_lines.len() == 1
&& node_size.cross(constants.dir).is_some()
&& (!constants.is_wrap
|| matches!(
constants.align_content,
AlignContent::Stretch | AlignContent::SpaceEvenly | AlignContent::SpaceAround
))
{
// If the flex container is single-line and has a definite cross size,
// the cross size of the flex line is the flex container’s inner cross size.
if !constants.is_wrap && node_size.cross(constants.dir).is_some() {
let cross_axis_padding_border = constants.content_box_inset.cross_axis_sum(constants.dir);
let cross_min_size = constants.min_size.cross(constants.dir);
let cross_max_size = constants.max_size.cross(constants.dir);
Expand All @@ -1450,19 +1427,20 @@ fn calculate_cross_size(flex_lines: &mut [FlexLine], node_size: Size<Option<f32>
.maybe_max(0.0)
.unwrap_or(0.0);
} else {
for line in flex_lines.iter_mut() {
// 1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose
// align-self is baseline, and whose cross-axis margins are both non-auto. Find the
// largest of the distances between each item’s baseline and its hypothetical outer
// cross-start edge, and the largest of the distances between each item’s baseline
// and its hypothetical outer cross-end edge, and sum these two values.

// 2. Among all the items not collected by the previous step, find the largest
// outer hypothetical cross size.
// Otherwise, for each flex line:
//
// 1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose
// align-self is baseline, and whose cross-axis margins are both non-auto. Find the
// largest of the distances between each item’s baseline and its hypothetical outer
// cross-start edge, and the largest of the distances between each item’s baseline
// and its hypothetical outer cross-end edge, and sum these two values.

// 3. The used cross-size of the flex line is the largest of the numbers found in the
// previous two steps and zero.
// 2. Among all the items not collected by the previous step, find the largest
// outer hypothetical cross size.

// 3. The used cross-size of the flex line is the largest of the numbers found in the
// previous two steps and zero.
for line in flex_lines.iter_mut() {
let max_baseline: f32 = line.items.iter().map(|child| child.baseline).fold(0.0, |acc, x| acc.max(x));
line.cross_size = line
.items
Expand All @@ -1479,7 +1457,9 @@ fn calculate_cross_size(flex_lines: &mut [FlexLine], node_size: Size<Option<f32>
})
.fold(0.0, |acc, x| acc.max(x));
}
// If the flex container is single-line, then clamp the line’s cross-size to be within the container’s computed min and max cross sizes.

// If the flex container is single-line, then clamp the line’s cross-size to be within the container’s computed min and max cross sizes.
// Note that if CSS 2.1’s definition of min/max-width/height applied more generally, this behavior would fall out automatically.
if !constants.is_wrap {
let cross_axis_padding_border = constants.content_box_inset.cross_axis_sum(constants.dir);
let cross_min_size = constants.min_size.cross(constants.dir);
Expand Down
17 changes: 17 additions & 0 deletions test_fixtures/flex/align_content_space_around_wrapped_single.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!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">
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="width: 100px; height: 100px; flex-direction: row; flex-wrap: wrap; align-content: space-around;">
<div style="height: 10px; width: 50px;"></div>
</div>

</body>
</html>
17 changes: 17 additions & 0 deletions test_fixtures/flex/align_content_space_between_wrapped_single.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!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">
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="width: 100px; height: 100px; flex-direction: row; flex-wrap: wrap; align-content: space-between;">
<div style="height: 10px; width: 50px;"></div>
</div>

</body>
</html>
17 changes: 17 additions & 0 deletions test_fixtures/flex/align_content_space_evenly_wrapped_single.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!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">
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="width: 100px; height: 100px; flex-direction: row; flex-wrap: wrap; align-content: space-between;">
<div style="height: 10px; width: 50px;"></div>
</div>

</body>
</html>
19 changes: 19 additions & 0 deletions test_fixtures/flex/align_content_stretch_row_wrap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!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">
<title>
Test description
</title>
</head>
<body>

<div id="test-root" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 100px;">
<div style="width: 50px; height: 150px;"></div>
</div>
</div>

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

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

Loading

0 comments on commit 30d7c8f

Please sign in to comment.