tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 709HTML 662Markdown 12TOML 62348 Definitions

Fix percent sized tracks (#314)

* Fix FromPercent implementations for Dimension and LengthPercentage(Auto)

They were previously incorrectly returning the Points variant rather
than the Percent variant.

* Add more combinator functions to AvailableSpace

* Implement re-resolving percentage track sizes in the case of indefinite container size

* Rename tests for items with percentage sizes to percent_items_*

* Adds tests for percentage sized grid tracks

06a168cb163711059f7a98dc68d7a77225841876 · by Nico Burns · (3 years ago) · parent 320118ed7 · browse the tree at this commit

Semantic delta · 62

benches/generated/grid_percent_items_nested_moderate.rs

benches/generated/grid_percent_items_nested_with_padding_margin.rs

benches/generated/grid_percent_items_width_and_margin.rs

benches/generated/grid_percent_items_width_and_padding.rs

benches/generated/grid_percent_nested_moderate.rs

benches/generated/grid_percent_nested_with_padding_margin.rs

benches/generated/grid_percent_tracks_definite_overflow.rs

benches/generated/grid_percent_tracks_definite_underflow.rs

benches/generated/grid_percent_tracks_indefinite_only.rs

benches/generated/grid_percent_tracks_indefinite_with_content_overflow.rs

benches/generated/grid_percent_tracks_indefinite_with_content_underflow.rs

benches/generated/grid_percent_width_and_margin.rs

benches/generated/grid_percent_width_and_padding.rs

src/compute/grid/mod.rs

src/style/dimension.rs

src/style/grid.rs

tests/generated/grid_percent_items_nested_moderate.rs

tests/generated/grid_percent_items_nested_with_padding_margin.rs

tests/generated/grid_percent_items_width_and_margin.rs

tests/generated/grid_percent_items_width_and_padding.rs

tests/generated/grid_percent_nested_moderate.rs

tests/generated/grid_percent_nested_with_padding_margin.rs

tests/generated/grid_percent_tracks_definite_overflow.rs

tests/generated/grid_percent_tracks_definite_underflow.rs

tests/generated/grid_percent_tracks_indefinite_only.rs

tests/generated/grid_percent_tracks_indefinite_with_content_overflow.rs

tests/generated/grid_percent_tracks_indefinite_with_content_underflow.rs

tests/generated/grid_percent_width_and_margin.rs

tests/generated/grid_percent_width_and_padding.rs

44 files · +1327 −598

diff --git a/benches/generated/grid_percent_nested_moderate.rs b/benches/generated/grid_percent_items_nested_moderate.rs
similarity index 100%
rename from benches/generated/grid_percent_nested_moderate.rs
rename to benches/generated/grid_percent_items_nested_moderate.rs
diff --git a/benches/generated/grid_percent_nested_with_padding_margin.rs b/benches/generated/grid_percent_items_nested_with_padding_margin.rs
similarity index 100%
rename from benches/generated/grid_percent_nested_with_padding_margin.rs
rename to benches/generated/grid_percent_items_nested_with_padding_margin.rs
diff --git a/benches/generated/grid_percent_width_and_margin.rs b/benches/generated/grid_percent_items_width_and_margin.rs
similarity index 100%
rename from benches/generated/grid_percent_width_and_margin.rs
rename to benches/generated/grid_percent_items_width_and_margin.rs
diff --git a/benches/generated/grid_percent_width_and_padding.rs b/benches/generated/grid_percent_items_width_and_padding.rs
similarity index 100%
rename from benches/generated/grid_percent_width_and_padding.rs
rename to benches/generated/grid_percent_items_width_and_padding.rs
diff --git a/benches/generated/grid_percent_tracks_definite_overflow.rs b/benches/generated/grid_percent_tracks_definite_overflow.rs
new file mode 100644
index 000000000..102b6a446
--- /dev/null
+++ b/benches/generated/grid_percent_tracks_definite_overflow.rs
@@ -0,0 +1,27 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.5f32), percent(0.8f32)],
+                grid_template_columns: vec![percent(0.4f32), percent(0.4f32), percent(0.4f32)],
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(120f32),
+                    height: taffy::style::Dimension::Points(60f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_percent_tracks_definite_underflow.rs b/benches/generated/grid_percent_tracks_definite_underflow.rs
new file mode 100644
index 000000000..48d542fab
--- /dev/null
+++ b/benches/generated/grid_percent_tracks_definite_underflow.rs
@@ -0,0 +1,27 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.6f32)],
+                grid_template_columns: vec![percent(0.1f32), percent(0.2f32), percent(0.3f32)],
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(120f32),
+                    height: taffy::style::Dimension::Points(60f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_percent_tracks_indefinite_only.rs b/benches/generated/grid_percent_tracks_indefinite_only.rs
new file mode 100644
index 000000000..27c6d7492
--- /dev/null
+++ b/benches/generated/grid_percent_tracks_indefinite_only.rs
@@ -0,0 +1,23 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.6f32)],
+                grid_template_columns: vec![percent(0.1f32), percent(0.2f32), percent(0.3f32)],
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_percent_tracks_indefinite_with_content_overflow.rs b/benches/generated/grid_percent_tracks_indefinite_with_content_overflow.rs
new file mode 100644
index 000000000..8c06d6f6c
--- /dev/null
+++ b/benches/generated/grid_percent_tracks_indefinite_with_content_overflow.rs
@@ -0,0 +1,40 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(100f32),
+                height: taffy::style::Dimension::Points(100f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.5f32), percent(0.8f32)],
+                grid_template_columns: vec![percent(0.4f32), percent(0.4f32), percent(0.4f32)],
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5, node6],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_percent_tracks_indefinite_with_content_underflow.rs b/benches/generated/grid_percent_tracks_indefinite_with_content_underflow.rs
new file mode 100644
index 000000000..ae6efe06a
--- /dev/null
+++ b/benches/generated/grid_percent_tracks_indefinite_with_content_underflow.rs
@@ -0,0 +1,40 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(100f32),
+                height: taffy::style::Dimension::Points(100f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.6f32)],
+                grid_template_columns: vec![percent(0.1f32), percent(0.2f32), percent(0.3f32)],
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5, node6],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/mod.rs b/benches/generated/mod.rs
index a77424070..30c35db8b 100644
--- a/benches/generated/mod.rs
+++ b/benches/generated/mod.rs
@@ -405,13 +405,23 @@ mod grid_min_max_column_fixed_width_within_range;
 #[cfg(feature = "grid")]
 mod grid_out_of_order_items;
 #[cfg(feature = "grid")]
-mod grid_percent_nested_moderate;
+mod grid_percent_items_nested_moderate;
 #[cfg(feature = "grid")]
-mod grid_percent_nested_with_padding_margin;
+mod grid_percent_items_nested_with_padding_margin;
 #[cfg(feature = "grid")]
-mod grid_percent_width_and_margin;
+mod grid_percent_items_width_and_margin;
 #[cfg(feature = "grid")]
-mod grid_percent_width_and_padding;
+mod grid_percent_items_width_and_padding;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_definite_overflow;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_definite_underflow;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_indefinite_only;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_indefinite_with_content_overflow;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_indefinite_with_content_underflow;
 #[cfg(feature = "grid")]
 mod grid_placement_auto_negative;
 #[cfg(feature = "grid")]
@@ -919,13 +929,23 @@ fn benchmark(c: &mut Criterion) {
             #[cfg(feature = "grid")]
             grid_out_of_order_items::compute();
             #[cfg(feature = "grid")]
-            grid_percent_nested_moderate::compute();
+            grid_percent_items_nested_moderate::compute();
+            #[cfg(feature = "grid")]
+            grid_percent_items_nested_with_padding_margin::compute();
+            #[cfg(feature = "grid")]
+            grid_percent_items_width_and_margin::compute();
+            #[cfg(feature = "grid")]
+            grid_percent_items_width_and_padding::compute();
+            #[cfg(feature = "grid")]
+            grid_percent_tracks_definite_overflow::compute();
+            #[cfg(feature = "grid")]
+            grid_percent_tracks_definite_underflow::compute();
             #[cfg(feature = "grid")]
-            grid_percent_nested_with_padding_margin::compute();
+            grid_percent_tracks_indefinite_only::compute();
             #[cfg(feature = "grid")]
-            grid_percent_width_and_margin::compute();
+            grid_percent_tracks_indefinite_with_content_overflow::compute();
             #[cfg(feature = "grid")]
-            grid_percent_width_and_padding::compute();
+            grid_percent_tracks_indefinite_with_content_underflow::compute();
             #[cfg(feature = "grid")]
             grid_placement_auto_negative::compute();
             #[cfg(feature = "grid")]
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index 9ef66f0df..529dadaff 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -223,7 +223,27 @@ pub fn compute(
         height: container_border_box.height - padding.vertical_axis_sum() - border.vertical_axis_sum(),
     };
 
-    // 7. Track Alignment
+    // 7. Resolve percentage track base sizes
+    // In the case of an indefinitely sized container these resolve to zero during the "Initialise Tracks" step
+    // and therefore need to be re-resolved here based on the content-sized content box of the container
+    if !available_grid_space.width.is_definite() {
+        for column in &mut columns {
+            let min: Option<f32> =
+                column.min_track_sizing_function.resolved_percentage_size(container_content_box.width);
+            let max: Option<f32> =
+                column.max_track_sizing_function.resolved_percentage_size(container_content_box.width);
+            column.base_size = column.base_size.maybe_clamp(min, max);
+        }
+    }
+    if !available_grid_space.height.is_definite() {
+        for row in &mut rows {
+            let min: Option<f32> = row.min_track_sizing_function.resolved_percentage_size(container_content_box.height);
+            let max: Option<f32> = row.max_track_sizing_function.resolved_percentage_size(container_content_box.height);
+            row.base_size = row.base_size.maybe_clamp(min, max);
+        }
+    }
+
+    // 8. Track Alignment
 
     // Align columns
     align_tracks(
@@ -242,7 +262,7 @@ pub fn compute(
         style.align_content.unwrap_or(AlignContent::Stretch),
     );
 
-    // 8. Size, Align, and Position Grid Items
+    // 9. Size, Align, and Position Grid Items
 
     // Sort items back into original order to allow them to be matched up with styles
     items.sort_by_key(|item| item.source_order);
diff --git a/src/style/dimension.rs b/src/style/dimension.rs
index 01f5749b7..bd280cd4e 100644
--- a/src/style/dimension.rs
+++ b/src/style/dimension.rs
@@ -26,7 +26,7 @@ impl FromPoints for LengthPercentage {
 }
 impl FromPercent for LengthPercentage {
     fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
-        Self::Points(percent.into())
+        Self::Percent(percent.into())
     }
 }
 
@@ -57,7 +57,7 @@ impl FromPoints for LengthPercentageAuto {
 }
 impl FromPercent for LengthPercentageAuto {
     fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
-        Self::Points(percent.into())
+        Self::Percent(percent.into())
     }
 }
 
@@ -111,7 +111,7 @@ impl FromPoints for Dimension {
 }
 impl FromPercent for Dimension {
     fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
-        Self::Points(percent.into())
+        Self::Percent(percent.into())
     }
 }
 
@@ -226,6 +226,27 @@ impl AvailableSpace {
         self.into_option().unwrap()
     }
 
+    /// Return self if definite or a default value
+    pub fn or(self, default: AvailableSpace) -> AvailableSpace {
+        match self {
+            AvailableSpace::Definite(_) => self,
+            _ => default,
+        }
+    }
+
+    /// Return self if definite or a the result of the default value callback
+    pub fn or_else(self, default_cb: impl FnOnce() -> AvailableSpace) -> AvailableSpace {
+        match self {
+            AvailableSpace::Definite(_) => self,
+            _ => default_cb(),
+        }
+    }
+
+    /// Return the definite value or the result of the default value callback
+    pub fn unwrap_or_else(self, default_cb: impl FnOnce() -> f32) -> f32 {
+        self.into_option().unwrap_or_else(default_cb)
+    }
+
     /// If passed value is Some then return AvailableSpace::Definite containing that value, else return self
     pub fn maybe_set(self, value: Option<f32>) -> AvailableSpace {
         match value {
diff --git a/src/style/grid.rs b/src/style/grid.rs
index e06f49cdc..918f17482 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -323,6 +323,17 @@ impl MaxTrackSizingFunction {
             MinContent | MaxContent | FitContent(_) | Auto | Flex(_) => None,
         }
     }
+
+    /// Resolve percentage values against the passed parent_size, returning Some(value)
+    /// Non-percentage values always return None.
+    #[inline(always)]
+    pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
+        use MaxTrackSizingFunction::{Auto, *};
+        match self {
+            Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
+            Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | FitContent(_) | Auto | Flex(_) => None,
+        }
+    }
 }
 
 /// Minimum track sizing function
@@ -380,6 +391,17 @@ impl MinTrackSizingFunction {
             MinContent | MaxContent | Auto => None,
         }
     }
+
+    /// Resolve percentage values against the passed parent_size, returning Some(value)
+    /// Non-percentage values always return None.
+    #[inline(always)]
+    pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
+        use MinTrackSizingFunction::{Auto, *};
+        match self {
+            Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
+            Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | Auto => None,
+        }
+    }
 }
 
 /// The sizing function for a grid track (row/column) (either auto-track or template track)
diff --git a/test_fixtures/grid_percent_nested_moderate.html b/test_fixtures/grid_percent_items_nested_moderate.html
similarity index 100%
rename from test_fixtures/grid_percent_nested_moderate.html
rename to test_fixtures/grid_percent_items_nested_moderate.html
diff --git a/test_fixtures/grid_percent_nested_with_padding_margin.html b/test_fixtures/grid_percent_items_nested_with_padding_margin.html
similarity index 100%
rename from test_fixtures/grid_percent_nested_with_padding_margin.html
rename to test_fixtures/grid_percent_items_nested_with_padding_margin.html
diff --git a/test_fixtures/grid_percent_width_and_margin.html b/test_fixtures/grid_percent_items_width_and_margin.html
similarity index 100%
rename from test_fixtures/grid_percent_width_and_margin.html
rename to test_fixtures/grid_percent_items_width_and_margin.html
diff --git a/test_fixtures/grid_percent_width_and_padding.html b/test_fixtures/grid_percent_items_width_and_padding.html
similarity index 100%
rename from test_fixtures/grid_percent_width_and_padding.html
rename to test_fixtures/grid_percent_items_width_and_padding.html
diff --git a/test_fixtures/grid_percent_tracks_definite_overflow.html b/test_fixtures/grid_percent_tracks_definite_overflow.html
new file mode 100644
index 000000000..e7b172033
--- /dev/null
+++ b/test_fixtures/grid_percent_tracks_definite_overflow.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="height: 60px; width: 120px; display: grid; grid-template-columns: 40% 40% 40%;grid-template-rows: 50% 80%;">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_percent_tracks_definite_underflow.html b/test_fixtures/grid_percent_tracks_definite_underflow.html
new file mode 100644
index 000000000..a897f9fed
--- /dev/null
+++ b/test_fixtures/grid_percent_tracks_definite_underflow.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="height: 60px; width: 120px; display: grid; grid-template-columns: 10% 20% 30%;grid-template-rows: 30% 60%;">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_percent_tracks_indefinite_only.html b/test_fixtures/grid_percent_tracks_indefinite_only.html
new file mode 100644
index 000000000..382f31e8a
--- /dev/null
+++ b/test_fixtures/grid_percent_tracks_indefinite_only.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="display: grid; grid-template-columns: 10% 20% 30%;grid-template-rows: 30% 60%;">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_percent_tracks_indefinite_with_content_overflow.html b/test_fixtures/grid_percent_tracks_indefinite_with_content_overflow.html
new file mode 100644
index 000000000..faaade179
--- /dev/null
+++ b/test_fixtures/grid_percent_tracks_indefinite_with_content_overflow.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display: grid; grid-template-columns: 40% 40% 40%;grid-template-rows: 50% 80%;">
+  <div style="grid-row:1;grid-column:1;width: 100px; height: 100px;"></div>
+  <div style="grid-row:1;grid-column:1"></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_percent_tracks_indefinite_with_content_underflow.html b/test_fixtures/grid_percent_tracks_indefinite_with_content_underflow.html
new file mode 100644
index 000000000..0479bfc0a
--- /dev/null
+++ b/test_fixtures/grid_percent_tracks_indefinite_with_content_underflow.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display: grid; grid-template-columns: 10% 20% 30%;grid-template-rows: 30% 60%;">
+  <div style="grid-row:1;grid-column:1;width: 100px; height: 100px;"></div>
+  <div style="grid-row:1;grid-column:1"></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/grid_percent_nested_moderate.rs b/tests/generated/grid_percent_items_nested_moderate.rs
similarity index 99%
rename from tests/generated/grid_percent_nested_moderate.rs
rename to tests/generated/grid_percent_items_nested_moderate.rs
index 19f0cbba1..454d27cc9 100644
--- a/tests/generated/grid_percent_nested_moderate.rs
+++ b/tests/generated/grid_percent_items_nested_moderate.rs
@@ -1,5 +1,5 @@
 #[test]
-fn grid_percent_nested_moderate() {
+fn grid_percent_items_nested_moderate() {
     use slotmap::Key;
     #[allow(unused_imports)]
     use taffy::{layout::Layout, prelude::*};
diff --git a/tests/generated/grid_percent_nested_with_padding_margin.rs b/tests/generated/grid_percent_items_nested_with_padding_margin.rs
similarity index 99%
rename from tests/generated/grid_percent_nested_with_padding_margin.rs
rename to tests/generated/grid_percent_items_nested_with_padding_margin.rs
index 786f53654..e44485f79 100644
--- a/tests/generated/grid_percent_nested_with_padding_margin.rs
+++ b/tests/generated/grid_percent_items_nested_with_padding_margin.rs
@@ -1,5 +1,5 @@
 #[test]
-fn grid_percent_nested_with_padding_margin() {
+fn grid_percent_items_nested_with_padding_margin() {
     use slotmap::Key;
     #[allow(unused_imports)]
     use taffy::{layout::Layout, prelude::*};
diff --git a/tests/generated/grid_percent_width_and_margin.rs b/tests/generated/grid_percent_items_width_and_margin.rs
similarity index 98%
rename from tests/generated/grid_percent_width_and_margin.rs
rename to tests/generated/grid_percent_items_width_and_margin.rs
index 4db83e269..4c20afdb8 100644
--- a/tests/generated/grid_percent_width_and_margin.rs
+++ b/tests/generated/grid_percent_items_width_and_margin.rs
@@ -1,5 +1,5 @@
 #[test]
-fn grid_percent_width_and_margin() {
+fn grid_percent_items_width_and_margin() {
     use slotmap::Key;
     #[allow(unused_imports)]
     use taffy::{layout::Layout, prelude::*};
diff --git a/tests/generated/grid_percent_width_and_padding.rs b/tests/generated/grid_percent_items_width_and_padding.rs
similarity index 98%
rename from tests/generated/grid_percent_width_and_padding.rs
rename to tests/generated/grid_percent_items_width_and_padding.rs
index e9d8e0c0c..0231e8867 100644
--- a/tests/generated/grid_percent_width_and_padding.rs
+++ b/tests/generated/grid_percent_items_width_and_padding.rs
@@ -1,5 +1,5 @@
 #[test]
-fn grid_percent_width_and_padding() {
+fn grid_percent_items_width_and_padding() {
     use slotmap::Key;
     #[allow(unused_imports)]
     use taffy::{layout::Layout, prelude::*};
diff --git a/tests/generated/grid_percent_tracks_definite_overflow.rs b/tests/generated/grid_percent_tracks_definite_overflow.rs
new file mode 100644
index 000000000..5ec7c3d77
--- /dev/null
+++ b/tests/generated/grid_percent_tracks_definite_overflow.rs
@@ -0,0 +1,67 @@
+#[test]
+fn grid_percent_tracks_definite_overflow() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.5f32), percent(0.8f32)],
+                grid_template_columns: vec![percent(0.4f32), percent(0.4f32), percent(0.4f32)],
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(120f32),
+                    height: taffy::style::Dimension::Points(60f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5],
+        )
+        .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, 120f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 120f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 60f32, 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, 48f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 48f32, size.width);
+    assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 30f32, 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(node1).unwrap();
+    assert_eq!(size.width, 48f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 48f32, size.width);
+    assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 30f32, size.height);
+    assert_eq!(location.x, 48f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 48f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+    assert_eq!(size.width, 48f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 48f32, size.width);
+    assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 30f32, size.height);
+    assert_eq!(location.x, 96f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 96f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 48f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 48f32, size.width);
+    assert_eq!(size.height, 48f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 48f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.x);
+    assert_eq!(location.y, 30f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 30f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+    assert_eq!(size.width, 48f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 48f32, size.width);
+    assert_eq!(size.height, 48f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 48f32, size.height);
+    assert_eq!(location.x, 48f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 48f32, location.x);
+    assert_eq!(location.y, 30f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 30f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+    assert_eq!(size.width, 48f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 48f32, size.width);
+    assert_eq!(size.height, 48f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 48f32, size.height);
+    assert_eq!(location.x, 96f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 96f32, location.x);
+    assert_eq!(location.y, 30f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 30f32, location.y);
+}
diff --git a/tests/generated/grid_percent_tracks_definite_underflow.rs b/tests/generated/grid_percent_tracks_definite_underflow.rs
new file mode 100644
index 000000000..480c54175
--- /dev/null
+++ b/tests/generated/grid_percent_tracks_definite_underflow.rs
@@ -0,0 +1,67 @@
+#[test]
+fn grid_percent_tracks_definite_underflow() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.6f32)],
+                grid_template_columns: vec![percent(0.1f32), percent(0.2f32), percent(0.3f32)],
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(120f32),
+                    height: taffy::style::Dimension::Points(60f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5],
+        )
+        .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, 120f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 120f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 60f32, 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, 12f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 12f32, size.width);
+    assert_eq!(size.height, 18f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 18f32, 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(node1).unwrap();
+    assert_eq!(size.width, 24f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 24f32, size.width);
+    assert_eq!(size.height, 18f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 18f32, size.height);
+    assert_eq!(location.x, 12f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 12f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+    assert_eq!(size.width, 36f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 36f32, size.width);
+    assert_eq!(size.height, 18f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 18f32, size.height);
+    assert_eq!(location.x, 36f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 36f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 12f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 12f32, size.width);
+    assert_eq!(size.height, 36f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 36f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.x);
+    assert_eq!(location.y, 18f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 18f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+    assert_eq!(size.width, 24f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 24f32, size.width);
+    assert_eq!(size.height, 36f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 36f32, size.height);
+    assert_eq!(location.x, 12f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 12f32, location.x);
+    assert_eq!(location.y, 18f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 18f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+    assert_eq!(size.width, 36f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 36f32, size.width);
+    assert_eq!(size.height, 36f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 36f32, size.height);
+    assert_eq!(location.x, 36f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 36f32, location.x);
+    assert_eq!(location.y, 18f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 18f32, location.y);
+}
diff --git a/tests/generated/grid_percent_tracks_indefinite_only.rs b/tests/generated/grid_percent_tracks_indefinite_only.rs
new file mode 100644
index 000000000..068400b0e
--- /dev/null
+++ b/tests/generated/grid_percent_tracks_indefinite_only.rs
@@ -0,0 +1,63 @@
+#[test]
+fn grid_percent_tracks_indefinite_only() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.6f32)],
+                grid_template_columns: vec![percent(0.1f32), percent(0.2f32), percent(0.3f32)],
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5],
+        )
+        .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, 0f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 0f32, 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, 0f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, 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(node1).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 0f32, size.width);
+    assert_eq!(size.height, 0f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 0f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_percent_tracks_indefinite_with_content_overflow.rs b/tests/generated/grid_percent_tracks_indefinite_with_content_overflow.rs
new file mode 100644
index 000000000..25b4f29de
--- /dev/null
+++ b/tests/generated/grid_percent_tracks_indefinite_with_content_overflow.rs
@@ -0,0 +1,85 @@
+#[test]
+fn grid_percent_tracks_indefinite_with_content_overflow() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(100f32),
+                height: taffy::style::Dimension::Points(100f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.5f32), percent(0.8f32)],
+                grid_template_columns: vec![percent(0.4f32), percent(0.4f32), percent(0.4f32)],
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5, node6],
+        )
+        .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(node1).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 50f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 50f32, size.height);
+    assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 80f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, size.width);
+    assert_eq!(size.height, 80f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 80f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 50f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, size.width);
+    assert_eq!(size.height, 80f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 80f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 50f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node6).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node6.data(), 40f32, size.width);
+    assert_eq!(size.height, 80f32, "height of node {:?}. Expected {}. Actual {}", node6.data(), 80f32, size.height);
+    assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node6.data(), 80f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node6.data(), 50f32, location.y);
+}
diff --git a/tests/generated/grid_percent_tracks_indefinite_with_content_underflow.rs b/tests/generated/grid_percent_tracks_indefinite_with_content_underflow.rs
new file mode 100644
index 000000000..95d46337b
--- /dev/null
+++ b/tests/generated/grid_percent_tracks_indefinite_with_content_underflow.rs
@@ -0,0 +1,85 @@
+#[test]
+fn grid_percent_tracks_indefinite_with_content_underflow() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(100f32),
+                height: taffy::style::Dimension::Points(100f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            grid_row: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            grid_column: taffy::geometry::Line { start: line(1i16), end: taffy::style::GridPlacement::Auto },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_rows: vec![percent(0.3f32), percent(0.6f32)],
+                grid_template_columns: vec![percent(0.1f32), percent(0.2f32), percent(0.3f32)],
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3, node4, node5, node6],
+        )
+        .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(node1).unwrap();
+    assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 10f32, size.width);
+    assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 30f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 20f32, size.width);
+    assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 30f32, size.height);
+    assert_eq!(location.x, 10f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 10f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 30f32, size.width);
+    assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 30f32, size.height);
+    assert_eq!(location.x, 30f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 30f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+    assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 10f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 60f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, location.x);
+    assert_eq!(location.y, 30f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 30f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+    assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 20f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 60f32, size.height);
+    assert_eq!(location.x, 10f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 10f32, location.x);
+    assert_eq!(location.y, 30f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 30f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node6).unwrap();
+    assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node6.data(), 30f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node6.data(), 60f32, size.height);
+    assert_eq!(location.x, 30f32, "x of node {:?}. Expected {}. Actual {}", node6.data(), 30f32, location.x);
+    assert_eq!(location.y, 30f32, "y of node {:?}. Expected {}. Actual {}", node6.data(), 30f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index 2d331fd51..965ebe5e9 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -404,13 +404,23 @@ mod grid_min_max_column_fixed_width_within_range;
 #[cfg(feature = "grid")]
 mod grid_out_of_order_items;
 #[cfg(feature = "grid")]
-mod grid_percent_nested_moderate;
+mod grid_percent_items_nested_moderate;
 #[cfg(feature = "grid")]
-mod grid_percent_nested_with_padding_margin;
+mod grid_percent_items_nested_with_padding_margin;
 #[cfg(feature = "grid")]
-mod grid_percent_width_and_margin;
+mod grid_percent_items_width_and_margin;
 #[cfg(feature = "grid")]
-mod grid_percent_width_and_padding;
+mod grid_percent_items_width_and_padding;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_definite_overflow;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_definite_underflow;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_indefinite_only;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_indefinite_with_content_overflow;
+#[cfg(feature = "grid")]
+mod grid_percent_tracks_indefinite_with_content_underflow;
 #[cfg(feature = "grid")]
 mod grid_placement_auto_negative;
 #[cfg(feature = "grid")]