gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 87Markdown 12TOML 91924 Sutichaykuna

Grid: Fix sizing issues in complex cases (#355)

* Fix complex grid sizing

- Don't constrain grid item's avaiable space based on a grid container's definite available space
- Pass estimates from §11.1. Grid Sizing Algorithm as available space rather than known_dimensions
- Apply stretch sizing to compute known_dimensions when sizing tracks
- Prioritise align/justify self over parent's align/justify items

* Fix typo in comment

76722686b0999e997dbe9c280ff9ea8567e0e95c · ruwaq Nico Burns · (3 wata ñawpaq) · tayta bf3dfaec9 · kay commitpi sach'ata qhaway

Semántico sayk'uy · 83

benches/generated/grid_percent_item_inside_stretch_item.rs

benches/generated/grid_percent_items_nested_inside_stretch_alignment.rs

benches/generated/grid_percent_items_nested_with_margin.rs

benches/generated/gridflex_column_integration.rs

benches/generated/gridflex_kitchen_sink.rs

benches/generated/gridflex_kitchen_sink_minimise.rs

benches/generated/gridflex_kitchen_sink_minimise2.rs

benches/generated/gridflex_kitchen_sink_minimise3.rs

benches/generated/gridflex_row_integration.rs

src/compute/grid/alignment.rs

src/compute/grid/mod.rs

  • ukhunpi t'ikrakurqan fn compute pub

src/compute/grid/placement.rs

src/compute/grid/track_sizing.rs

src/compute/grid/types/grid_item.rs

src/compute/mod.rs

tests/generated/grid_percent_item_inside_stretch_item.rs

tests/generated/grid_percent_items_nested_inside_stretch_alignment.rs

tests/generated/grid_percent_items_nested_with_margin.rs

tests/generated/gridflex_column_integration.rs

tests/generated/gridflex_kitchen_sink.rs

tests/generated/gridflex_kitchen_sink_minimise.rs

tests/generated/gridflex_kitchen_sink_minimise2.rs

tests/generated/gridflex_kitchen_sink_minimise3.rs

tests/generated/gridflex_row_integration.rs

35 qillqakuna · +1612 −60

diff --git a/benches/generated/grid_percent_item_inside_stretch_item.rs b/benches/generated/grid_percent_item_inside_stretch_item.rs
new file mode 100644
index 000000000..9b583f82c
--- /dev/null
+++ b/benches/generated/grid_percent_item_inside_stretch_item.rs
@@ -0,0 +1,32 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            display: taffy::style::Display::Grid,
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style { display: taffy::style::Display::Grid, ..Default::default() },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_percent_items_nested_inside_stretch_alignment.rs b/benches/generated/grid_percent_items_nested_inside_stretch_alignment.rs
new file mode 100644
index 000000000..7f46b1673
--- /dev/null
+++ b/benches/generated/grid_percent_items_nested_inside_stretch_alignment.rs
@@ -0,0 +1,34 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            display: taffy::style::Display::Grid,
+            padding: taffy::geometry::Rect {
+                left: zero(),
+                right: zero(),
+                top: taffy::style::LengthPercentage::Percent(0.2f32),
+                bottom: zero(),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style { display: taffy::style::Display::Grid, ..Default::default() },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(200f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_percent_items_nested_with_margin.rs b/benches/generated/grid_percent_items_nested_with_margin.rs
new file mode 100644
index 000000000..f89bdece3
--- /dev/null
+++ b/benches/generated/grid_percent_items_nested_with_margin.rs
@@ -0,0 +1,38 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.45f32), height: auto() },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                right: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                top: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                bottom: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(200f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/gridflex_column_integration.rs b/benches/generated/gridflex_column_integration.rs
new file mode 100644
index 000000000..78a7112c8
--- /dev/null
+++ b/benches/generated/gridflex_column_integration.rs
@@ -0,0 +1,83 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node01 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node02 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node03 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![flex(1f32), flex(1f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .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();
+}
diff --git a/benches/generated/gridflex_kitchen_sink.rs b/benches/generated/gridflex_kitchen_sink.rs
new file mode 100644
index 000000000..92a7959f8
--- /dev/null
+++ b/benches/generated/gridflex_kitchen_sink.rs
@@ -0,0 +1,100 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node000 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(20f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node00100 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(20f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node00101 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node00102 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node00103 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0010 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.1f32)],
+                grid_template_columns: vec![auto(), percent(0.1f32)],
+                ..Default::default()
+            },
+            &[node00100, node00101, node00102, node00103],
+        )
+        .unwrap();
+    let node001 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_grow: 1f32,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0010],
+        )
+        .unwrap();
+    let node00 = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node000, node001]).unwrap();
+    let node01 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node02 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node03 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![flex(1f32), flex(1f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/gridflex_kitchen_sink_minimise.rs b/benches/generated/gridflex_kitchen_sink_minimise.rs
new file mode 100644
index 000000000..4de835855
--- /dev/null
+++ b/benches/generated/gridflex_kitchen_sink_minimise.rs
@@ -0,0 +1,25 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![points(20f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/gridflex_kitchen_sink_minimise2.rs b/benches/generated/gridflex_kitchen_sink_minimise2.rs
new file mode 100644
index 000000000..90274c83d
--- /dev/null
+++ b/benches/generated/gridflex_kitchen_sink_minimise2.rs
@@ -0,0 +1,36 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(20f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![auto()],
+                grid_template_columns: vec![auto()],
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_grow: 1f32,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/gridflex_kitchen_sink_minimise3.rs b/benches/generated/gridflex_kitchen_sink_minimise3.rs
new file mode 100644
index 000000000..eaf04c78d
--- /dev/null
+++ b/benches/generated/gridflex_kitchen_sink_minimise3.rs
@@ -0,0 +1,38 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(20f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node02 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node03 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.1f32)],
+                grid_template_columns: vec![auto(), percent(0.1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/gridflex_row_integration.rs b/benches/generated/gridflex_row_integration.rs
new file mode 100644
index 000000000..5fb1f1e99
--- /dev/null
+++ b/benches/generated/gridflex_row_integration.rs
@@ -0,0 +1,78 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node01 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node02 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node03 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![flex(1f32), flex(1f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/mod.rs b/benches/generated/mod.rs
index 611172882..b7934aabd 100644
--- a/benches/generated/mod.rs
+++ b/benches/generated/mod.rs
@@ -641,8 +641,14 @@ mod grid_out_of_order_items;
 #[cfg(feature = "grid")]
 mod grid_overflow_rows;
 #[cfg(feature = "grid")]
+mod grid_percent_item_inside_stretch_item;
+#[cfg(feature = "grid")]
+mod grid_percent_items_nested_inside_stretch_alignment;
+#[cfg(feature = "grid")]
 mod grid_percent_items_nested_moderate;
 #[cfg(feature = "grid")]
+mod grid_percent_items_nested_with_margin;
+#[cfg(feature = "grid")]
 mod grid_percent_items_nested_with_padding_margin;
 #[cfg(feature = "grid")]
 mod grid_percent_items_width_and_margin;
@@ -698,6 +704,18 @@ mod grid_span_2_min_content_min_content_indefinite;
 mod grid_span_6_all_non_flex_indefinite;
 #[cfg(feature = "grid")]
 mod grid_span_8_all_track_types_indefinite;
+#[cfg(feature = "grid")]
+mod gridflex_column_integration;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink_minimise;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink_minimise2;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink_minimise3;
+#[cfg(feature = "grid")]
+mod gridflex_row_integration;
 mod intrinsic_sizing_cross_size_column;
 mod intrinsic_sizing_main_size_column;
 mod intrinsic_sizing_main_size_column_nested;
@@ -1461,8 +1479,14 @@ fn benchmark(c: &mut Criterion) {
             #[cfg(feature = "grid")]
             grid_overflow_rows::compute();
             #[cfg(feature = "grid")]
+            grid_percent_item_inside_stretch_item::compute();
+            #[cfg(feature = "grid")]
+            grid_percent_items_nested_inside_stretch_alignment::compute();
+            #[cfg(feature = "grid")]
             grid_percent_items_nested_moderate::compute();
             #[cfg(feature = "grid")]
+            grid_percent_items_nested_with_margin::compute();
+            #[cfg(feature = "grid")]
             grid_percent_items_nested_with_padding_margin::compute();
             #[cfg(feature = "grid")]
             grid_percent_items_width_and_margin::compute();
@@ -1518,6 +1542,18 @@ fn benchmark(c: &mut Criterion) {
             grid_span_6_all_non_flex_indefinite::compute();
             #[cfg(feature = "grid")]
             grid_span_8_all_track_types_indefinite::compute();
+            #[cfg(feature = "grid")]
+            gridflex_column_integration::compute();
+            #[cfg(feature = "grid")]
+            gridflex_kitchen_sink::compute();
+            #[cfg(feature = "grid")]
+            gridflex_kitchen_sink_minimise::compute();
+            #[cfg(feature = "grid")]
+            gridflex_kitchen_sink_minimise2::compute();
+            #[cfg(feature = "grid")]
+            gridflex_kitchen_sink_minimise3::compute();
+            #[cfg(feature = "grid")]
+            gridflex_row_integration::compute();
             intrinsic_sizing_cross_size_column::compute();
             intrinsic_sizing_main_size_column::compute();
             intrinsic_sizing_main_size_column_nested::compute();
diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs
index 82c901818..0c0ed9f81 100644
--- a/src/compute/grid/alignment.rs
+++ b/src/compute/grid/alignment.rs
@@ -99,14 +99,14 @@ pub(super) fn align_and_position_item(
     // and the then height is calculated from the width according the aspect ratio
     // See: https://www.w3.org/TR/css-grid-1/#grid-item-sizing
     let alignment_styles = InBothAbsAxis {
-        horizontal: container_alignment_styles.horizontal.or(justify_self).unwrap_or_else(|| {
+        horizontal: justify_self.or(container_alignment_styles.horizontal).unwrap_or_else(|| {
             if inherent_size.width.is_some() {
                 AlignSelf::Start
             } else {
                 AlignSelf::Stretch
             }
         }),
-        vertical: container_alignment_styles.vertical.or(align_self).unwrap_or_else(|| {
+        vertical: align_self.or(container_alignment_styles.vertical).unwrap_or_else(|| {
             if inherent_size.height.is_some() || aspect_ratio.is_some() {
                 AlignSelf::Start
             } else {
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index c584eb2e1..87841eb7c 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -108,6 +108,7 @@ pub fn compute(
         in_flow_children_iter,
         style.grid_auto_flow,
         style.align_items.unwrap_or(AlignItems::Stretch),
+        style.justify_items.unwrap_or(AlignItems::Stretch),
     );
 
     // Extract track counts from previous step (auto-placement can expand the number of tracks)
@@ -140,16 +141,21 @@ pub fn compute(
     // https://www.w3.org/TR/css-grid-1/#available-grid-space
     let padding = style.padding.resolve_or_zero(parent_size.width);
     let border = style.border.resolve_or_zero(parent_size.width);
-    let margin = style.margin.resolve_or_zero(parent_size.width);
     let aspect_ratio = style.aspect_ratio;
     let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
     let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
     let size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
 
-    let constrained_available_space = size
+    let constrained_available_space = known_dimensions
+        .or(size)
         .maybe_clamp(min_size, max_size)
         .map(|size| size.map(AvailableSpace::Definite))
-        .unwrap_or(available_space.maybe_clamp(min_size, max_size));
+        .unwrap_or(available_space.map(|space| match space {
+            // Available grid space should not depend on Definite available space as a grid is allowed
+            // to expand beyond it's available space
+            AvailableSpace::Definite(_) => AvailableSpace::MaxContent,
+            _ => space,
+        }));
 
     let available_grid_space = Size {
         width: constrained_available_space
@@ -160,7 +166,7 @@ pub fn compute(
             .map_definite_value(|space| space - padding.vertical_axis_sum() - border.vertical_axis_sum()),
     };
 
-    let outer_node_size = size.maybe_clamp(min_size, max_size).or(parent_size.maybe_sub(margin.sum_axes()));
+    let outer_node_size = known_dimensions.or(size.maybe_clamp(min_size, max_size).or(min_size));
     let mut inner_node_size = Size {
         width: outer_node_size.width.map(|space| space - padding.horizontal_axis_sum() - border.horizontal_axis_sum()),
         height: outer_node_size.height.map(|space| space - padding.vertical_axis_sum() - border.vertical_axis_sum()),
@@ -205,7 +211,7 @@ pub fn compute(
     let initial_column_sum = columns.iter().map(|track| track.base_size).sum::<f32>();
     inner_node_size.width = inner_node_size.width.or_else(|| initial_column_sum.into());
 
-    items.iter_mut().for_each(|item| item.known_dimensions_cache = None);
+    items.iter_mut().for_each(|item| item.available_space_cache = None);
 
     // Run track sizing algorithm for Block axis
     track_sizing_algorithm(
@@ -280,18 +286,18 @@ pub fn compute(
             .iter_mut()
             .filter(|item| item.crosses_intrinsic_column)
             .map(|item| {
-                let known_dimensions = item.known_dimensions(
+                let available_space = item.available_space(
                     AbstractAxis::Inline,
                     &rows,
                     inner_node_size.height,
                     |track: &GridTrack, _| Some(track.base_size),
                 );
                 let new_min_content_contribution =
-                    item.min_content_contribution(AbstractAxis::Inline, tree, known_dimensions, inner_node_size);
+                    item.min_content_contribution(AbstractAxis::Inline, tree, available_space, inner_node_size);
 
                 let has_changed = Some(new_min_content_contribution) != item.min_content_contribution_cache.width;
 
-                item.known_dimensions_cache = Some(known_dimensions);
+                item.available_space_cache = Some(available_space);
                 item.min_content_contribution_cache.width = Some(new_min_content_contribution);
                 item.max_content_contribution_cache.width = None;
                 item.minimum_contribution_cache.width = None;
@@ -303,7 +309,7 @@ pub fn compute(
     } else {
         // Clear intrisic width caches
         items.iter_mut().for_each(|item| {
-            item.known_dimensions_cache = None;
+            item.available_space_cache = None;
             item.min_content_contribution_cache.width = None;
             item.max_content_contribution_cache.width = None;
             item.minimum_contribution_cache.width = None;
@@ -342,18 +348,18 @@ pub fn compute(
                 .iter_mut()
                 .filter(|item| item.crosses_intrinsic_column)
                 .map(|item| {
-                    let known_dimensions = item.known_dimensions(
+                    let available_space = item.available_space(
                         AbstractAxis::Block,
                         &columns,
                         inner_node_size.width,
                         |track: &GridTrack, _| Some(track.base_size),
                     );
                     let new_min_content_contribution =
-                        item.min_content_contribution(AbstractAxis::Block, tree, known_dimensions, inner_node_size);
+                        item.min_content_contribution(AbstractAxis::Block, tree, available_space, inner_node_size);
 
                     let has_changed = Some(new_min_content_contribution) != item.min_content_contribution_cache.height;
 
-                    item.known_dimensions_cache = Some(known_dimensions);
+                    item.available_space_cache = Some(available_space);
                     item.min_content_contribution_cache.height = Some(new_min_content_contribution);
                     item.max_content_contribution_cache.height = None;
                     item.minimum_contribution_cache.height = None;
@@ -365,7 +371,7 @@ pub fn compute(
         } else {
             items.iter_mut().for_each(|item| {
                 // Clear intrisic height caches
-                item.known_dimensions_cache = None;
+                item.available_space_cache = None;
                 item.min_content_contribution_cache.height = None;
                 item.max_content_contribution_cache.height = None;
                 item.minimum_contribution_cache.height = None;
diff --git a/src/compute/grid/placement.rs b/src/compute/grid/placement.rs
index 5d829b804..52cfbf8d7 100644
--- a/src/compute/grid/placement.rs
+++ b/src/compute/grid/placement.rs
@@ -18,6 +18,7 @@ pub(super) fn place_grid_items<'a, ChildIter>(
     children_iter: impl Fn() -> ChildIter,
     grid_auto_flow: GridAutoFlow,
     align_items: AlignItems,
+    justify_items: AlignItems,
 ) where
     ChildIter: Iterator<Item = (usize, Node, &'a Style)>,
 {
@@ -54,6 +55,7 @@ pub(super) fn place_grid_items<'a, ChildIter>(
                 index,
                 style,
                 align_items,
+                justify_items,
                 primary_axis,
                 row_span,
                 col_span,
@@ -84,6 +86,7 @@ pub(super) fn place_grid_items<'a, ChildIter>(
                 index,
                 style,
                 align_items,
+                justify_items,
                 primary_axis,
                 primary_span,
                 secondary_span,
@@ -139,6 +142,7 @@ pub(super) fn place_grid_items<'a, ChildIter>(
                 index,
                 style,
                 align_items,
+                justify_items,
                 primary_axis,
                 primary_span,
                 secondary_span,
@@ -297,6 +301,7 @@ fn record_grid_placement(
     index: usize,
     style: &Style,
     parent_align_items: AlignItems,
+    parent_justify_items: AlignItems,
     primary_axis: AbsoluteAxis,
     primary_span: Line<OriginZeroLine>,
     secondary_span: Line<OriginZeroLine>,
@@ -321,6 +326,7 @@ fn record_grid_placement(
         row_span,
         style,
         parent_align_items,
+        parent_justify_items,
         index as u16,
     ));
 
@@ -368,7 +374,14 @@ mod tests {
                 CellOccupancyMatrix::with_track_counts(estimated_sizes.0, estimated_sizes.1);
 
             // Run placement algorithm
-            place_grid_items(&mut cell_occupancy_matrix, &mut items, children_iter, flow, AlignSelf::Start);
+            place_grid_items(
+                &mut cell_occupancy_matrix,
+                &mut items,
+                children_iter,
+                flow,
+                AlignSelf::Start,
+                AlignSelf::Start,
+            );
 
             // Assert that each item has been placed in the right location
             let mut sorted_children = children.clone();
diff --git a/src/compute/grid/track_sizing.rs b/src/compute/grid/track_sizing.rs
index 72912160d..51a4a7f8b 100644
--- a/src/compute/grid/track_sizing.rs
+++ b/src/compute/grid/track_sizing.rs
@@ -3,7 +3,7 @@
 use super::types::{GridItem, GridTrack, TrackCounts};
 use crate::axis::AbstractAxis;
 use crate::compute::{GenericAlgorithm, LayoutAlgorithm};
-use crate::geometry::{Rect, Size};
+use crate::geometry::Size;
 use crate::layout::SizingMode;
 use crate::math::MaybeMath;
 use crate::prelude::{LayoutTree, TaffyMinContent};
@@ -91,13 +91,13 @@ where
     Tree: LayoutTree,
     EstimateFunction: Fn(&GridTrack, Option<f32>) -> Option<f32>,
 {
-    /// Compute the known_dimensions to be passed to the child sizing functions
+    /// Compute the available_space to be passed to the child sizing functions
     /// These are estimates based on either the max track sizing function or the provisional base size in the opposite
     /// axis to the one currently being sized.
     /// https://www.w3.org/TR/css-grid-1/#algo-overview
     #[inline(always)]
-    fn known_dimensions(&self, item: &mut GridItem) -> Size<Option<f32>> {
-        item.known_dimensions_cached(
+    fn available_space(&self, item: &mut GridItem) -> Size<Option<f32>> {
+        item.available_space_cached(
             self.axis,
             self.other_axis_tracks,
             self.inner_node_size.get(self.axis.other()),
@@ -109,33 +109,26 @@ where
     /// to zero if the container size is indefinite as otherwise this would introduce a cyclic dependency.
     #[inline(always)]
     fn margins_axis_sums_with_baseline_shims(&self, item: &mut GridItem) -> Size<f32> {
-        let parent_width = self.inner_node_size.width;
-        Rect {
-            left: item.margin.left.resolve_or_zero(Some(0.0)),
-            right: item.margin.right.resolve_or_zero(Some(0.0)),
-            top: item.margin.top.resolve_or_zero(parent_width) + item.baseline_shim,
-            bottom: item.margin.bottom.resolve_or_zero(parent_width),
-        }
-        .sum_axes()
+        item.margins_axis_sums_with_baseline_shims(self.inner_node_size.width)
     }
 
     /// Retrieve the item's min content contribution from the cache or compute it using the provided parameters
     #[inline(always)]
     fn min_content_contribution(&mut self, item: &mut GridItem) -> f32 {
-        let known_dimensions = self.known_dimensions(item);
+        let available_space = self.available_space(item);
         let margin_axis_sums = self.margins_axis_sums_with_baseline_shims(item);
         let contribution =
-            item.min_content_contribution_cached(self.axis, self.tree, known_dimensions, self.inner_node_size);
+            item.min_content_contribution_cached(self.axis, self.tree, available_space, self.inner_node_size);
         contribution + margin_axis_sums.get(self.axis)
     }
 
     /// Retrieve the item's max content contribution from the cache or compute it using the provided parameters
     #[inline(always)]
     fn max_content_contribution(&mut self, item: &mut GridItem) -> f32 {
-        let known_dimensions = self.known_dimensions(item);
+        let available_space = self.available_space(item);
         let margin_axis_sums = self.margins_axis_sums_with_baseline_shims(item);
         let contribution =
-            item.max_content_contribution_cached(self.axis, self.tree, known_dimensions, self.inner_node_size);
+            item.max_content_contribution_cached(self.axis, self.tree, available_space, self.inner_node_size);
         contribution + margin_axis_sums.get(self.axis)
     }
 
@@ -147,10 +140,10 @@ where
     /// Because the minimum contribution often depends on the size of the item’s content, it is considered a type of intrinsic size contribution.
     #[inline(always)]
     fn minimum_contribution(&mut self, item: &mut GridItem, axis_tracks: &[GridTrack]) -> f32 {
-        let known_dimensions = self.known_dimensions(item);
+        let available_space = self.available_space(item);
         let margin_axis_sums = self.margins_axis_sums_with_baseline_shims(item);
         let contribution =
-            item.minimum_contribution_cached(self.tree, self.axis, axis_tracks, known_dimensions, self.inner_node_size);
+            item.minimum_contribution_cached(self.tree, self.axis, axis_tracks, available_space, self.inner_node_size);
         contribution + margin_axis_sums.get(self.axis)
     }
 }
diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs
index 92ef22e64..168e654d9 100644
--- a/src/compute/grid/types/grid_item.rs
+++ b/src/compute/grid/types/grid_item.rs
@@ -8,11 +8,10 @@ use crate::layout::SizingMode;
 use crate::math::MaybeMath;
 use crate::node::Node;
 use crate::prelude::LayoutTree;
-use crate::resolve::MaybeResolve;
+use crate::resolve::{MaybeResolve, ResolveOrZero};
 use crate::style::{
-    AlignItems, AlignSelf, LengthPercentageAuto, MaxTrackSizingFunction, MinTrackSizingFunction, Style,
+    AlignItems, AlignSelf, AvailableSpace, LengthPercentageAuto, MaxTrackSizingFunction, MinTrackSizingFunction, Style,
 };
-use crate::style_helpers::*;
 use core::ops::Range;
 
 /// Represents a single grid item
@@ -38,6 +37,8 @@ pub(in super::super) struct GridItem {
     pub margin: Rect<LengthPercentageAuto>,
     /// The item's align_self property, or the parent's align_items property is not set
     pub align_self: AlignSelf,
+    /// The item's justify_self property, or the parent's justify_items property is not set
+    pub justify_self: AlignSelf,
     /// The items first baseline (horizontal)
     pub baseline: Option<f32>,
     /// Shim for baseline alignment that acts like an extra top margin
@@ -62,7 +63,7 @@ pub(in super::super) struct GridItem {
 
     // Caches for intrinsic size computation. These caches are only valid for a single run of the track-sizing algorithm.
     /// Cache for the known_dimensions input to intrinsic sizing computation
-    pub known_dimensions_cache: Option<Size<Option<f32>>>,
+    pub available_space_cache: Option<Size<Option<f32>>>,
     /// Cache for the min-content size
     pub min_content_contribution_cache: Size<Option<f32>>,
     /// Cache for the minimum contribution
@@ -79,6 +80,7 @@ impl GridItem {
         row_span: Line<OriginZeroLine>,
         style: &Style,
         parent_align_items: AlignItems,
+        parent_justify_items: AlignItems,
         source_order: u16,
     ) -> Self {
         GridItem {
@@ -88,6 +90,7 @@ impl GridItem {
             column: col_span,
             margin: style.margin,
             align_self: style.align_self.unwrap_or(parent_align_items),
+            justify_self: style.justify_self.unwrap_or(parent_justify_items),
             baseline: None,
             baseline_shim: 0.0,
             row_indexes: Line { start: 0, end: 0 }, // Properly initialised later
@@ -96,7 +99,7 @@ impl GridItem {
             crosses_flexible_column: false,         // Properly initialised later
             crosses_intrinsic_row: false,           // Properly initialised later
             crosses_intrinsic_column: false,        // Properly initialised later
-            known_dimensions_cache: None,
+            available_space_cache: None,
             min_content_contribution_cache: Size::NONE,
             max_content_contribution_cache: Size::NONE,
             minimum_contribution_cache: Size::NONE,
@@ -200,10 +203,72 @@ impl GridItem {
     }
 
     /// Compute the known_dimensions to be passed to the child sizing functions
+    /// The key thing that is being done here is applying stretch alignment, which is necessary to
+    /// allow percentage sizes further down the tree to resolve properly in some cases
+    fn known_dimensions(
+        &self,
+        tree: &mut impl LayoutTree,
+        inner_node_size: Size<Option<f32>>,
+        grid_area_size: Size<Option<f32>>,
+    ) -> Size<Option<f32>> {
+        let margins = self.margins_axis_sums_with_baseline_shims(inner_node_size.width);
+
+        let style = tree.style(self.node);
+        let aspect_ratio = style.aspect_ratio;
+        let inherent_size = style.size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
+        let min_size = style.min_size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
+        let max_size = style.max_size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
+
+        let grid_area_minus_item_margins_size = grid_area_size.maybe_sub(margins);
+
+        // If node is absolutely positioned and width is not set explicitly, then deduce it
+        // from left, right and container_content_box if both are set.
+        let width = inherent_size.width.or_else(|| {
+            // Apply width based on stretch alignment if:
+            //  - Alignment style is "stretch"
+            //  - The node is not absolutely positioned
+            //  - The node does not have auto margins in this axis.
+            if style.margin.left != LengthPercentageAuto::Auto
+                && style.margin.right != LengthPercentageAuto::Auto
+                && self.justify_self == AlignSelf::Stretch
+            {
+                return grid_area_minus_item_margins_size.width;
+            }
+
+            None
+        });
+        // Reapply aspect ratio after stretch and absolute position width adjustments
+        let Size { width, height } =
+            Size { width, height: inherent_size.height }.maybe_apply_aspect_ratio(aspect_ratio);
+
+        let height = height.or_else(|| {
+            // Apply height based on stretch alignment if:
+            //  - Alignment style is "stretch"
+            //  - The node is not absolutely positioned
+            //  - The node does not have auto margins in this axis.
+            if style.margin.top != LengthPercentageAuto::Auto
+                && style.margin.bottom != LengthPercentageAuto::Auto
+                && self.align_self == AlignSelf::Stretch
+            {
+                return grid_area_minus_item_margins_size.height;
+            }
+
+            None
+        });
+        // Reapply aspect ratio after stretch and absolute position height adjustments
+        let Size { width, height } = Size { width, height }.maybe_apply_aspect_ratio(aspect_ratio);
+
+        // Clamp size by min and max width/height
+        let Size { width, height } = Size { width, height }.maybe_clamp(min_size, max_size);
+
+        Size { width, height }
+    }
+
+    /// Compute the available_space to be passed to the child sizing functions
     /// These are estimates based on either the max track sizing function or the provisional base size in the opposite
     /// axis to the one currently being sized.
     /// https://www.w3.org/TR/css-grid-1/#algo-overview
-    pub fn known_dimensions(
+    pub fn available_space(
         &self,
         axis: AbstractAxis,
         other_axis_tracks: &[GridTrack],
@@ -225,36 +290,53 @@ impl GridItem {
         size
     }
 
-    /// Retrieve the known_dimensions from the cache or compute them using the passed parameters
-    pub fn known_dimensions_cached(
+    /// Retrieve the available_space from the cache or compute them using the passed parameters
+    pub fn available_space_cached(
         &mut self,
         axis: AbstractAxis,
         other_axis_tracks: &[GridTrack],
         other_axis_available_space: Option<f32>,
         get_track_size_estimate: impl Fn(&GridTrack, Option<f32>) -> Option<f32>,
     ) -> Size<Option<f32>> {
-        self.known_dimensions_cache.unwrap_or_else(|| {
-            let known_dimensions =
-                self.known_dimensions(axis, other_axis_tracks, other_axis_available_space, get_track_size_estimate);
-            self.known_dimensions_cache = Some(known_dimensions);
-            known_dimensions
+        self.available_space_cache.unwrap_or_else(|| {
+            let available_spaces =
+                self.available_space(axis, other_axis_tracks, other_axis_available_space, get_track_size_estimate);
+            self.available_space_cache = Some(available_spaces);
+            available_spaces
         })
     }
 
+    /// Compute the item's resolved margins for size contributions. Horizontal percentage margins always resolve
+    /// to zero if the container size is indefinite as otherwise this would introduce a cyclic dependency.
+    #[inline(always)]
+    pub fn margins_axis_sums_with_baseline_shims(&self, inner_node_width: Option<f32>) -> Size<f32> {
+        Rect {
+            left: self.margin.left.resolve_or_zero(Some(0.0)),
+            right: self.margin.right.resolve_or_zero(Some(0.0)),
+            top: self.margin.top.resolve_or_zero(inner_node_width) + self.baseline_shim,
+            bottom: self.margin.bottom.resolve_or_zero(inner_node_width),
+        }
+        .sum_axes()
+    }
+
     /// Compute the item's min content contribution from the provided parameters
     pub fn min_content_contribution(
         &self,
         axis: AbstractAxis,
         tree: &mut impl LayoutTree,
-        known_dimensions: Size<Option<f32>>,
+        available_space: Size<Option<f32>>,
         inner_node_size: Size<Option<f32>>,
     ) -> f32 {
+        let known_dimensions = self.known_dimensions(tree, inner_node_size, available_space);
         GenericAlgorithm::measure_size(
             tree,
             self.node,
             known_dimensions,
-            inner_node_size,
-            Size::MIN_CONTENT,
+            available_space,
+            available_space.map(|opt| match opt {
+                Some(size) => AvailableSpace::Definite(size),
+                None => AvailableSpace::MinContent,
+            }),
             SizingMode::InherentSize,
         )
         .get(axis)
@@ -266,11 +348,11 @@ impl GridItem {
         &mut self,
         axis: AbstractAxis,
         tree: &mut impl LayoutTree,
-        known_dimensions: Size<Option<f32>>,
+        available_space: Size<Option<f32>>,
         inner_node_size: Size<Option<f32>>,
     ) -> f32 {
         self.min_content_contribution_cache.get(axis).unwrap_or_else(|| {
-            let size = self.min_content_contribution(axis, tree, known_dimensions, inner_node_size);
+            let size = self.min_content_contribution(axis, tree, available_space, inner_node_size);
             self.min_content_contribution_cache.set(axis, Some(size));
             size
         })
@@ -281,15 +363,19 @@ impl GridItem {
         &self,
         axis: AbstractAxis,
         tree: &mut impl LayoutTree,
-        known_dimensions: Size<Option<f32>>,
+        available_space: Size<Option<f32>>,
         inner_node_size: Size<Option<f32>>,
     ) -> f32 {
+        let known_dimensions = self.known_dimensions(tree, inner_node_size, available_space);
         GenericAlgorithm::measure_size(
             tree,
             self.node,
             known_dimensions,
-            inner_node_size,
-            Size::MAX_CONTENT,
+            available_space,
+            available_space.map(|opt| match opt {
+                Some(size) => AvailableSpace::Definite(size),
+                None => AvailableSpace::MaxContent,
+            }),
             SizingMode::InherentSize,
         )
         .get(axis)
@@ -301,11 +387,11 @@ impl GridItem {
         &mut self,
         axis: AbstractAxis,
         tree: &mut impl LayoutTree,
-        known_dimensions: Size<Option<f32>>,
+        available_space: Size<Option<f32>>,
         inner_node_size: Size<Option<f32>>,
     ) -> f32 {
         self.max_content_contribution_cache.get(axis).unwrap_or_else(|| {
-            let size = self.max_content_contribution(axis, tree, known_dimensions, inner_node_size);
+            let size = self.max_content_contribution(axis, tree, available_space, inner_node_size);
             self.max_content_contribution_cache.set(axis, Some(size));
             size
         })
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 5bf1dc6dd..479644b91 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -149,8 +149,6 @@ fn compute_node_layout(
         return cached_size_and_baselines;
     }
 
-    #[cfg(feature = "debug")]
-    NODE_LOGGER.log("COMPUTE");
     #[cfg(feature = "debug")]
     debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
 
@@ -248,7 +246,7 @@ fn debug_log_node(
     run_mode: RunMode,
     sizing_mode: SizingMode,
 ) {
-    NODE_LOGGER.labelled_debug_log("run_mode", run_mode);
+    NODE_LOGGER.debug_log(run_mode);
     NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
     NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
     NODE_LOGGER.labelled_debug_log("available_space", available_space);
diff --git a/test_fixtures/grid_percent_item_inside_stretch_item.html b/test_fixtures/grid_percent_item_inside_stretch_item.html
new file mode 100644
index 000000000..cba30846a
--- /dev/null
+++ b/test_fixtures/grid_percent_item_inside_stretch_item.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="display:grid;width: 100px; height: 100px;">
+  <div style="display: grid;">
+    <div style="display: grid;width: 50%;"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_percent_items_nested_inside_stretch_alignment.html b/test_fixtures/grid_percent_items_nested_inside_stretch_alignment.html
new file mode 100644
index 000000000..970ef562c
--- /dev/null
+++ b/test_fixtures/grid_percent_items_nested_inside_stretch_alignment.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="display:grid;width: 200px;">
+  <div style="display: grid;">
+    <div style="display: grid;padding-top: 20%;"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_percent_items_nested_with_margin.html b/test_fixtures/grid_percent_items_nested_with_margin.html
new file mode 100644
index 000000000..12f27c2c3
--- /dev/null
+++ b/test_fixtures/grid_percent_items_nested_with_margin.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="display: grid;width: 200px;">
+  <div style="display: grid;width: 50%;">
+    <div style="width: 45%; margin: 5%;"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/gridflex_column_integration.html b/test_fixtures/gridflex_column_integration.html
new file mode 100644
index 000000000..f68d01a1a
--- /dev/null
+++ b/test_fixtures/gridflex_column_integration.html
@@ -0,0 +1,22 @@
+<!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="display: grid; grid-template-columns: 1fr 1fr;grid-template-rows: 1fr 1fr;">
+    <div>HH</div>
+    <div>HH</div>
+    <div>HH</div>
+    <div>HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/gridflex_kitchen_sink.html b/test_fixtures/gridflex_kitchen_sink.html
new file mode 100644
index 000000000..4ed76c35e
--- /dev/null
+++ b/test_fixtures/gridflex_kitchen_sink.html
@@ -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">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="display: grid; grid-template-columns: 1fr 1fr;grid-template-rows: 1fr 1fr;">
+    <div>
+      <div style="width: 20px"></div>
+      <div style="width: 50px;flex-grow: 1">
+        <div style="display: grid; grid-template-columns: auto 10%;grid-template-rows: 30% 10%">
+          <div style="width: 20px"></div>
+          <div></div>
+          <div></div>
+          <div></div>
+        </div>
+      </div>
+    </div>
+    <div>HH</div>
+    <div>HH</div>
+    <div>HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/gridflex_kitchen_sink_minimise.html b/test_fixtures/gridflex_kitchen_sink_minimise.html
new file mode 100644
index 000000000..211d45c28
--- /dev/null
+++ b/test_fixtures/gridflex_kitchen_sink_minimise.html
@@ -0,0 +1,20 @@
+<!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">
+  <div style="display: grid; grid-template-columns: 1fr 1fr;grid-template-rows: 20px">
+    <div style="width: 50px"></div>
+    <div></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/gridflex_kitchen_sink_minimise2.html b/test_fixtures/gridflex_kitchen_sink_minimise2.html
new file mode 100644
index 000000000..5423cd5c5
--- /dev/null
+++ b/test_fixtures/gridflex_kitchen_sink_minimise2.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="width: 50px;flex-grow: 1">
+  <div style="display: grid; grid-template-columns: auto;grid-template-rows:auto">
+    <div style="height:20px;width: 20px"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/gridflex_kitchen_sink_minimise3.html b/test_fixtures/gridflex_kitchen_sink_minimise3.html
new file mode 100644
index 000000000..50fe2a458
--- /dev/null
+++ b/test_fixtures/gridflex_kitchen_sink_minimise3.html
@@ -0,0 +1,22 @@
+<!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: 50px;">
+  <div style="display: grid;grid-template-columns: auto 10%;grid-template-rows: 30% 10%">
+    <div style="height: 20px;width: 20px"></div>
+    <div></div>
+    <div></div>
+    <div></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/gridflex_row_integration.html b/test_fixtures/gridflex_row_integration.html
new file mode 100644
index 000000000..e7516eb95
--- /dev/null
+++ b/test_fixtures/gridflex_row_integration.html
@@ -0,0 +1,22 @@
+<!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">
+  <div  style="display: grid; grid-template-columns: 1fr 1fr;grid-template-rows: 1fr 1fr;">
+    <div>HH</div>
+    <div>HH</div>
+    <div>HH</div>
+    <div>HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/grid_percent_item_inside_stretch_item.rs b/tests/generated/grid_percent_item_inside_stretch_item.rs
new file mode 100644
index 000000000..705df3986
--- /dev/null
+++ b/tests/generated/grid_percent_item_inside_stretch_item.rs
@@ -0,0 +1,52 @@
+#[test]
+fn grid_percent_item_inside_stretch_item() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            display: taffy::style::Display::Grid,
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style { display: taffy::style::Display::Grid, ..Default::default() },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 50f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_percent_items_nested_inside_stretch_alignment.rs b/tests/generated/grid_percent_items_nested_inside_stretch_alignment.rs
new file mode 100644
index 000000000..e164551b4
--- /dev/null
+++ b/tests/generated/grid_percent_items_nested_inside_stretch_alignment.rs
@@ -0,0 +1,54 @@
+#[test]
+fn grid_percent_items_nested_inside_stretch_alignment() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            display: taffy::style::Display::Grid,
+            padding: taffy::geometry::Rect {
+                left: zero(),
+                right: zero(),
+                top: taffy::style::LengthPercentage::Percent(0.2f32),
+                bottom: zero(),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style { display: taffy::style::Display::Grid, ..Default::default() },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(200f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, size.width);
+    assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 200f32, size.width);
+    assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 40f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_percent_items_nested_with_margin.rs b/tests/generated/grid_percent_items_nested_with_margin.rs
new file mode 100644
index 000000000..71197b74f
--- /dev/null
+++ b/tests/generated/grid_percent_items_nested_with_margin.rs
@@ -0,0 +1,58 @@
+#[test]
+fn grid_percent_items_nested_with_margin() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.45f32), height: auto() },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                right: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                top: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                bottom: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(200f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 45f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 45f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 5f32, location.y);
+}
diff --git a/tests/generated/gridflex_column_integration.rs b/tests/generated/gridflex_column_integration.rs
new file mode 100644
index 000000000..71835a678
--- /dev/null
+++ b/tests/generated/gridflex_column_integration.rs
@@ -0,0 +1,118 @@
+#[test]
+fn gridflex_column_integration() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node01 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node02 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node03 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![flex(1f32), flex(1f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .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::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 10f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node02).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node02.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node02.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node02.data(), 0f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node02.data(), 10f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node03).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node03.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node03.data(), 10f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node03.data(), 20f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node03.data(), 10f32, location.y);
+}
diff --git a/tests/generated/gridflex_kitchen_sink.rs b/tests/generated/gridflex_kitchen_sink.rs
new file mode 100644
index 000000000..465718d92
--- /dev/null
+++ b/tests/generated/gridflex_kitchen_sink.rs
@@ -0,0 +1,170 @@
+#[test]
+fn gridflex_kitchen_sink() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node000 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(20f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node00100 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(20f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node00101 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node00102 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node00103 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0010 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.1f32)],
+                grid_template_columns: vec![auto(), percent(0.1f32)],
+                ..Default::default()
+            },
+            &[node00100, node00101, node00102, node00103],
+        )
+        .unwrap();
+    let node001 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_grow: 1f32,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0010],
+        )
+        .unwrap();
+    let node00 = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node000, node001]).unwrap();
+    let node01 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node02 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node03 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![flex(1f32), flex(1f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 140f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 140f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 140f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 140f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 70f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 70f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node000).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node000.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node000.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node000.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node000.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node001).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node001.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node001.data(), 10f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node001.data(), 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node001.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0010).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node0010.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node0010.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0010.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0010.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00100).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00100.data(), 20f32, size.width);
+    assert_eq!(size.height, 3f32, "height of node {:?}. Expected {}. Actual {}", node00100.data(), 3f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00100.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00100.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00101).unwrap();
+    assert_eq!(size.width, 2f32, "width of node {:?}. Expected {}. Actual {}", node00101.data(), 2f32, size.width);
+    assert_eq!(size.height, 3f32, "height of node {:?}. Expected {}. Actual {}", node00101.data(), 3f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node00101.data(), 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00101.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00102).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00102.data(), 20f32, size.width);
+    assert_eq!(size.height, 1f32, "height of node {:?}. Expected {}. Actual {}", node00102.data(), 1f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00102.data(), 0f32, location.x);
+    assert_eq!(location.y, 3f32, "y of node {:?}. Expected {}. Actual {}", node00102.data(), 3f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00103).unwrap();
+    assert_eq!(size.width, 2f32, "width of node {:?}. Expected {}. Actual {}", node00103.data(), 2f32, size.width);
+    assert_eq!(size.height, 1f32, "height of node {:?}. Expected {}. Actual {}", node00103.data(), 1f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node00103.data(), 20f32, location.x);
+    assert_eq!(location.y, 3f32, "y of node {:?}. Expected {}. Actual {}", node00103.data(), 3f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 70f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 70f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 10f32, size.height);
+    assert_eq!(location.x, 70f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 70f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node02).unwrap();
+    assert_eq!(size.width, 70f32, "width of node {:?}. Expected {}. Actual {}", node02.data(), 70f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node02.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node02.data(), 0f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node02.data(), 10f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node03).unwrap();
+    assert_eq!(size.width, 70f32, "width of node {:?}. Expected {}. Actual {}", node03.data(), 70f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node03.data(), 10f32, size.height);
+    assert_eq!(location.x, 70f32, "x of node {:?}. Expected {}. Actual {}", node03.data(), 70f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node03.data(), 10f32, location.y);
+}
diff --git a/tests/generated/gridflex_kitchen_sink_minimise.rs b/tests/generated/gridflex_kitchen_sink_minimise.rs
new file mode 100644
index 000000000..65e214c29
--- /dev/null
+++ b/tests/generated/gridflex_kitchen_sink_minimise.rs
@@ -0,0 +1,50 @@
+#[test]
+fn gridflex_kitchen_sink_minimise() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![points(20f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+}
diff --git a/tests/generated/gridflex_kitchen_sink_minimise2.rs b/tests/generated/gridflex_kitchen_sink_minimise2.rs
new file mode 100644
index 000000000..2ed6b78a3
--- /dev/null
+++ b/tests/generated/gridflex_kitchen_sink_minimise2.rs
@@ -0,0 +1,56 @@
+#[test]
+fn gridflex_kitchen_sink_minimise2() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(20f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![auto()],
+                grid_template_columns: vec![auto()],
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_grow: 1f32,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+}
diff --git a/tests/generated/gridflex_kitchen_sink_minimise3.rs b/tests/generated/gridflex_kitchen_sink_minimise3.rs
new file mode 100644
index 000000000..6876ba77a
--- /dev/null
+++ b/tests/generated/gridflex_kitchen_sink_minimise3.rs
@@ -0,0 +1,73 @@
+#[test]
+fn gridflex_kitchen_sink_minimise3() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(20f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node02 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node03 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.1f32)],
+                grid_template_columns: vec![auto(), percent(0.1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(50f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 2f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 2f32, size.width);
+    assert_eq!(size.height, 6f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 6f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node02).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node02.data(), 20f32, size.width);
+    assert_eq!(size.height, 2f32, "height of node {:?}. Expected {}. Actual {}", node02.data(), 2f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node02.data(), 0f32, location.x);
+    assert_eq!(location.y, 6f32, "y of node {:?}. Expected {}. Actual {}", node02.data(), 6f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node03).unwrap();
+    assert_eq!(size.width, 2f32, "width of node {:?}. Expected {}. Actual {}", node03.data(), 2f32, size.width);
+    assert_eq!(size.height, 2f32, "height of node {:?}. Expected {}. Actual {}", node03.data(), 2f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node03.data(), 20f32, location.x);
+    assert_eq!(location.y, 6f32, "y of node {:?}. Expected {}. Actual {}", node03.data(), 6f32, location.y);
+}
diff --git a/tests/generated/gridflex_row_integration.rs b/tests/generated/gridflex_row_integration.rs
new file mode 100644
index 000000000..bf536a65c
--- /dev/null
+++ b/tests/generated/gridflex_row_integration.rs
@@ -0,0 +1,113 @@
+#[test]
+fn gridflex_row_integration() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node01 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node02 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node03 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![flex(1f32), flex(1f32)],
+                grid_template_columns: vec![flex(1f32), flex(1f32)],
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 10f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node02).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node02.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node02.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node02.data(), 0f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node02.data(), 10f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node03).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node03.data(), 20f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node03.data(), 10f32, size.height);
+    assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node03.data(), 20f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node03.data(), 10f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index 53ff8577b..83b4a2a7b 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -640,8 +640,14 @@ mod grid_out_of_order_items;
 #[cfg(feature = "grid")]
 mod grid_overflow_rows;
 #[cfg(feature = "grid")]
+mod grid_percent_item_inside_stretch_item;
+#[cfg(feature = "grid")]
+mod grid_percent_items_nested_inside_stretch_alignment;
+#[cfg(feature = "grid")]
 mod grid_percent_items_nested_moderate;
 #[cfg(feature = "grid")]
+mod grid_percent_items_nested_with_margin;
+#[cfg(feature = "grid")]
 mod grid_percent_items_nested_with_padding_margin;
 #[cfg(feature = "grid")]
 mod grid_percent_items_width_and_margin;
@@ -697,6 +703,18 @@ mod grid_span_2_min_content_min_content_indefinite;
 mod grid_span_6_all_non_flex_indefinite;
 #[cfg(feature = "grid")]
 mod grid_span_8_all_track_types_indefinite;
+#[cfg(feature = "grid")]
+mod gridflex_column_integration;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink_minimise;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink_minimise2;
+#[cfg(feature = "grid")]
+mod gridflex_kitchen_sink_minimise3;
+#[cfg(feature = "grid")]
+mod gridflex_row_integration;
 mod intrinsic_sizing_cross_size_column;
 mod intrinsic_sizing_main_size_column;
 mod intrinsic_sizing_main_size_column_nested;