gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81412 Sutichaykuna

Flexbox: pass correct cross-axis available space when computing an item'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

dab541d6104d58e2e10ce90c4a1dad0b703160cd · ruwaq Nico Burns · (3 wata ñawpaq) · tayta 25ffaee23 · kay commitpi sach'ata qhaway

Semántico sayk'uy · 19

src/compute/flexbox.rs

src/compute/leaf.rs

  • ukhunpi t'ikrakurqan fn compute pub

tests/generated/bevy_issue_9530.rs

tests/generated/bevy_issue_9530_reduced.rs

tests/generated/bevy_issue_9530_reduced2.rs

tests/generated/bevy_issue_9530_reduced3.rs

tests/generated/bevy_issue_9530_reduced4.rs

tests/generated/mod.rs

13 qillqakuna · +479 −9

diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index 6f61cb78c..27cc53cc6 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -271,6 +271,8 @@ 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.content_box_inset.main_axis_sum(constants.dir);
@@ -278,10 +280,15 @@ fn compute_preliminary(
         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);
@@ -689,7 +696,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
@@ -848,14 +855,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_content_box_inset = constants.content_box_inset.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()
@@ -940,6 +948,20 @@ 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 = tree
@@ -947,7 +969,7 @@ fn determine_container_main_size(
                                         item.node,
                                         Size::NONE,
                                         constants.node_inner_size,
-                                        Size { width: main_axis_available_space, height: main_axis_available_space },
+                                        child_available_space,
                                         SizingMode::InherentSize,
                                         Line::FALSE,
                                     )
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index 8041e0cf8..040e02ca1 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -68,6 +68,7 @@ pub 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;
@@ -126,13 +127,17 @@ pub fn compute(
     if let Some(measurable) = measurable {
         // Compute available space
         let available_space = Size {
-            width: available_space.width.maybe_set(node_size.width).maybe_set(node_max_size.width).map_definite_value(
-                |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) - content_box_inset.horizontal_axis_sum()
-                },
-            ),
+                }),
             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| {
diff --git a/test_fixtures/bevy_issue_9530.html b/test_fixtures/bevy_issue_9530.html
new file mode 100644
index 000000000..4b346eb59
--- /dev/null
+++ b/test_fixtures/bevy_issue_9530.html
@@ -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>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_9530_reduced.html b/test_fixtures/bevy_issue_9530_reduced.html
new file mode 100644
index 000000000..4d6f223f8
--- /dev/null
+++ b/test_fixtures/bevy_issue_9530_reduced.html
@@ -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>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_9530_reduced2.html b/test_fixtures/bevy_issue_9530_reduced2.html
new file mode 100644
index 000000000..f488740ae
--- /dev/null
+++ b/test_fixtures/bevy_issue_9530_reduced2.html
@@ -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>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_9530_reduced3.html b/test_fixtures/bevy_issue_9530_reduced3.html
new file mode 100644
index 000000000..44488c9c0
--- /dev/null
+++ b/test_fixtures/bevy_issue_9530_reduced3.html
@@ -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>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_9530_reduced4.html b/test_fixtures/bevy_issue_9530_reduced4.html
new file mode 100644
index 000000000..42f84c156
--- /dev/null
+++ b/test_fixtures/bevy_issue_9530_reduced4.html
@@ -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>
\ No newline at end of file
diff --git a/tests/generated/bevy_issue_9530.rs b/tests/generated/bevy_issue_9530.rs
new file mode 100644
index 000000000..88d28a39f
--- /dev/null
+++ b/tests/generated/bevy_issue_9530.rs
@@ -0,0 +1,113 @@
+#[test]
+fn bevy_issue_9530() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            flex_direction: taffy::style::FlexDirection::Column,
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Length(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Length(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node11 = taffy . new_leaf_with_measure (taffy :: style :: Style { align_items : Some (taffy :: style :: AlignItems :: Center) , align_content : Some (taffy :: style :: AlignContent :: Center) , justify_content : Some (taffy :: style :: JustifyContent :: Center) , flex_grow : 1f32 , margin : taffy :: geometry :: Rect { left : taffy :: style :: LengthPercentageAuto :: Length (20f32) , right : taffy :: style :: LengthPercentageAuto :: Length (20f32) , top : taffy :: style :: LengthPercentageAuto :: Length (20f32) , bottom : taffy :: style :: LengthPercentageAuto :: Length (20f32) , } , .. Default :: default () } , taffy :: tree :: MeasureFunc :: Raw (| known_dimensions , available_space | { const TEXT : & str = "HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH" ; super :: measure_standard_text (known_dimensions , available_space , TEXT , super :: WritingMode :: Horizontal , None) }) ,) . unwrap () ;
+    let node12 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Length(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                flex_grow: 1f32,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(1f32), height: auto() },
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Length(20f32),
+                    right: taffy::style::LengthPercentageAuto::Length(20f32),
+                    top: taffy::style::LengthPercentageAuto::Length(20f32),
+                    bottom: taffy::style::LengthPercentageAuto::Length(20f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Length(20f32),
+                    right: taffy::style::LengthPercentage::Length(20f32),
+                    top: taffy::style::LengthPercentage::Length(20f32),
+                    bottom: taffy::style::LengthPercentage::Length(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10, node11, node12],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                align_items: Some(taffy::style::AlignItems::Center),
+                align_content: Some(taffy::style::AlignContent::Center),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(300f32),
+                    height: taffy::style::Dimension::Length(300f32),
+                },
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Auto,
+                    right: taffy::style::LengthPercentageAuto::Auto,
+                    top: taffy::style::LengthPercentageAuto::Auto,
+                    bottom: taffy::style::LengthPercentageAuto::Auto,
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::util::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 300f32, "width of node {:?}. Expected {}. Actual {}", node, 300f32, size.width);
+    assert_eq!(size.height, 300f32, "height of node {:?}. Expected {}. Actual {}", node, 300f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 300f32, "width of node {:?}. Expected {}. Actual {}", node0, 300f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node0, 0f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 300f32, "width of node {:?}. Expected {}. Actual {}", node1, 300f32, size.width);
+    assert_eq!(size.height, 420f32, "height of node {:?}. Expected {}. Actual {}", node1, 420f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node1, 20f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 260f32, "width of node {:?}. Expected {}. Actual {}", node10, 260f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node10, 50f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node10, 20f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node10, 20f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node11).unwrap();
+    assert_eq!(size.width, 220f32, "width of node {:?}. Expected {}. Actual {}", node11, 220f32, size.width);
+    assert_eq!(size.height, 240f32, "height of node {:?}. Expected {}. Actual {}", node11, 240f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node11, 40f32, location.x);
+    assert_eq!(location.y, 90f32, "y of node {:?}. Expected {}. Actual {}", node11, 90f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node12).unwrap();
+    assert_eq!(size.width, 260f32, "width of node {:?}. Expected {}. Actual {}", node12, 260f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node12, 50f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node12, 20f32, location.x);
+    assert_eq!(location.y, 350f32, "y of node {:?}. Expected {}. Actual {}", node12, 350f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_9530_reduced.rs b/tests/generated/bevy_issue_9530_reduced.rs
new file mode 100644
index 000000000..17af524b6
--- /dev/null
+++ b/tests/generated/bevy_issue_9530_reduced.rs
@@ -0,0 +1,60 @@
+#[test]
+fn bevy_issue_9530_reduced() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { flex_grow: 1f32, ..Default::default() },
+            taffy::tree::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                flex_grow: 1f32,
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Length(40f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::util::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node, 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node, 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0, 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0, 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node00, 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node00, 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00, 0f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_9530_reduced2.rs b/tests/generated/bevy_issue_9530_reduced2.rs
new file mode 100644
index 000000000..ea22bf42a
--- /dev/null
+++ b/tests/generated/bevy_issue_9530_reduced2.rs
@@ -0,0 +1,63 @@
+#[test]
+fn bevy_issue_9530_reduced2() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { flex_grow: 1f32, ..Default::default() },
+            taffy::tree::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                flex_grow: 1f32,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Length(80f32), height: auto() },
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Length(20f32),
+                    right: taffy::style::LengthPercentageAuto::Length(20f32),
+                    top: taffy::style::LengthPercentageAuto::Length(0f32),
+                    bottom: taffy::style::LengthPercentageAuto::Length(0f32),
+                },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::util::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 120f32, "width of node {:?}. Expected {}. Actual {}", node, 120f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node, 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node0, 80f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0, 20f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node0, 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node00, 80f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node00, 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00, 0f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_9530_reduced3.rs b/tests/generated/bevy_issue_9530_reduced3.rs
new file mode 100644
index 000000000..c296e4a83
--- /dev/null
+++ b/tests/generated/bevy_issue_9530_reduced3.rs
@@ -0,0 +1,54 @@
+#[test]
+fn bevy_issue_9530_reduced3() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style {
+                flex_grow: 1f32,
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Length(20f32),
+                    right: taffy::style::LengthPercentageAuto::Length(20f32),
+                    top: taffy::style::LengthPercentageAuto::Length(0f32),
+                    bottom: taffy::style::LengthPercentageAuto::Length(0f32),
+                },
+                ..Default::default()
+            },
+            taffy::tree::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Length(80f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::util::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node, 80f32, size.width);
+    assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node, 40f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0, 40f32, size.width);
+    assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0, 40f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node0, 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_9530_reduced4.rs b/tests/generated/bevy_issue_9530_reduced4.rs
new file mode 100644
index 000000000..6a124c2be
--- /dev/null
+++ b/tests/generated/bevy_issue_9530_reduced4.rs
@@ -0,0 +1,53 @@
+#[test]
+fn bevy_issue_9530_reduced4() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style {
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Length(20f32),
+                    right: taffy::style::LengthPercentageAuto::Length(20f32),
+                    top: taffy::style::LengthPercentageAuto::Length(20f32),
+                    bottom: taffy::style::LengthPercentageAuto::Length(20f32),
+                },
+                ..Default::default()
+            },
+            taffy::tree::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Length(80f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::util::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node, 80f32, size.width);
+    assert_eq!(size.height, 80f32, "height of node {:?}. Expected {}. Actual {}", node, 80f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0, 40f32, size.width);
+    assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0, 40f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node0, 20f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node0, 20f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index 1b78dfd3e..836f00a1b 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -205,6 +205,11 @@ mod bevy_issue_8017;
 mod bevy_issue_8017_reduced;
 mod bevy_issue_8082;
 mod bevy_issue_8082_percent;
+mod bevy_issue_9530;
+mod bevy_issue_9530_reduced;
+mod bevy_issue_9530_reduced2;
+mod bevy_issue_9530_reduced3;
+mod bevy_issue_9530_reduced4;
 mod block_absolute_aspect_ratio_aspect_ratio_overrides_height_of_full_inset;
 mod block_absolute_aspect_ratio_fill_height;
 mod block_absolute_aspect_ratio_fill_height_from_inset;