tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definiciones

Fix: Make CSS Grid algorithm correctly apply max width/height and available space when it is the root node (#491)

* Add viewport control to gentest setup

* Add tests for max-width and available space on a CSS Grid root node

* Only treat definite available grid space as indefinite when container size
is indefinite, and only do so for the final two track sizing steps.

(cherry picked from commit 9958624168dfe671c82cbe3afb8ba6a7d35f7454)

ae87fd0283feff32a5ceffe4c77394ff6ca88d39 · por Nico Burns · (hace 3 años) · padre 3803328e1 · ver el árbol en este commit

Delta semántico · 36

scripts/gentest/src/main.rs

scripts/gentest/test_helper.js

src/compute/grid/mod.rs

  • cambió por dentro fn compute pub

src/compute/grid/track_sizing.rs

tests/generated/grid_available_space_greater_than_max_content.rs

tests/generated/grid_available_space_smaller_than_max_content.rs

tests/generated/grid_available_space_smaller_than_min_content.rs

tests/generated/grid_max_width_greater_than_max_content.rs

tests/generated/grid_max_width_less_than_max_content_with_min_content.rs

tests/generated/grid_max_width_smaller_than_max_content.rs

tests/generated/grid_max_width_smaller_than_min_content.rs

20 archivos · +834 −58

diff --git a/scripts/gentest/src/main.rs b/scripts/gentest/src/main.rs
index fee14f8ae..615a710ae 100644
--- a/scripts/gentest/src/main.rs
+++ b/scripts/gentest/src/main.rs
@@ -10,6 +10,47 @@ use quote::{format_ident, quote};
 use serde_json::Value;
 use syn::Ident;
 
+macro_rules! dim_quoted_renamed {
+    ($obj:ident, $in_name:ident, $out_name:ident, $value_mapper:ident, $default:expr) => {
+        let $out_name = match $obj.get(stringify!($in_name)) {
+            Some(Value::Object(ref value)) => {
+                let dim = $value_mapper(value);
+                quote!($out_name: #dim,)
+            }
+            _ => {
+                let dim = $default;
+                quote!($out_name: #dim,)
+            }
+        };
+    };
+}
+
+macro_rules! dim_quoted {
+    ($obj:ident, $dim_name:ident, $value_mapper: ident, $default:expr) => {
+        dim_quoted_renamed!($obj, $dim_name, $dim_name, $value_mapper, $default)
+    };
+}
+
+macro_rules! edges_quoted {
+    ($style:ident, $val:ident, $value_mapper:ident, $default_value: expr) => {
+        let $val = match $style[stringify!($val)] {
+            Value::Object(ref value) => {
+                dim_quoted!(value, left, $value_mapper, $default_value);
+                dim_quoted!(value, right, $value_mapper, $default_value);
+                dim_quoted!(value, top, $value_mapper, $default_value);
+                dim_quoted!(value, bottom, $value_mapper, $default_value);
+
+                let edges = quote!(taffy::geometry::Rect {
+                    #left #right #top #bottom
+                });
+
+                quote!($val: #edges,)
+            },
+            _ => quote!(),
+        };
+    };
+}
+
 #[tokio::main]
 async fn main() {
     env_logger::init();
@@ -127,6 +168,20 @@ fn generate_test(name: impl AsRef<str>, description: &Value) -> TokenStream {
 
     let set_rounding_mode = if use_rounding { quote!() } else { quote!(taffy.disable_rounding();) };
 
+    // Compute available space
+    let viewport = &description["viewport"];
+    let available_space = if viewport["width"]["unit"] == "max-content" && viewport["height"]["unit"] == "max-content" {
+        quote!(taffy::geometry::Size::MAX_CONTENT)
+    } else {
+        dim_quoted!(viewport, width, generate_available_space, quote!(taffy::style::AvailableSpace::MAX_CONTENT));
+        dim_quoted!(viewport, height, generate_available_space, quote!(taffy::style::AvailableSpace::MAX_CONTENT));
+        quote!(
+            taffy::geometry::Size {
+                #width #height
+            }
+        )
+    };
+
     quote!(
         #[test]
         fn #name() {
@@ -136,7 +191,7 @@ fn generate_test(name: impl AsRef<str>, description: &Value) -> TokenStream {
             let mut taffy = taffy::Taffy::new();
             #set_rounding_mode
             #node_description
-            taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+            taffy.compute_layout(node, #available_space).unwrap();
 
             println!("\nComputed tree:");
             taffy::debug::print_tree(&taffy, node);
@@ -191,47 +246,6 @@ fn generate_assertions(ident: &str, node: &Value, use_rounding: bool) -> TokenSt
     }
 }
 
-macro_rules! dim_quoted_renamed {
-    ($obj:ident, $in_name:ident, $out_name:ident, $value_mapper:ident, $default:expr) => {
-        let $out_name = match $obj.get(stringify!($in_name)) {
-            Some(Value::Object(ref value)) => {
-                let dim = $value_mapper(value);
-                quote!($out_name: #dim,)
-            }
-            _ => {
-                let dim = $default;
-                quote!($out_name: #dim,)
-            }
-        };
-    };
-}
-
-macro_rules! dim_quoted {
-    ($obj:ident, $dim_name:ident, $value_mapper: ident, $default:expr) => {
-        dim_quoted_renamed!($obj, $dim_name, $dim_name, $value_mapper, $default)
-    };
-}
-
-macro_rules! edges_quoted {
-    ($style:ident, $val:ident, $value_mapper:ident, $default_value: expr) => {
-        let $val = match $style[stringify!($val)] {
-            Value::Object(ref value) => {
-                dim_quoted!(value, left, $value_mapper, $default_value);
-                dim_quoted!(value, right, $value_mapper, $default_value);
-                dim_quoted!(value, top, $value_mapper, $default_value);
-                dim_quoted!(value, bottom, $value_mapper, $default_value);
-
-                let edges = quote!(taffy::geometry::Rect {
-                    #left #right #top #bottom
-                });
-
-                quote!($val: #edges,)
-            },
-            _ => quote!(),
-        };
-    };
-}
-
 fn generate_node(ident: &str, node: &Value) -> TokenStream {
     let style = &node["style"];
 
@@ -660,6 +674,24 @@ fn generate_dimension(dimen: &serde_json::Map<String, Value>) -> TokenStream {
     }
 }
 
+fn generate_available_space(dimen: &serde_json::Map<String, Value>) -> TokenStream {
+    let unit = dimen.get("unit").unwrap();
+    let value = || dimen.get("value").unwrap().as_f64().unwrap() as f32;
+
+    match unit {
+        Value::String(ref unit) => match unit.as_ref() {
+            "max-content" => quote!(taffy::style::AvailableSpace::MaxContent),
+            "min-content" => quote!(taffy::style::AvailableSpace::MaxContent),
+            "points" => {
+                let value = value();
+                quote!(taffy::style::AvailableSpace::Definite(#value))
+            }
+            _ => unreachable!(),
+        },
+        _ => unreachable!(),
+    }
+}
+
 fn generate_grid_auto_flow(auto_flow: &serde_json::Map<String, Value>) -> TokenStream {
     let direction = auto_flow.get("direction").unwrap().as_str().unwrap();
     let algorithm = auto_flow.get("algorithm").unwrap().as_str().unwrap();
diff --git a/scripts/gentest/test_base_style.css b/scripts/gentest/test_base_style.css
index 452a2d703..749dbe6ba 100644
--- a/scripts/gentest/test_base_style.css
+++ b/scripts/gentest/test_base_style.css
@@ -31,6 +31,15 @@ body > * {
   border-color: red;
 }
 
+.viewport {
+  display: flex;
+  align-items: start;
+  justify-content: start;
+  /* Defaults: can be overriden in individual tests */
+  width: max-content;
+  height: max-content;
+}
+
 #test-root {
   font-family: ahem;
   line-height: 1;
diff --git a/scripts/gentest/test_helper.js b/scripts/gentest/test_helper.js
index b05eb7e7d..27f66a816 100644
--- a/scripts/gentest/test_helper.js
+++ b/scripts/gentest/test_helper.js
@@ -81,6 +81,20 @@ class TrackSizingParser {
 
 }
 
+function parseViewportConstraint(e) {
+  if (e.parentNode.classList.contains('viewport')) {
+    return {
+      width: parseDimension(e.parentNode.style.width || 'max-content'),
+      height: parseDimension(e.parentNode.style.height || 'max-content'),
+    }
+  } else {
+    return {
+      width: { unit: 'max-content' },
+      height: { unit: 'max-content' },
+    }
+  }
+}
+
 function parseRepetition(input) {
   if (input === "auto-fill") return { unit: 'auto-fill' };
   if (input === "auto-fit") return { unit: 'auto-fit' };
@@ -283,6 +297,8 @@ function describeElement(e) {
     // Whether the test should enable rounding
     useRounding: e.getAttribute("data-test-rounding") !== "false",
 
+    viewport: parseViewportConstraint(e),
+
     children: Array.from(e.children).map(c => describeElement(c)),
   }
 }
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index 09a91eb09..a1393e26a 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -149,14 +149,10 @@ pub fn compute(
 
     let constrained_available_space = known_dimensions
         .or(size)
-        .maybe_clamp(min_size, max_size)
         .map(|size| size.map(AvailableSpace::Definite))
-        .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,
-        }));
+        .unwrap_or(available_space)
+        .maybe_clamp(min_size, max_size)
+        .maybe_max(padding_border_size);
 
     let available_grid_space = Size {
         width: constrained_available_space
@@ -167,7 +163,7 @@ pub fn compute(
             .map_definite_value(|space| space - padding.vertical_axis_sum() - border.vertical_axis_sum()),
     };
 
-    let outer_node_size = known_dimensions.or(size.maybe_clamp(min_size, max_size).or(min_size));
+    let outer_node_size = known_dimensions.or(size).maybe_clamp(min_size, max_size).maybe_max(padding_border_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()),
@@ -232,16 +228,23 @@ pub fn compute(
     let initial_row_sum = rows.iter().map(|track| track.base_size).sum::<f32>();
     inner_node_size.height = inner_node_size.height.or_else(|| initial_row_sum.into());
 
+    #[cfg(feature = "debug")]
+    NODE_LOGGER.labelled_debug_log("initial_column_sum", initial_column_sum);
+    #[cfg(feature = "debug")]
+    NODE_LOGGER.labelled_debug_log("initial_row_sum", initial_row_sum);
+
     // 6. Compute container size
     let resolved_style_size = known_dimensions.or(style.size.maybe_resolve(parent_size));
     let container_border_box = Size {
         width: resolved_style_size
             .get(AbstractAxis::Inline)
             .unwrap_or_else(|| initial_column_sum + padding.horizontal_axis_sum() + border.horizontal_axis_sum())
+            .maybe_clamp(min_size.width, max_size.width)
             .max(padding_border_size.width),
         height: resolved_style_size
             .get(AbstractAxis::Block)
             .unwrap_or_else(|| initial_row_sum + padding.vertical_axis_sum() + border.vertical_axis_sum())
+            .maybe_clamp(min_size.height, max_size.height)
             .max(padding_border_size.height),
     };
     let container_content_box = Size {
diff --git a/src/compute/grid/track_sizing.rs b/src/compute/grid/track_sizing.rs
index 704402518..3f5a671c4 100644
--- a/src/compute/grid/track_sizing.rs
+++ b/src/compute/grid/track_sizing.rs
@@ -327,6 +327,19 @@ pub(super) fn track_sizing_algorithm<Tree: LayoutTree>(
     // Distributes free space (if any) to tracks with FINITE growth limits, up to their limits.
     maximise_tracks(axis_tracks, inner_node_size.get(axis), available_grid_space.get(axis));
 
+    // For the purpose of the final two expansion steps ("Expand Flexible Tracks" and "Stretch auto Tracks"), we only want to expand
+    // into space generated by the grid container's size (as defined by either it's preferred size style or by it's parent node through
+    // something like stretch alignment), not just any available space. To do this we map definite available space to AvailableSpace::MaxContent
+    // in the case that inner_node_size is None
+    let axis_available_space_for_expansion = if let Some(available_space) = inner_node_size.get(axis) {
+        AvailableSpace::Definite(available_space)
+    } else {
+        match available_grid_space.get(axis) {
+            AvailableSpace::MinContent => AvailableSpace::MinContent,
+            AvailableSpace::MaxContent | AvailableSpace::Definite(_) => AvailableSpace::MaxContent,
+        }
+    };
+
     // 11.7. Expand Flexible Tracks
     // This step sizes flexible tracks using the largest value it can assign to an fr without exceeding the available space.
     expand_flexible_tracks(
@@ -336,13 +349,13 @@ pub(super) fn track_sizing_algorithm<Tree: LayoutTree>(
         items,
         axis_min_size,
         axis_max_size,
-        available_grid_space,
+        axis_available_space_for_expansion,
         inner_node_size,
     );
 
     // 11.8. Stretch auto Tracks
     // This step expands tracks that have an auto max track sizing function by dividing any remaining positive, definite free space equally amongst them.
-    stretch_auto_tracks(axis, axis_tracks, axis_min_size, available_grid_space);
+    stretch_auto_tracks(axis_tracks, axis_min_size, axis_available_space_for_expansion);
 }
 
 /// Whether it is a minimum or maximum size's space being distributed
@@ -1083,11 +1096,11 @@ fn expand_flexible_tracks(
     items: &mut [GridItem],
     axis_min_size: Option<f32>,
     axis_max_size: Option<f32>,
-    available_grid_space: Size<AvailableSpace>,
+    axis_available_space_for_expansion: AvailableSpace,
     inner_node_size: Size<Option<f32>>,
 ) {
     // First, find the grid’s used flex fraction:
-    let flex_fraction = match available_grid_space.get(axis) {
+    let flex_fraction = match axis_available_space_for_expansion {
         // If the free space is zero:
         //    The used flex fraction is zero.
         // Otherwise, if the free space is a definite length:
@@ -1237,10 +1250,9 @@ fn find_size_of_fr(tracks: &[GridTrack], space_to_fill: f32) -> f32 {
 /// This step expands tracks that have an auto max track sizing function by dividing any remaining positive, definite free space equally amongst them.
 #[inline(always)]
 fn stretch_auto_tracks(
-    axis: AbstractAxis,
     axis_tracks: &mut [GridTrack],
     axis_min_size: Option<f32>,
-    available_grid_space: Size<AvailableSpace>,
+    axis_available_space_for_expansion: AvailableSpace,
 ) {
     let num_auto_tracks =
         axis_tracks.iter().filter(|track| track.max_track_sizing_function == MaxTrackSizingFunction::Auto).count();
@@ -1249,8 +1261,8 @@ fn stretch_auto_tracks(
 
         // If the free space is indefinite, but the grid container has a definite min-width/height
         // use that size to calculate the free space for this step instead.
-        let free_space = if available_grid_space.get(axis).is_definite() {
-            available_grid_space.get(axis).compute_free_space(used_space)
+        let free_space = if axis_available_space_for_expansion.is_definite() {
+            axis_available_space_for_expansion.compute_free_space(used_space)
         } else {
             match axis_min_size {
                 Some(size) => size - used_space,
diff --git a/test_fixtures/grid_available_space_greater_than_max_content.html b/test_fixtures/grid_available_space_greater_than_max_content.html
new file mode 100644
index 000000000..4674700d8
--- /dev/null
+++ b/test_fixtures/grid_available_space_greater_than_max_content.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 class="viewport" style="width: 400px;">
+  <div id="test-root" style="display: grid; grid-template-columns: auto auto;">
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_available_space_smaller_than_max_content.html b/test_fixtures/grid_available_space_smaller_than_max_content.html
new file mode 100644
index 000000000..f952ac4a2
--- /dev/null
+++ b/test_fixtures/grid_available_space_smaller_than_max_content.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 class="viewport" style="width: 80px;">
+  <div id="test-root" style="display: grid; grid-template-columns: auto auto;">
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_available_space_smaller_than_min_content.html b/test_fixtures/grid_available_space_smaller_than_min_content.html
new file mode 100644
index 000000000..a848831d7
--- /dev/null
+++ b/test_fixtures/grid_available_space_smaller_than_min_content.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 class="viewport" style="width: 60px;">
+  <div id="test-root" style="display: grid; grid-template-columns: auto auto;">
+    <div>HHHH&ZeroWidthSpace;HHHH</div>
+    <div>HHHH&ZeroWidthSpace;HHHH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_max_width_greater_than_max_content.html b/test_fixtures/grid_max_width_greater_than_max_content.html
new file mode 100644
index 000000000..88918ce10
--- /dev/null
+++ b/test_fixtures/grid_max_width_greater_than_max_content.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" style="display: grid; grid-template-columns: max-content;">
+  <div style="display: grid; max-width: 400px; grid-template-columns: auto auto;">
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_max_width_less_than_max_content_with_min_content.html b/test_fixtures/grid_max_width_less_than_max_content_with_min_content.html
new file mode 100644
index 000000000..5fe02bf63
--- /dev/null
+++ b/test_fixtures/grid_max_width_less_than_max_content_with_min_content.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" style="display: grid; grid-template-columns: min-content;">
+  <div style="display: grid; max-width: 80px; grid-template-columns: auto auto;">
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_max_width_smaller_than_max_content.html b/test_fixtures/grid_max_width_smaller_than_max_content.html
new file mode 100644
index 000000000..6ca0be76a
--- /dev/null
+++ b/test_fixtures/grid_max_width_smaller_than_max_content.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" style="display: grid; grid-template-columns: max-content;">
+  <div style="display: grid; max-width: 80px; grid-template-columns: auto auto;">
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+    <div>HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH&ZeroWidthSpace;HH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_max_width_smaller_than_min_content.html b/test_fixtures/grid_max_width_smaller_than_min_content.html
new file mode 100644
index 000000000..26d21dbce
--- /dev/null
+++ b/test_fixtures/grid_max_width_smaller_than_min_content.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" style="display: grid; grid-template-columns: max-content;">
+  <div style="display: grid; max-width: 60px; grid-template-columns: auto auto;">
+    <div>HHHH&ZeroWidthSpace;HHHH</div>
+    <div>HHHH&ZeroWidthSpace;HHHH</div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/grid_available_space_greater_than_max_content.rs b/tests/generated/grid_available_space_greater_than_max_content.rs
new file mode 100644
index 000000000..2e5085a57
--- /dev/null
+++ b/tests/generated/grid_available_space_greater_than_max_content.rs
@@ -0,0 +1,74 @@
+#[test]
+fn grid_available_space_greater_than_max_content() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node1 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![auto(), auto()],
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy
+        .compute_layout(
+            node,
+            taffy::geometry::Size {
+                width: taffy::style::AvailableSpace::Definite(400f32),
+                height: taffy::style::AvailableSpace::MaxContent,
+            },
+        )
+        .unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 160f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 160f32, 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, 80f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 80f32, 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(node1).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 80f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 10f32, size.height);
+    assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 80f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_available_space_smaller_than_max_content.rs b/tests/generated/grid_available_space_smaller_than_max_content.rs
new file mode 100644
index 000000000..10c3b0979
--- /dev/null
+++ b/tests/generated/grid_available_space_smaller_than_max_content.rs
@@ -0,0 +1,74 @@
+#[test]
+fn grid_available_space_smaller_than_max_content() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node1 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HH\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![auto(), auto()],
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy
+        .compute_layout(
+            node,
+            taffy::geometry::Size {
+                width: taffy::style::AvailableSpace::Definite(80f32),
+                height: taffy::style::AvailableSpace::MaxContent,
+            },
+        )
+        .unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 80f32, 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(node1).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_available_space_smaller_than_min_content.rs b/tests/generated/grid_available_space_smaller_than_min_content.rs
new file mode 100644
index 000000000..528149a81
--- /dev/null
+++ b/tests/generated/grid_available_space_smaller_than_min_content.rs
@@ -0,0 +1,74 @@
+#[test]
+fn grid_available_space_smaller_than_min_content() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HHHH\u{200b}HHHH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node1 = taffy
+        .new_leaf_with_measure(
+            taffy::style::Style { ..Default::default() },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HHHH\u{200b}HHHH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![auto(), auto()],
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy
+        .compute_layout(
+            node,
+            taffy::geometry::Size {
+                width: taffy::style::AvailableSpace::Definite(60f32),
+                height: taffy::style::AvailableSpace::MaxContent,
+            },
+        )
+        .unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 80f32, 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(node1).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_max_width_greater_than_max_content.rs b/tests/generated/grid_max_width_greater_than_max_content.rs
new file mode 100644
index 000000000..66009978e
--- /dev/null
+++ b/tests/generated/grid_max_width_greater_than_max_content.rs
@@ -0,0 +1,82 @@
+#[test]
+fn grid_max_width_greater_than_max_content() {
+    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\u{200b}HH\u{200b}HH\u{200b}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\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![auto(), auto()],
+                max_size: taffy::geometry::Size { width: taffy::style::Dimension::Points(400f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![max_content()],
+                ..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, 160f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 160f32, 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, 160f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 160f32, 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, 80f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 80f32, 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, 80f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 80f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 10f32, size.height);
+    assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 80f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_max_width_less_than_max_content_with_min_content.rs b/tests/generated/grid_max_width_less_than_max_content_with_min_content.rs
new file mode 100644
index 000000000..8a5b810f8
--- /dev/null
+++ b/tests/generated/grid_max_width_less_than_max_content_with_min_content.rs
@@ -0,0 +1,82 @@
+#[test]
+fn grid_max_width_less_than_max_content_with_min_content() {
+    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\u{200b}HH\u{200b}HH\u{200b}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\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![auto(), auto()],
+                max_size: taffy::geometry::Size { width: taffy::style::Dimension::Points(80f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![min_content()],
+                ..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, 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, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, 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, 20f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, 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);
+    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, 40f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 40f32, 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);
+}
diff --git a/tests/generated/grid_max_width_smaller_than_max_content.rs b/tests/generated/grid_max_width_smaller_than_max_content.rs
new file mode 100644
index 000000000..5857f2658
--- /dev/null
+++ b/tests/generated/grid_max_width_smaller_than_max_content.rs
@@ -0,0 +1,82 @@
+#[test]
+fn grid_max_width_smaller_than_max_content() {
+    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\u{200b}HH\u{200b}HH\u{200b}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\u{200b}HH\u{200b}HH\u{200b}HH";
+                super::measure_standard_text(
+                    known_dimensions,
+                    available_space,
+                    TEXT,
+                    super::WritingMode::Horizontal,
+                    None,
+                )
+            }),
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![auto(), auto()],
+                max_size: taffy::geometry::Size { width: taffy::style::Dimension::Points(80f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![max_content()],
+                ..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, 80f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 80f32, 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, 80f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 80f32, 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, 40f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 40f32, 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, 40f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 40f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+}
diff --git a/tests/generated/grid_max_width_smaller_than_min_content.rs b/tests/generated/grid_max_width_smaller_than_min_content.rs
new file mode 100644
index 000000000..3563034a1
--- /dev/null
+++ b/tests/generated/grid_max_width_smaller_than_min_content.rs
@@ -0,0 +1,82 @@
+#[test]
+fn grid_max_width_smaller_than_min_content() {
+    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 = "HHHH\u{200b}HHHH";
+                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 = "HHHH\u{200b}HHHH";
+                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_columns: vec![auto(), auto()],
+                max_size: taffy::geometry::Size { width: taffy::style::Dimension::Points(60f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                grid_template_columns: vec![max_content()],
+                ..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, 60f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 60f32, 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, 60f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 60f32, 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, 40f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 40f32, 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, 40f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 40f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 40f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index 05c7f1243..ef715dd44 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -467,6 +467,12 @@ mod grid_auto_single_item_fixed_width_with_definite_width;
 #[cfg(feature = "grid")]
 mod grid_auto_takes_precedence_over_fr;
 #[cfg(feature = "grid")]
+mod grid_available_space_greater_than_max_content;
+#[cfg(feature = "grid")]
+mod grid_available_space_smaller_than_max_content;
+#[cfg(feature = "grid")]
+mod grid_available_space_smaller_than_min_content;
+#[cfg(feature = "grid")]
 mod grid_basic;
 #[cfg(feature = "grid")]
 mod grid_basic_implicit_tracks;
@@ -591,6 +597,14 @@ mod grid_max_content_single_item_span_2_gap_percent_definite;
 #[cfg(feature = "grid")]
 mod grid_max_content_single_item_span_2_gap_percent_indefinite;
 #[cfg(feature = "grid")]
+mod grid_max_width_greater_than_max_content;
+#[cfg(feature = "grid")]
+mod grid_max_width_less_than_max_content_with_min_content;
+#[cfg(feature = "grid")]
+mod grid_max_width_smaller_than_max_content;
+#[cfg(feature = "grid")]
+mod grid_max_width_smaller_than_min_content;
+#[cfg(feature = "grid")]
 mod grid_min_content_flex_column;
 #[cfg(feature = "grid")]
 mod grid_min_content_flex_row;