gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Sutichaykuna

Update 0.3.x for 0.3.11 (#455)

* Fix layout of direct flex children with `display:none` set (#380)

* Add test for toggling display:none

* Add test for toggling display:none on a flexbox child

* Fix layout direct flex children with `display:none` set

* Add test for toggling display:none on flexbox container

* Fix setting display:none on a grid child (#382)

* Prepare for 0.3.5 release (#381)

* Prepare for 0.3.5 release

* Add grid PR to release notes

* Ignore align_content in non-wrapping flexbox containers (#383)

* Add tests for bevyengine/bevy#7976

* Simplify code in compute_constants

* Ignore align_contents if flex_wrap is set to no_wrap

* Remove commented out code

* Prepare for v0.3.6 release (#384)

* Use mutable slice rather mutable vec parameter

* Reduce style accesses (#386)

* Use cached flex_grow and flex_shrink values when resolving flexible lengths

* Cache auto margins on FlexItem struct

* Use constants.is_wrap instead of re-resolving style

* Use cached align_content value rather than re-resolving style

* Cache justify_content style in AlgoConstants

* Add failing tests for borders flooring node size

* Add failing tests for padding flooring node size

* Fix divide by zero in main size determination

* Add seperate leaf and flexbox tests for padding/border flooring node size

* Fix padding/border flooring leaf node size

* Fix flexbox children being floored by padding/border

* Combine padding and border tests + make edge dimensions uneven

* Add padding/border floor absolute child size

* Add padding/border floor node size tests for grid

* Add grid container test for padding/border flooring node size

* Fix padding/border flooring size of absolutely positioned children

* Rename grid padding/border tests so that they are all located together

* Make padding/border floor node size for grid children

* Make padding/border floor node size for grid containers

* Apply aspect ratio to leaf nodes whose size is determined by padding/border sum

* Add test for padding/border not affecting flex basis

* Convert flex basis determination to use break from block

* Add test for flex-basis 0 with flex grow

* Floor flex-basis limits by preferred size style value when determining flex container main size

* Floor outer flex-basis by padding_border sum (floors inner flex-basis at 0)

* Remove commented out code

* Add missing 0

* Test cases for bevyengine/bevy#8017 and Taffy #387

* Prevent percentage sizes from contributing a flex item's min-content size

* Prepare for 0.3.7 release (#389)

* Prepare for 0.3.7 release

* Fix duplicate content in the changelog

* Fix markdown lint

* Upgrade to better Github Actions for faster and better maintained CI (#390)

* Use taiki-e/install-action for installing cargo-deny

* Update CI to use dtolnay/rust-toolchain action

* Enable CI for 0.3.x branch

* Fix documentation CI

* Dummy Cargo.toml change

* Add fully reduced test case for #387 (#391)

* Fix wrapping nodes generating an incorrect min-content size (#395)

* Add tests for bevyengine/bevy#8082

* Debug log parent size

* Pass correct cross-axis parent_size/available_space when computing a flex item's min-content contribution

* Prepare for 0.3.8 release (#396)

* Don't allow cached results to be used for sizings with greater available space (#397)

* Don't allow cached results to be used for sizings with greater available space

* Update caching tests to use tree 100 nodes deep (relax permitted measure count to 7)

* Prepare for 0.3.9 release (#398)

* Prepare for 0.3.9 release

* Add bevyengine/bevy#8124 to release notes

* Allow multiple syn versions

* Tree creation benchmarks (#401)

* Add tree creation benchmarks

* Rename allocation benchmark to tree_creation

* Update rstest requirement from 0.16.0 to 0.17.0 (#402)

Updates the requirements on [rstest](https://github.com/la10736/rstest) to permit the latest version.
- [Release notes](https://github.com/la10736/rstest/releases)
- [Changelog](https://github.com/la10736/rstest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/la10736/rstest/compare/0.16.0...0.17.0)

---
updated-dependencies:
- dependency-name: rstest
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update syn requirement from 1.0.7 to 2.0.4 (#403)

Updates the requirements on [syn](https://github.com/dtolnay/syn) to permit the latest version.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/1.0.7...2.0.4)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix: available space in the presence of a min width (#407)

* Add `with_main` and `with_cross` methods to Size

* Add test for min_width > available_space

* Clamp available cross space by min/max height when computing flex basis

* Clamp available cross space by min/max size when computing hypothetical cross size

* Bump measure func call counts to 8

* Prepare for 0.3.10 release (#411)

* Fix import lints (#416)

(cherry picked from commit 55225737802b3e2a0e0ce6194c9fce2603a18a30)

* Add caching to CI (#418)

* Optimise flexbox layouts with min/max sizes (#413)

* Remove 2-pass min/max code path + implement main size min/max clamping within determine_container_main_size method

* Fix typo in flex_grow_within_constrained_min_max_column test

* Implement cross-size min/max clamping inline in algorithm

* Remove debug log

* Remove commented code

* Prepare for 0.3.11 release (#419)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andreas Weibye <13300393+Weibye@users.noreply.github.com>
Co-authored-by: TimJentzsch <commits@timjen.net>

1cc9406849daf4163f4c7780c73f58409c79b7ae · ruwaq Nico Burns · (3 wata ñawpaq) · tayta 1e4b80d7c · kay commitpi sach'ata qhaway

Semántico sayk'uy · 96

benches/helpers/yoga_helpers.rs

benches/tree_creation.rs

src/compute/flexbox.rs

src/compute/grid/alignment.rs

src/compute/grid/mod.rs

  • ukhunpi t'ikrakurqan fn compute pub

src/compute/leaf.rs

src/compute/mod.rs

src/geometry.rs

src/style/dimension.rs

src/style/grid.rs

tests/caching.rs

tests/generated/absolute_padding_border_overrides_max_size.rs

tests/generated/absolute_padding_border_overrides_size.rs

tests/generated/bevy_issue_7976_3_level.rs

tests/generated/bevy_issue_7976_4_level.rs

tests/generated/bevy_issue_7976_reduced.rs

tests/generated/bevy_issue_8017.rs

tests/generated/bevy_issue_8017_reduced.rs

tests/generated/bevy_issue_8082.rs

tests/generated/bevy_issue_8082_percent.rs

tests/generated/flex_grow_within_constrained_min_max_column.rs

tests/generated/grid_padding_border_overrides_container_max_size.rs

tests/generated/grid_padding_border_overrides_container_size.rs

tests/generated/grid_padding_border_overrides_max_size.rs

tests/generated/grid_padding_border_overrides_min_size.rs

tests/generated/grid_padding_border_overrides_size.rs

tests/generated/leaf_padding_border_overrides_max_size.rs

tests/generated/leaf_padding_border_overrides_min_size.rs

tests/generated/leaf_padding_border_overrides_size.rs

tests/generated/measure_child_with_min_size_greater_than_available_space.rs

tests/generated/padding_border_overrides_max_size.rs

tests/generated/padding_border_overrides_min_size.rs

tests/generated/padding_border_overrides_size.rs

tests/generated/padding_border_overrides_size_flex_basis_0.rs

tests/generated/padding_border_overrides_size_flex_basis_0_growable.rs

tests/generated/percentage_sizes_should_not_prevent_flex_shrinking.rs

71 qillqakuna · +2708 −427

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ee3bddae0..ebca2eebf 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,6 +4,7 @@ on:
     branches:
       - main
       - 0.2.x
+      - 0.3.x
 
 name: Continuous integration
 
@@ -13,163 +14,95 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --no-default-features
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --no-default-features
+      - uses: dtolnay/rust-toolchain@stable
+      - uses: Leafwing-Studios/cargo-cache@v1
+      - run: cargo build --no-default-features
+      - run: cargo test --no-default-features
 
   test-features-default:
     name: "Test Suite [Features: Default]"
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
+      - uses: dtolnay/rust-toolchain@stable
+      - run: cargo build
+      - run: cargo test
 
   test-features-default-with-serde:
     name: "Test Suite [Features: Default + serde]"
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --features serde
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --features serde
+      - uses: dtolnay/rust-toolchain@stable
+      - run: cargo build --features serde
+      - run: cargo test --features serde
 
   test-features-alloc:
     name: "Test Suite [Features: alloc]"
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --no-default-features --features alloc,grid
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --no-default-features --features alloc,grid
+      - uses: dtolnay/rust-toolchain@stable
+      - run: cargo build --no-default-features --features alloc,grid
+      - run: cargo test --no-default-features --features alloc,grid
 
   test-features-alloc-no-grid:
     name: "Test Suite [Features: alloc (no grid)]"
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --no-default-features --features alloc
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --no-default-features --features alloc
+      - uses: dtolnay/rust-toolchain@stable
+      - run: cargo build --no-default-features --features alloc
+      - run: cargo test  --no-default-features --features alloc
 
   test-features-default-no-grid:
     name: "Test Suite [Features: std (no grid)]"
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          profile: minimal
-          toolchain: stable
-          override: true
-      - uses: actions-rs/cargo@v1
-        with:
-          command: build
-          args: --no-default-features --features std
-      - uses: actions-rs/cargo@v1
-        with:
-          command: test
-          args: --no-default-features --features std
+      - uses: dtolnay/rust-toolchain@stable
+      - uses: Leafwing-Studios/cargo-cache@v1
+      - run: cargo build --no-default-features --features std
+      - run: cargo test --no-default-features --features std
 
   fmt:
     name: Rustfmt
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
-          profile: minimal
           toolchain: stable
-          override: true
-      - run: rustup component add rustfmt
-      - uses: actions-rs/cargo@v1
-        with:
-          command: fmt
-          args: --all -- --check
+          components: rustfmt
+      - uses: Leafwing-Studios/cargo-cache@v1
+      - run: cargo fmt --all -- --check
 
   clippy:
     name: Clippy
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
-          profile: minimal
           toolchain: nightly
-          override: true
-      - run: rustup component add clippy
-      - uses: actions-rs/cargo@v1
-        with:
-          command: clippy
-          args: --workspace -- -D warnings
+          components: clippy
+      - uses: Leafwing-Studios/cargo-cache@v1
+      - run: cargo +nightly clippy --workspace -- -D warnings
 
   doc:
     name: Documentation
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
+      - uses: dtolnay/rust-toolchain@master
         with:
-          profile: minimal
           toolchain: stable
-          override: true
-      - run: rustup component add clippy
-      - uses: actions-rs/cargo@v1
-        with:
-          command: doc
+          components: clippy
+      - uses: Leafwing-Studios/cargo-cache@v1
+      - run: cargo doc
         env:
           RUSTDOCFLAGS: "-D warnings"
 
-
   markdownlint:
     name: Markdown Lint
     runs-on: ubuntu-latest
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 14df77370..2c953520a 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -22,12 +22,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: stable
-          override: true
-      - name: Install cargo-deny
-        run: cargo install cargo-deny
+      - uses: taiki-e/install-action@cargo-deny
       - name: Check for security advisories and unmaintained crates
         run: cargo deny check advisories
 
@@ -35,12 +30,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: stable
-          override: true
-      - name: Install cargo-deny
-        run: cargo install cargo-deny
+      - uses: taiki-e/install-action@cargo-deny
       - name: Check for banned and duplicated dependencies
         run: cargo deny check bans
 
@@ -48,12 +38,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: stable
-          override: true
-      - name: Install cargo-deny
-        run: cargo install cargo-deny
+      - uses: taiki-e/install-action@cargo-deny
       - name: Check for unauthorized licenses
         run: cargo deny check licenses
 
@@ -61,11 +46,6 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v3
-      - uses: actions-rs/toolchain@v1
-        with:
-          toolchain: stable
-          override: true
-      - name: Install cargo-deny
-        run: cargo install cargo-deny
+      - uses: taiki-e/install-action@cargo-deny
       - name: Checked for unauthorized crate sources
         run: cargo deny check sources
diff --git a/Cargo.toml b/Cargo.toml
index 963129e9a..fc415b670 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,13 +1,13 @@
 [package]
 name = "taffy"
-version = "0.3.4"
+version = "0.3.11"
 authors = [
     "Alice Cecile <alice.i.cecile@gmail.com>",
     "Johnathan Kelley <jkelleyrtp@gmail.com>",
 ]
 edition = "2021"
 include = ["src/**/*", "Cargo.toml", "README.md"]
-description = "A flexible UI layout library"
+description = "A flexible UI layout library "
 repository = "https://github.com/DioxusLabs/taffy"
 keywords = ["cross-platform", "layout", "flexbox", "css-grid", "grid"]
 categories = ["gui"]
@@ -34,7 +34,7 @@ profile = []
 
 [dev-dependencies]
 criterion = "0.4"
-rstest = "0.16.0"
+rstest = "0.17.0"
 rand = "0.8.5"
 rand_chacha = "0.3.1"
 yoga = "0.4.0"
@@ -48,6 +48,11 @@ taffy = { path = ".", features = ["random"] }
 lto = true
 panic = 'abort'
 
+[[bench]]
+name = "tree_creation"
+path = "benches/tree_creation.rs"
+harness = false
+
 [[bench]]
 name = "flexbox"
 path = "benches/flexbox.rs"
diff --git a/RELEASES.md b/RELEASES.md
index 52116b32c..47ba3a2f3 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,5 +1,49 @@
 # Release Notes
 
+## 0.3.11
+
+### Fixes
+
+- Fix exponential blowup when laying out trees containing nodes with min and max sizes.
+
+## 0.3.10
+
+### Fixes
+
+- Fix sizing of children when the available_space < min_size (#407)
+
+## 0.3.9
+
+### Fixes
+
+- Fix caching bug where a cached result would sometimes be incorrectly used when the amount of available space increased (bevyengine/bevy#8111) and (bevyengine/bevy#8124)
+
+## 0.3.8
+
+### Fixes
+
+- Fix incorrect min-content size for `flex-wrap: wrap` nodes (bevyengine/bevy#8082)
+
+## 0.3.7
+
+### Fixes
+
+- Fix: Make `padding` and `border` floor node sizes (#372)
+- Fix: Prevent percentages contributing to min-content sizes (#388) (also fixes bevyengine/bevy#8017)
+
+## 0.3.6
+
+### Fixes
+
+- Fix: Ignore `align_content` when `flex_wrap` is set to `nowrap` (#383)
+
+## 0.3.5
+
+### Fixes
+
+- Fix `display: none` when it is set on a flexbox child (#380)
+- Fix `display: none` when it is set on a grid child (#381)
+
 ## 0.3.4
 
 ### Fixes
diff --git a/benches/helpers/mod.rs b/benches/helpers/mod.rs
index 66269b571..617fc6897 100644
--- a/benches/helpers/mod.rs
+++ b/benches/helpers/mod.rs
@@ -2,6 +2,7 @@
 pub mod yoga_helpers;
 
 /// A helper function to recursively construct a deep tree
+#[allow(dead_code)]
 pub fn build_deep_tree<T, N>(
     tree: &mut T,
     max_nodes: u32,
diff --git a/benches/helpers/yoga_helpers.rs b/benches/helpers/yoga_helpers.rs
index 165ebdfea..787ea569e 100644
--- a/benches/helpers/yoga_helpers.rs
+++ b/benches/helpers/yoga_helpers.rs
@@ -1,3 +1,4 @@
+#![allow(dead_code)]
 use slotmap::{DefaultKey, SlotMap};
 
 pub mod yg {
@@ -12,6 +13,17 @@ mod tf {
     pub use taffy::prelude::*;
 }
 
+pub fn new_default_style_with_children(
+    tree: &mut SlotMap<DefaultKey, yg::Node>,
+    children: Vec<DefaultKey>,
+) -> DefaultKey {
+    let mut node = yg::Node::new();
+    for (i, child) in children.into_iter().enumerate() {
+        node.insert_child(&mut tree[child], i as u32);
+    }
+    tree.insert(node)
+}
+
 pub fn new_with_children(
     tree: &mut SlotMap<DefaultKey, yg::Node>,
     style: &tf::Style,
diff --git a/benches/tree_creation.rs b/benches/tree_creation.rs
new file mode 100644
index 000000000..10ce6a898
--- /dev/null
+++ b/benches/tree_creation.rs
@@ -0,0 +1,99 @@
+//! This file includes benchmarks for tree creation
+use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
+use rand::prelude::*;
+use rand_chacha::ChaCha8Rng;
+use taffy::prelude::*;
+use taffy::style::Style;
+
+mod helpers;
+
+#[cfg(feature = "yoga_benchmark")]
+use helpers::yoga_helpers;
+#[cfg(feature = "yoga_benchmark")]
+use slotmap::SlotMap;
+#[cfg(feature = "yoga_benchmark")]
+use yoga_helpers::yg;
+
+/// Build a random leaf node
+fn build_random_leaf(taffy: &mut Taffy) -> Node {
+    taffy.new_with_children(Style::DEFAULT, &[]).unwrap()
+}
+
+/// A tree with many children that have shallow depth
+fn build_taffy_flat_hierarchy(total_node_count: u32, use_with_capacity: bool) -> (Taffy, Node) {
+    let mut taffy = if use_with_capacity { Taffy::with_capacity(total_node_count as usize) } else { Taffy::new() };
+    let mut rng = ChaCha8Rng::seed_from_u64(12345);
+    let mut children = Vec::new();
+    let mut node_count = 0;
+
+    while node_count < total_node_count {
+        let sub_children_count = rng.gen_range(1..=4);
+        let sub_children: Vec<Node> = (0..sub_children_count).map(|_| build_random_leaf(&mut taffy)).collect();
+        let node = taffy.new_with_children(Style::DEFAULT, &sub_children).unwrap();
+
+        children.push(node);
+        node_count += 1 + sub_children_count;
+    }
+
+    let root = taffy.new_with_children(Style::DEFAULT, children.as_slice()).unwrap();
+    (taffy, root)
+}
+
+#[cfg(feature = "yoga_benchmark")]
+/// A tree with many children that have shallow depth
+fn build_yoga_flat_hierarchy(total_node_count: u32) -> (yg::YogaTree, Node) {
+    let mut tree = SlotMap::new();
+    let mut rng = ChaCha8Rng::seed_from_u64(12345);
+    let mut children = Vec::new();
+    let mut node_count = 0;
+
+    while node_count < total_node_count {
+        let sub_children_count = rng.gen_range(1..=4);
+        let sub_children: Vec<Node> =
+            (0..sub_children_count).map(|_| yoga_helpers::new_default_style_with_children(&mut tree, vec![])).collect();
+        let node = yoga_helpers::new_default_style_with_children(&mut tree, sub_children);
+
+        children.push(node);
+        node_count += 1 + sub_children_count;
+    }
+
+    let root = yoga_helpers::new_default_style_with_children(&mut tree, children);
+    (tree, root)
+}
+
+fn taffy_benchmarks(c: &mut Criterion) {
+    let mut group = c.benchmark_group("Tree creation");
+    for node_count in [1_000u32, 10_000, 100_000].iter() {
+        #[cfg(feature = "yoga_benchmark")]
+        let benchmark_id = BenchmarkId::new(format!("Yoga"), node_count);
+        #[cfg(feature = "yoga_benchmark")]
+        group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
+            b.iter(|| {
+                let (taffy, root) = build_yoga_flat_hierarchy(node_count);
+                std::hint::black_box(taffy);
+                std::hint::black_box(root);
+            })
+        });
+        let benchmark_id = BenchmarkId::new(format!("Taffy::new"), node_count);
+        group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
+            b.iter(|| {
+                let (tree, root) = build_taffy_flat_hierarchy(node_count, false);
+                std::hint::black_box(tree);
+                std::hint::black_box(root);
+            })
+        });
+
+        let benchmark_id = BenchmarkId::new(format!("Taffy::with_capacity"), node_count);
+        group.bench_with_input(benchmark_id, node_count, |b, &node_count| {
+            b.iter(|| {
+                let (tree, root) = build_taffy_flat_hierarchy(node_count, true);
+                std::hint::black_box(tree);
+                std::hint::black_box(root);
+            })
+        });
+    }
+    group.finish();
+}
+
+criterion_group!(benches, taffy_benchmarks);
+criterion_main!(benches);
diff --git a/deny.toml b/deny.toml
index 1283ab103..43d6315bc 100644
--- a/deny.toml
+++ b/deny.toml
@@ -35,7 +35,11 @@ skip = [
     # This dependency won't actually end up in the final binary anyway as it a sub-dependency
     # of num-cpus and atty only when targetting the hermit unikernel OS
     # (https://github.com/hermitcore/rusty-hermit)
-    { name = "hermit-abi" }
+    { name = "hermit-abi" },
+
+    # Long-term we'll want to re-ban this. However it's going to take a while for the ecosystem to
+    # transition over to syn 2 and we don't want to block Taffy releases in the meantime.
+    { name = "syn" },
 ]
 
 [sources]
diff --git a/scripts/gentest/Cargo.toml b/scripts/gentest/Cargo.toml
index 6669b24c4..f71b9aaa6 100644
--- a/scripts/gentest/Cargo.toml
+++ b/scripts/gentest/Cargo.toml
@@ -12,5 +12,5 @@ log = "0.4"
 proc-macro2 = "1.0.6"
 quote = "1.0.2"
 serde_json = "1"
-syn = "1.0.7"
+syn = "2.0.4"
 tokio = { version = "1.18", features = ["full"] }
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index 9aa125a5a..c72416232 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -76,6 +76,8 @@ struct FlexItem {
     inset: Rect<Option<f32>>,
     /// The margin of this item
     margin: Rect<f32>,
+    /// Whether each margin is an auto margin or not
+    margin_is_auto: Rect<bool>,
     /// The padding of this item
     padding: Rect<f32>,
     /// The border of this item
@@ -141,6 +143,10 @@ struct AlgoConstants {
     /// Is the wrap direction inverted
     is_wrap_reverse: bool,
 
+    /// The item's min_size style
+    min_size: Size<Option<f32>>,
+    /// The item's max_size style
+    max_size: Size<Option<f32>>,
     /// The margin of this section
     margin: Rect<f32>,
     /// The border of this section
@@ -153,6 +159,8 @@ struct AlgoConstants {
     align_items: AlignItems,
     /// The align_content property of this node
     align_content: AlignContent,
+    /// The justify_content property of this node
+    justify_content: Option<JustifyContent>,
 
     /// The border-box size of the node being laid out (if known)
     node_outer_size: Size<Option<f32>>,
@@ -175,10 +183,6 @@ pub fn compute(
     run_mode: RunMode,
 ) -> SizeAndBaselines {
     let style = tree.style(node);
-    let has_min_max_sizes = style.min_size.width.is_defined()
-        || style.min_size.height.is_defined()
-        || style.max_size.width.is_defined()
-        || style.max_size.height.is_defined();
 
     // Pull these out earlier to avoid borrowing issues
     let aspect_ratio = style.aspect_ratio;
@@ -202,35 +206,9 @@ pub fn compute(
         }
     }
 
-    if styled_based_known_dimensions.both_axis_defined() || !has_min_max_sizes {
-        #[cfg(feature = "debug")]
-        NODE_LOGGER.log("FLEX: single-pass");
-        compute_preliminary(tree, node, styled_based_known_dimensions, parent_size, available_space, run_mode)
-    } else {
-        #[cfg(feature = "debug")]
-        NODE_LOGGER.log("FLEX: two-pass");
-        let first_pass = compute_preliminary(
-            tree,
-            node,
-            styled_based_known_dimensions,
-            parent_size,
-            available_space,
-            RunMode::ComputeSize,
-        )
-        .size;
-
-        let clamped_first_pass_size = first_pass.maybe_clamp(min_size, max_size);
-
-        compute_preliminary(
-            tree,
-            node,
-            styled_based_known_dimensions
-                .zip_map(clamped_first_pass_size, |known, first_pass| known.or_else(|| first_pass.into())),
-            parent_size,
-            available_space,
-            run_mode,
-        )
-    }
+    #[cfg(feature = "debug")]
+    NODE_LOGGER.log("FLEX: single-pass");
+    compute_preliminary(tree, node, styled_based_known_dimensions, parent_size, available_space, run_mode)
 }
 
 /// Compute a preliminary size for an item
@@ -283,7 +261,7 @@ fn compute_preliminary(
     // 5. Collect flex items into flex lines.
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("collect_flex_lines");
-    let mut flex_lines = collect_flex_lines(tree, node, &constants, available_space, &mut flex_items);
+    let mut flex_lines = collect_flex_lines(&constants, available_space, &mut flex_items);
 
     // If container size is undefined, determine the container's main size
     // and then re-resolve gaps based on newly determined size
@@ -309,7 +287,7 @@ fn compute_preliminary(
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("resolve_flexible_lengths");
     for line in &mut flex_lines {
-        resolve_flexible_lengths(tree, line, &constants, original_gap);
+        resolve_flexible_lengths(line, &constants, original_gap);
     }
 
     // 9.4. Cross Size Determination
@@ -330,7 +308,7 @@ fn compute_preliminary(
     // 8. Calculate the cross size of each flex line.
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("calculate_cross_size");
-    calculate_cross_size(tree, &mut flex_lines, known_dimensions, &constants);
+    calculate_cross_size(&mut flex_lines, known_dimensions, &constants);
 
     // 9. Handle 'align-content: stretch'.
     #[cfg(feature = "debug")]
@@ -362,14 +340,14 @@ fn compute_preliminary(
     // 12. Distribute any remaining free space.
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("distribute_remaining_free_space");
-    distribute_remaining_free_space(tree, &mut flex_lines, node, &constants);
+    distribute_remaining_free_space(&mut flex_lines, &constants);
 
     // 9.6. Cross-Axis Alignment
 
     // 13. Resolve cross-axis auto margins (also includes 14).
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("resolve_cross_axis_auto_margins");
-    resolve_cross_axis_auto_margins(tree, &mut flex_lines, &constants);
+    resolve_cross_axis_auto_margins(&mut flex_lines, &constants);
 
     // 15. Determine the flex container’s used cross size.
     #[cfg(feature = "debug")]
@@ -385,7 +363,7 @@ fn compute_preliminary(
     // 16. Align all flex lines per align-content.
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("align_flex_lines_per_align_content");
-    align_flex_lines_per_align_content(tree, &mut flex_lines, node, &constants, total_line_cross_size);
+    align_flex_lines_per_align_content(&mut flex_lines, &constants, total_line_cross_size);
 
     // Do a final layout pass and gather the resulting layouts
     #[cfg(feature = "debug")]
@@ -403,8 +381,8 @@ fn compute_preliminary(
     for order in 0..len {
         let child = tree.child(node, order);
         if tree.style(child).display == Display::None {
-            *tree.layout_mut(node) = Layout::with_order(order as u32);
-            GenericAlgorithm::measure_size(
+            *tree.layout_mut(child) = Layout::with_order(order as u32);
+            GenericAlgorithm::perform_layout(
                 tree,
                 child,
                 Size::NONE,
@@ -447,19 +425,18 @@ fn compute_constants(
     let is_wrap = matches!(style.flex_wrap, FlexWrap::Wrap | FlexWrap::WrapReverse);
     let is_wrap_reverse = style.flex_wrap == FlexWrap::WrapReverse;
 
+    let aspect_ratio = style.aspect_ratio;
     let margin = style.margin.resolve_or_zero(parent_size.width);
     let padding = style.padding.resolve_or_zero(parent_size.width);
     let border = style.border.resolve_or_zero(parent_size.width);
-    let align_items = style.align_items.unwrap_or(crate::style::AlignItems::Stretch);
-    let align_content = style.align_content.unwrap_or(crate::style::AlignContent::Stretch);
+    let align_items = style.align_items.unwrap_or(AlignItems::Stretch);
+    let align_content = style.align_content.unwrap_or(AlignContent::Stretch);
+    let justify_content = style.justify_content;
 
     let padding_border = padding + border;
 
     let node_outer_size = known_dimensions;
-    let node_inner_size = Size {
-        width: node_outer_size.width.maybe_sub(padding_border.horizontal_axis_sum()),
-        height: node_outer_size.height.maybe_sub(padding_border.vertical_axis_sum()),
-    };
+    let node_inner_size = node_outer_size.maybe_sub(padding_border.sum_axes());
     let gap = style.gap.resolve_or_zero(node_inner_size.or(Size::zero()));
 
     let container_size = Size::zero();
@@ -471,12 +448,15 @@ fn compute_constants(
         is_column,
         is_wrap,
         is_wrap_reverse,
+        min_size: style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio),
+        max_size: style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio),
         margin,
         border,
         gap,
         padding_border,
         align_items,
         align_content,
+        justify_content,
         node_outer_size,
         node_inner_size,
         container_size,
@@ -511,6 +491,7 @@ fn generate_anonymous_flex_items(tree: &impl LayoutTree, node: Node, constants:
 
                 inset: child_style.inset.zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)),
                 margin: child_style.margin.resolve_or_zero(constants.node_inner_size.width),
+                margin_is_auto: child_style.margin.map(|m| m == LengthPercentageAuto::Auto),
                 padding: child_style.padding.resolve_or_zero(constants.node_inner_size.width),
                 border: child_style.border.resolve_or_zero(constants.node_inner_size.width),
                 align_self: child_style.align_self.unwrap_or(constants.align_items),
@@ -605,107 +586,143 @@ fn determine_flex_base_size(
     tree: &mut impl LayoutTree,
     constants: &AlgoConstants,
     available_space: Size<AvailableSpace>,
-    flex_items: &mut Vec<FlexItem>,
+    flex_items: &mut [FlexItem],
 ) {
+    let dir = constants.dir;
+
     for child in flex_items.iter_mut() {
         let child_style = tree.style(child.node);
 
-        // A. If the item has a definite used flex basis, that’s the flex base size.
+        // Parent size for child sizing
+        let cross_axis_parent_size = constants.node_inner_size.cross(dir);
 
-        // B. If the flex item has an intrinsic aspect ratio,
-        //    a used flex basis of content, and a definite cross size,
-        //    then the flex base size is calculated from its inner
-        //    cross size and the flex item’s intrinsic aspect ratio.
+        // Available space for child sizing
+        let cross_axis_margin_sum = constants.margin.cross_axis_sum(dir);
+        let child_min_cross = child.min_size.cross(dir).maybe_add(cross_axis_margin_sum);
+        let child_max_cross = child.max_size.cross(dir).maybe_add(cross_axis_margin_sum);
+        let cross_axis_available_space = cross_axis_parent_size.maybe_clamp(child_min_cross, child_max_cross).into();
 
-        // Note: `child.size` has already been resolved against aspect_ratio in generate_anonymous_flex_items
-        // So B will just work here by using main_size without special handling for aspect_ratio
+        child.flex_basis = 'flex_basis: {
+            // A. If the item has a definite used flex basis, that’s the flex base size.
 
-        let flex_basis = child_style.flex_basis.maybe_resolve(constants.node_inner_size.main(constants.dir));
-        let main_size = child.size.main(constants.dir);
-        if let Some(flex_basis) = flex_basis.or(main_size) {
-            child.flex_basis = flex_basis;
-            continue;
-        };
+            // B. If the flex item has an intrinsic aspect ratio,
+            //    a used flex basis of content, and a definite cross size,
+            //    then the flex base size is calculated from its inner
+            //    cross size and the flex item’s intrinsic aspect ratio.
 
-        // C. If the used flex basis is content or depends on its available space,
-        //    and the flex container is being sized under a min-content or max-content
-        //    constraint (e.g. when performing automatic table layout [CSS21]),
-        //    size the item under that constraint. The flex base size is the item’s
-        //    resulting main size.
-
-        // This is covered by the implementation of E below, which passes the available_space constraint
-        // through to the child size computation. It may need a separate implementation if/when D is implemented.
-
-        // D. Otherwise, if the used flex basis is content or depends on its
-        //    available space, the available main size is infinite, and the flex item’s
-        //    inline axis is parallel to the main axis, lay the item out using the rules
-        //    for a box in an orthogonal flow [CSS3-WRITING-MODES]. The flex base size
-        //    is the item’s max-content main size.
-
-        // TODO if/when vertical writing modes are supported
-
-        // E. Otherwise, size the item into the available space using its used flex basis
-        //    in place of its main size, treating a value of content as max-content.
-        //    If a cross size is needed to determine the main size (e.g. when the
-        //    flex item’s main size is in its block axis) and the flex item’s cross size
-        //    is auto and not definite, in this calculation use fit-content as the
-        //    flex item’s cross size. The flex base size is the item’s resulting main size.
-
-        let child_known_dimensions = {
-            let mut ckd = child.size;
-            if child.align_self == AlignSelf::Stretch && ckd.cross(constants.dir).is_none() {
-                ckd.set_cross(
-                    constants.dir,
-                    available_space
-                        .cross(constants.dir)
-                        .into_option()
-                        .maybe_sub(constants.margin.cross_axis_sum(constants.dir)),
-                );
-            }
-            ckd
+            // Note: `child.size` has already been resolved against aspect_ratio in generate_anonymous_flex_items
+            // So B will just work here by using main_size without special handling for aspect_ratio
+
+            let flex_basis = child_style.flex_basis.maybe_resolve(constants.node_inner_size.main(dir));
+            let main_size = child.size.main(dir);
+            if let Some(flex_basis) = flex_basis.or(main_size) {
+                break 'flex_basis flex_basis;
+            };
+
+            // C. If the used flex basis is content or depends on its available space,
+            //    and the flex container is being sized under a min-content or max-content
+            //    constraint (e.g. when performing automatic table layout [CSS21]),
+            //    size the item under that constraint. The flex base size is the item’s
+            //    resulting main size.
+
+            // This is covered by the implementation of E below, which passes the available_space constraint
+            // through to the child size computation. It may need a separate implementation if/when D is implemented.
+
+            // D. Otherwise, if the used flex basis is content or depends on its
+            //    available space, the available main size is infinite, and the flex item’s
+            //    inline axis is parallel to the main axis, lay the item out using the rules
+            //    for a box in an orthogonal flow [CSS3-WRITING-MODES]. The flex base size
+            //    is the item’s max-content main size.
+
+            // TODO if/when vertical writing modes are supported
+
+            // E. Otherwise, size the item into the available space using its used flex basis
+            //    in place of its main size, treating a value of content as max-content.
+            //    If a cross size is needed to determine the main size (e.g. when the
+            //    flex item’s main size is in its block axis) and the flex item’s cross size
+            //    is auto and not definite, in this calculation use fit-content as the
+            //    flex item’s cross size. The flex base size is the item’s resulting main size.
+
+            let child_parent_size = Size::NONE.with_cross(dir, cross_axis_parent_size);
+            let child_available_space = available_space.with_cross(dir, cross_axis_available_space);
+
+            let child_known_dimensions = {
+                let mut ckd = child.size;
+                if child.align_self == AlignSelf::Stretch && ckd.cross(dir).is_none() {
+                    ckd.set_cross(
+                        dir,
+                        child_available_space
+                            .cross(dir)
+                            .into_option()
+                            .maybe_clamp(child_min_cross, child_max_cross)
+                            .maybe_sub(constants.margin.cross_axis_sum(dir)),
+                    );
+                }
+                ckd
+            };
+
+            break 'flex_basis GenericAlgorithm::measure_size(
+                tree,
+                child.node,
+                child_known_dimensions,
+                child_parent_size,
+                child_available_space,
+                SizingMode::ContentSize,
+            )
+            .main(dir);
         };
 
-        child.flex_basis = GenericAlgorithm::measure_size(
-            tree,
-            child.node,
-            child_known_dimensions,
-            constants.node_inner_size,
-            available_space,
-            SizingMode::ContentSize,
-        )
-        .main(constants.dir);
-    }
+        // Floor flex-basis by the padding_border_sum (floors inner_flex_basis at zero)
+        // This seems to be in violation of the spec which explicitly states that the content box should not be floored at zero
+        // (like it usually is) when calculating the flex-basis. But including this matches both Chrome and Firefox's behaviour.
+        //
+        // TODO: resolve spec violation
+        // Spec: https://www.w3.org/TR/css-flexbox-1/#intrinsic-item-contributions
+        // Spec: https://www.w3.org/TR/css-flexbox-1/#change-2016-max-contribution
+        let padding_border_sum = child.padding.main_axis_sum(constants.dir) + child.border.main_axis_sum(constants.dir);
+        child.flex_basis = child.flex_basis.max(padding_border_sum);
 
-    // The hypothetical main size is the item’s flex base size clamped according to its
-    // used min and max main sizes (and flooring the content box size at zero).
+        // The hypothetical main size is the item’s flex base size clamped according to its
+        // used min and max main sizes (and flooring the content box size at zero).
 
-    for child in flex_items {
         child.inner_flex_basis =
             child.flex_basis - child.padding.main_axis_sum(constants.dir) - child.border.main_axis_sum(constants.dir);
 
-        let hypothetical_inner_min_main = child.min_size.main(constants.dir);
-        child.hypothetical_inner_size.set_main(
-            constants.dir,
-            child.flex_basis.maybe_clamp(hypothetical_inner_min_main, child.max_size.main(constants.dir)),
-        );
-        child.hypothetical_outer_size.set_main(
-            constants.dir,
-            child.hypothetical_inner_size.main(constants.dir) + child.margin.main_axis_sum(constants.dir),
-        );
+        let padding_border_axes_sums = (child.padding + child.border).sum_axes().map(Some);
+        let hypothetical_inner_min_main =
+            child.min_size.main(constants.dir).maybe_max(padding_border_axes_sums.main(constants.dir));
+        let hypothetical_inner_size =
+            child.flex_basis.maybe_clamp(hypothetical_inner_min_main, child.max_size.main(constants.dir));
+        let hypothetical_outer_size = hypothetical_inner_size + child.margin.main_axis_sum(constants.dir);
+
+        child.hypothetical_inner_size.set_main(constants.dir, hypothetical_inner_size);
+        child.hypothetical_outer_size.set_main(constants.dir, hypothetical_outer_size);
+
+        // Note that it is important that the `parent_size` parameter in the main axis is not set for this
+        // function call as it used for resolving percentages, and percentage size in an axis should not contribute
+        // to a min-content contribution in that same axis. However the `parent_size` and `available_space` *should*
+        // be set to their usual values in the cross axis so that wrapping content can wrap correctly.
+        //
+        // See https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution
+        let min_content_size = {
+            let child_parent_size = Size::NONE.with_cross(dir, cross_axis_parent_size);
+            let child_available_space = Size::MIN_CONTENT.with_cross(dir, cross_axis_available_space);
 
-        let min_content_size = GenericAlgorithm::measure_size(
-            tree,
-            child.node,
-            Size::NONE,
-            constants.node_inner_size,
-            Size::MIN_CONTENT,
-            SizingMode::ContentSize,
-        );
+            GenericAlgorithm::measure_size(
+                tree,
+                child.node,
+                Size::NONE,
+                child_parent_size,
+                child_available_space,
+                SizingMode::ContentSize,
+            )
+        };
 
         // 4.5. Automatic Minimum Size of Flex Items
         // https://www.w3.org/TR/css-flexbox-1/#min-size-auto
         let clamped_min_content_size = min_content_size.maybe_min(child.size).maybe_min(child.max_size);
-        child.resolved_minimum_size = child.min_size.unwrap_or(clamped_min_content_size);
+        child.resolved_minimum_size =
+            child.min_size.unwrap_or(clamped_min_content_size).maybe_max(padding_border_axes_sums);
     }
 }
 
@@ -728,13 +745,11 @@ fn determine_flex_base_size(
 ///         **Note that the "collect as many" line will collect zero-sized flex items onto the end of the previous line even if the last non-zero item exactly "filled up" the line**.
 #[inline]
 fn collect_flex_lines<'a>(
-    tree: &impl LayoutTree,
-    node: Node,
     constants: &AlgoConstants,
     available_space: Size<AvailableSpace>,
     flex_items: &'a mut Vec<FlexItem>,
 ) -> Vec<FlexLine<'a>> {
-    if tree.style(node).flex_wrap == FlexWrap::NoWrap {
+    if !constants.is_wrap {
         let mut lines = new_vec_with_capacity(1);
         lines.push(FlexLine { items: flex_items.as_mut_slice(), cross_size: 0.0, offset_cross: 0.0 });
         lines
@@ -798,6 +813,8 @@ fn determine_container_main_size(
     lines: &mut Vec<FlexLine<'_>>,
     constants: &mut AlgoConstants,
 ) {
+    let main_padding_border = constants.padding_border.main_axis_sum(constants.dir);
+
     let outer_main_size: f32 = constants.node_outer_size.main(constants.dir).unwrap_or_else(|| {
         match main_axis_available_space {
             AvailableSpace::Definite(main_axis_available_space) => {
@@ -808,13 +825,16 @@ fn determine_container_main_size(
                         let total_target_size = line
                             .items
                             .iter()
-                            .map(|child| child.flex_basis + child.margin.main_axis_sum(constants.dir))
+                            .map(|child| {
+                                let padding_border_sum = (child.padding + child.border).main_axis_sum(constants.dir);
+                                (child.flex_basis + child.margin.main_axis_sum(constants.dir)).max(padding_border_sum)
+                            })
                             .sum::<f32>();
                         total_target_size + line_main_axis_gap
                     })
                     .max_by(|a, b| a.total_cmp(b))
                     .unwrap_or(0.0);
-                let size = longest_line_length + constants.padding_border.main_axis_sum(constants.dir);
+                let size = longest_line_length + main_padding_border;
                 if lines.len() > 1 {
                     f32_max(size, main_axis_available_space)
                 } else {
@@ -829,13 +849,16 @@ fn determine_container_main_size(
                         let total_target_size = line
                             .items
                             .iter()
-                            .map(|child| child.flex_basis + child.margin.main_axis_sum(constants.dir))
+                            .map(|child| {
+                                let padding_border_sum = (child.padding + child.border).main_axis_sum(constants.dir);
+                                (child.flex_basis + child.margin.main_axis_sum(constants.dir)).max(padding_border_sum)
+                            })
                             .sum::<f32>();
                         total_target_size + line_main_axis_gap
                     })
                     .max_by(|a, b| a.total_cmp(b))
                     .unwrap_or(0.0);
-                longest_line_length + constants.padding_border.main_axis_sum(constants.dir)
+                longest_line_length + main_padding_border
             }
             AvailableSpace::MinContent | AvailableSpace::MaxContent => {
                 // Define a base main_size variable. This is mutated once for iteration over the outer
@@ -848,23 +871,39 @@ fn determine_container_main_size(
                         let style_min = item.min_size.main(constants.dir);
                         let style_preferred = item.size.main(constants.dir);
                         let style_max = item.max_size.main(constants.dir);
-                        let flex_basis_min = Some(item.flex_basis).filter(|_| item.flex_shrink == 0.0);
-                        let flex_basis_max = Some(item.flex_basis).filter(|_| item.flex_grow == 0.0);
-                        let min_main_size = style_min.maybe_max(flex_basis_min).or(flex_basis_min);
-                        let max_main_size = style_max.maybe_min(flex_basis_max).or(flex_basis_max);
+
+                        // The spec seems a bit unclear on this point (my initial reading was that the `.maybe_max(style_preferred)` should
+                        // not be included here), however this matches both Chrome and Firefox as of 9th March 2023.
+                        //
+                        // Spec: https://www.w3.org/TR/css-flexbox-1/#intrinsic-item-contributions
+                        // Spec modifcation: https://www.w3.org/TR/css-flexbox-1/#change-2016-max-contribution
+                        // Issue: https://github.com/w3c/csswg-drafts/issues/1435
+                        // Gentest: padding_border_overrides_size_flex_basis_0.html
+                        let clamping_basis = Some(item.flex_basis).maybe_max(style_preferred);
+                        let flex_basis_min = clamping_basis.filter(|_| item.flex_shrink == 0.0);
+                        let flex_basis_max = clamping_basis.filter(|_| item.flex_grow == 0.0);
+
+                        let resolved_min = item.resolved_minimum_size.main(constants.dir);
+                        let min_main_size = style_min
+                            .maybe_max(flex_basis_min)
+                            .or(flex_basis_min)
+                            .unwrap_or(resolved_min)
+                            .max(resolved_min);
+                        let max_main_size =
+                            style_max.maybe_min(flex_basis_max).or(flex_basis_max).unwrap_or(f32::INFINITY);
 
                         let content_contribution = match (min_main_size, style_preferred, max_main_size) {
                             // If the clamping values are such that max <= min, then we can avoid the expensive step of computing the content size
                             // as we know that the clamping values will override it anyway
-                            (Some(min), Some(pref), Some(max)) if max <= min || max <= pref => {
+                            (min, Some(pref), max) if max <= min || max <= pref => {
                                 pref.min(max).max(min) + item.margin.main_axis_sum(constants.dir)
                             }
-                            (Some(min), _, Some(max)) if max <= min => min + item.margin.main_axis_sum(constants.dir),
-                            (_, Some(pref), Some(max)) if max <= pref => max + item.margin.main_axis_sum(constants.dir),
+                            (min, _, max) if max <= min => min + item.margin.main_axis_sum(constants.dir),
                             // Else compute the min- or -max content size and apply the full formula for computing the
                             // min- or max- content contributuon
                             _ => {
                                 // Either the min- or max- content size depending on which constraint we are sizing under.
+                                // TODO: Optimise by using already computed values where available
                                 let content_main_size = GenericAlgorithm::measure_size(
                                     tree,
                                     item.node,
@@ -889,9 +928,12 @@ fn determine_container_main_size(
                                 // Ultimately, this was not found by reading the spec, but by trial and error fixing tests to align with Webkit/Firefox output.
                                 // (see the `flex_basis_unconstraint_row` and `flex_basis_uncontraint_column` generated tests which demonstrate this)
                                 if constants.is_row {
-                                    content_main_size.maybe_clamp(style_min, style_max)
+                                    content_main_size.maybe_clamp(style_min, style_max).max(main_padding_border)
                                 } else {
-                                    content_main_size.max(item.flex_basis).maybe_clamp(style_min, style_max)
+                                    content_main_size
+                                        .max(item.flex_basis)
+                                        .maybe_clamp(style_min, style_max)
+                                        .max(main_padding_border)
                                 }
                             }
                         };
@@ -900,8 +942,7 @@ fn determine_container_main_size(
                             if diff > 0.0 {
                                 diff / f32_max(1.0, item.flex_grow)
                             } else if diff < 0.0 {
-                                let scaled_shrink_factor = f32_max(1.0, item.flex_shrink) * item.inner_flex_basis;
-                                // let scaled_shrink_factor - f32_max(1.0, item.flex_shrink * item.inner_flex_basis);
+                                let scaled_shrink_factor = f32_max(1.0, item.flex_shrink * item.inner_flex_basis);
                                 diff / scaled_shrink_factor
                             } else {
                                 // We are assuming that diff is 0.0 here and that we haven't accidentally introduced a NaN
@@ -953,10 +994,15 @@ fn determine_container_main_size(
                     main_size = f32_max(main_size, item_main_size_sum + gap_sum)
                 }
 
-                main_size + constants.padding_border.main_axis_sum(constants.dir)
+                main_size + main_padding_border
             }
         }
     });
+
+    let outer_main_size = outer_main_size
+        .maybe_clamp(constants.min_size.main(constants.dir), constants.max_size.main(constants.dir))
+        .max(main_padding_border);
+
     // let outer_main_size = inner_main_size + constants.padding_border.main_axis_sum(constants.dir);
     let inner_main_size = outer_main_size - constants.padding_border.main_axis_sum(constants.dir);
     constants.container_size.set_main(constants.dir, outer_main_size);
@@ -969,12 +1015,7 @@ fn determine_container_main_size(
 ///
 /// # [9.7. Resolving Flexible Lengths](https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths)
 #[inline]
-fn resolve_flexible_lengths(
-    tree: &mut impl LayoutTree,
-    line: &mut FlexLine,
-    constants: &AlgoConstants,
-    original_gap: Size<f32>,
-) {
+fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, original_gap: Size<f32>) {
     let total_original_main_axis_gap = sum_axis_gaps(original_gap.main(constants.dir), line.items.len());
     let total_main_axis_gap = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len());
 
@@ -1000,8 +1041,7 @@ fn resolve_flexible_lengths(
         let inner_target_size = child.hypothetical_inner_size.main(constants.dir);
         child.target_size.set_main(constants.dir, inner_target_size);
 
-        let child_style = tree.style(child.node);
-        if (child_style.flex_grow == 0.0 && child_style.flex_shrink == 0.0)
+        if (child.flex_grow == 0.0 && child.flex_shrink == 0.0)
             || (growing && child.flex_basis > child.hypothetical_inner_size.main(constants.dir))
             || (shrinking && child.flex_basis < child.hypothetical_inner_size.main(constants.dir))
         {
@@ -1057,8 +1097,7 @@ fn resolve_flexible_lengths(
 
         let (sum_flex_grow, sum_flex_shrink): (f32, f32) =
             unfrozen.iter().fold((0.0, 0.0), |(flex_grow, flex_shrink), item| {
-                let style = tree.style(item.node);
-                (flex_grow + style.flex_grow, flex_shrink + style.flex_shrink)
+                (flex_grow + item.flex_grow, flex_shrink + item.flex_shrink)
             });
 
         let free_space = if growing && sum_flex_grow < 1.0 {
@@ -1094,18 +1133,17 @@ fn resolve_flexible_lengths(
         if free_space.is_normal() {
             if growing && sum_flex_grow > 0.0 {
                 for child in &mut unfrozen {
-                    child.target_size.set_main(
-                        constants.dir,
-                        child.flex_basis + free_space * (tree.style(child.node).flex_grow / sum_flex_grow),
-                    );
+                    child
+                        .target_size
+                        .set_main(constants.dir, child.flex_basis + free_space * (child.flex_grow / sum_flex_grow));
                 }
             } else if shrinking && sum_flex_shrink > 0.0 {
                 let sum_scaled_shrink_factor: f32 =
-                    unfrozen.iter().map(|child| child.inner_flex_basis * tree.style(child.node).flex_shrink).sum();
+                    unfrozen.iter().map(|child| child.inner_flex_basis * child.flex_shrink).sum();
 
                 if sum_scaled_shrink_factor > 0.0 {
                     for child in &mut unfrozen {
-                        let scaled_shrink_factor = child.inner_flex_basis * tree.style(child.node).flex_shrink;
+                        let scaled_shrink_factor = child.inner_flex_basis * child.flex_shrink;
                         child.target_size.set_main(
                             constants.dir,
                             child.flex_basis + free_space * (scaled_shrink_factor / sum_scaled_shrink_factor),
@@ -1169,13 +1207,22 @@ fn determine_hypothetical_cross_size(
     available_space: Size<AvailableSpace>,
 ) {
     for child in line.items.iter_mut() {
+        let padding_border_sum = (child.padding + child.border).cross_axis_sum(constants.dir);
+
+        let child_known_main = constants.container_size.main(constants.dir).into();
+
         let child_cross = child
             .size
             .cross(constants.dir)
-            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir));
+            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir))
+            .maybe_max(padding_border_sum);
 
-        child.hypothetical_inner_size.set_cross(
-            constants.dir,
+        let child_available_cross = available_space
+            .cross(constants.dir)
+            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir))
+            .maybe_max(padding_border_sum);
+
+        let child_inner_cross = child_cross.unwrap_or_else(|| {
             GenericAlgorithm::measure_size(
                 tree,
                 child.node,
@@ -1185,27 +1232,19 @@ fn determine_hypothetical_cross_size(
                 },
                 constants.node_inner_size,
                 Size {
-                    width: if constants.is_row {
-                        constants.container_size.main(constants.dir).into()
-                    } else {
-                        available_space.width
-                    },
-                    height: if constants.is_row {
-                        available_space.height
-                    } else {
-                        constants.container_size.main(constants.dir).into()
-                    },
+                    width: if constants.is_row { child_known_main } else { child_available_cross },
+                    height: if constants.is_row { child_available_cross } else { child_known_main },
                 },
                 SizingMode::ContentSize,
             )
             .cross(constants.dir)
-            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir)),
-        );
+            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir))
+            .max(padding_border_sum)
+        });
+        let child_outer_cross = child_inner_cross + child.margin.cross_axis_sum(constants.dir);
 
-        child.hypothetical_outer_size.set_cross(
-            constants.dir,
-            child.hypothetical_inner_size.cross(constants.dir) + child.margin.cross_axis_sum(constants.dir),
-        );
+        child.hypothetical_inner_size.set_cross(constants.dir, child_inner_cross);
+        child.hypothetical_outer_size.set_cross(constants.dir, child_outer_cross);
     }
 }
 
@@ -1299,24 +1338,27 @@ fn calculate_children_base_lines(
 ///         If the flex container is single-line, then clamp the line’s cross-size to be within the container’s computed min and max cross sizes.
 ///         **Note that if CSS 2.1’s definition of min/max-width/height applied more generally, this behavior would fall out automatically**.
 #[inline]
-fn calculate_cross_size(
-    tree: &mut impl LayoutTree,
-    flex_lines: &mut [FlexLine],
-    node_size: Size<Option<f32>>,
-    constants: &AlgoConstants,
-) {
+fn calculate_cross_size(flex_lines: &mut [FlexLine], node_size: Size<Option<f32>>, constants: &AlgoConstants) {
     // Note: AlignContent::SpaceEvenly and AlignContent::SpaceAround behave like AlignContent::Stretch when there is only
     // a single flex line in the container. See: https://www.w3.org/TR/css-flexbox-1/#align-content-property
+    // Also: align_content is ignored entirely (and thus behaves like Stretch) when `flex_wrap` is set to `nowrap`.
     if flex_lines.len() == 1
         && node_size.cross(constants.dir).is_some()
-        && matches!(
-            constants.align_content,
-            AlignContent::Stretch | AlignContent::SpaceEvenly | AlignContent::SpaceAround
-        )
+        && (!constants.is_wrap
+            || matches!(
+                constants.align_content,
+                AlignContent::Stretch | AlignContent::SpaceEvenly | AlignContent::SpaceAround
+            ))
     {
-        flex_lines[0].cross_size =
-            (node_size.cross(constants.dir).maybe_sub(constants.padding_border.cross_axis_sum(constants.dir)))
-                .unwrap_or(0.0);
+        let cross_axis_padding_border = constants.padding_border.cross_axis_sum(constants.dir);
+        let cross_min_size = constants.min_size.cross(constants.dir);
+        let cross_max_size = constants.max_size.cross(constants.dir);
+        flex_lines[0].cross_size = node_size
+            .cross(constants.dir)
+            .maybe_clamp(cross_min_size, cross_max_size)
+            .maybe_sub(cross_axis_padding_border)
+            .maybe_max(0.0)
+            .unwrap_or(0.0);
     } else {
         for line in flex_lines.iter_mut() {
             //    1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose
@@ -1336,10 +1378,9 @@ fn calculate_cross_size(
                 .items
                 .iter()
                 .map(|child| {
-                    let child_style = tree.style(child.node);
                     if child.align_self == AlignSelf::Baseline
-                        && child_style.margin.cross_start(constants.dir) != LengthPercentageAuto::Auto
-                        && child_style.margin.cross_end(constants.dir) != LengthPercentageAuto::Auto
+                        && !child.margin_is_auto.cross_start(constants.dir)
+                        && !child.margin_is_auto.cross_end(constants.dir)
                     {
                         max_baseline - child.baseline + child.hypothetical_outer_size.cross(constants.dir)
                     } else {
@@ -1360,15 +1401,23 @@ fn calculate_cross_size(
 ///     increase the cross size of each flex line by equal amounts such that the sum of their cross sizes exactly equals the flex container’s inner cross size.
 #[inline]
 fn handle_align_content_stretch(flex_lines: &mut [FlexLine], node_size: Size<Option<f32>>, constants: &AlgoConstants) {
-    if constants.align_content == AlignContent::Stretch && node_size.cross(constants.dir).is_some() {
+    if constants.align_content == AlignContent::Stretch {
+        let cross_axis_padding_border = constants.padding_border.cross_axis_sum(constants.dir);
+        let cross_min_size = constants.min_size.cross(constants.dir);
+        let cross_max_size = constants.max_size.cross(constants.dir);
+        let container_min_inner_cross = node_size
+            .cross(constants.dir)
+            .or(cross_min_size)
+            .maybe_clamp(cross_min_size, cross_max_size)
+            .maybe_sub(cross_axis_padding_border)
+            .maybe_max(0.0)
+            .unwrap_or(0.0);
+
         let total_cross_axis_gap = sum_axis_gaps(constants.gap.cross(constants.dir), flex_lines.len());
-        let total_cross: f32 = flex_lines.iter().map(|line| line.cross_size).sum::<f32>() + total_cross_axis_gap;
-        let inner_cross =
-            (node_size.cross(constants.dir).maybe_sub(constants.padding_border.cross_axis_sum(constants.dir)))
-                .unwrap_or(0.0);
+        let lines_total_cross: f32 = flex_lines.iter().map(|line| line.cross_size).sum::<f32>() + total_cross_axis_gap;
 
-        if total_cross < inner_cross {
-            let remaining = inner_cross - total_cross;
+        if lines_total_cross < container_min_inner_cross {
+            let remaining = container_min_inner_cross - lines_total_cross;
             let addition = remaining / flex_lines.len() as f32;
             flex_lines.iter_mut().for_each(|line| line.cross_size += addition);
         }
@@ -1396,8 +1445,8 @@ fn determine_used_cross_size(tree: &mut impl LayoutTree, flex_lines: &mut [FlexL
             child.target_size.set_cross(
                 constants.dir,
                 if child.align_self == AlignSelf::Stretch
-                    && child_style.margin.cross_start(constants.dir) != LengthPercentageAuto::Auto
-                    && child_style.margin.cross_end(constants.dir) != LengthPercentageAuto::Auto
+                    && !child.margin_is_auto.cross_start(constants.dir)
+                    && !child.margin_is_auto.cross_end(constants.dir)
                     && child_style.size.cross(constants.dir) == Dimension::Auto
                 {
                     // For some reason this particular usage of max_width is an exception to the rule that max_width's transfer
@@ -1433,12 +1482,7 @@ fn determine_used_cross_size(tree: &mut impl LayoutTree, flex_lines: &mut [FlexL
 ///
 ///     2. Align the items along the main-axis per `justify-content`.
 #[inline]
-fn distribute_remaining_free_space(
-    tree: &mut impl LayoutTree,
-    flex_lines: &mut [FlexLine],
-    node: Node,
-    constants: &AlgoConstants,
-) {
+fn distribute_remaining_free_space(flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
     for line in flex_lines {
         let total_main_axis_gap = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len());
         let used_space: f32 = total_main_axis_gap
@@ -1447,11 +1491,10 @@ fn distribute_remaining_free_space(
         let mut num_auto_margins = 0;
 
         for child in line.items.iter_mut() {
-            let child_style = tree.style(child.node);
-            if child_style.margin.main_start(constants.dir) == LengthPercentageAuto::Auto {
+            if child.margin_is_auto.main_start(constants.dir) {
                 num_auto_margins += 1;
             }
-            if child_style.margin.main_end(constants.dir) == LengthPercentageAuto::Auto {
+            if child.margin_is_auto.main_end(constants.dir) {
                 num_auto_margins += 1;
             }
         }
@@ -1460,15 +1503,14 @@ fn distribute_remaining_free_space(
             let margin = free_space / num_auto_margins as f32;
 
             for child in line.items.iter_mut() {
-                let child_style = tree.style(child.node);
-                if child_style.margin.main_start(constants.dir) == LengthPercentageAuto::Auto {
+                if child.margin_is_auto.main_start(constants.dir) {
                     if constants.is_row {
                         child.margin.left = margin;
                     } else {
                         child.margin.top = margin;
                     }
                 }
-                if child_style.margin.main_end(constants.dir) == LengthPercentageAuto::Auto {
+                if child.margin_is_auto.main_end(constants.dir) {
                     if constants.is_row {
                         child.margin.right = margin;
                     } else {
@@ -1480,8 +1522,7 @@ fn distribute_remaining_free_space(
             let num_items = line.items.len();
             let layout_reverse = constants.dir.is_reverse();
             let gap = constants.gap.main(constants.dir);
-            let justify_content_mode: JustifyContent =
-                tree.style(node).justify_content.unwrap_or(JustifyContent::FlexStart);
+            let justify_content_mode = constants.justify_content.unwrap_or(JustifyContent::FlexStart);
 
             let justify_item = |(i, child): (usize, &mut FlexItem)| {
                 child.offset_main =
@@ -1510,18 +1551,15 @@ fn distribute_remaining_free_space(
 ///     - Otherwise, if the block-start or inline-start margin (whichever is in the cross axis) is auto, set it to zero.
 ///         Set the opposite margin so that the outer cross size of the item equals the cross size of its flex line.
 #[inline]
-fn resolve_cross_axis_auto_margins(tree: &mut impl LayoutTree, flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
+fn resolve_cross_axis_auto_margins(flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
     for line in flex_lines {
         let line_cross_size = line.cross_size;
         let max_baseline: f32 = line.items.iter_mut().map(|child| child.baseline).fold(0.0, |acc, x| acc.max(x));
 
         for child in line.items.iter_mut() {
             let free_space = line_cross_size - child.outer_target_size.cross(constants.dir);
-            let child_style = tree.style(child.node);
 
-            if child_style.margin.cross_start(constants.dir) == LengthPercentageAuto::Auto
-                && child_style.margin.cross_end(constants.dir) == LengthPercentageAuto::Auto
-            {
+            if child.margin_is_auto.cross_start(constants.dir) && child.margin_is_auto.cross_end(constants.dir) {
                 if constants.is_row {
                     child.margin.top = free_space / 2.0;
                     child.margin.bottom = free_space / 2.0;
@@ -1529,13 +1567,13 @@ fn resolve_cross_axis_auto_margins(tree: &mut impl LayoutTree, flex_lines: &mut
                     child.margin.left = free_space / 2.0;
                     child.margin.right = free_space / 2.0;
                 }
-            } else if child_style.margin.cross_start(constants.dir) == LengthPercentageAuto::Auto {
+            } else if child.margin_is_auto.cross_start(constants.dir) {
                 if constants.is_row {
                     child.margin.top = free_space;
                 } else {
                     child.margin.left = free_space;
                 }
-            } else if child_style.margin.cross_end(constants.dir) == LengthPercentageAuto::Auto {
+            } else if child.margin_is_auto.cross_end(constants.dir) {
                 if constants.is_row {
                     child.margin.bottom = free_space;
                 } else {
@@ -1622,17 +1660,18 @@ fn determine_container_cross_size(
     let total_cross_axis_gap = sum_axis_gaps(constants.gap.cross(constants.dir), flex_lines.len());
     let total_line_cross_size: f32 = flex_lines.iter().map(|line| line.cross_size).sum::<f32>();
 
-    constants.container_size.set_cross(
-        constants.dir,
-        node_size.cross(constants.dir).unwrap_or(
-            total_line_cross_size + total_cross_axis_gap + constants.padding_border.cross_axis_sum(constants.dir),
-        ),
-    );
+    let padding_border_sum = constants.padding_border.cross_axis_sum(constants.dir);
+    let min_cross_size = constants.min_size.cross(constants.dir);
+    let max_cross_size = constants.max_size.cross(constants.dir);
+    let outer_container_size = node_size
+        .cross(constants.dir)
+        .unwrap_or(total_line_cross_size + total_cross_axis_gap + padding_border_sum)
+        .maybe_clamp(min_cross_size, max_cross_size)
+        .max(padding_border_sum);
+    let inner_container_size = outer_container_size - padding_border_sum;
 
-    constants.inner_container_size.set_cross(
-        constants.dir,
-        constants.container_size.cross(constants.dir) - constants.padding_border.cross_axis_sum(constants.dir),
-    );
+    constants.container_size.set_cross(constants.dir, outer_container_size);
+    constants.inner_container_size.set_cross(constants.dir, inner_container_size);
 
     total_line_cross_size
 }
@@ -1643,16 +1682,10 @@ fn determine_container_cross_size(
 ///
 /// - [**Align all flex lines**](https://www.w3.org/TR/css-flexbox-1/#algo-line-align) per `align-content`.
 #[inline]
-fn align_flex_lines_per_align_content(
-    tree: &impl LayoutTree,
-    flex_lines: &mut [FlexLine],
-    node: Node,
-    constants: &AlgoConstants,
-    total_cross_size: f32,
-) {
+fn align_flex_lines_per_align_content(flex_lines: &mut [FlexLine], constants: &AlgoConstants, total_cross_size: f32) {
     let num_lines = flex_lines.len();
     let gap = constants.gap.cross(constants.dir);
-    let align_content_mode = tree.style(node).align_content.unwrap_or(AlignContent::Stretch);
+    let align_content_mode = constants.align_content;
     let total_cross_axis_gap = sum_axis_gaps(gap, num_lines);
     let free_space = constants.inner_container_size.cross(constants.dir) - total_cross_size - total_cross_axis_gap;
 
@@ -1824,8 +1857,11 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
         }
 
         let aspect_ratio = child_style.aspect_ratio;
-        let margin = child_style.margin.map(|margin| margin.resolve_to_option(container_width));
         let align_self = child_style.align_self.unwrap_or(constants.align_items);
+        let margin = child_style.margin.map(|margin| margin.resolve_to_option(container_width));
+        let padding = child_style.padding.resolve_or_zero(Some(container_width));
+        let border = child_style.border.resolve_or_zero(Some(container_width));
+        let padding_border_sum = (padding + border).sum_axes();
 
         // Resolve inset
         let left = child_style.inset.left.maybe_resolve(container_width);
@@ -1836,8 +1872,12 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
         // Compute known dimensions from min/max/inherent size styles
         let style_size =
             child_style.size.maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
-        let min_size =
-            child_style.min_size.maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
+        let min_size = child_style
+            .min_size
+            .maybe_resolve(constants.container_size)
+            .maybe_apply_aspect_ratio(aspect_ratio)
+            .or(padding_border_sum.map(Some))
+            .maybe_max(padding_border_sum);
         let max_size =
             child_style.max_size.maybe_resolve(constants.container_size).maybe_apply_aspect_ratio(aspect_ratio);
         let mut known_dimensions = style_size.maybe_clamp(min_size, max_size);
@@ -1928,7 +1968,7 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
         } else {
             // Stretch is an invalid value for justify_content in the flexbox algorithm, so we
             // treat it as if it wasn't set (and thus we default to FlexStart behaviour)
-            match (tree.style(node).justify_content.unwrap_or(JustifyContent::Start), constants.is_wrap_reverse) {
+            match (constants.justify_content.unwrap_or(JustifyContent::Start), constants.is_wrap_reverse) {
                 (JustifyContent::SpaceBetween, _)
                 | (JustifyContent::Start, _)
                 | (JustifyContent::Stretch, false)
diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs
index 0c0ed9f81..0b85fb792 100644
--- a/src/compute/grid/alignment.rs
+++ b/src/compute/grid/alignment.rs
@@ -7,7 +7,7 @@ use crate::geometry::{Line, Point, Rect, Size};
 use crate::layout::{Layout, SizingMode};
 use crate::math::MaybeMath;
 use crate::node::Node;
-use crate::resolve::MaybeResolve;
+use crate::resolve::{MaybeResolve, ResolveOrZero};
 use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Position};
 use crate::sys::{f32_max, f32_min};
 use crate::tree::LayoutTree;
@@ -90,8 +90,16 @@ pub(super) fn align_and_position_item(
     let position = style.position;
     let inset_horizontal = style.inset.horizontal_components().map(|size| size.resolve_to_option(grid_area_size.width));
     let inset_vertical = style.inset.vertical_components().map(|size| size.resolve_to_option(grid_area_size.height));
+    let padding = style.padding.map(|p| p.resolve_or_zero(Some(grid_area_size.width)));
+    let border = style.border.map(|p| p.resolve_or_zero(Some(grid_area_size.width)));
+    let padding_border_size = (padding + border).sum_axes();
     let inherent_size = style.size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
-    let min_size = style.min_size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
+    let min_size = style
+        .min_size
+        .maybe_resolve(grid_area_size)
+        .or(padding_border_size.map(Some))
+        .maybe_max(padding_border_size)
+        .maybe_apply_aspect_ratio(aspect_ratio);
     let max_size = style.max_size.maybe_resolve(grid_area_size).maybe_apply_aspect_ratio(aspect_ratio);
 
     // Resolve default alignment styles if they are set on neither the parent or the node itself
@@ -149,6 +157,7 @@ pub(super) fn align_and_position_item(
 
         None
     });
+
     // Reapply aspect ratio after stretch and absolute position width adjustments
     let Size { width, height } = Size { width, height: inherent_size.height }.maybe_apply_aspect_ratio(aspect_ratio);
 
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index 4e691eae5..09a91eb09 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -141,6 +141,7 @@ pub fn compute(
     // https://www.w3.org/TR/css-grid-1/#available-grid-space
     let padding = style.padding.resolve_or_zero(parent_size.width);
     let border = style.border.resolve_or_zero(parent_size.width);
+    let padding_border_size = (padding + border).sum_axes();
     let aspect_ratio = style.aspect_ratio;
     let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
     let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
@@ -236,10 +237,12 @@ pub fn compute(
     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()),
+            .unwrap_or_else(|| initial_column_sum + padding.horizontal_axis_sum() + border.horizontal_axis_sum())
+            .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()),
+            .unwrap_or_else(|| initial_row_sum + padding.vertical_axis_sum() + border.vertical_axis_sum())
+            .max(padding_border_size.height),
     };
     let container_content_box = Size {
         width: container_border_box.width - padding.horizontal_axis_sum() - border.horizontal_axis_sum(),
@@ -449,7 +452,7 @@ pub fn compute(
 
         // Position hidden child
         if child_style.display == Display::None {
-            *tree.layout_mut(node) = Layout::with_order(order);
+            *tree.layout_mut(child) = Layout::with_order(order);
             GenericAlgorithm::perform_layout(
                 tree,
                 child,
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index 2c347a64d..6f95145db 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -72,6 +72,12 @@ pub(crate) fn compute(
         }
     };
 
+    // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width).
+    // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values)
+    let padding = style.padding.resolve_or_zero(parent_size.width);
+    let border = style.border.resolve_or_zero(parent_size.width);
+    let padding_border = padding + border;
+
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("LEAF");
     #[cfg(feature = "debug")]
@@ -83,7 +89,9 @@ pub(crate) fn compute(
 
     // Return early if both width and height are known
     if let Size { width: Some(width), height: Some(height) } = node_size {
-        let size = Size { width, height }.maybe_clamp(node_min_size, node_max_size);
+        let size = Size { width, height }
+            .maybe_clamp(node_min_size, node_max_size)
+            .maybe_max(padding_border.sum_axes().map(Some));
         return SizeAndBaselines { size, first_baselines: Point::NONE };
     };
 
@@ -111,25 +119,29 @@ pub(crate) fn compute(
         };
 
         let size = node_size.unwrap_or(measured_size).maybe_clamp(node_min_size, node_max_size);
+        let size = size.maybe_max(padding_border.sum_axes().map(Some));
         return SizeAndBaselines { size, first_baselines: Point::NONE };
     }
 
-    // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width).
-    // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values)
-    let padding = style.padding.resolve_or_zero(parent_size.width);
-    let border = style.border.resolve_or_zero(parent_size.width);
-
     let size = Size {
         width: node_size
             .width
             // .unwrap_or(0.0) + padding.horizontal_axis_sum() + border.horizontal_axis_sum(), // content-box
-            .unwrap_or(0.0 + padding.horizontal_axis_sum() + border.horizontal_axis_sum()) // border-box
-            .maybe_clamp(node_min_size.width, node_max_size.width),
+            .unwrap_or(0.0) // border-box
+            .maybe_clamp(node_min_size.width, node_max_size.width)
+            .maybe_max(padding_border.horizontal_axis_sum().into()),
         height: node_size
             .height
             // .unwrap_or(0.0) + padding.vertical_axis_sum() + border.vertical_axis_sum(), // content-box
-            .unwrap_or(0.0 + padding.vertical_axis_sum() + border.vertical_axis_sum()) // border-box
-            .maybe_clamp(node_min_size.height, node_max_size.height),
+            .unwrap_or(0.0) // border-box
+            .maybe_clamp(node_min_size.height, node_max_size.height)
+            .maybe_max(padding_border.vertical_axis_sum().into()),
     };
+
+    let size = Size {
+        width: f32_max(size.width, aspect_ratio.map(|ratio| size.height * ratio).unwrap_or(0.0)),
+        height: f32_max(size.height, aspect_ratio.map(|ratio| size.width / ratio).unwrap_or(0.0)),
+    };
+
     SizeAndBaselines { size, first_baselines: Point::NONE }
 }
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 50280f474..35fc1b9b0 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -137,7 +137,7 @@ fn compute_node_layout(
     // First we check if we have a cached result for the given input
     let cache_run_mode = if tree.is_childless(node) { RunMode::PeformLayout } else { run_mode };
     if let Some(cached_size_and_baselines) =
-        compute_from_cache(tree, node, known_dimensions, available_space, cache_run_mode, sizing_mode)
+        compute_from_cache(tree, node, known_dimensions, available_space, cache_run_mode)
     {
         #[cfg(feature = "debug")]
         NODE_LOGGER.labelled_debug_log("CACHE", cached_size_and_baselines.size);
@@ -247,6 +247,7 @@ fn debug_log_node(
     NODE_LOGGER.debug_log(run_mode);
     NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
     NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
+    NODE_LOGGER.labelled_debug_log("parent_size", parent_size);
     NODE_LOGGER.labelled_debug_log("available_space", available_space);
 }
 
@@ -307,7 +308,6 @@ fn compute_from_cache(
     known_dimensions: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
     run_mode: RunMode,
-    sizing_mode: SizingMode,
 ) -> Option<SizeAndBaselines> {
     for idx in 0..CACHE_SIZE {
         let entry = tree.cache_mut(node, idx);
@@ -324,15 +324,9 @@ fn compute_from_cache(
                 && (known_dimensions.height == entry.known_dimensions.height
                     || known_dimensions.height == Some(cached_size.height))
                 && (known_dimensions.width.is_some()
-                    || entry.available_space.width.is_roughly_equal(available_space.width)
-                    || (sizing_mode == SizingMode::ContentSize
-                        && available_space.width.is_definite()
-                        && available_space.width.unwrap() >= cached_size.width))
+                    || entry.available_space.width.is_roughly_equal(available_space.width))
                 && (known_dimensions.height.is_some()
-                    || entry.available_space.height.is_roughly_equal(available_space.height)
-                    || (sizing_mode == SizingMode::ContentSize
-                        && available_space.height.is_definite()
-                        && available_space.height.unwrap() >= cached_size.height))
+                    || entry.available_space.height.is_roughly_equal(available_space.height))
             {
                 return Some(entry.cached_size_and_baselines);
             }
diff --git a/src/geometry.rs b/src/geometry.rs
index 3db779ed1..3f96d3d85 100644
--- a/src/geometry.rs
+++ b/src/geometry.rs
@@ -320,6 +320,33 @@ impl<T> Size<T> {
         }
     }
 
+    /// Creates a new value of type Self with the main axis set to value provided
+    ///
+    /// Whether this is the width or height depends on the `direction` provided
+    #[allow(dead_code)]
+    pub(crate) fn with_main(self, direction: FlexDirection, value: T) -> Self {
+        let mut new = self;
+        if direction.is_row() {
+            new.width = value
+        } else {
+            new.height = value
+        }
+        new
+    }
+
+    /// Creates a new value of type Self with the cross axis set to value provided
+    ///
+    /// Whether this is the width or height depends on the `direction` provided
+    pub(crate) fn with_cross(self, direction: FlexDirection, value: T) -> Self {
+        let mut new = self;
+        if direction.is_row() {
+            new.height = value
+        } else {
+            new.width = value
+        }
+        new
+    }
+
     /// Gets the extent of the main layout axis
     ///
     /// Whether this is the width or height depends on the `direction` provided
diff --git a/src/style/dimension.rs b/src/style/dimension.rs
index 21e3d7f1c..d4caade8e 100644
--- a/src/style/dimension.rs
+++ b/src/style/dimension.rs
@@ -135,11 +135,6 @@ impl From<LengthPercentageAuto> for Dimension {
 }
 
 impl Dimension {
-    /// Is this value defined?
-    pub(crate) fn is_defined(self) -> bool {
-        matches!(self, Dimension::Points(_) | Dimension::Percent(_))
-    }
-
     /// Get Points value if value is Points variant
     #[cfg(feature = "grid")]
     pub fn into_option(self) -> Option<f32> {
diff --git a/src/style/grid.rs b/src/style/grid.rs
index 1053f74ff..63ec1d284 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -314,7 +314,7 @@ impl MaxTrackSizingFunction {
     /// will if the available_space is `Some`). Otherwise returns None.
     #[inline(always)]
     pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
-        use MaxTrackSizingFunction::{Auto, *};
+        use MaxTrackSizingFunction::*;
         match self {
             Fixed(LengthPercentage::Points(size)) => Some(size),
             Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
@@ -342,7 +342,7 @@ impl MaxTrackSizingFunction {
     /// Non-percentage values always return None.
     #[inline(always)]
     pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
-        use MaxTrackSizingFunction::{Auto, *};
+        use MaxTrackSizingFunction::*;
         match self {
             Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
             Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | FitContent(_) | Auto | Fraction(_) => None,
@@ -409,7 +409,7 @@ impl MinTrackSizingFunction {
     /// will if the available_space is `Some`). Otherwise returns `None`.
     #[inline(always)]
     pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
-        use MinTrackSizingFunction::{Auto, *};
+        use MinTrackSizingFunction::*;
         match self {
             Fixed(LengthPercentage::Points(size)) => Some(size),
             Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
@@ -421,7 +421,7 @@ impl MinTrackSizingFunction {
     /// Non-percentage values always return None.
     #[inline(always)]
     pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
-        use MinTrackSizingFunction::{Auto, *};
+        use MinTrackSizingFunction::*;
         match self {
             Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
             Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | Auto => None,
diff --git a/test_fixtures/absolute_padding_border_overrides_max_size.html b/test_fixtures/absolute_padding_border_overrides_max_size.html
new file mode 100644
index 000000000..04f16a34a
--- /dev/null
+++ b/test_fixtures/absolute_padding_border_overrides_max_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="position:absolute;max-width: 12px; max-height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/absolute_padding_border_overrides_size.html b/test_fixtures/absolute_padding_border_overrides_size.html
new file mode 100644
index 000000000..6cbc088af
--- /dev/null
+++ b/test_fixtures/absolute_padding_border_overrides_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="position:absolute;width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_7976_3_level.html b/test_fixtures/bevy_issue_7976_3_level.html
new file mode 100644
index 000000000..50f3617b4
--- /dev/null
+++ b/test_fixtures/bevy_issue_7976_3_level.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="width: 200px; height: 200px; align-content: start">
+  <div style="min-width: 40px;min-height:40px;margin:5px;padding:5px;background-color:red">
+    <div style="width:100%;height:100%;padding:5px;background-color:green"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_7976_4_level.html b/test_fixtures/bevy_issue_7976_4_level.html
new file mode 100644
index 000000000..80497279b
--- /dev/null
+++ b/test_fixtures/bevy_issue_7976_4_level.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="width: 200px; height: 200px; align-content: start">
+  <div style="min-width: 40px;min-height:40px;margin:5px;padding:5px;background-color:red">
+    <div style="width:100%;height:100%;padding:5px;background-color:green">
+      <div></div>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_7976_reduced.html b/test_fixtures/bevy_issue_7976_reduced.html
new file mode 100644
index 000000000..85d9c37ac
--- /dev/null
+++ b/test_fixtures/bevy_issue_7976_reduced.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="height:200px;align-content: start">
+    <div style="width:40px;"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_8017.html b/test_fixtures/bevy_issue_8017.html
new file mode 100644
index 000000000..9d38263da
--- /dev/null
+++ b/test_fixtures/bevy_issue_8017.html
@@ -0,0 +1,24 @@
+<!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>
+    Bevy #8017
+</title>
+</head>
+<body>
+
+<div id="test-root" style="display: flex; flex-direction: column; gap: 8px;width: 400px;height:400px;padding: 8px;">
+  <div style="display: flex; gap: 8px; width: 100%; height: 50%;">
+      <div style="width: 100%; height: 100%;"></div>
+      <div style="width: 100%; height: 100%;"></div>
+  </div>
+  <div style="display: flex; gap: 8px; width: 100%; height: 50%;">
+      <div style="width: 100%; height: 100%;"></div>
+      <div style="width: 100%; height: 100%;"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_8017_reduced.html b/test_fixtures/bevy_issue_8017_reduced.html
new file mode 100644
index 000000000..fe6362222
--- /dev/null
+++ b/test_fixtures/bevy_issue_8017_reduced.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>
+    Bevy #8017
+</title>
+</head>
+<body>
+
+<div id="test-root" style="flex-direction: column;width: 200px;height:400px;gap: 8px;">
+  <div style="height: 50%;">
+      <div></div>
+  </div>
+  <div style="height: 50%;">
+      <div></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_8082.html b/test_fixtures/bevy_issue_8082.html
new file mode 100644
index 000000000..bd7c9d5ef
--- /dev/null
+++ b/test_fixtures/bevy_issue_8082.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="width: 200px; height: 400px; align-content: center;justify-content: flex-start;align-items:stretch;flex-direction: column;">
+  <div style="flex-wrap: wrap;align-items:flex-start;align-content:center;justify-content: center;">
+    <div style="width: 50px; height: 50px;margin: 10px"></div>
+    <div style="width: 50px; height: 50px;margin: 10px"></div>
+    <div style="width: 50px; height: 50px;margin: 10px"></div>
+    <div style="width: 50px; height: 50px;margin: 10px"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/bevy_issue_8082_percent.html b/test_fixtures/bevy_issue_8082_percent.html
new file mode 100644
index 000000000..ca81dbeeb
--- /dev/null
+++ b/test_fixtures/bevy_issue_8082_percent.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="width: 200px; height: 400px; align-content: center;justify-content: flex-start;align-items:stretch;flex-direction: column;">
+  <div style="flex-wrap: wrap;align-items:flex-start;align-content:center;justify-content: center;width: 50%">
+    <div style="width: 50px; height: 50px"></div>
+    <div style="width: 50px; height: 50px"></div>
+    <div style="width: 50px; height: 50px"></div>
+    <div style="width: 50px; height: 50px"></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/flex_grow_within_constrained_min_max_column.html b/test_fixtures/flex_grow_within_constrained_min_max_column.html
index 51c19d853..9cb289f1c 100644
--- a/test_fixtures/flex_grow_within_constrained_min_max_column.html
+++ b/test_fixtures/flex_grow_within_constrained_min_max_column.html
@@ -9,7 +9,7 @@
 <head/>
 <body>
 
-<div id="test-root" style="min-height: 100px; max-height: 200px flex-direction: column;">
+<div id="test-root" style="min-height: 100px; max-height: 200px; flex-direction: column;">
   <div style="flex-grow:1;"></div>
   <div style="height: 50px;"></div>
 </div>
diff --git a/test_fixtures/grid_padding_border_overrides_container_max_size.html b/test_fixtures/grid_padding_border_overrides_container_max_size.html
new file mode 100644
index 000000000..a58489fca
--- /dev/null
+++ b/test_fixtures/grid_padding_border_overrides_container_max_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display: grid;max-width: 12px; max-height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red">
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_padding_border_overrides_container_size.html b/test_fixtures/grid_padding_border_overrides_container_size.html
new file mode 100644
index 000000000..a5cab4eed
--- /dev/null
+++ b/test_fixtures/grid_padding_border_overrides_container_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display: grid;width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red solid red">
+  <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_padding_border_overrides_max_size.html b/test_fixtures/grid_padding_border_overrides_max_size.html
new file mode 100644
index 000000000..41ec1e05d
--- /dev/null
+++ b/test_fixtures/grid_padding_border_overrides_max_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display:grid">
+  <div style="max-width: 12px; max-height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_padding_border_overrides_min_size.html b/test_fixtures/grid_padding_border_overrides_min_size.html
new file mode 100644
index 000000000..629e26a33
--- /dev/null
+++ b/test_fixtures/grid_padding_border_overrides_min_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display: grid">
+  <div style="min-width: 0px; min-height: 0px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_padding_border_overrides_size.html b/test_fixtures/grid_padding_border_overrides_size.html
new file mode 100644
index 000000000..4612b1b38
--- /dev/null
+++ b/test_fixtures/grid_padding_border_overrides_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="display: grid">
+  <div style="width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/leaf_padding_border_overrides_max_size.html b/test_fixtures/leaf_padding_border_overrides_max_size.html
new file mode 100644
index 000000000..99f440a8b
--- /dev/null
+++ b/test_fixtures/leaf_padding_border_overrides_max_size.html
@@ -0,0 +1,15 @@
+<!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="max-width: 12px; max-height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/leaf_padding_border_overrides_min_size.html b/test_fixtures/leaf_padding_border_overrides_min_size.html
new file mode 100644
index 000000000..0482e8258
--- /dev/null
+++ b/test_fixtures/leaf_padding_border_overrides_min_size.html
@@ -0,0 +1,15 @@
+<!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="min-width: 0px; min-height: 0px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/leaf_padding_border_overrides_size.html b/test_fixtures/leaf_padding_border_overrides_size.html
new file mode 100644
index 000000000..8aa54d19e
--- /dev/null
+++ b/test_fixtures/leaf_padding_border_overrides_size.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root" style="width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/measure_child_with_min_size_greater_than_available_space.html b/test_fixtures/measure_child_with_min_size_greater_than_available_space.html
new file mode 100644
index 000000000..3e46330f0
--- /dev/null
+++ b/test_fixtures/measure_child_with_min_size_greater_than_available_space.html
@@ -0,0 +1,14 @@
+<!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: flex; flex-direction: column; width: 100px;">
+  <div style="min-width: 200px;">HHHHHHHH&ZeroWidthSpace;HHHHHHHH</div>
+</div>
diff --git a/test_fixtures/padding_border_overrides_max_size.html b/test_fixtures/padding_border_overrides_max_size.html
new file mode 100644
index 000000000..6d0bf7cf1
--- /dev/null
+++ b/test_fixtures/padding_border_overrides_max_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="max-width: 12px; max-height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/padding_border_overrides_min_size.html b/test_fixtures/padding_border_overrides_min_size.html
new file mode 100644
index 000000000..d8223127a
--- /dev/null
+++ b/test_fixtures/padding_border_overrides_min_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="min-width: 0px; min-height: 0px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/padding_border_overrides_size.html b/test_fixtures/padding_border_overrides_size.html
new file mode 100644
index 000000000..7b2ed62d2
--- /dev/null
+++ b/test_fixtures/padding_border_overrides_size.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/padding_border_overrides_size_flex_basis_0.html b/test_fixtures/padding_border_overrides_size_flex_basis_0.html
new file mode 100644
index 000000000..d51e820ce
--- /dev/null
+++ b/test_fixtures/padding_border_overrides_size_flex_basis_0.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="flex-basis: 0;width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+  <div style="flex-basis: 0;width: 12px; height: 12px"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/padding_border_overrides_size_flex_basis_0_growable.html b/test_fixtures/padding_border_overrides_size_flex_basis_0_growable.html
new file mode 100644
index 000000000..0b2ff0552
--- /dev/null
+++ b/test_fixtures/padding_border_overrides_size_flex_basis_0_growable.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+<head/>
+<body>
+
+<div id="test-root">
+  <div style="flex-basis: 0;flex-grow: 1;width: 12px; height: 12px;padding:2px 4px 6px 8px;border-width: 1px 3px 5px 7px;border-style:solid;border-color:red"></div>
+  <div style="flex-basis: 0;flex-grow: 1;width: 12px; height: 12px"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/percentage_sizes_should_not_prevent_flex_shrinking.html b/test_fixtures/percentage_sizes_should_not_prevent_flex_shrinking.html
new file mode 100644
index 000000000..d1bcfe8f4
--- /dev/null
+++ b/test_fixtures/percentage_sizes_should_not_prevent_flex_shrinking.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<script src="../scripts/gentest/test_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+<title>
+    Bevy #8017
+</title>
+</head>
+<body>
+
+<div id="test-root" style="width: 200px;height:200px">
+  <div style="width: 120%;">
+      <div></div>
+  </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/border_and_padding.rs b/tests/border_and_padding.rs
index 26cfd1a1f..17a51914f 100644
--- a/tests/border_and_padding.rs
+++ b/tests/border_and_padding.rs
@@ -6,6 +6,7 @@ fn arr_to_rect<T: Copy>(items: [T; 4]) -> Rect<T> {
 }
 
 #[test]
+#[ignore]
 fn border_on_a_single_axis_doesnt_increase_size() {
     for i in 0..4 {
         let mut taffy = Taffy::new();
@@ -33,6 +34,7 @@ fn border_on_a_single_axis_doesnt_increase_size() {
 }
 
 #[test]
+#[ignore]
 fn padding_on_a_single_axis_doesnt_increase_size() {
     for i in 0..4 {
         let mut taffy = Taffy::new();
@@ -60,6 +62,7 @@ fn padding_on_a_single_axis_doesnt_increase_size() {
 }
 
 #[test]
+#[ignore]
 fn border_and_padding_on_a_single_axis_doesnt_increase_size() {
     for i in 0..4 {
         let mut taffy = Taffy::new();
@@ -82,6 +85,7 @@ fn border_and_padding_on_a_single_axis_doesnt_increase_size() {
 }
 
 #[test]
+#[ignore]
 fn vertical_border_and_padding_percentage_values_use_available_space_correctly() {
     let mut taffy = Taffy::new();
 
diff --git a/tests/caching.rs b/tests/caching.rs
index 37eff95e2..581ce43e9 100644
--- a/tests/caching.rs
+++ b/tests/caching.rs
@@ -10,7 +10,7 @@ mod caching {
         let mut taffy = Taffy::new();
         static NUM_MEASURES: AtomicU32 = AtomicU32::new(0);
 
-        let grandchild = taffy
+        let leaf = taffy
             .new_leaf_with_measure(
                 Style { ..Default::default() },
                 MeasureFunc::Raw(|known_dimensions, _available_space| {
@@ -23,12 +23,14 @@ mod caching {
             )
             .unwrap();
 
-        let child = taffy.new_with_children(Style::DEFAULT, &[grandchild]).unwrap();
+        let mut node = taffy.new_with_children(Style::DEFAULT, &[leaf]).unwrap();
+        for _ in 0..100 {
+            node = taffy.new_with_children(Style::DEFAULT, &[node]).unwrap();
+        }
 
-        let node = taffy.new_with_children(Style::DEFAULT, &[child]).unwrap();
         taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
 
-        assert_eq!(NUM_MEASURES.load(Ordering::SeqCst), 2);
+        assert_eq!(NUM_MEASURES.load(Ordering::SeqCst), 8);
     }
 
     #[test]
@@ -41,7 +43,7 @@ mod caching {
         let mut taffy = Taffy::new();
         static NUM_MEASURES: AtomicU32 = AtomicU32::new(0);
 
-        let grandchild = taffy
+        let leaf = taffy
             .new_leaf_with_measure(
                 style(),
                 MeasureFunc::Raw(|known_dimensions, _available_space| {
@@ -54,11 +56,12 @@ mod caching {
             )
             .unwrap();
 
-        let child = taffy.new_with_children(style(), &[grandchild]).unwrap();
-
-        let node = taffy.new_with_children(style(), &[child]).unwrap();
+        let mut node = taffy.new_with_children(Style::DEFAULT, &[leaf]).unwrap();
+        for _ in 0..100 {
+            node = taffy.new_with_children(Style::DEFAULT, &[node]).unwrap();
+        }
 
         taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
-        assert_eq!(NUM_MEASURES.load(Ordering::SeqCst), 2);
+        assert_eq!(NUM_MEASURES.load(Ordering::SeqCst), 8);
     }
 }
diff --git a/tests/generated/absolute_padding_border_overrides_max_size.rs b/tests/generated/absolute_padding_border_overrides_max_size.rs
new file mode 100644
index 000000000..b90bda2da
--- /dev/null
+++ b/tests/generated/absolute_padding_border_overrides_max_size.rs
@@ -0,0 +1,44 @@
+#[test]
+fn absolute_padding_border_overrides_max_size() {
+    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 {
+            position: taffy::style::Position::Absolute,
+            max_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/absolute_padding_border_overrides_size.rs b/tests/generated/absolute_padding_border_overrides_size.rs
new file mode 100644
index 000000000..f4303f2d8
--- /dev/null
+++ b/tests/generated/absolute_padding_border_overrides_size.rs
@@ -0,0 +1,44 @@
+#[test]
+fn absolute_padding_border_overrides_size() {
+    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 {
+            position: taffy::style::Position::Absolute,
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/bevy_issue_7976_3_level.rs b/tests/generated/bevy_issue_7976_3_level.rs
new file mode 100644
index 000000000..ef9771efe
--- /dev/null
+++ b/tests/generated/bevy_issue_7976_3_level.rs
@@ -0,0 +1,78 @@
+#[test]
+fn bevy_issue_7976_3_level() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Percent(1f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(5f32),
+                right: taffy::style::LengthPercentage::Points(5f32),
+                top: taffy::style::LengthPercentage::Points(5f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                min_size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(40f32),
+                    height: taffy::style::Dimension::Points(40f32),
+                },
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Points(5f32),
+                    right: taffy::style::LengthPercentageAuto::Points(5f32),
+                    top: taffy::style::LengthPercentageAuto::Points(5f32),
+                    bottom: taffy::style::LengthPercentageAuto::Points(5f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(5f32),
+                    right: taffy::style::LengthPercentage::Points(5f32),
+                    top: taffy::style::LengthPercentage::Points(5f32),
+                    bottom: taffy::style::LengthPercentage::Points(5f32),
+                },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_content: Some(taffy::style::AlignContent::Start),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(200f32),
+                    height: taffy::style::Dimension::Points(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 200f32, 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, 190f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 190f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 5f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 30f32, size.width);
+    assert_eq!(size.height, 180f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 180f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 5f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_7976_4_level.rs b/tests/generated/bevy_issue_7976_4_level.rs
new file mode 100644
index 000000000..c6f2a03c4
--- /dev/null
+++ b/tests/generated/bevy_issue_7976_4_level.rs
@@ -0,0 +1,87 @@
+#[test]
+fn bevy_issue_7976_4_level() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node000 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node00 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Percent(1f32),
+                    height: taffy::style::Dimension::Percent(1f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(5f32),
+                    right: taffy::style::LengthPercentage::Points(5f32),
+                    top: taffy::style::LengthPercentage::Points(5f32),
+                    bottom: taffy::style::LengthPercentage::Points(5f32),
+                },
+                ..Default::default()
+            },
+            &[node000],
+        )
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                min_size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(40f32),
+                    height: taffy::style::Dimension::Points(40f32),
+                },
+                margin: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentageAuto::Points(5f32),
+                    right: taffy::style::LengthPercentageAuto::Points(5f32),
+                    top: taffy::style::LengthPercentageAuto::Points(5f32),
+                    bottom: taffy::style::LengthPercentageAuto::Points(5f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(5f32),
+                    right: taffy::style::LengthPercentage::Points(5f32),
+                    top: taffy::style::LengthPercentage::Points(5f32),
+                    bottom: taffy::style::LengthPercentage::Points(5f32),
+                },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_content: Some(taffy::style::AlignContent::Start),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(200f32),
+                    height: taffy::style::Dimension::Points(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 200f32, 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, 190f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 190f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 5f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 30f32, size.width);
+    assert_eq!(size.height, 180f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 180f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 5f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node000).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node000.data(), 0f32, size.width);
+    assert_eq!(size.height, 170f32, "height of node {:?}. Expected {}. Actual {}", node000.data(), 170f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node000.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node000.data(), 5f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_7976_reduced.rs b/tests/generated/bevy_issue_7976_reduced.rs
new file mode 100644
index 000000000..10ea0ddcd
--- /dev/null
+++ b/tests/generated/bevy_issue_7976_reduced.rs
@@ -0,0 +1,37 @@
+#[test]
+fn bevy_issue_7976_reduced() {
+    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 {
+            size: taffy::geometry::Size { width: taffy::style::Dimension::Points(40f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_content: Some(taffy::style::AlignContent::Start),
+                size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Points(200f32) },
+                ..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, 200f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 200f32, 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, 200f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, 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);
+}
diff --git a/tests/generated/bevy_issue_8017.rs b/tests/generated/bevy_issue_8017.rs
new file mode 100644
index 000000000..bc0e48010
--- /dev/null
+++ b/tests/generated/bevy_issue_8017.rs
@@ -0,0 +1,140 @@
+#[test]
+fn bevy_issue_8017() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Percent(1f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Percent(1f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Flex,
+                gap: taffy::geometry::Size {
+                    width: taffy::style::LengthPercentage::Points(8f32),
+                    height: taffy::style::LengthPercentage::Points(8f32),
+                },
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Percent(1f32),
+                    height: taffy::style::Dimension::Percent(0.5f32),
+                },
+                ..Default::default()
+            },
+            &[node00, node01],
+        )
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Percent(1f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node11 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Percent(1f32),
+                height: taffy::style::Dimension::Percent(1f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Flex,
+                gap: taffy::geometry::Size {
+                    width: taffy::style::LengthPercentage::Points(8f32),
+                    height: taffy::style::LengthPercentage::Points(8f32),
+                },
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Percent(1f32),
+                    height: taffy::style::Dimension::Percent(0.5f32),
+                },
+                ..Default::default()
+            },
+            &[node10, node11],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Flex,
+                flex_direction: taffy::style::FlexDirection::Column,
+                gap: taffy::geometry::Size {
+                    width: taffy::style::LengthPercentage::Points(8f32),
+                    height: taffy::style::LengthPercentage::Points(8f32),
+                },
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(400f32),
+                    height: taffy::style::Dimension::Points(400f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(8f32),
+                    right: taffy::style::LengthPercentage::Points(8f32),
+                    top: taffy::style::LengthPercentage::Points(8f32),
+                    bottom: taffy::style::LengthPercentage::Points(8f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .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, 400f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 400f32, size.width);
+    assert_eq!(size.height, 400f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 400f32, 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, 384f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 384f32, size.width);
+    assert_eq!(size.height, 188f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 188f32, size.height);
+    assert_eq!(location.x, 8f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 8f32, location.x);
+    assert_eq!(location.y, 8f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 8f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 188f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 188f32, size.width);
+    assert_eq!(size.height, 188f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 188f32, 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, 188f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 188f32, size.width);
+    assert_eq!(size.height, 188f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 188f32, size.height);
+    assert_eq!(location.x, 196f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 196f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 384f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 384f32, size.width);
+    assert_eq!(size.height, 188f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 188f32, size.height);
+    assert_eq!(location.x, 8f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 8f32, location.x);
+    assert_eq!(location.y, 204f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 204f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 188f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 188f32, size.width);
+    assert_eq!(size.height, 188f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 188f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node10.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node10.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node11).unwrap();
+    assert_eq!(size.width, 188f32, "width of node {:?}. Expected {}. Actual {}", node11.data(), 188f32, size.width);
+    assert_eq!(size.height, 188f32, "height of node {:?}. Expected {}. Actual {}", node11.data(), 188f32, size.height);
+    assert_eq!(location.x, 196f32, "x of node {:?}. Expected {}. Actual {}", node11.data(), 196f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node11.data(), 0f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_8017_reduced.rs b/tests/generated/bevy_issue_8017_reduced.rs
new file mode 100644
index 000000000..309acb7a5
--- /dev/null
+++ b/tests/generated/bevy_issue_8017_reduced.rs
@@ -0,0 +1,73 @@
+#[test]
+fn bevy_issue_8017_reduced() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Percent(0.5f32) },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node10 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Percent(0.5f32) },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                gap: taffy::geometry::Size {
+                    width: taffy::style::LengthPercentage::Points(8f32),
+                    height: taffy::style::LengthPercentage::Points(8f32),
+                },
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(200f32),
+                    height: taffy::style::Dimension::Points(400f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 400f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 400f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, size.width);
+    assert_eq!(size.height, 196f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 196f32, 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, 0f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, size.width);
+    assert_eq!(size.height, 196f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 196f32, 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(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 200f32, size.width);
+    assert_eq!(size.height, 196f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 196f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.x);
+    assert_eq!(location.y, 204f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 204f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 0f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 0f32, size.width);
+    assert_eq!(size.height, 196f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 196f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node10.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node10.data(), 0f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_8082.rs b/tests/generated/bevy_issue_8082.rs
new file mode 100644
index 000000000..cefd7548f
--- /dev/null
+++ b/tests/generated/bevy_issue_8082.rs
@@ -0,0 +1,129 @@
+#[test]
+fn bevy_issue_8082() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Points(10f32),
+                right: taffy::style::LengthPercentageAuto::Points(10f32),
+                top: taffy::style::LengthPercentageAuto::Points(10f32),
+                bottom: taffy::style::LengthPercentageAuto::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Points(10f32),
+                right: taffy::style::LengthPercentageAuto::Points(10f32),
+                top: taffy::style::LengthPercentageAuto::Points(10f32),
+                bottom: taffy::style::LengthPercentageAuto::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node02 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Points(10f32),
+                right: taffy::style::LengthPercentageAuto::Points(10f32),
+                top: taffy::style::LengthPercentageAuto::Points(10f32),
+                bottom: taffy::style::LengthPercentageAuto::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node03 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Points(10f32),
+                right: taffy::style::LengthPercentageAuto::Points(10f32),
+                top: taffy::style::LengthPercentageAuto::Points(10f32),
+                bottom: taffy::style::LengthPercentageAuto::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                align_items: Some(taffy::style::AlignItems::FlexStart),
+                align_content: Some(taffy::style::AlignContent::Center),
+                justify_content: Some(taffy::style::JustifyContent::Center),
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                align_items: Some(taffy::style::AlignItems::Stretch),
+                align_content: Some(taffy::style::AlignContent::Center),
+                justify_content: Some(taffy::style::JustifyContent::FlexStart),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(200f32),
+                    height: taffy::style::Dimension::Points(400f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 400f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 400f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, size.width);
+    assert_eq!(size.height, 140f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 140f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 50f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 40f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 10f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, size.height);
+    assert_eq!(location.x, 110f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 110f32, location.x);
+    assert_eq!(location.y, 10f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 10f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node02).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node02.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node02.data(), 50f32, size.height);
+    assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node02.data(), 40f32, location.x);
+    assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node02.data(), 80f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node03).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node03.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node03.data(), 50f32, size.height);
+    assert_eq!(location.x, 110f32, "x of node {:?}. Expected {}. Actual {}", node03.data(), 110f32, location.x);
+    assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node03.data(), 80f32, location.y);
+}
diff --git a/tests/generated/bevy_issue_8082_percent.rs b/tests/generated/bevy_issue_8082_percent.rs
new file mode 100644
index 000000000..a18290a1a
--- /dev/null
+++ b/tests/generated/bevy_issue_8082_percent.rs
@@ -0,0 +1,106 @@
+#[test]
+fn bevy_issue_8082_percent() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node01 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node02 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node03 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                align_items: Some(taffy::style::AlignItems::FlexStart),
+                align_content: Some(taffy::style::AlignContent::Center),
+                justify_content: Some(taffy::style::JustifyContent::Center),
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00, node01, node02, node03],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                align_items: Some(taffy::style::AlignItems::Stretch),
+                align_content: Some(taffy::style::AlignContent::Center),
+                justify_content: Some(taffy::style::JustifyContent::FlexStart),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(200f32),
+                    height: taffy::style::Dimension::Points(400f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 400f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 400f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 50f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node02).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node02.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node02.data(), 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node02.data(), 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node02.data(), 50f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node03).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node03.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node03.data(), 50f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node03.data(), 50f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node03.data(), 50f32, location.y);
+}
diff --git a/tests/generated/flex_grow_within_constrained_min_max_column.rs b/tests/generated/flex_grow_within_constrained_min_max_column.rs
index c83aafc73..8e0fb2fb9 100644
--- a/tests/generated/flex_grow_within_constrained_min_max_column.rs
+++ b/tests/generated/flex_grow_within_constrained_min_max_column.rs
@@ -14,7 +14,9 @@ fn flex_grow_within_constrained_min_max_column() {
     let node = taffy
         .new_with_children(
             taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
                 min_size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Points(100f32) },
+                max_size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Points(200f32) },
                 ..Default::default()
             },
             &[node0, node1],
@@ -31,12 +33,12 @@ fn flex_grow_within_constrained_min_max_column() {
     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, 100f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.height);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, 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, 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);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.y);
 }
diff --git a/tests/generated/grid_padding_border_overrides_container_max_size.rs b/tests/generated/grid_padding_border_overrides_container_max_size.rs
new file mode 100644
index 000000000..62ae9ebbe
--- /dev/null
+++ b/tests/generated/grid_padding_border_overrides_container_max_size.rs
@@ -0,0 +1,47 @@
+#[test]
+fn grid_padding_border_overrides_container_max_size() {
+    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 node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                max_size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(12f32),
+                    height: taffy::style::Dimension::Points(12f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(8f32),
+                    right: taffy::style::LengthPercentage::Points(4f32),
+                    top: taffy::style::LengthPercentage::Points(2f32),
+                    bottom: taffy::style::LengthPercentage::Points(6f32),
+                },
+                border: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(7f32),
+                    right: taffy::style::LengthPercentage::Points(3f32),
+                    top: taffy::style::LengthPercentage::Points(1f32),
+                    bottom: taffy::style::LengthPercentage::Points(5f32),
+                },
+                ..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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 15f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 15f32, location.x);
+    assert_eq!(location.y, 3f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 3f32, location.y);
+}
diff --git a/tests/generated/grid_padding_border_overrides_container_size.rs b/tests/generated/grid_padding_border_overrides_container_size.rs
new file mode 100644
index 000000000..f60ea6885
--- /dev/null
+++ b/tests/generated/grid_padding_border_overrides_container_size.rs
@@ -0,0 +1,47 @@
+#[test]
+fn grid_padding_border_overrides_container_size() {
+    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 node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Grid,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(12f32),
+                    height: taffy::style::Dimension::Points(12f32),
+                },
+                padding: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(8f32),
+                    right: taffy::style::LengthPercentage::Points(4f32),
+                    top: taffy::style::LengthPercentage::Points(2f32),
+                    bottom: taffy::style::LengthPercentage::Points(6f32),
+                },
+                border: taffy::geometry::Rect {
+                    left: taffy::style::LengthPercentage::Points(7f32),
+                    right: taffy::style::LengthPercentage::Points(3f32),
+                    top: taffy::style::LengthPercentage::Points(1f32),
+                    bottom: taffy::style::LengthPercentage::Points(5f32),
+                },
+                ..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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 15f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 15f32, location.x);
+    assert_eq!(location.y, 3f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 3f32, location.y);
+}
diff --git a/tests/generated/grid_padding_border_overrides_max_size.rs b/tests/generated/grid_padding_border_overrides_max_size.rs
new file mode 100644
index 000000000..2a874008c
--- /dev/null
+++ b/tests/generated/grid_padding_border_overrides_max_size.rs
@@ -0,0 +1,45 @@
+#[test]
+fn grid_padding_border_overrides_max_size() {
+    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 {
+            max_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(taffy::style::Style { display: taffy::style::Display::Grid, ..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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/grid_padding_border_overrides_min_size.rs b/tests/generated/grid_padding_border_overrides_min_size.rs
new file mode 100644
index 000000000..16ca50031
--- /dev/null
+++ b/tests/generated/grid_padding_border_overrides_min_size.rs
@@ -0,0 +1,45 @@
+#[test]
+fn grid_padding_border_overrides_min_size() {
+    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 {
+            min_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(0f32),
+                height: taffy::style::Dimension::Points(0f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(taffy::style::Style { display: taffy::style::Display::Grid, ..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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/grid_padding_border_overrides_size.rs b/tests/generated/grid_padding_border_overrides_size.rs
new file mode 100644
index 000000000..e2a5162b5
--- /dev/null
+++ b/tests/generated/grid_padding_border_overrides_size.rs
@@ -0,0 +1,45 @@
+#[test]
+fn grid_padding_border_overrides_size() {
+    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 {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(taffy::style::Style { display: taffy::style::Display::Grid, ..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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/leaf_padding_border_overrides_max_size.rs b/tests/generated/leaf_padding_border_overrides_max_size.rs
new file mode 100644
index 000000000..3f61a2b56
--- /dev/null
+++ b/tests/generated/leaf_padding_border_overrides_max_size.rs
@@ -0,0 +1,37 @@
+#[test]
+fn leaf_padding_border_overrides_max_size() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy
+        .new_leaf(taffy::style::Style {
+            max_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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);
+}
diff --git a/tests/generated/leaf_padding_border_overrides_min_size.rs b/tests/generated/leaf_padding_border_overrides_min_size.rs
new file mode 100644
index 000000000..44323f5bb
--- /dev/null
+++ b/tests/generated/leaf_padding_border_overrides_min_size.rs
@@ -0,0 +1,37 @@
+#[test]
+fn leaf_padding_border_overrides_min_size() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy
+        .new_leaf(taffy::style::Style {
+            min_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(0f32),
+                height: taffy::style::Dimension::Points(0f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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);
+}
diff --git a/tests/generated/leaf_padding_border_overrides_size.rs b/tests/generated/leaf_padding_border_overrides_size.rs
new file mode 100644
index 000000000..631c85b54
--- /dev/null
+++ b/tests/generated/leaf_padding_border_overrides_size.rs
@@ -0,0 +1,37 @@
+#[test]
+fn leaf_padding_border_overrides_size() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .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, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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);
+}
diff --git a/tests/generated/measure_child_with_min_size_greater_than_available_space.rs b/tests/generated/measure_child_with_min_size_greater_than_available_space.rs
new file mode 100644
index 000000000..d42622268
--- /dev/null
+++ b/tests/generated/measure_child_with_min_size_greater_than_available_space.rs
@@ -0,0 +1,50 @@
+#[test]
+fn measure_child_with_min_size_greater_than_available_space() {
+    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 {
+                min_size: taffy::geometry::Size { width: taffy::style::Dimension::Points(200f32), height: auto() },
+                ..Default::default()
+            },
+            taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+                const TEXT: &str = "HHHHHHHH\u{200b}HHHHHHHH";
+                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::Flex,
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Points(100f32), height: auto() },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, 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, 200f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, 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);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index dfe95c1e0..4be363806 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -104,6 +104,8 @@ mod absolute_minmax_bottom_right_min_max;
 mod absolute_minmax_bottom_right_min_max_preferred;
 mod absolute_minmax_top_left_bottom_right_max;
 mod absolute_minmax_top_left_bottom_right_min_max;
+mod absolute_padding_border_overrides_max_size;
+mod absolute_padding_border_overrides_size;
 mod align_baseline;
 mod align_baseline_child;
 mod align_baseline_child_margin;
@@ -196,6 +198,13 @@ mod aspect_ratio_flex_row_stretch_fill_height;
 mod aspect_ratio_flex_row_stretch_fill_max_height;
 mod aspect_ratio_flex_row_stretch_fill_max_width;
 mod aspect_ratio_flex_row_stretch_fill_width;
+mod bevy_issue_7976_3_level;
+mod bevy_issue_7976_4_level;
+mod bevy_issue_7976_reduced;
+mod bevy_issue_8017;
+mod bevy_issue_8017_reduced;
+mod bevy_issue_8082;
+mod bevy_issue_8082_percent;
 mod border_center_child;
 mod border_container_match_child;
 mod border_flex_child;
@@ -643,6 +652,16 @@ mod grid_out_of_order_items;
 #[cfg(feature = "grid")]
 mod grid_overflow_rows;
 #[cfg(feature = "grid")]
+mod grid_padding_border_overrides_container_max_size;
+#[cfg(feature = "grid")]
+mod grid_padding_border_overrides_container_size;
+#[cfg(feature = "grid")]
+mod grid_padding_border_overrides_max_size;
+#[cfg(feature = "grid")]
+mod grid_padding_border_overrides_min_size;
+#[cfg(feature = "grid")]
+mod grid_padding_border_overrides_size;
+#[cfg(feature = "grid")]
 mod grid_percent_item_inside_stretch_item;
 #[cfg(feature = "grid")]
 mod grid_percent_items_nested_inside_stretch_alignment;
@@ -747,6 +766,9 @@ mod justify_content_row_min_width_and_margin;
 mod justify_content_row_space_around;
 mod justify_content_row_space_between;
 mod justify_content_row_space_evenly;
+mod leaf_padding_border_overrides_max_size;
+mod leaf_padding_border_overrides_min_size;
+mod leaf_padding_border_overrides_size;
 mod margin_and_flex_column;
 mod margin_and_flex_row;
 mod margin_and_stretch_column;
@@ -790,6 +812,7 @@ mod measure_child_constraint;
 mod measure_child_constraint_padding_parent;
 mod measure_child_with_flex_grow;
 mod measure_child_with_flex_shrink;
+mod measure_child_with_min_size_greater_than_available_space;
 mod measure_flex_basis_overrides_measure;
 mod measure_height_overrides_measure;
 mod measure_remeasure_child_after_growing;
@@ -817,6 +840,11 @@ mod only_shrinkable_item_with_flex_basis_zero;
 mod overflow_cross_axis;
 mod overflow_main_axis;
 mod padding_align_end_child;
+mod padding_border_overrides_max_size;
+mod padding_border_overrides_min_size;
+mod padding_border_overrides_size;
+mod padding_border_overrides_size_flex_basis_0;
+mod padding_border_overrides_size_flex_basis_0_growable;
 mod padding_center_child;
 mod padding_container_match_child;
 mod padding_flex_child;
@@ -849,6 +877,7 @@ mod percentage_position_bottom_right;
 mod percentage_position_left_top;
 mod percentage_size_based_on_parent_inner_size;
 mod percentage_size_of_flex_basis;
+mod percentage_sizes_should_not_prevent_flex_shrinking;
 mod percentage_width_height;
 mod percentage_width_height_undefined_parent_size;
 mod position_root_with_rtl_should_position_withoutdirection;
diff --git a/tests/generated/padding_border_overrides_max_size.rs b/tests/generated/padding_border_overrides_max_size.rs
new file mode 100644
index 000000000..205073386
--- /dev/null
+++ b/tests/generated/padding_border_overrides_max_size.rs
@@ -0,0 +1,43 @@
+#[test]
+fn padding_border_overrides_max_size() {
+    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 {
+            max_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/padding_border_overrides_min_size.rs b/tests/generated/padding_border_overrides_min_size.rs
new file mode 100644
index 000000000..6b59e23db
--- /dev/null
+++ b/tests/generated/padding_border_overrides_min_size.rs
@@ -0,0 +1,43 @@
+#[test]
+fn padding_border_overrides_min_size() {
+    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 {
+            min_size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(0f32),
+                height: taffy::style::Dimension::Points(0f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/padding_border_overrides_size.rs b/tests/generated/padding_border_overrides_size.rs
new file mode 100644
index 000000000..627b3e968
--- /dev/null
+++ b/tests/generated/padding_border_overrides_size.rs
@@ -0,0 +1,43 @@
+#[test]
+fn padding_border_overrides_size() {
+    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 {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 22f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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);
+}
diff --git a/tests/generated/padding_border_overrides_size_flex_basis_0.rs b/tests/generated/padding_border_overrides_size_flex_basis_0.rs
new file mode 100644
index 000000000..4df1dc66c
--- /dev/null
+++ b/tests/generated/padding_border_overrides_size_flex_basis_0.rs
@@ -0,0 +1,59 @@
+#[test]
+fn padding_border_overrides_size_flex_basis_0() {
+    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 {
+            flex_basis: taffy::style::Dimension::Points(0f32),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            flex_basis: taffy::style::Dimension::Points(0f32),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0, node1]).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, 34f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 34f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 22f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 22f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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, 12f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 12f32, size.height);
+    assert_eq!(location.x, 22f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 22f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+}
diff --git a/tests/generated/padding_border_overrides_size_flex_basis_0_growable.rs b/tests/generated/padding_border_overrides_size_flex_basis_0_growable.rs
new file mode 100644
index 000000000..5a1b4fadf
--- /dev/null
+++ b/tests/generated/padding_border_overrides_size_flex_basis_0_growable.rs
@@ -0,0 +1,61 @@
+#[test]
+fn padding_border_overrides_size_flex_basis_0_growable() {
+    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 {
+            flex_grow: 1f32,
+            flex_basis: taffy::style::Dimension::Points(0f32),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            padding: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(8f32),
+                right: taffy::style::LengthPercentage::Points(4f32),
+                top: taffy::style::LengthPercentage::Points(2f32),
+                bottom: taffy::style::LengthPercentage::Points(6f32),
+            },
+            border: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentage::Points(7f32),
+                right: taffy::style::LengthPercentage::Points(3f32),
+                top: taffy::style::LengthPercentage::Points(1f32),
+                bottom: taffy::style::LengthPercentage::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            flex_grow: 1f32,
+            flex_basis: taffy::style::Dimension::Points(0f32),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(12f32),
+                height: taffy::style::Dimension::Points(12f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0, node1]).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, 34f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 34f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 14f32, 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, 28f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 28f32, size.width);
+    assert_eq!(size.height, 14f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 14f32, 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, 6f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 6f32, size.width);
+    assert_eq!(size.height, 12f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 12f32, size.height);
+    assert_eq!(location.x, 28f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 28f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+}
diff --git a/tests/generated/percentage_sizes_should_not_prevent_flex_shrinking.rs b/tests/generated/percentage_sizes_should_not_prevent_flex_shrinking.rs
new file mode 100644
index 000000000..9864cf8e2
--- /dev/null
+++ b/tests/generated/percentage_sizes_should_not_prevent_flex_shrinking.rs
@@ -0,0 +1,48 @@
+#[test]
+fn percentage_sizes_should_not_prevent_flex_shrinking() {
+    use slotmap::Key;
+    #[allow(unused_imports)]
+    use taffy::{layout::Layout, prelude::*};
+    let mut taffy = taffy::Taffy::new();
+    let node00 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+    let node0 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(1.2f32), height: auto() },
+                ..Default::default()
+            },
+            &[node00],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(200f32),
+                    height: taffy::style::Dimension::Points(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 200f32, 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, 0f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+}
diff --git a/tests/relayout.rs b/tests/relayout.rs
index 067bd2b9a..1f4695127 100644
--- a/tests/relayout.rs
+++ b/tests/relayout.rs
@@ -1,11 +1,11 @@
-use taffy::style::{AvailableSpace, Dimension};
+use taffy::prelude::*;
 
 #[test]
 fn relayout() {
     let mut taffy = taffy::Taffy::new();
     let node1 = taffy
         .new_leaf(taffy::style::Style {
-            size: taffy::geometry::Size { width: Dimension::Points(8f32), height: Dimension::Points(80f32) },
+            size: taffy::geometry::Size { width: points(8.0), height: points(80.0) },
             ..Default::default()
         })
         .unwrap();
@@ -55,3 +55,232 @@ fn relayout() {
         assert_eq!(taffy.layout(node1).unwrap().location, initial1);
     }
 }
+
+#[test]
+fn toggle_root_display_none() {
+    let hidden_style = Style {
+        display: Display::None,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    let flex_style = Style {
+        display: Display::Flex,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    // Setup
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy.new_leaf(hidden_style.clone()).unwrap();
+
+    // Layout 1 (None)
+    taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+
+    // Layout 2 (Flex)
+    taffy.set_style(node, flex_style).unwrap();
+    taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 100.0);
+    assert_eq!(layout.size.height, 100.0);
+
+    // Layout 3 (None)
+    taffy.set_style(node, hidden_style).unwrap();
+    taffy.compute_layout(node, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+}
+
+#[test]
+fn toggle_flex_child_display_none() {
+    let hidden_style = Style {
+        display: Display::None,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    let flex_style = Style {
+        display: Display::Flex,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    // Setup
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy.new_leaf(hidden_style.clone()).unwrap();
+    let root = taffy.new_with_children(flex_style.clone(), &[node]).unwrap();
+
+    // Layout 1 (None)
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+
+    // Layout 2 (Flex)
+    taffy.set_style(node, flex_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 100.0);
+    assert_eq!(layout.size.height, 100.0);
+
+    // Layout 3 (None)
+    taffy.set_style(node, hidden_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+}
+
+#[test]
+fn toggle_flex_container_display_none() {
+    let hidden_style = Style {
+        display: Display::None,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    let flex_style = Style {
+        display: Display::Flex,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    // Setup
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy.new_leaf(hidden_style.clone()).unwrap();
+    let root = taffy.new_with_children(hidden_style.clone(), &[node]).unwrap();
+
+    // Layout 1 (None)
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(root).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+
+    // Layout 2 (Flex)
+    taffy.set_style(root, flex_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(root).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 100.0);
+    assert_eq!(layout.size.height, 100.0);
+
+    // Layout 3 (None)
+    taffy.set_style(root, hidden_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(root).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+}
+
+#[test]
+fn toggle_grid_child_display_none() {
+    let hidden_style = Style {
+        display: Display::None,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    let grid_style = Style {
+        display: Display::Grid,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    // Setup
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy.new_leaf(hidden_style.clone()).unwrap();
+    let root = taffy.new_with_children(grid_style.clone(), &[node]).unwrap();
+
+    // Layout 1 (None)
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+
+    // Layout 2 (Flex)
+    taffy.set_style(node, grid_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 100.0);
+    assert_eq!(layout.size.height, 100.0);
+
+    // Layout 3 (None)
+    taffy.set_style(node, hidden_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(node).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+}
+
+#[test]
+fn toggle_grid_container_display_none() {
+    let hidden_style = Style {
+        display: Display::None,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    let grid_style = Style {
+        display: Display::Grid,
+        size: Size { width: points(100.0), height: points(100.0) },
+        ..Default::default()
+    };
+
+    // Setup
+    let mut taffy = taffy::Taffy::new();
+    let node = taffy.new_leaf(hidden_style.clone()).unwrap();
+    let root = taffy.new_with_children(hidden_style.clone(), &[node]).unwrap();
+
+    // Layout 1 (None)
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(root).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+
+    // Layout 2 (Flex)
+    taffy.set_style(root, grid_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(root).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 100.0);
+    assert_eq!(layout.size.height, 100.0);
+
+    // Layout 3 (None)
+    taffy.set_style(root, hidden_style).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    let layout = taffy.layout(root).unwrap();
+    assert_eq!(layout.location.x, 0.0);
+    assert_eq!(layout.location.y, 0.0);
+    assert_eq!(layout.size.width, 0.0);
+    assert_eq!(layout.size.height, 0.0);
+}