gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1111HTML 1039Markdown 12TOML 94524 Definiciones

Implement legacy text alignment (#698)

* Add TextAlign style

* Add legacy text-align support to the test generator

* Implement legacy text alignment

* Fix docs

42f75c6023434c27c9d6e69e2f3f3b5818ddd8e3 · por Nico Burns · (hace 2 años) · padre 5e4dcf1e1 · ver el árbol en este commit

Delta semántico · 23

scripts/gentest/src/main.rs

scripts/gentest/test_helper.js

src/compute/block.rs

src/style/block.rs

src/style/mod.rs

src/tree/traits.rs

tests/generated/block/block_item_text_align_center.rs

tests/generated/block/block_item_text_align_left.rs

tests/generated/block/block_item_text_align_right.rs

tests/generated/block/mod.rs

14 archivos · +836 −9

diff --git a/scripts/gentest/src/main.rs b/scripts/gentest/src/main.rs
index 9b519e5be..6a5d0ff16 100644
--- a/scripts/gentest/src/main.rs
+++ b/scripts/gentest/src/main.rs
@@ -444,6 +444,16 @@ fn generate_node(ident: &str, node: &Value) -> TokenStream {
         (quote!(), quote!())
     };
 
+    let text_align = match style["textAlign"] {
+        Value::String(ref value) => match value.as_ref() {
+            "-webkit-left" => quote!(text_align: taffy::style::TextAlign::LegacyLeft,),
+            "-webkit-right" => quote!(text_align: taffy::style::TextAlign::LegacyRight,),
+            "-webkit-center" => quote!(text_align: taffy::style::TextAlign::LegacyCenter,),
+            _ => quote!(),
+        },
+        _ => quote!(),
+    };
+
     let align_items = match style["alignItems"] {
         Value::String(ref value) => match value.as_ref() {
             "start" => quote!(align_items: Some(taffy::style::AlignItems::Start),),
@@ -618,6 +628,7 @@ fn generate_node(ident: &str, node: &Value) -> TokenStream {
         #box_sizing
         #direction
         #position
+        #text_align
         #flex_direction
         #flex_wrap
         #overflow
diff --git a/scripts/gentest/test_helper.js b/scripts/gentest/test_helper.js
index f776dc65b..09a53e897 100644
--- a/scripts/gentest/test_helper.js
+++ b/scripts/gentest/test_helper.js
@@ -209,10 +209,12 @@ function describeElement(e) {
 
       position: parseEnum(e.style.position),
       direction: parseEnum(e.style.direction),
-      flexDirection: parseEnum(e.style.flexDirection),
 
       writingMode: parseEnum(e.style.writingMode),
 
+      textAlign: parseEnum(e.style.textAlign),
+
+      flexDirection: parseEnum(e.style.flexDirection),
       flexWrap: parseEnum(e.style.flexWrap),
       overflowX: parseEnum(e.style.overflowX),
       overflowY: parseEnum(e.style.overflowY),
diff --git a/src/compute/block.rs b/src/compute/block.rs
index 512e885fa..02f5d14a7 100644
--- a/src/compute/block.rs
+++ b/src/compute/block.rs
@@ -9,7 +9,7 @@ use crate::util::sys::f32_max;
 use crate::util::sys::Vec;
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
-use crate::{BoxGenerationMode, BoxSizing, LayoutBlockContainer};
+use crate::{BlockContainerStyle, BoxGenerationMode, BoxSizing, LayoutBlockContainer, TextAlign};
 
 #[cfg(feature = "content_size")]
 use super::common::content_size::compute_content_size_contribution;
@@ -190,6 +190,8 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs:
         || matches!(size.height, Some(h) if h > 0.0)
         || matches!(min_size.height, Some(h) if h > 0.0);
 
+    let text_align = style.text_align();
+
     drop(style);
 
     // 1. Generate items
@@ -219,6 +221,7 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs:
             container_outer_width,
             content_box_inset,
             resolved_content_box_inset,
+            text_align,
             own_margins_collapse_with_children,
         );
     let container_outer_height = known_dimensions
@@ -383,6 +386,7 @@ fn perform_final_layout_on_in_flow_children(
     container_outer_width: f32,
     content_box_inset: Rect<f32>,
     resolved_content_box_inset: Rect<f32>,
+    text_align: TextAlign,
     own_margins_collapse_with_children: Line<bool>,
 ) -> (Size<f32>, f32, CollapsibleMarginSet, CollapsibleMarginSet) {
     // Resolve container_inner_width for sizing child nodes using initial content_box_inset
@@ -469,11 +473,26 @@ fn perform_final_layout_on_in_flow_children(
                 x: resolved_content_box_inset.left,
                 y: committed_y_offset + active_collapsible_margin_set.resolve(),
             };
-            let location = Point {
+            let mut location = Point {
                 x: resolved_content_box_inset.left + inset_offset.x + resolved_margin.left,
                 y: committed_y_offset + inset_offset.y + y_margin_offset,
             };
 
+            // Apply alignment
+            let item_outer_width = item_layout.size.width + resolved_margin.horizontal_axis_sum();
+            if item_outer_width < container_inner_width {
+                match text_align {
+                    TextAlign::Auto => {
+                        // Do nothing
+                    }
+                    TextAlign::LegacyLeft => {
+                        // Do nothing. Left aligned by default.
+                    }
+                    TextAlign::LegacyRight => location.x += container_inner_width - item_outer_width,
+                    TextAlign::LegacyCenter => location.x += (container_inner_width - item_outer_width) / 2.0,
+                }
+            }
+
             let scrollbar_size = Size {
                 width: if item.overflow.y == Overflow::Scroll { item.scrollbar_width } else { 0.0 },
                 height: if item.overflow.x == Overflow::Scroll { item.scrollbar_width } else { 0.0 },
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index 8a44ed36d..91e89775f 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -153,7 +153,7 @@ struct AlgoConstants {
     inner_container_size: Size<f32>,
 }
 
-/// Computes the layout of [`LayoutPartialTree`] according to the flexbox algorithm
+/// Computes the layout of a box according to the flexbox algorithm
 pub fn compute_flexbox_layout(
     tree: &mut impl LayoutFlexboxContainer,
     node: NodeId,
diff --git a/src/style/block.rs b/src/style/block.rs
new file mode 100644
index 000000000..04b758336
--- /dev/null
+++ b/src/style/block.rs
@@ -0,0 +1,26 @@
+//! Style types for Block layout
+use crate::{CoreStyle, Style};
+
+/// The set of styles required for a CSS Grid item (child of a CSS Grid container)
+pub trait BlockContainerStyle: CoreStyle {
+    /// Defines which row in the grid the item should start and end at
+    #[inline(always)]
+    fn text_align(&self) -> TextAlign {
+        Style::DEFAULT.text_align
+    }
+}
+
+/// Used by block layout to implement the legacy behaviour of `<center>` and `<div align="left | right | center">`
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum TextAlign {
+    /// No special legacy text align behaviour.
+    #[default]
+    Auto,
+    /// Corresponds to `-webkit-left` or `-moz-left` in browsers
+    LegacyLeft,
+    /// Corresponds to `-webkit-right` or `-moz-right` in browsers
+    LegacyRight,
+    /// Corresponds to `-webkit-center` or `-moz-center` in browsers
+    LegacyCenter,
+}
diff --git a/src/style/mod.rs b/src/style/mod.rs
index d32924879..67d8e047a 100644
--- a/src/style/mod.rs
+++ b/src/style/mod.rs
@@ -2,17 +2,20 @@
 mod alignment;
 mod dimension;
 
+#[cfg(feature = "block_layout")]
+mod block;
 #[cfg(feature = "flexbox")]
 mod flex;
+#[cfg(feature = "grid")]
+mod grid;
 
 pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf};
 pub use self::dimension::{AvailableSpace, Dimension, LengthPercentage, LengthPercentageAuto};
 
+#[cfg(feature = "block_layout")]
+pub use self::block::{BlockContainerStyle, TextAlign};
 #[cfg(feature = "flexbox")]
 pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle};
-
-#[cfg(feature = "grid")]
-mod grid;
 #[cfg(feature = "grid")]
 pub(crate) use self::grid::{GenericGridPlacement, OriginZeroGridPlacement};
 #[cfg(feature = "grid")]
@@ -20,6 +23,7 @@ pub use self::grid::{
     GridAutoFlow, GridContainerStyle, GridItemStyle, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction,
     MinTrackSizingFunction, NonRepeatedTrackSizingFunction, TrackSizingFunction,
 };
+
 use crate::geometry::{Point, Rect, Size};
 
 #[cfg(feature = "grid")]
@@ -394,13 +398,20 @@ pub struct Style {
     #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
     pub gap: Size<LengthPercentage>,
 
-    // Flexbox properties
+    // Block container properties
+    /// How items elements should aligned in the inline axis
+    #[cfg(feature = "block_layout")]
+    pub text_align: TextAlign,
+
+    // Flexbox container properties
     /// Which direction does the main axis flow in?
     #[cfg(feature = "flexbox")]
     pub flex_direction: FlexDirection,
     /// Should elements wrap, or stay in a single line?
     #[cfg(feature = "flexbox")]
     pub flex_wrap: FlexWrap,
+
+    // Flexbox item properties
     /// Sets the initial main axis size of the item
     #[cfg(feature = "flexbox")]
     pub flex_basis: Dimension,
@@ -472,6 +483,9 @@ impl Style {
         align_content: None,
         #[cfg(any(feature = "flexbox", feature = "grid"))]
         justify_content: None,
+        // Block
+        #[cfg(feature = "block_layout")]
+        text_align: TextAlign::Auto,
         // Flexbox
         #[cfg(feature = "flexbox")]
         flex_direction: FlexDirection::Row,
@@ -629,6 +643,22 @@ impl<T: CoreStyle> CoreStyle for &'_ T {
     }
 }
 
+#[cfg(feature = "block_layout")]
+impl BlockContainerStyle for &Style {
+    #[inline(always)]
+    fn text_align(&self) -> TextAlign {
+        self.text_align
+    }
+}
+
+#[cfg(feature = "block_layout")]
+impl<T: BlockContainerStyle> BlockContainerStyle for &'_ T {
+    #[inline(always)]
+    fn text_align(&self) -> TextAlign {
+        (*self).text_align()
+    }
+}
+
 #[cfg(feature = "flexbox")]
 impl FlexboxContainerStyle for &Style {
     #[inline(always)]
@@ -890,6 +920,8 @@ mod tests {
             padding: Rect::zero(),
             border: Rect::zero(),
             gap: Size::zero(),
+            #[cfg(feature = "block_layout")]
+            text_align: Default::default(),
             #[cfg(feature = "flexbox")]
             flex_grow: 0.0,
             #[cfg(feature = "flexbox")]
diff --git a/src/tree/traits.rs b/src/tree/traits.rs
index a549232ea..e9382ae95 100644
--- a/src/tree/traits.rs
+++ b/src/tree/traits.rs
@@ -133,6 +133,8 @@ use crate::style::{AvailableSpace, CoreStyle};
 use crate::style::{FlexboxContainerStyle, FlexboxItemStyle};
 #[cfg(feature = "grid")]
 use crate::style::{GridContainerStyle, GridItemStyle};
+#[cfg(feature = "block_layout")]
+use crate::BlockContainerStyle;
 use core::ops::{Deref, DerefMut};
 
 /// This trait is Taffy's abstraction for downward tree traversal.
@@ -251,7 +253,7 @@ pub trait LayoutGridContainer: LayoutPartialTree {
 /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Block layout
 pub trait LayoutBlockContainer: LayoutPartialTree {
     /// The style type representing the CSS Block container's styles
-    type BlockContainerStyle<'a>: CoreStyle
+    type BlockContainerStyle<'a>: BlockContainerStyle
     where
         Self: 'a;
     /// The style type representing each CSS Block item's styles
diff --git a/test_fixtures/block/block_item_text_align_center.html b/test_fixtures/block/block_item_text_align_center.html
new file mode 100644
index 000000000..4fb5dcdb3
--- /dev/null
+++ b/test_fixtures/block/block_item_text_align_center.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+</head>
+<body>
+
+<div id="test-root" style="display: block; width: 200px; height: 200px; text-align: -webkit-center;">
+  <div style="max-width: 100px; height: 50px;"></div>
+  <div style="max-width: 300px; height: 50px;"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/block/block_item_text_align_left.html b/test_fixtures/block/block_item_text_align_left.html
new file mode 100644
index 000000000..c91efe9ae
--- /dev/null
+++ b/test_fixtures/block/block_item_text_align_left.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+</head>
+<body>
+
+<div id="test-root" style="display: block; width: 200px; height: 200px; text-align: -webkit-left;">
+  <div style="max-width: 100px; height: 50px;"></div>
+  <div style="max-width: 300px; height: 50px;"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/block/block_item_text_align_right.html b/test_fixtures/block/block_item_text_align_right.html
new file mode 100644
index 000000000..80a27eec4
--- /dev/null
+++ b/test_fixtures/block/block_item_text_align_right.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <script src="../../scripts/gentest/test_helper.js"></script>
+  <link rel="stylesheet" type="text/css" href="../../scripts/gentest/test_base_style.css">
+  <title>
+    Test description
+  </title>
+</head>
+<body>
+
+<div id="test-root" style="display: block; width: 200px; height: 200px; text-align: -webkit-right;">
+  <div style="max-width: 100px; height: 50px;"></div>
+  <div style="max-width: 300px; height: 50px;"></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/block/block_item_text_align_center.rs b/tests/generated/block/block_item_text_align_center.rs
new file mode 100644
index 000000000..b64c3c2c8
--- /dev/null
+++ b/tests/generated/block/block_item_text_align_center.rs
@@ -0,0 +1,226 @@
+#[test]
+#[allow(non_snake_case)]
+fn block_item_text_align_center__border_box() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout, TaffyTree};
+    let mut taffy: TaffyTree<crate::TextMeasure> = TaffyTree::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(100f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(300f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Block,
+                text_align: taffy::style::TextAlign::LegacyCenter,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(200f32),
+                    height: taffy::style::Dimension::Length(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap();
+    println!("\nComputed tree:");
+    taffy.print_tree(node);
+    println!();
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node, 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node, 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0, 100f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0, 50f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node0, 50f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1, 200f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1, 50f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_height()
+    );
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn block_item_text_align_center__content_box() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout, TaffyTree};
+    let mut taffy: TaffyTree<crate::TextMeasure> = TaffyTree::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            box_sizing: taffy::style::BoxSizing::ContentBox,
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(100f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            box_sizing: taffy::style::BoxSizing::ContentBox,
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(300f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Block,
+                box_sizing: taffy::style::BoxSizing::ContentBox,
+                text_align: taffy::style::TextAlign::LegacyCenter,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(200f32),
+                    height: taffy::style::Dimension::Length(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap();
+    println!("\nComputed tree:");
+    taffy.print_tree(node);
+    println!();
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node, 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node, 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0, 100f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0, 50f32, size.height);
+    assert_eq!(location.x, 50f32, "x of node {:?}. Expected {}. Actual {}", node0, 50f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1, 200f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1, 50f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_height()
+    );
+}
diff --git a/tests/generated/block/block_item_text_align_left.rs b/tests/generated/block/block_item_text_align_left.rs
new file mode 100644
index 000000000..82513df84
--- /dev/null
+++ b/tests/generated/block/block_item_text_align_left.rs
@@ -0,0 +1,226 @@
+#[test]
+#[allow(non_snake_case)]
+fn block_item_text_align_left__border_box() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout, TaffyTree};
+    let mut taffy: TaffyTree<crate::TextMeasure> = TaffyTree::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(100f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(300f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Block,
+                text_align: taffy::style::TextAlign::LegacyLeft,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(200f32),
+                    height: taffy::style::Dimension::Length(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap();
+    println!("\nComputed tree:");
+    taffy.print_tree(node);
+    println!();
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node, 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node, 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0, 100f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1, 200f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1, 50f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_height()
+    );
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn block_item_text_align_left__content_box() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout, TaffyTree};
+    let mut taffy: TaffyTree<crate::TextMeasure> = TaffyTree::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            box_sizing: taffy::style::BoxSizing::ContentBox,
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(100f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            box_sizing: taffy::style::BoxSizing::ContentBox,
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(300f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Block,
+                box_sizing: taffy::style::BoxSizing::ContentBox,
+                text_align: taffy::style::TextAlign::LegacyLeft,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(200f32),
+                    height: taffy::style::Dimension::Length(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap();
+    println!("\nComputed tree:");
+    taffy.print_tree(node);
+    println!();
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node, 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node, 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0, 100f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1, 200f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1, 50f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_height()
+    );
+}
diff --git a/tests/generated/block/block_item_text_align_right.rs b/tests/generated/block/block_item_text_align_right.rs
new file mode 100644
index 000000000..0c4f6d8d4
--- /dev/null
+++ b/tests/generated/block/block_item_text_align_right.rs
@@ -0,0 +1,226 @@
+#[test]
+#[allow(non_snake_case)]
+fn block_item_text_align_right__border_box() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout, TaffyTree};
+    let mut taffy: TaffyTree<crate::TextMeasure> = TaffyTree::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(100f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(300f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Block,
+                text_align: taffy::style::TextAlign::LegacyRight,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(200f32),
+                    height: taffy::style::Dimension::Length(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap();
+    println!("\nComputed tree:");
+    taffy.print_tree(node);
+    println!();
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node, 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node, 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0, 100f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0, 50f32, size.height);
+    assert_eq!(location.x, 100f32, "x of node {:?}. Expected {}. Actual {}", node0, 100f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1, 200f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1, 50f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_height()
+    );
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn block_item_text_align_right__content_box() {
+    #[allow(unused_imports)]
+    use taffy::{prelude::*, tree::Layout, TaffyTree};
+    let mut taffy: TaffyTree<crate::TextMeasure> = TaffyTree::new();
+    let node0 = taffy
+        .new_leaf(taffy::style::Style {
+            box_sizing: taffy::style::BoxSizing::ContentBox,
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(100f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node1 = taffy
+        .new_leaf(taffy::style::Style {
+            box_sizing: taffy::style::BoxSizing::ContentBox,
+            size: taffy::geometry::Size { width: auto(), height: taffy::style::Dimension::Length(50f32) },
+            max_size: taffy::geometry::Size { width: taffy::style::Dimension::Length(300f32), height: auto() },
+            ..Default::default()
+        })
+        .unwrap();
+    let node = taffy
+        .new_with_children(
+            taffy::style::Style {
+                display: taffy::style::Display::Block,
+                box_sizing: taffy::style::BoxSizing::ContentBox,
+                text_align: taffy::style::TextAlign::LegacyRight,
+                size: taffy::geometry::Size {
+                    width: taffy::style::Dimension::Length(200f32),
+                    height: taffy::style::Dimension::Length(200f32),
+                },
+                ..Default::default()
+            },
+            &[node0, node1],
+        )
+        .unwrap();
+    taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap();
+    println!("\nComputed tree:");
+    taffy.print_tree(node);
+    println!();
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node, 200f32, size.width);
+    assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node, 200f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap();
+    assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0, 100f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node0, 50f32, size.height);
+    assert_eq!(location.x, 100f32, "x of node {:?}. Expected {}. Actual {}", node0, 100f32, location.x);
+    assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node0,
+        0f32,
+        layout.scroll_height()
+    );
+    #[cfg_attr(not(feature = "content_size"), allow(unused_variables))]
+    let layout @ Layout { size, location, .. } = taffy.layout(node1).unwrap();
+    assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node1, 200f32, size.width);
+    assert_eq!(size.height, 50f32, "height of node {:?}. Expected {}. Actual {}", node1, 50f32, size.height);
+    assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1, 0f32, location.x);
+    assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node1, 50f32, location.y);
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_width(),
+        0f32,
+        "scroll_width of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_width()
+    );
+    #[cfg(feature = "content_size")]
+    assert_eq!(
+        layout.scroll_height(),
+        0f32,
+        "scroll_height of node {:?}. Expected {}. Actual {}",
+        node1,
+        0f32,
+        layout.scroll_height()
+    );
+}
diff --git a/tests/generated/block/mod.rs b/tests/generated/block/mod.rs
index dacd4f83d..621d0358a 100644
--- a/tests/generated/block/mod.rs
+++ b/tests/generated/block/mod.rs
@@ -81,6 +81,9 @@ mod block_inset_percentage;
 mod block_intrinsic_width;
 mod block_item_max_width;
 mod block_item_min_width_overrides_max_width;
+mod block_item_text_align_center;
+mod block_item_text_align_left;
+mod block_item_text_align_right;
 mod block_margin_auto_bottom;
 mod block_margin_auto_bottom_and_top;
 mod block_margin_auto_left;