Skip to content

Commit

Permalink
Flexbox: pass correct cross-axis available space when computing an it…
Browse files Browse the repository at this point in the history
…em's intrinsic main size (+misc fixes) (#522)

* Add tests for bevyengine/bevy#9350

* Pass accurate cross-axis available space when computing a flexbox item's intrinsic main size

* Subtract child margin not parent margin when computing stretch-alignment known size

* Add extra debug logs to flexbox algorithm

* Apply margins to leaf nodes when computing available space for measure functions

(cherry picked from commit dab541d)
  • Loading branch information
nicoburns committed Aug 14, 2023
1 parent 1b519ec commit 057d234
Show file tree
Hide file tree
Showing 13 changed files with 478 additions and 5 deletions.
32 changes: 27 additions & 5 deletions src/compute/flexbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,24 @@ fn compute_preliminary(

// If container size is undefined, determine the container's main size
// and then re-resolve gaps based on newly determined size
#[cfg(feature = "debug")]
NODE_LOGGER.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.padding_border.main_axis_sum(constants.dir);
constants.inner_container_size.set_main(constants.dir, inner_main_size);
constants.container_size.set_main(constants.dir, outer_main_size);
} else {
// Sets constants.container_size and constants.outer_container_size
determine_container_main_size(tree, available_space.main(constants.dir), &mut flex_lines, &mut constants);
determine_container_main_size(tree, available_space, &mut flex_lines, &mut constants);
constants.node_inner_size.set_main(constants.dir, Some(constants.inner_container_size.main(constants.dir)));
constants.node_outer_size.set_main(constants.dir, Some(constants.container_size.main(constants.dir)));

#[cfg(feature = "debug")]
NODE_LOGGER.labelled_debug_log("constants.node_outer_size", constants.node_outer_size);
#[cfg(feature = "debug")]
NODE_LOGGER.labelled_debug_log("constants.node_inner_size", constants.node_inner_size);

// Re-resolve percentage gaps
let style = tree.style(node);
let inner_container_size = constants.inner_container_size.main(constants.dir);
Expand Down Expand Up @@ -655,7 +662,7 @@ fn determine_flex_base_size(
.cross(dir)
.into_option()
.maybe_clamp(child_min_cross, child_max_cross)
.maybe_sub(constants.margin.cross_axis_sum(dir)),
.maybe_sub(child.margin.cross_axis_sum(dir)),
);
}
ckd
Expand Down Expand Up @@ -809,14 +816,15 @@ fn collect_flex_lines<'a>(
/// Determine the container's main size (if not already known)
fn determine_container_main_size(
tree: &mut impl LayoutTree,
main_axis_available_space: AvailableSpace,
available_space: Size<AvailableSpace>,
lines: &mut Vec<FlexLine<'_>>,
constants: &mut AlgoConstants,
) {
let dir = constants.dir;
let main_padding_border = constants.padding_border.main_axis_sum(constants.dir);

let outer_main_size: f32 = constants.node_outer_size.main(constants.dir).unwrap_or_else(|| {
match main_axis_available_space {
match available_space.main(dir) {
AvailableSpace::Definite(main_axis_available_space) => {
let longest_line_length: f32 = lines
.iter()
Expand Down Expand Up @@ -902,14 +910,28 @@ fn determine_container_main_size(
// Else compute the min- or -max content size and apply the full formula for computing the
// min- or max- content contributuon
_ => {
// Parent size for child sizing
let cross_axis_parent_size = constants.node_inner_size.cross(dir);

// Available space for child sizing
let cross_axis_margin_sum = constants.margin.cross_axis_sum(dir);
let child_min_cross = item.min_size.cross(dir).maybe_add(cross_axis_margin_sum);
let child_max_cross = item.max_size.cross(dir).maybe_add(cross_axis_margin_sum);
let cross_axis_available_space: AvailableSpace = available_space
.cross(dir)
.map_definite_value(|val| cross_axis_parent_size.unwrap_or(val))
.maybe_clamp(child_min_cross, child_max_cross);

let child_available_space = available_space.with_cross(dir, cross_axis_available_space);

// Either the min- or max- content size depending on which constraint we are sizing under.
// TODO: Optimise by using already computed values where available
let content_main_size = GenericAlgorithm::measure_size(
tree,
item.node,
Size::NONE,
constants.node_inner_size,
Size { width: main_axis_available_space, height: main_axis_available_space },
child_available_space,
SizingMode::InherentSize,
)
.main(constants.dir)
Expand Down
3 changes: 3 additions & 0 deletions src/compute/leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pub(crate) fn compute(

// Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width).
// This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values)
let margin = style.margin.resolve_or_zero(parent_size.width);
let padding = style.padding.resolve_or_zero(parent_size.width);
let border = style.border.resolve_or_zero(parent_size.width);
let padding_border = padding + border;
Expand All @@ -100,11 +101,13 @@ pub(crate) fn compute(
let available_space = Size {
width: available_space
.width
.maybe_sub(margin.horizontal_axis_sum())
.maybe_set(node_size.width)
.maybe_set(node_max_size.width)
.map_definite_value(|size| size.maybe_clamp(node_min_size.width, node_max_size.width)),
height: available_space
.height
.maybe_sub(margin.vertical_axis_sum())
.maybe_set(node_size.height)
.maybe_set(node_max_size.height)
.map_definite_value(|size| size.maybe_clamp(node_min_size.height, node_max_size.height)),
Expand Down
23 changes: 23 additions & 0 deletions test_fixtures/bevy_issue_9530.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!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="background: white; width: 300px; height: 300px; margin: auto; align-content: center; align-items: center; flex-direction: column;">
<div style="width: 100%; height: 20px; flex-direction: column; background: red;"></div>
<div style="width: 100%; flex-grow: 1; padding: 20px; margin: 20px; flex-direction: column; background: red;">
<div style="width: 100%; height: 50px;"></div>
<div style="/*width: 100%; */flex-grow: 1; align-content: center; align-items: center; justify-content: center; margin: 20px; background: blue;">HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH</div>
<div style="width: 100%; height: 50px;"></div>

</div>
</div>

</body>
</html>
19 changes: 19 additions & 0 deletions test_fixtures/bevy_issue_9530_reduced.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="flex-direction: column; width: 40px;">
<div style="flex-direction: column; flex-grow: 1;">
<div style="flex-grow: 1;">HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
</div>
</div>

</body>
</html>
19 changes: 19 additions & 0 deletions test_fixtures/bevy_issue_9530_reduced2.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="flex-direction: column;">
<div style="flex-direction: column; flex-grow: 1; width: 80px; margin: 0 20px;">
<div style="flex-grow: 1;">HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
</div>
</div>

</body>
</html>
17 changes: 17 additions & 0 deletions test_fixtures/bevy_issue_9530_reduced3.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="flex-direction: column; width: 80px;">
<div style="flex-grow: 1; margin: 0 20px;">HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
</div>

</body>
</html>
17 changes: 17 additions & 0 deletions test_fixtures/bevy_issue_9530_reduced4.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="flex-direction: column; width: 80px;">
<div style="margin: 20px;">HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
</div>

</body>
</html>
Loading

0 comments on commit 057d234

Please sign in to comment.