tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definiciones

Fix flexbox baseline alignment (#325)

* Fix baseline alignment with margins and padding

* Don't run baseline alignment on flex columns

* Enable baseline child multiline tests

* Refactor baseline alignment to be returned by perform_layout function

- Introduce LayoutAlgorithm trait

* Only calculate child baseline for baseline alignment when necessary

* Add disabled test for grid item baseline alignment

* Apply suggestions from code review

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>

* Add documentation on what a baseline is

* Rename compute_generic functions back to compute

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>

b91874d4e34ecc9054b468a338ffcae6f61a1b4a · por Nico Burns · (hace 3 años) · padre e05b9093d · ver el árbol en este commit

Delta semántico · 76

benches/generated/align_baseline_child_margin.rs

benches/generated/align_baseline_child_margin_percent.rs

benches/generated/align_baseline_child_multiline_no_override_on_secondline.rs

benches/generated/align_baseline_child_multiline_override.rs

benches/generated/align_baseline_child_padding.rs

benches/generated/align_baseline_multiline.rs

benches/generated/align_baseline_multiline_row_and_column.rs

src/compute/flexbox.rs

src/compute/grid/alignment.rs

src/compute/grid/mod.rs

src/compute/grid/types/grid_item.rs

src/compute/leaf.rs

src/compute/mod.rs

src/geometry.rs

  • nueva def NONE pub
  • cambió de firma def ZERO pub

src/layout.rs

src/prelude.rs

tests/generated/align_baseline_child_margin.rs

tests/generated/align_baseline_child_margin_percent.rs

tests/generated/align_baseline_child_multiline_no_override_on_secondline.rs

tests/generated/align_baseline_child_multiline_override.rs

tests/generated/align_baseline_child_padding.rs

tests/generated/align_baseline_multiline.rs

tests/generated/align_baseline_multiline_row_and_column.rs

40 archivos · +1892 −288

diff --git a/benches/generated/align_baseline_child_margin.rs b/benches/generated/align_baseline_child_margin.rs
new file mode 100644
index 000000000..84ff33372
--- /dev/null
+++ b/benches/generated/align_baseline_child_margin.rs
@@ -0,0 +1,62 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = 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(5f32),
+                right: taffy::style::LengthPercentageAuto::Points(5f32),
+                top: taffy::style::LengthPercentageAuto::Points(5f32),
+                bottom: taffy::style::LengthPercentageAuto::Points(5f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            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),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/align_baseline_child_margin_percent.rs b/benches/generated/align_baseline_child_margin_percent.rs
new file mode 100644
index 000000000..d10b5fdc6
--- /dev/null
+++ b/benches/generated/align_baseline_child_margin_percent.rs
@@ -0,0 +1,62 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = 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::Percent(0.05f32),
+                right: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                top: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                bottom: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+                right: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+                top: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+                bottom: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/align_baseline_child_multiline_no_override_on_secondline.rs b/benches/generated/align_baseline_child_multiline_no_override_on_secondline.rs
new file mode 100644
index 000000000..8bca54b9f
--- /dev/null
+++ b/benches/generated/align_baseline_child_multiline_no_override_on_secondline.rs
@@ -0,0 +1,78 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(60f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node11 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node12 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node13 = taffy
+        .new_leaf(taffy::style::Style {
+            align_self: Some(taffy::style::AlignSelf::Baseline),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(25f32),
+                },
+                ..Default::default()
+            },
+            &[node10, node11, node12, node13],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/align_baseline_child_multiline_override.rs b/benches/generated/align_baseline_child_multiline_override.rs
new file mode 100644
index 000000000..f6f4cdc5f
--- /dev/null
+++ b/benches/generated/align_baseline_child_multiline_override.rs
@@ -0,0 +1,79 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(60f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node11 = taffy
+        .new_leaf(taffy::style::Style {
+            align_self: Some(taffy::style::AlignSelf::Baseline),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node12 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node13 = taffy
+        .new_leaf(taffy::style::Style {
+            align_self: Some(taffy::style::AlignSelf::Baseline),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(25f32),
+                },
+                ..Default::default()
+            },
+            &[node10, node11, node12, node13],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/align_baseline_child_padding.rs b/benches/generated/align_baseline_child_padding.rs
new file mode 100644
index 000000000..9600fac71
--- /dev/null
+++ b/benches/generated/align_baseline_child_padding.rs
@@ -0,0 +1,62 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = 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 node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                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()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                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()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/align_baseline_multiline.rs b/benches/generated/align_baseline_multiline.rs
new file mode 100644
index 000000000..048accde9
--- /dev/null
+++ b/benches/generated/align_baseline_multiline.rs
@@ -0,0 +1,82 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = 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 node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node20 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node20],
+        )
+        .unwrap();
+    let node3 = 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 node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/align_baseline_multiline_row_and_column.rs b/benches/generated/align_baseline_multiline_row_and_column.rs
new file mode 100644
index 000000000..19c0e8a7a
--- /dev/null
+++ b/benches/generated/align_baseline_multiline_row_and_column.rs
@@ -0,0 +1,82 @@
+pub fn compute() {
+    #[allow(unused_imports)]
+    use taffy::prelude::*;
+    let mut taffy = taffy::Taffy::new();
+    let node0 = 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 node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(50f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node20 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node20],
+        )
+        .unwrap();
+    let node3 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/mod.rs b/benches/generated/mod.rs
index 33a6c0582..dc6e01760 100644
--- a/benches/generated/mod.rs
+++ b/benches/generated/mod.rs
@@ -107,13 +107,20 @@ mod absolute_minmax_top_left_bottom_right_max;
 mod absolute_minmax_top_left_bottom_right_min_max;
 mod align_baseline;
 mod align_baseline_child;
+mod align_baseline_child_margin;
+mod align_baseline_child_margin_percent;
 mod align_baseline_child_multiline;
+mod align_baseline_child_multiline_no_override_on_secondline;
+mod align_baseline_child_multiline_override;
+mod align_baseline_child_padding;
 mod align_baseline_child_top;
 mod align_baseline_child_top2;
 mod align_baseline_column;
 mod align_baseline_double_nested_child;
+mod align_baseline_multiline;
 mod align_baseline_multiline_column;
 mod align_baseline_multiline_column2;
+mod align_baseline_multiline_row_and_column;
 mod align_baseline_nested_child;
 mod align_baseline_nested_column;
 mod align_center_should_size_based_on_content;
@@ -768,13 +775,20 @@ fn benchmark(c: &mut Criterion) {
             absolute_minmax_top_left_bottom_right_min_max::compute();
             align_baseline::compute();
             align_baseline_child::compute();
+            align_baseline_child_margin::compute();
+            align_baseline_child_margin_percent::compute();
             align_baseline_child_multiline::compute();
+            align_baseline_child_multiline_no_override_on_secondline::compute();
+            align_baseline_child_multiline_override::compute();
+            align_baseline_child_padding::compute();
             align_baseline_child_top::compute();
             align_baseline_child_top2::compute();
             align_baseline_column::compute();
             align_baseline_double_nested_child::compute();
+            align_baseline_multiline::compute();
             align_baseline_multiline_column::compute();
             align_baseline_multiline_column2::compute();
+            align_baseline_multiline_row_and_column::compute();
             align_baseline_nested_child::compute();
             align_baseline_nested_column::compute();
             align_center_should_size_based_on_content::compute();
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index a77d25037..9bb26f3ff 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -4,9 +4,9 @@
 use core::f32;
 
 use crate::compute::common::alignment::compute_alignment_offset;
-use crate::compute::compute_node_layout;
+use crate::compute::{GenericAlgorithm, LayoutAlgorithm};
 use crate::geometry::{Point, Rect, Size};
-use crate::layout::{Layout, RunMode, SizingMode};
+use crate::layout::{Layout, RunMode, SizeAndBaselines, SizingMode};
 use crate::math::MaybeMath;
 use crate::node::Node;
 use crate::prelude::{TaffyMaxContent, TaffyMinContent};
@@ -23,6 +23,34 @@ use crate::tree::LayoutTree;
 #[cfg(feature = "debug")]
 use crate::debug::NODE_LOGGER;
 
+/// The public interface to Taffy's Flexbox algorithm implementation
+pub(crate) struct FlexboxAlgorithm;
+impl LayoutAlgorithm for FlexboxAlgorithm {
+    const NAME: &'static str = "FLEXBOX";
+
+    fn perform_layout(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        _sizing_mode: SizingMode,
+    ) -> SizeAndBaselines {
+        compute(tree, node, known_dimensions, parent_size, available_space, RunMode::PeformLayout)
+    }
+
+    fn measure_size(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        _sizing_mode: SizingMode,
+    ) -> Size<f32> {
+        compute(tree, node, known_dimensions, parent_size, available_space, RunMode::ComputeSize).size
+    }
+}
+
 /// The intermediate results of a flexbox calculation for a single item
 struct FlexItem {
     /// The identifier for the associated [`Node`](crate::node::Node)
@@ -137,7 +165,7 @@ pub fn compute(
     parent_size: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
     run_mode: RunMode,
-) -> Size<f32> {
+) -> SizeAndBaselines {
     let style = tree.style(node);
     let has_min_max_sizes = style.min_size.width.is_defined()
         || style.min_size.height.is_defined()
@@ -159,7 +187,8 @@ pub fn compute(
             parent_size,
             available_space,
             RunMode::ComputeSize,
-        );
+        )
+        .size;
 
         let clamped_first_pass_size = first_pass.maybe_clamp(min_size, max_size);
 
@@ -186,7 +215,7 @@ fn compute_preliminary(
     parent_size: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
     run_mode: RunMode,
-) -> Size<f32> {
+) -> SizeAndBaselines {
     // Define some general constants we will need for the remainder of the algorithm.
     let mut constants = compute_constants(tree.style(node), known_dimensions, parent_size);
 
@@ -206,8 +235,6 @@ fn compute_preliminary(
     NODE_LOGGER.log("determine_available_space");
     let available_space = determine_available_space(known_dimensions, available_space, &constants);
 
-    let has_baseline_child = flex_items.iter().any(|child| child.align_self == AlignSelf::Baseline);
-
     // 3. Determine the flex base size and hypothetical main size of each item.
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("determine_flex_base_size");
@@ -279,13 +306,11 @@ fn compute_preliminary(
         determine_hypothetical_cross_size(tree, line, &constants, available_space);
     }
 
-    // TODO - probably should move this somewhere else as it doesn't make a ton of sense here but we need it below
-    // TODO - This is expensive and should only be done if we really require a baseline. aka, make it lazy
-    if has_baseline_child {
-        #[cfg(feature = "debug")]
-        NODE_LOGGER.log("calculate_children_base_lines");
-        calculate_children_base_lines(tree, node, known_dimensions, available_space, &mut flex_lines, &constants);
-    }
+    // Calculate child baselines. This function is internally smart and only computes child baselines
+    // if they are necessary.
+    #[cfg(feature = "debug")]
+    NODE_LOGGER.log("calculate_children_base_lines");
+    calculate_children_base_lines(tree, known_dimensions, available_space, &mut flex_lines, &constants);
 
     // 8. Calculate the cross size of each flex line.
     #[cfg(feature = "debug")]
@@ -339,8 +364,7 @@ fn compute_preliminary(
     // We have the container size.
     // If our caller does not care about performing layout we are done now.
     if run_mode == RunMode::ComputeSize {
-        let container_size = constants.container_size;
-        return container_size;
+        return SizeAndBaselines { size: constants.container_size, first_baselines: Point::NONE };
     }
 
     // 16. Align all flex lines per align-content.
@@ -365,19 +389,34 @@ fn compute_preliminary(
         let child = tree.child(node, order);
         if tree.style(child).display == Display::None {
             *tree.layout_mut(node) = Layout::with_order(order as u32);
-            compute_node_layout(
+            GenericAlgorithm::measure_size(
                 tree,
                 child,
                 Size::NONE,
                 Size::NONE,
                 Size::MAX_CONTENT,
-                RunMode::PeformLayout,
                 SizingMode::InherentSize,
             );
         }
     }
 
-    constants.container_size
+    // 8.5. Flex Container Baselines: calculate the flex container's first baseline
+    // See https://www.w3.org/TR/css-flexbox-1/#flex-baselines
+    let first_vertical_baseline = if flex_lines.is_empty() {
+        None
+    } else {
+        flex_lines[0]
+            .items
+            .iter()
+            .find(|item| constants.is_column || item.align_self == AlignSelf::Baseline)
+            .or_else(|| flex_lines[0].items.iter().next())
+            .map(|child| {
+                let offset_vertical = if constants.is_row { child.offset_cross } else { child.offset_main };
+                offset_vertical + child.baseline
+            })
+    };
+
+    SizeAndBaselines { size: constants.container_size, first_baselines: Point { x: None, y: first_vertical_baseline } }
 }
 
 /// Compute constants that can be reused during the flexbox algorithm.
@@ -617,13 +656,12 @@ fn determine_flex_base_size(
             ckd
         };
 
-        child.flex_basis = compute_node_layout(
+        child.flex_basis = GenericAlgorithm::measure_size(
             tree,
             child.node,
             child_known_dimensions,
             constants.node_inner_size,
             available_space,
-            RunMode::ComputeSize,
             SizingMode::ContentSize,
         )
         .main(constants.dir);
@@ -636,13 +674,12 @@ fn determine_flex_base_size(
         child.inner_flex_basis =
             child.flex_basis - child.padding.main_axis_sum(constants.dir) - child.border.main_axis_sum(constants.dir);
 
-        let min_content_size = compute_node_layout(
+        let min_content_size = GenericAlgorithm::measure_size(
             tree,
             child.node,
             Size::NONE,
             constants.node_inner_size,
             Size::MIN_CONTENT,
-            RunMode::ComputeSize,
             SizingMode::ContentSize,
         );
 
@@ -968,7 +1005,7 @@ fn determine_hypothetical_cross_size(
 
         child.hypothetical_inner_size.set_cross(
             constants.dir,
-            compute_node_layout(
+            GenericAlgorithm::measure_size(
                 tree,
                 child.node,
                 Size {
@@ -988,7 +1025,6 @@ fn determine_hypothetical_cross_size(
                         constants.container_size.main(constants.dir).into()
                     },
                 },
-                RunMode::ComputeSize,
                 SizingMode::ContentSize,
             )
             .cross(constants.dir)
@@ -1006,25 +1042,33 @@ fn determine_hypothetical_cross_size(
 #[inline]
 fn calculate_children_base_lines(
     tree: &mut impl LayoutTree,
-    node: Node,
     node_size: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
     flex_lines: &mut [FlexLine],
     constants: &AlgoConstants,
 ) {
-    /// Recursively calculates the baseline for children
-    fn calc_baseline(db: &impl LayoutTree, node: Node, layout: &Layout) -> f32 {
-        if let Some(first_child) = db.children(node).next() {
-            let layout = db.layout(*first_child);
-            calc_baseline(db, *first_child, layout)
-        } else {
-            layout.size.height
-        }
+    // Only compute baselines for flex rows because we only support baseline alignment in the cross axis
+    // where that axis is also the inline axis
+    // TODO: this may need revisiting if/when we support vertical writing modes
+    if !constants.is_row {
+        return;
     }
 
     for line in flex_lines {
+        // If a flex line has one or zero items participating in baseline alignment then baseline alignment is a no-op so we skip
+        let line_baseline_child_count =
+            line.items.iter().filter(|child| child.align_self == AlignSelf::Baseline).count();
+        if line_baseline_child_count <= 1 {
+            continue;
+        }
+
         for child in line.items.iter_mut() {
-            let preliminary_size = compute_node_layout(
+            // Only calculate baselines for children participating in baseline alignment
+            if child.align_self != AlignSelf::Baseline {
+                continue;
+            }
+
+            let measured_size_and_baselines = GenericAlgorithm::perform_layout(
                 tree,
                 child.node,
                 Size {
@@ -1052,19 +1096,13 @@ fn calculate_children_base_lines(
                         constants.container_size.height.into()
                     },
                 },
-                RunMode::PeformLayout,
                 SizingMode::ContentSize,
             );
 
-            child.baseline = calc_baseline(
-                tree,
-                child.node,
-                &Layout {
-                    order: tree.children(node).position(|n| *n == child.node).unwrap() as u32,
-                    size: preliminary_size,
-                    location: Point::zero(),
-                },
-            );
+            let baseline = measured_size_and_baselines.first_baselines.y;
+            let height = measured_size_and_baselines.size.height;
+
+            child.baseline = baseline.unwrap_or(height) + child.margin.top;
         }
     }
 }
@@ -1131,7 +1169,6 @@ fn calculate_cross_size(
                     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_style.size.cross(constants.dir) == Dimension::Auto
                     {
                         max_baseline - child.baseline + child.hypothetical_outer_size.cross(constants.dir)
                     } else {
@@ -1471,15 +1508,15 @@ fn calculate_flex_item(
     node_inner_size: Size<Option<f32>>,
     direction: FlexDirection,
 ) {
-    let preliminary_size = compute_node_layout(
+    let preliminary_size_and_baselines = GenericAlgorithm::perform_layout(
         tree,
         item.node,
         item.target_size.map(|s| s.into()),
         node_inner_size,
         container_size.map(|s| s.into()),
-        RunMode::PeformLayout,
         SizingMode::ContentSize,
     );
+    let preliminary_size = preliminary_size_and_baselines.size;
 
     let offset_main = *total_offset_main
         + item.offset_main
@@ -1492,11 +1529,21 @@ fn calculate_flex_item(
         + item.margin.cross_start(direction)
         + (item.inset.cross_start(direction).unwrap_or(0.0) - item.inset.cross_end(direction).unwrap_or(0.0));
 
+    if direction.is_row() {
+        let baseline_offset_cross = total_offset_cross + item.offset_cross + item.margin.cross_start(direction);
+        let inner_baseline = preliminary_size_and_baselines.first_baselines.y.unwrap_or(preliminary_size.height);
+        item.baseline = baseline_offset_cross + inner_baseline;
+    } else {
+        let baseline_offset_main = *total_offset_main + item.offset_main + item.margin.main_start(direction);
+        let inner_baseline = preliminary_size_and_baselines.first_baselines.y.unwrap_or(preliminary_size.height);
+        item.baseline = baseline_offset_main + inner_baseline;
+    }
+
     let order = tree.children(node).position(|n| *n == item.node).unwrap() as u32;
 
     *tree.layout_mut(item.node) = Layout {
         order,
-        size: preliminary_size,
+        size: preliminary_size_and_baselines.size,
         location: Point {
             x: if direction.is_row() { offset_main } else { offset_cross },
             y: if direction.is_column() { offset_main } else { offset_cross },
@@ -1640,7 +1687,7 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
             known_dimensions = known_dimensions.maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size);
         }
 
-        let measured_size = compute_node_layout(
+        let measured_size_and_baselines = GenericAlgorithm::perform_layout(
             tree,
             child,
             known_dimensions,
@@ -1649,9 +1696,9 @@ fn perform_absolute_layout_on_absolute_children(tree: &mut impl LayoutTree, node
                 width: AvailableSpace::Definite(container_width.maybe_clamp(min_size.width, max_size.width)),
                 height: AvailableSpace::Definite(container_height.maybe_clamp(min_size.height, max_size.height)),
             },
-            RunMode::PeformLayout,
             SizingMode::ContentSize,
         );
+        let measured_size = measured_size_and_baselines.size;
         let final_size = known_dimensions.unwrap_or(measured_size).maybe_clamp(min_size, max_size);
 
         let non_auto_margin = margin.map(|m| m.unwrap_or(0.0));
diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs
index cd8cf13f2..d1df39c55 100644
--- a/src/compute/grid/alignment.rs
+++ b/src/compute/grid/alignment.rs
@@ -2,9 +2,9 @@
 use super::types::GridTrack;
 use crate::axis::InBothAbsAxis;
 use crate::compute::common::alignment::compute_alignment_offset;
-use crate::compute::compute_node_layout;
+use crate::compute::{GenericAlgorithm, LayoutAlgorithm};
 use crate::geometry::{Line, Point, Rect, Size};
-use crate::layout::{Layout, RunMode, SizingMode};
+use crate::layout::{Layout, SizingMode};
 use crate::math::MaybeMath;
 use crate::node::Node;
 use crate::resolve::MaybeResolve;
@@ -176,18 +176,18 @@ pub(super) fn align_and_position_item(
     let Size { width, height } = Size { width, height }.maybe_clamp(min_size, max_size);
 
     // Layout node
-    let measured_size = compute_node_layout(
+    let measured_size_and_baselines = GenericAlgorithm::perform_layout(
         tree,
         node,
         Size { width, height },
         grid_area_size.map(Option::Some),
         grid_area_minus_item_margins_size.map(AvailableSpace::Definite),
-        RunMode::PeformLayout,
         SizingMode::InherentSize,
     );
 
     // Resolve final size
-    let Size { width, height } = Size { width, height }.unwrap_or(measured_size).maybe_clamp(min_size, max_size);
+    let Size { width, height } =
+        Size { width, height }.unwrap_or(measured_size_and_baselines.size).maybe_clamp(min_size, max_size);
 
     let x = align_item_within_area(
         Line { start: grid_area.left, end: grid_area.right },
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index 5cca095ce..dc74c3920 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -1,8 +1,8 @@
 //! This module is a partial implementation of the CSS Grid Level 1 specification
 //! https://www.w3.org/TR/css-grid-1/
 use crate::axis::{AbsoluteAxis, AbstractAxis, InBothAbsAxis};
-use crate::geometry::{Line, Rect, Size};
-use crate::layout::{Layout, RunMode, SizingMode};
+use crate::geometry::{Line, Point, Rect, Size};
+use crate::layout::{Layout, RunMode, SizeAndBaselines, SizingMode};
 use crate::math::MaybeMath;
 use crate::node::Node;
 use crate::resolve::{MaybeResolve, ResolveOrZero};
@@ -22,7 +22,7 @@ pub(crate) use types::{GridCoordinate, GridLine, OriginZeroLine};
 #[cfg(feature = "debug")]
 use crate::debug::NODE_LOGGER;
 
-use super::compute_node_layout;
+use super::{GenericAlgorithm, LayoutAlgorithm};
 
 mod alignment;
 mod explicit_grid;
@@ -32,6 +32,34 @@ mod track_sizing;
 mod types;
 mod util;
 
+/// The public interface to Taffy's CSS Grid algorithm implementation
+pub(crate) struct CssGridAlgorithm;
+impl LayoutAlgorithm for CssGridAlgorithm {
+    const NAME: &'static str = "CSS GRID";
+
+    fn perform_layout(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        _sizing_mode: SizingMode,
+    ) -> SizeAndBaselines {
+        compute(tree, node, known_dimensions, parent_size, available_space, RunMode::PeformLayout)
+    }
+
+    fn measure_size(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        _sizing_mode: SizingMode,
+    ) -> Size<f32> {
+        compute(tree, node, known_dimensions, parent_size, available_space, RunMode::ComputeSize).size
+    }
+}
+
 /// Grid layout algorithm
 /// This consists of a few phases:
 ///   - Resolving the explicit grid
@@ -44,7 +72,8 @@ pub fn compute(
     known_dimensions: Size<Option<f32>>,
     parent_size: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
-) -> Size<f32> {
+    _run_mode: RunMode,
+) -> SizeAndBaselines {
     let get_child_styles_iter = |node| tree.children(node).map(|child_node: &Node| tree.style(*child_node));
     let style = tree.style(node).clone();
     let child_styles_iter = get_child_styles_iter(node);
@@ -290,13 +319,12 @@ pub fn compute(
         // Position hidden child
         if child_style.display == Display::None {
             *tree.layout_mut(node) = Layout::with_order(order);
-            compute_node_layout(
+            GenericAlgorithm::perform_layout(
                 tree,
                 child,
                 Size::NONE,
                 Size::NONE,
                 Size::MAX_CONTENT,
-                RunMode::PeformLayout,
                 SizingMode::InherentSize,
             );
             order += 1;
@@ -341,5 +369,5 @@ pub fn compute(
         }
     });
 
-    container_border_box
+    SizeAndBaselines { size: container_border_box, first_baselines: Point::NONE }
 }
diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs
index fcd76cd41..7eef6da71 100644
--- a/src/compute/grid/types/grid_item.rs
+++ b/src/compute/grid/types/grid_item.rs
@@ -1,10 +1,10 @@
 //! Contains GridItem used to represent a single grid item during layout
 use super::GridTrack;
 use crate::axis::AbstractAxis;
-use crate::compute::compute_node_layout;
 use crate::compute::grid::OriginZeroLine;
+use crate::compute::{GenericAlgorithm, LayoutAlgorithm};
 use crate::geometry::{Line, Rect, Size};
-use crate::layout::{RunMode, SizingMode};
+use crate::layout::SizingMode;
 use crate::node::Node;
 use crate::prelude::LayoutTree;
 use crate::resolve::MaybeResolve;
@@ -188,13 +188,12 @@ impl GridItem {
         inner_node_size: Size<Option<f32>>,
     ) -> Size<f32> {
         self.min_content_contribution_cache.unwrap_or_else(|| {
-            let size = compute_node_layout(
+            let size = GenericAlgorithm::measure_size(
                 tree,
                 self.node,
                 known_dimensions,
                 inner_node_size,
                 Size::MIN_CONTENT,
-                RunMode::ComputeSize,
                 SizingMode::InherentSize,
             );
             self.min_content_contribution_cache = Some(size);
@@ -210,13 +209,12 @@ impl GridItem {
         inner_node_size: Size<Option<f32>>,
     ) -> Size<f32> {
         self.max_content_contribution_cache.unwrap_or_else(|| {
-            let size = compute_node_layout(
+            let size = GenericAlgorithm::measure_size(
                 tree,
                 self.node,
                 known_dimensions,
                 inner_node_size,
                 Size::MAX_CONTENT,
-                RunMode::ComputeSize,
                 SizingMode::InherentSize,
             );
             self.max_content_contribution_cache = Some(size);
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index 9257c10d1..2c347a64d 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -1,7 +1,8 @@
 //! Computes size using styles and measure functions
 
-use crate::geometry::Size;
-use crate::layout::{RunMode, SizingMode};
+use crate::compute::LayoutAlgorithm;
+use crate::geometry::{Point, Size};
+use crate::layout::{SizeAndBaselines, SizingMode};
 use crate::math::MaybeMath;
 use crate::node::Node;
 use crate::resolve::{MaybeResolve, ResolveOrZero};
@@ -12,6 +13,34 @@ use crate::tree::LayoutTree;
 #[cfg(feature = "debug")]
 use crate::debug::NODE_LOGGER;
 
+/// The public interface to Taffy's leaf node algorithm implementation
+pub(crate) struct LeafAlgorithm;
+impl LayoutAlgorithm for LeafAlgorithm {
+    const NAME: &'static str = "LEAF";
+
+    fn perform_layout(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        sizing_mode: SizingMode,
+    ) -> SizeAndBaselines {
+        compute(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
+    }
+
+    fn measure_size(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        sizing_mode: SizingMode,
+    ) -> Size<f32> {
+        compute(tree, node, known_dimensions, parent_size, available_space, sizing_mode).size
+    }
+}
+
 /// Compute the size of a leaf node (node with no children)
 pub(crate) fn compute(
     tree: &mut impl LayoutTree,
@@ -19,9 +48,8 @@ pub(crate) fn compute(
     known_dimensions: Size<Option<f32>>,
     parent_size: Size<Option<f32>>,
     available_space: Size<AvailableSpace>,
-    _run_mode: RunMode,
     sizing_mode: SizingMode,
-) -> Size<f32> {
+) -> SizeAndBaselines {
     let style = tree.style(node);
 
     // Resolve node's preferred/min/max sizes (width/heights) against the available space (percentages resolve to pixel values)
@@ -55,7 +83,8 @@ pub(crate) fn compute(
 
     // Return early if both width and height are known
     if let Size { width: Some(width), height: Some(height) } = node_size {
-        return Size { width, height }.maybe_clamp(node_min_size, node_max_size);
+        let size = Size { width, height }.maybe_clamp(node_min_size, node_max_size);
+        return SizeAndBaselines { size, first_baselines: Point::NONE };
     };
 
     if tree.needs_measure(node) {
@@ -81,7 +110,8 @@ pub(crate) fn compute(
             height: f32_max(measured_size.height, aspect_ratio.map(|ratio| measured_size.width / ratio).unwrap_or(0.0)),
         };
 
-        return node_size.unwrap_or(measured_size).maybe_clamp(node_min_size, node_max_size);
+        let size = node_size.unwrap_or(measured_size).maybe_clamp(node_min_size, node_max_size);
+        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).
@@ -89,7 +119,7 @@ pub(crate) fn compute(
     let padding = style.padding.resolve_or_zero(parent_size.width);
     let border = style.border.resolve_or_zero(parent_size.width);
 
-    Size {
+    let size = Size {
         width: node_size
             .width
             // .unwrap_or(0.0) + padding.horizontal_axis_sum() + border.horizontal_axis_sum(), // content-box
@@ -100,5 +130,6 @@ pub(crate) fn compute(
             // .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),
-    }
+    };
+    SizeAndBaselines { size, first_baselines: Point::NONE }
 }
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 4c0357a58..8e9a20307 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -10,12 +10,16 @@ pub(crate) mod grid;
 use crate::data::CACHE_SIZE;
 use crate::error::TaffyError;
 use crate::geometry::{Point, Size};
-use crate::layout::{Cache, Layout, RunMode, SizingMode};
+use crate::layout::{Cache, Layout, RunMode, SizeAndBaselines, SizingMode};
 use crate::node::Node;
 use crate::style::{AvailableSpace, Display};
 use crate::sys::round;
 use crate::tree::LayoutTree;
 
+use self::flexbox::FlexboxAlgorithm;
+use self::grid::CssGridAlgorithm;
+use self::leaf::LeafAlgorithm;
+
 #[cfg(feature = "debug")]
 use crate::debug::NODE_LOGGER;
 
@@ -26,17 +30,16 @@ pub fn compute_layout(
     available_space: Size<AvailableSpace>,
 ) -> Result<(), TaffyError> {
     // Recursively compute node layout
-    let size = compute_node_layout(
+    let size_and_baselines = GenericAlgorithm::perform_layout(
         tree,
         root,
         Size::NONE,
         available_space.into_options(),
         available_space,
-        RunMode::PeformLayout,
         SizingMode::InherentSize,
     );
 
-    let layout = Layout { order: 0, size, location: Point::ZERO };
+    let layout = Layout { order: 0, size: size_and_baselines.size, location: Point::ZERO };
     *tree.layout_mut(root) = layout;
 
     // Recursively round the layout's of this node and all children
@@ -45,6 +48,78 @@ pub fn compute_layout(
     Ok(())
 }
 
+/// A common interface that all Taffy layout algorithms conform to
+pub(crate) trait LayoutAlgorithm {
+    /// The name of the algorithm (mainly used for debug purposes)
+    const NAME: &'static str;
+
+    /// Compute the size of the node given the specified constraints
+    fn measure_size(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        sizing_mode: SizingMode,
+    ) -> Size<f32>;
+
+    /// Perform a full layout on the node given the specified constraints
+    fn perform_layout(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        sizing_mode: SizingMode,
+    ) -> SizeAndBaselines;
+}
+
+/// The public interface to a generic algorithm that abstracts over all of Taffy's algorithms
+/// and applies the correct one based on the `Display` style
+pub struct GenericAlgorithm;
+impl LayoutAlgorithm for GenericAlgorithm {
+    const NAME: &'static str = "GENERIC";
+
+    fn perform_layout(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        sizing_mode: SizingMode,
+    ) -> SizeAndBaselines {
+        compute_node_layout(
+            tree,
+            node,
+            known_dimensions,
+            parent_size,
+            available_space,
+            RunMode::PeformLayout,
+            sizing_mode,
+        )
+    }
+
+    fn measure_size(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        sizing_mode: SizingMode,
+    ) -> Size<f32> {
+        compute_node_layout(
+            tree,
+            node,
+            known_dimensions,
+            parent_size,
+            available_space,
+            RunMode::ComputeSize,
+            sizing_mode,
+        )
+        .size
+    }
+}
+
 /// Updates the stored layout of the provided `node` and its children
 fn compute_node_layout(
     tree: &mut impl LayoutTree,
@@ -54,7 +129,7 @@ fn compute_node_layout(
     available_space: Size<AvailableSpace>,
     run_mode: RunMode,
     sizing_mode: SizingMode,
-) -> Size<f32> {
+) -> SizeAndBaselines {
     #[cfg(feature = "debug")]
     NODE_LOGGER.push_node(node);
     #[cfg(feature = "debug")]
@@ -62,69 +137,121 @@ 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) =
+    if let Some(cached_size_and_baselines) =
         compute_from_cache(tree, node, known_dimensions, available_space, cache_run_mode, sizing_mode)
     {
         #[cfg(feature = "debug")]
-        NODE_LOGGER.labelled_debug_log("CACHE", cached_size);
-        #[cfg(feature = "debug")]
-        NODE_LOGGER.labelled_debug_log("run_mode", run_mode);
+        NODE_LOGGER.labelled_debug_log("CACHE", cached_size_and_baselines.size);
         #[cfg(feature = "debug")]
-        NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
-        #[cfg(feature = "debug")]
-        NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
-        #[cfg(feature = "debug")]
-        NODE_LOGGER.labelled_debug_log("available_space", available_space);
+        debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
         #[cfg(feature = "debug")]
         NODE_LOGGER.pop_node();
-        return cached_size;
+        return cached_size_and_baselines;
     }
 
     #[cfg(feature = "debug")]
     NODE_LOGGER.log("COMPUTE");
     #[cfg(feature = "debug")]
-    NODE_LOGGER.labelled_debug_log("run_mode", run_mode);
-    #[cfg(feature = "debug")]
-    NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
-    #[cfg(feature = "debug")]
-    NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
-    #[cfg(feature = "debug")]
-    NODE_LOGGER.labelled_debug_log("available_space", available_space);
-
-    // If this is a leaf node we can skip a lot of this function in some cases
-    let computed_size = if tree.is_childless(node) {
+    debug_log_node(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
+
+    /// Inlined function generic over the LayoutAlgorithm to reduce code duplication
+    #[inline(always)]
+    fn perform_computations<Algorithm: LayoutAlgorithm>(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        known_dimensions: Size<Option<f32>>,
+        parent_size: Size<Option<f32>>,
+        available_space: Size<AvailableSpace>,
+        run_mode: RunMode,
+        sizing_mode: SizingMode,
+    ) -> SizeAndBaselines {
         #[cfg(feature = "debug")]
-        NODE_LOGGER.log("Algo: leaf");
-        self::leaf::compute(tree, node, known_dimensions, parent_size, available_space, run_mode, sizing_mode)
+        NODE_LOGGER.log(Algorithm::NAME);
+
+        match run_mode {
+            RunMode::PeformLayout => {
+                Algorithm::perform_layout(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
+            }
+            RunMode::ComputeSize => {
+                let size =
+                    Algorithm::measure_size(tree, node, known_dimensions, parent_size, available_space, sizing_mode);
+                SizeAndBaselines { size, first_baselines: Point::NONE }
+            }
+        }
+    }
+
+    let computed_size_and_baselines = if tree.is_childless(node) {
+        perform_computations::<LeafAlgorithm>(
+            tree,
+            node,
+            known_dimensions,
+            parent_size,
+            available_space,
+            run_mode,
+            sizing_mode,
+        )
     } else {
-        // println!("match {:?}", tree.style(node).display);
         match tree.style(node).display {
-            Display::Flex => {
-                #[cfg(feature = "debug")]
-                NODE_LOGGER.log("Algo: flexbox");
-                self::flexbox::compute(tree, node, known_dimensions, parent_size, available_space, run_mode)
-            }
+            Display::Flex => perform_computations::<FlexboxAlgorithm>(
+                tree,
+                node,
+                known_dimensions,
+                parent_size,
+                available_space,
+                run_mode,
+                sizing_mode,
+            ),
             #[cfg(feature = "grid")]
-            Display::Grid => self::grid::compute(tree, node, known_dimensions, parent_size, available_space),
-            Display::None => {
-                #[cfg(feature = "debug")]
-                NODE_LOGGER.log("Algo: none");
-                perform_hidden_layout(tree, node)
-            }
+            Display::Grid => perform_computations::<CssGridAlgorithm>(
+                tree,
+                node,
+                known_dimensions,
+                parent_size,
+                available_space,
+                run_mode,
+                sizing_mode,
+            ),
+            Display::None => perform_computations::<HiddenAlgorithm>(
+                tree,
+                node,
+                known_dimensions,
+                parent_size,
+                available_space,
+                run_mode,
+                sizing_mode,
+            ),
         }
     };
 
     // Cache result
     let cache_slot = compute_cache_slot(known_dimensions, available_space);
-    *tree.cache_mut(node, cache_slot) =
-        Some(Cache { known_dimensions, available_space, run_mode: cache_run_mode, cached_size: computed_size });
+    *tree.cache_mut(node, cache_slot) = Some(Cache {
+        known_dimensions,
+        available_space,
+        run_mode: cache_run_mode,
+        cached_size_and_baselines: computed_size_and_baselines,
+    });
 
     #[cfg(feature = "debug")]
-    NODE_LOGGER.labelled_debug_log("RESULT", computed_size);
+    NODE_LOGGER.labelled_debug_log("RESULT", computed_size_and_baselines.size);
     #[cfg(feature = "debug")]
     NODE_LOGGER.pop_node();
 
-    computed_size
+    computed_size_and_baselines
+}
+
+#[cfg(feature = "debug")]
+fn debug_log_node(
+    known_dimensions: Size<Option<f32>>,
+    parent_size: Size<Option<f32>>,
+    available_space: Size<AvailableSpace>,
+    run_mode: RunMode,
+    sizing_mode: SizingMode,
+) {
+    NODE_LOGGER.labelled_debug_log("run_mode", run_mode);
+    NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
+    NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
+    NODE_LOGGER.labelled_debug_log("available_space", available_space);
 }
 
 /// Return the cache slot to cache the current computed result in
@@ -180,7 +307,7 @@ fn compute_from_cache(
     available_space: Size<AvailableSpace>,
     run_mode: RunMode,
     sizing_mode: SizingMode,
-) -> Option<Size<f32>> {
+) -> Option<SizeAndBaselines> {
     for idx in 0..CACHE_SIZE {
         let entry = tree.cache_mut(node, idx);
         if let Some(entry) = entry {
@@ -189,22 +316,24 @@ fn compute_from_cache(
                 return None;
             }
 
+            let cached_size = entry.cached_size_and_baselines.size;
+
             if (known_dimensions.width == entry.known_dimensions.width
-                || known_dimensions.width == Some(entry.cached_size.width))
+                || known_dimensions.width == Some(cached_size.width))
                 && (known_dimensions.height == entry.known_dimensions.height
-                    || known_dimensions.height == Some(entry.cached_size.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() >= entry.cached_size.width))
+                        && available_space.width.unwrap() >= cached_size.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() >= entry.cached_size.height))
+                        && available_space.height.unwrap() >= cached_size.height))
             {
-                return Some(entry.cached_size);
+                return Some(entry.cached_size_and_baselines);
             }
         }
     }
@@ -212,9 +341,38 @@ fn compute_from_cache(
     None
 }
 
+/// The public interface to Taffy's hidden node algorithm implementation
+struct HiddenAlgorithm;
+impl LayoutAlgorithm for HiddenAlgorithm {
+    const NAME: &'static str = "NONE";
+
+    fn perform_layout(
+        tree: &mut impl LayoutTree,
+        node: Node,
+        _known_dimensions: Size<Option<f32>>,
+        _parent_size: Size<Option<f32>>,
+        _available_space: Size<AvailableSpace>,
+        _sizing_mode: SizingMode,
+    ) -> SizeAndBaselines {
+        perform_hidden_layout(tree, node);
+        SizeAndBaselines { size: Size::ZERO, first_baselines: Point::NONE }
+    }
+
+    fn measure_size(
+        _tree: &mut impl LayoutTree,
+        _node: Node,
+        _known_dimensions: Size<Option<f32>>,
+        _parent_size: Size<Option<f32>>,
+        _available_space: Size<AvailableSpace>,
+        _sizing_mode: SizingMode,
+    ) -> Size<f32> {
+        Size::ZERO
+    }
+}
+
 /// Creates a layout for this node and its children, recursively.
 /// Each hidden node has zero size and is placed at the origin
-fn perform_hidden_layout(tree: &mut impl LayoutTree, node: Node) -> Size<f32> {
+fn perform_hidden_layout(tree: &mut impl LayoutTree, node: Node) {
     /// Recursive function to apply hidden layout to all descendents
     fn perform_hidden_layout_inner(tree: &mut impl LayoutTree, node: Node, order: u32) {
         *tree.layout_mut(node) = Layout::with_order(order);
@@ -226,8 +384,6 @@ fn perform_hidden_layout(tree: &mut impl LayoutTree, node: Node) -> Size<f32> {
     for order in 0..tree.child_count(node) {
         perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
     }
-
-    Size::ZERO
 }
 
 /// Rounds the calculated [`NodeData`] according to the spec
diff --git a/src/geometry.rs b/src/geometry.rs
index 3df769443..21a187b00 100644
--- a/src/geometry.rs
+++ b/src/geometry.rs
@@ -441,7 +441,12 @@ pub struct Point<T> {
 
 impl Point<f32> {
     /// A [`Point`] with values (0,0), representing the origin
-    pub const ZERO: Point<f32> = Self { x: 0.0, y: 0.0 };
+    pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
+}
+
+impl Point<Option<f32>> {
+    /// A [`Point`] with values (None, None)
+    pub const NONE: Self = Self { x: None, y: None };
 }
 
 /// Generic struct which holds a "min" value and a "max" value
diff --git a/src/layout.rs b/src/layout.rs
index c9e343f6b..13fabe78e 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -22,8 +22,22 @@ pub enum SizingMode {
     InherentSize,
 }
 
+/// A struct containing both the size of a node and it's first baseline in each dimension (if it has any)
+///
+/// A baseline is the line on which text sits. Your node likely has a baseline if it is a text node, or contains
+/// children that may be text nodes. See https://www.w3.org/TR/css-writing-modes-3/#intro-baselines for details.
+/// If your node does not have a baseline (or you are unsure how to compute it), then simply return `Point::NONE`
+/// for the first_baselines field
+#[derive(Debug, Copy, Clone)]
+pub struct SizeAndBaselines {
+    /// The size of the node
+    pub size: Size<f32>,
+    /// The first baseline of the node in each dimension, if any
+    pub first_baselines: Point<Option<f32>>,
+}
+
 /// The final result of a layout algorithm for a single [`Node`](crate::node::Node).
-#[derive(Copy, Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
 pub struct Layout {
     /// The relative ordering of the node
     ///
@@ -67,6 +81,6 @@ pub struct Cache {
     /// Whether or not layout should be recomputed
     pub(crate) run_mode: RunMode,
 
-    /// The cached size of the item
-    pub(crate) cached_size: Size<f32>,
+    /// The cached size and baselines of the item
+    pub(crate) cached_size_and_baselines: SizeAndBaselines,
 }
diff --git a/src/prelude.rs b/src/prelude.rs
index 2ec946cf6..2cff4edc5 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -1,7 +1,29 @@
 //! Commonly used types
 
+use crate::compute::LayoutAlgorithm;
+use crate::layout::{SizeAndBaselines, SizingMode};
+
+/// Apply the flexbox algorithm and recursively layout the specified node
+#[inline(always)]
+pub fn layout_flexbox(
+    tree: &mut impl LayoutTree,
+    node: Node,
+    known_dimensions: Size<Option<f32>>,
+    parent_size: Size<Option<f32>>,
+    available_space: Size<AvailableSpace>,
+    sizing_mode: SizingMode,
+) -> SizeAndBaselines {
+    crate::compute::flexbox::FlexboxAlgorithm::perform_layout(
+        tree,
+        node,
+        known_dimensions,
+        parent_size,
+        available_space,
+        sizing_mode,
+    )
+}
+
 pub use crate::{
-    compute::flexbox::compute as layout_flexbox,
     geometry::{Line, Rect, Size},
     layout::Layout,
     node::{Node, Taffy},
diff --git a/test_fixtures/xalign_baseline_child_margin.html b/test_fixtures/align_baseline_child_margin.html
similarity index 88%
rename from test_fixtures/xalign_baseline_child_margin.html
rename to test_fixtures/align_baseline_child_margin.html
index 79e7e4422..00cda4c96 100644
--- a/test_fixtures/xalign_baseline_child_margin.html
+++ b/test_fixtures/align_baseline_child_margin.html
@@ -12,7 +12,7 @@
 <div id="test-root" style="width: 100px; height: 100px; flex-direction:row; align-items: baseline;">
   <div style="width: 50px; height: 50px;margin: 5px;"></div>
   <div style="flex-direction: column;width: 50px; height: 20px;">
-    <div style="width: 50px; height: 10px;margin: 1px;"></div>
+    <div style="width: 50px; height: 10px;margin: 5px;"></div>
   </div>
 </div>
 
diff --git a/test_fixtures/xalign_baseline_child_margin_percent.html b/test_fixtures/align_baseline_child_margin_percent.html
similarity index 100%
rename from test_fixtures/xalign_baseline_child_margin_percent.html
rename to test_fixtures/align_baseline_child_margin_percent.html
diff --git a/test_fixtures/xalign_baseline_child_multiline_no_override_on_secondline.html b/test_fixtures/align_baseline_child_multiline_no_override_on_secondline.html
similarity index 100%
rename from test_fixtures/xalign_baseline_child_multiline_no_override_on_secondline.html
rename to test_fixtures/align_baseline_child_multiline_no_override_on_secondline.html
diff --git a/test_fixtures/xalign_baseline_child_multiline_override.html b/test_fixtures/align_baseline_child_multiline_override.html
similarity index 100%
rename from test_fixtures/xalign_baseline_child_multiline_override.html
rename to test_fixtures/align_baseline_child_multiline_override.html
diff --git a/test_fixtures/xalign_baseline_child_padding.html b/test_fixtures/align_baseline_child_padding.html
similarity index 100%
rename from test_fixtures/xalign_baseline_child_padding.html
rename to test_fixtures/align_baseline_child_padding.html
diff --git a/test_fixtures/xalign_baseline_multiline.html b/test_fixtures/align_baseline_multiline.html
similarity index 100%
rename from test_fixtures/xalign_baseline_multiline.html
rename to test_fixtures/align_baseline_multiline.html
diff --git a/test_fixtures/xalign_baseline_multiline_row_and_column.html b/test_fixtures/align_baseline_multiline_row_and_column.html
similarity index 100%
rename from test_fixtures/xalign_baseline_multiline_row_and_column.html
rename to test_fixtures/align_baseline_multiline_row_and_column.html
diff --git a/test_fixtures/xgrid_align_items_baseline_complex.html b/test_fixtures/xgrid_align_items_baseline_complex.html
new file mode 100644
index 000000000..31ff0b017
--- /dev/null
+++ b/test_fixtures/xgrid_align_items_baseline_complex.html
@@ -0,0 +1,33 @@
+<!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: 120px; width: 120px; display: grid; grid-template-columns: 40px 40px 40px;grid-template-rows: 40px 40px 40px;align-items: baseline;">
+  <div style="height: 20px;width: 20px"></div>
+  <div style="height: 20px;width: 20px">
+    <div style="height: 10px"></div>
+  </div>
+  <div style="height: 20px;width: 20px">
+    <div style="height: 10px"></div>
+  </div>
+  <div style="height: 20px;width: 20px"></div>
+  <div style="height: 20px;width: 20px"></div>
+  <div style="height: 20px;width: 20px"></div>
+  <div style="height: 20px;width: 20px">
+    <div style="height: 10px"></div>
+  </div>
+  <div style="height: 20px;width: 20px">
+    <div style="height: 5px"></div>
+  </div>
+  <div style="height: 20px;width: 20px"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/align_baseline_child_margin.rs b/tests/generated/align_baseline_child_margin.rs
new file mode 100644
index 000000000..fc4b78bdd
--- /dev/null
+++ b/tests/generated/align_baseline_child_margin.rs
@@ -0,0 +1,87 @@
+#[test]
+fn align_baseline_child_margin() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            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),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            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),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..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, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, 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(node1).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.x);
+    assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 10f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node10.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node10.data(), 5f32, location.y);
+}
diff --git a/tests/generated/align_baseline_child_margin_percent.rs b/tests/generated/align_baseline_child_margin_percent.rs
new file mode 100644
index 000000000..f02ac320b
--- /dev/null
+++ b/tests/generated/align_baseline_child_margin_percent.rs
@@ -0,0 +1,87 @@
+#[test]
+fn align_baseline_child_margin_percent() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                right: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                top: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+                bottom: taffy::style::LengthPercentageAuto::Percent(0.05f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            margin: taffy::geometry::Rect {
+                left: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+                right: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+                top: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+                bottom: taffy::style::LengthPercentageAuto::Percent(0.01f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..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, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, 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(node1).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.x);
+    assert_eq!(location.y, 45f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 45f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 10f32, size.height);
+    assert_eq!(location.x, 1f32, "x of node {:?}. Expected {}. Actual {}", node10.data(), 1f32, location.x);
+    assert_eq!(location.y, 1f32, "y of node {:?}. Expected {}. Actual {}", node10.data(), 1f32, location.y);
+}
diff --git a/tests/generated/align_baseline_child_multiline_no_override_on_secondline.rs b/tests/generated/align_baseline_child_multiline_no_override_on_secondline.rs
new file mode 100644
index 000000000..e988cae89
--- /dev/null
+++ b/tests/generated/align_baseline_child_multiline_no_override_on_secondline.rs
@@ -0,0 +1,118 @@
+#[test]
+fn align_baseline_child_multiline_no_override_on_secondline() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(60f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node11 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node12 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node13 = taffy
+        .new_leaf(taffy::style::Style {
+            align_self: Some(taffy::style::AlignSelf::Baseline),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(25f32),
+                },
+                ..Default::default()
+            },
+            &[node10, node11, node12, node13],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..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, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 60f32, 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, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 25f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 25f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.x);
+    assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 25f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 25f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 20f32, 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, 25f32, "width of node {:?}. Expected {}. Actual {}", node11.data(), 25f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node11.data(), 10f32, size.height);
+    assert_eq!(location.x, 25f32, "x of node {:?}. Expected {}. Actual {}", node11.data(), 25f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node11.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node12).unwrap();
+    assert_eq!(size.width, 25f32, "width of node {:?}. Expected {}. Actual {}", node12.data(), 25f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node12.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node12.data(), 0f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node12.data(), 20f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node13).unwrap();
+    assert_eq!(size.width, 25f32, "width of node {:?}. Expected {}. Actual {}", node13.data(), 25f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node13.data(), 10f32, size.height);
+    assert_eq!(location.x, 25f32, "x of node {:?}. Expected {}. Actual {}", node13.data(), 25f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node13.data(), 20f32, location.y);
+}
diff --git a/tests/generated/align_baseline_child_multiline_override.rs b/tests/generated/align_baseline_child_multiline_override.rs
new file mode 100644
index 000000000..a4673a4fa
--- /dev/null
+++ b/tests/generated/align_baseline_child_multiline_override.rs
@@ -0,0 +1,119 @@
+#[test]
+fn align_baseline_child_multiline_override() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(60f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node11 = taffy
+        .new_leaf(taffy::style::Style {
+            align_self: Some(taffy::style::AlignSelf::Baseline),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node12 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node13 = taffy
+        .new_leaf(taffy::style::Style {
+            align_self: Some(taffy::style::AlignSelf::Baseline),
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(25f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(25f32),
+                },
+                ..Default::default()
+            },
+            &[node10, node11, node12, node13],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..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, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, size.width);
+    assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 60f32, 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, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 25f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 25f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 25f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 25f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 20f32, 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, 25f32, "width of node {:?}. Expected {}. Actual {}", node11.data(), 25f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node11.data(), 10f32, size.height);
+    assert_eq!(location.x, 25f32, "x of node {:?}. Expected {}. Actual {}", node11.data(), 25f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node11.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node12).unwrap();
+    assert_eq!(size.width, 25f32, "width of node {:?}. Expected {}. Actual {}", node12.data(), 25f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node12.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node12.data(), 0f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node12.data(), 20f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node13).unwrap();
+    assert_eq!(size.width, 25f32, "width of node {:?}. Expected {}. Actual {}", node13.data(), 25f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node13.data(), 10f32, size.height);
+    assert_eq!(location.x, 25f32, "x of node {:?}. Expected {}. Actual {}", node13.data(), 25f32, location.x);
+    assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node13.data(), 20f32, location.y);
+}
diff --git a/tests/generated/align_baseline_child_padding.rs b/tests/generated/align_baseline_child_padding.rs
new file mode 100644
index 000000000..650dcc43e
--- /dev/null
+++ b/tests/generated/align_baseline_child_padding.rs
@@ -0,0 +1,87 @@
+#[test]
+fn align_baseline_child_padding() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                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()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                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()
+            },
+            &[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, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, 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(node1).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, size.height);
+    assert_eq!(location.x, 45f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 45f32, location.x);
+    assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 10f32, size.height);
+    assert_eq!(location.x, 5f32, "x of node {:?}. Expected {}. Actual {}", node10.data(), 5f32, location.x);
+    assert_eq!(location.y, 5f32, "y of node {:?}. Expected {}. Actual {}", node10.data(), 5f32, location.y);
+}
diff --git a/tests/generated/align_baseline_multiline.rs b/tests/generated/align_baseline_multiline.rs
new file mode 100644
index 000000000..f8313b493
--- /dev/null
+++ b/tests/generated/align_baseline_multiline.rs
@@ -0,0 +1,122 @@
+#[test]
+fn align_baseline_multiline() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node20 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node20],
+        )
+        .unwrap();
+    let node3 = 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 node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, size.width);
+    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, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.x);
+    assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 10f32, 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(node2).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.x);
+    assert_eq!(location.y, 100f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 100f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node20).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node20.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node20.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node20.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node20.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 50f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 50f32, location.x);
+    assert_eq!(location.y, 60f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 60f32, location.y);
+}
diff --git a/tests/generated/align_baseline_multiline_row_and_column.rs b/tests/generated/align_baseline_multiline_row_and_column.rs
new file mode 100644
index 000000000..0e0d0c0b8
--- /dev/null
+++ b/tests/generated/align_baseline_multiline_row_and_column.rs
@@ -0,0 +1,122 @@
+#[test]
+fn align_baseline_multiline_row_and_column() {
+    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(50f32),
+                height: taffy::style::Dimension::Points(50f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node10 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(50f32),
+                },
+                ..Default::default()
+            },
+            &[node10],
+        )
+        .unwrap();
+    let node20 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(10f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node2 = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_direction: taffy::style::FlexDirection::Column,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(50f32),
+                    height: taffy::style::Dimension::Points(20f32),
+                },
+                ..Default::default()
+            },
+            &[node20],
+        )
+        .unwrap();
+    let node3 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size {
+                width: taffy::style::Dimension::Points(50f32),
+                height: taffy::style::Dimension::Points(20f32),
+            },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                flex_wrap: taffy::style::FlexWrap::Wrap,
+                align_items: Some(taffy::style::AlignItems::Baseline),
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Points(100f32),
+                    height: taffy::style::Dimension::Points(100f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1, node2, node3],
+        )
+        .unwrap();
+    taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+    println!("\nComputed tree:");
+    taffy::debug::print_tree(&taffy, node);
+    println!();
+    let Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+    assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 50f32, size.width);
+    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, 50f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 50f32, location.x);
+    assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node10).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node10.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node10.data(), 10f32, 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(node2).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 20f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.x);
+    assert_eq!(location.y, 100f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 100f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node20).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node20.data(), 50f32, size.width);
+    assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node20.data(), 10f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node20.data(), 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node20.data(), 0f32, location.y);
+    let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+    assert_eq!(size.width, 50f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 50f32, size.width);
+    assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 20f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 50f32, location.x);
+    assert_eq!(location.y, 90f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 90f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index 2fd953c58..829311ccb 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -106,13 +106,20 @@ mod absolute_minmax_top_left_bottom_right_max;
 mod absolute_minmax_top_left_bottom_right_min_max;
 mod align_baseline;
 mod align_baseline_child;
+mod align_baseline_child_margin;
+mod align_baseline_child_margin_percent;
 mod align_baseline_child_multiline;
+mod align_baseline_child_multiline_no_override_on_secondline;
+mod align_baseline_child_multiline_override;
+mod align_baseline_child_padding;
 mod align_baseline_child_top;
 mod align_baseline_child_top2;
 mod align_baseline_column;
 mod align_baseline_double_nested_child;
+mod align_baseline_multiline;
 mod align_baseline_multiline_column;
 mod align_baseline_multiline_column2;
+mod align_baseline_multiline_row_and_column;
 mod align_baseline_nested_child;
 mod align_baseline_nested_column;
 mod align_center_should_size_based_on_content;