gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Sutichaykuna

Remove `LayoutAlgorithm` trait (#562)

* Rename SizeBaselinesAndMargins to LayoutOutput

* Remove LayoutAlgorithm trait + add LayoutInput struct

* Implement fmt::Display for style::Display + use in taffy_tree compute function

* Update release notes

daa07e0f4e3e009f5b0c11ada5df9785efd4b2c2 · ruwaq Nico Burns · (3 wata ñawpaq) · tayta 67f286f36 · kay commitpi sach'ata qhaway

Semántico sayk'uy · 49

src/compute/block.rs

src/compute/flexbox.rs

src/compute/grid/mod.rs

src/compute/leaf.rs

src/compute/mod.rs

src/compute/taffy_tree.rs

src/style/mod.rs

src/tree/cache.rs

  • silq'uyninpi t'ikrakurqan struct CacheEntry pub
  • silq'uyninpi t'ikrakurqan fn get pub
  • silq'uyninpi t'ikrakurqan fn store pub

src/tree/layout.rs

src/tree/mod.rs

src/tree/taffy_tree/tree.rs

13 qillqakuna · +166 −501

diff --git a/RELEASES.md b/RELEASES.md
index 0dd1e7e7f..10f3bf388 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -87,11 +87,16 @@ Example usage change:
 ### Added
 
 - Support for [CSS Block layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout/Block_and_Inline_Layout_in_Normal_Flow#elements_participating_in_a_block_formatting_context) has been added. This can be used via the new `Display::Block` variant of the `Display` enum. Note that inline, inline-block and float have *not* been implemented. The use case supported is block container nodes which contain block-level children.
+- Support for running each layout algorithm individually on a single node via the following top-level functions:
+  - `compute_flexbox_layout`
+  - `compute_grid_layout`
+  - `compute_leaf_layout`
+  - `compute_hidden_layout`
 - Added `insert_child_at_index()` method to the `Taffy` tree. This can be used to insert a child node at any position instead of just the end.
 
 ### Removed
 
-- `layout_flexbox()` has been removed from the prelude. Use `FlexboxAlgorithm::perform_layout()` instead.
+- `layout_flexbox()` has been removed from the prelude. Use `taffy::compute_flexbox_layout` instead.
 - The following methods have been removed from the `LayoutTree` trait: `parent`, `is_childless`, `layout`, `measure_node`, `needs_measure`, `cache_mut` and `mark_dirty`. These no longer need to be implemented in custom implementations of `LayoutTree`.
 
 ### Changes
diff --git a/src/compute/block.rs b/src/compute/block.rs
index dd27bac88..19fbb3baf 100644
--- a/src/compute/block.rs
+++ b/src/compute/block.rs
@@ -1,9 +1,8 @@
 //! Computes the CSS block layout algorithm in the case that the block container being laid out contains only block-level boxes
-use crate::compute::LayoutAlgorithm;
 use crate::geometry::{Line, Point, Rect, Size};
 use crate::style::{AvailableSpace, Display, LengthPercentageAuto, Overflow, Position};
 use crate::style_helpers::TaffyMaxContent;
-use crate::tree::{CollapsibleMarginSet, Layout, RunMode, SizeBaselinesAndMargins, SizingMode};
+use crate::tree::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
 use crate::tree::{LayoutTree, NodeId};
 use crate::util::debug::debug_log;
 use crate::util::sys::f32_max;
@@ -11,53 +10,6 @@ use crate::util::sys::Vec;
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
 
-/// The public interface to Taffy's Block algorithm implementation
-pub struct BlockAlgorithm;
-impl LayoutAlgorithm for BlockAlgorithm {
-    const NAME: &'static str = "BLOCK";
-
-    fn perform_layout(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins {
-        compute(
-            tree,
-            node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            RunMode::PerformLayout,
-            vertical_margins_are_collapsible,
-        )
-    }
-
-    fn measure_size(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        vertical_margins_are_collapsible: Line<bool>,
-    ) -> Size<f32> {
-        compute(
-            tree,
-            node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            RunMode::ComputeSize,
-            vertical_margins_are_collapsible,
-        )
-        .size
-    }
-}
-
 /// Per-child data that is accumulated and modified over the course of the layout algorithm
 struct BlockItem {
     /// The identifier for the associated node
@@ -93,15 +45,8 @@ struct BlockItem {
 }
 
 /// Computes the layout of [`LayoutTree`] according to the block layout algorithm
-pub fn compute(
-    tree: &mut impl LayoutTree,
-    node_id: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-    vertical_margins_are_collapsible: Line<bool>,
-) -> SizeBaselinesAndMargins {
+pub fn compute_block_layout(tree: &mut impl LayoutTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
+    let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
     let style = tree.style(node_id);
 
     // Pull these out earlier to avoid borrowing issues
@@ -140,27 +85,15 @@ pub fn compute(
     }
 
     debug_log!("BLOCK");
-    compute_inner(
-        tree,
-        node_id,
-        styled_based_known_dimensions,
-        parent_size,
-        available_space,
-        run_mode,
-        vertical_margins_are_collapsible,
-    )
+    compute_inner(tree, node_id, LayoutInput { known_dimensions: styled_based_known_dimensions, ..inputs })
 }
 
 /// Computes the layout of [`LayoutTree`] according to the block layout algorithm
-fn compute_inner(
-    tree: &mut impl LayoutTree,
-    node_id: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-    vertical_margins_are_collapsible: Line<bool>,
-) -> SizeBaselinesAndMargins {
+fn compute_inner(tree: &mut impl LayoutTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
+    let LayoutInput {
+        known_dimensions, parent_size, available_space, run_mode, vertical_margins_are_collapsible, ..
+    } = inputs;
+
     let style = tree.style(node_id);
     let raw_padding = style.padding;
     let raw_border = style.border;
@@ -282,7 +215,7 @@ fn compute_inner(
     let can_be_collapsed_through =
         !has_styles_preventing_being_collapsed_through && all_in_flow_children_can_be_collapsed_through;
 
-    SizeBaselinesAndMargins {
+    LayoutOutput {
         size: final_outer_size,
         first_baselines: Point::NONE,
         top_margin: if own_margins_collapse_with_children.start {
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index 39ca93790..6f23973e0 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -2,7 +2,6 @@
 use core::f32;
 
 use crate::compute::common::alignment::compute_alignment_offset;
-use crate::compute::LayoutAlgorithm;
 use crate::geometry::{Line, Point, Rect, Size};
 use crate::prelude::{TaffyMaxContent, TaffyMinContent};
 use crate::style::{
@@ -10,7 +9,7 @@ use crate::style::{
     LengthPercentageAuto, Overflow, Position,
 };
 use crate::style::{FlexDirection, Style};
-use crate::tree::{Layout, RunMode, SizeBaselinesAndMargins, SizingMode};
+use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
 use crate::tree::{LayoutTree, NodeId};
 use crate::util::debug::debug_log;
 use crate::util::sys::Vec;
@@ -18,36 +17,6 @@ use crate::util::sys::{f32_max, new_vec_with_capacity};
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
 
-/// The public interface to Taffy's Flexbox algorithm implementation
-pub struct FlexboxAlgorithm;
-impl LayoutAlgorithm for FlexboxAlgorithm {
-    const NAME: &'static str = "FLEXBOX";
-
-    fn perform_layout(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        _vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins {
-        compute(tree, node, known_dimensions, parent_size, available_space, RunMode::PerformLayout)
-    }
-
-    fn measure_size(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        _vertical_margins_are_collapsible: Line<bool>,
-    ) -> 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
@@ -181,14 +150,8 @@ struct AlgoConstants {
 }
 
 /// Computes the layout of [`LayoutTree`] according to the flexbox algorithm
-pub fn compute(
-    tree: &mut impl LayoutTree,
-    node: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-) -> SizeBaselinesAndMargins {
+pub fn compute_flexbox_layout(tree: &mut impl LayoutTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+    let LayoutInput { known_dimensions, parent_size, run_mode, .. } = inputs;
     let style = tree.style(node);
 
     // Pull these out earlier to avoid borrowing issues
@@ -214,18 +177,13 @@ pub fn compute(
     }
 
     debug_log!("FLEX: single-pass");
-    compute_preliminary(tree, node, styled_based_known_dimensions, parent_size, available_space, run_mode)
+    compute_preliminary(tree, node, LayoutInput { known_dimensions: styled_based_known_dimensions, ..inputs })
 }
 
 /// Compute a preliminary size for an item
-fn compute_preliminary(
-    tree: &mut impl LayoutTree,
-    node: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-) -> SizeBaselinesAndMargins {
+fn compute_preliminary(tree: &mut impl LayoutTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+    let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
+
     // 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);
 
@@ -402,10 +360,7 @@ fn compute_preliminary(
             })
     };
 
-    SizeBaselinesAndMargins::from_size_and_baselines(
-        constants.container_size,
-        Point { x: None, y: first_vertical_baseline },
-    )
+    LayoutOutput::from_size_and_baselines(constants.container_size, Point { x: None, y: first_vertical_baseline })
 }
 
 /// Compute constants that can be reused during the flexbox algorithm.
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index 3869201ab..5342102fd 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -4,7 +4,7 @@ use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis};
 use crate::geometry::{Line, Point, Rect, Size};
 use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Display, Overflow, Position};
 use crate::style_helpers::*;
-use crate::tree::{Layout, RunMode, SizeBaselinesAndMargins, SizingMode};
+use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
 use crate::tree::{LayoutTree, NodeId};
 use crate::util::debug::debug_log;
 use crate::util::sys::{f32_max, GridTrackVec, Vec};
@@ -21,8 +21,6 @@ use types::{CellOccupancyMatrix, GridTrack};
 
 pub(crate) use types::{GridCoordinate, GridLine, OriginZeroLine};
 
-use super::LayoutAlgorithm;
-
 mod alignment;
 mod explicit_grid;
 mod implicit_grid;
@@ -31,50 +29,15 @@ mod track_sizing;
 mod types;
 mod util;
 
-/// The public interface to Taffy's CSS Grid algorithm implementation
-pub struct CssGridAlgorithm;
-impl LayoutAlgorithm for CssGridAlgorithm {
-    const NAME: &'static str = "CSS GRID";
-
-    fn perform_layout(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        _vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins {
-        compute(tree, node, known_dimensions, parent_size, available_space, RunMode::PerformLayout)
-    }
-
-    fn measure_size(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        _vertical_margins_are_collapsible: Line<bool>,
-    ) -> 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
 ///   - Placing items (which also resolves the implicit grid)
 ///   - Track (row/column) sizing
 ///   - Alignment & Final item placement
-pub fn compute(
-    tree: &mut impl LayoutTree,
-    node: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-) -> SizeBaselinesAndMargins {
+pub fn compute_grid_layout(tree: &mut impl LayoutTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+    let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
+
     let get_child_styles_iter = |node| tree.children(node).map(|child_node: NodeId| tree.style(child_node));
     let style = tree.style(node).clone();
     let child_styles_iter = get_child_styles_iter(node);
@@ -542,8 +505,5 @@ pub fn compute(
         layout.location.y + item.baseline.unwrap_or(layout.size.height)
     };
 
-    SizeBaselinesAndMargins::from_size_and_baselines(
-        container_border_box,
-        Point { x: None, y: Some(grid_container_baseline) },
-    )
+    LayoutOutput::from_size_and_baselines(container_border_box, Point { x: None, y: Some(grid_container_baseline) })
 }
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index 6117c4ba4..7d4b03d87 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -4,63 +4,25 @@ use crate::geometry::{Point, Size};
 use crate::style::{AvailableSpace, Display, Overflow, Position, Style};
 use crate::tree::CollapsibleMarginSet;
 use crate::tree::NodeId;
-use crate::tree::{SizeBaselinesAndMargins, SizingMode};
+use crate::tree::{LayoutInput, LayoutOutput, SizingMode};
 use crate::util::debug::debug_log;
 use crate::util::sys::f32_max;
 use crate::util::MaybeMath;
 use crate::util::{MaybeResolve, ResolveOrZero};
 
-/// Perform full layout on a leaf node
-#[allow(clippy::too_many_arguments)]
-pub(crate) fn perform_layout<NodeContext, MeasureFunction>(
-    style: &Style,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    sizing_mode: SizingMode,
-    measure_function: MeasureFunction,
-    node_id: NodeId,
-    context: Option<&mut NodeContext>,
-) -> SizeBaselinesAndMargins
-where
-    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
-{
-    compute(style, known_dimensions, parent_size, available_space, sizing_mode, measure_function, node_id, context)
-}
-
-/// Measure a leaf node's size
-#[allow(clippy::too_many_arguments)]
-pub(crate) fn measure_size<NodeContext, MeasureFunction>(
-    style: &Style,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    sizing_mode: SizingMode,
-    measure_function: MeasureFunction,
-    node_id: NodeId,
-    context: Option<&mut NodeContext>,
-) -> Size<f32>
-where
-    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
-{
-    compute(style, known_dimensions, parent_size, available_space, sizing_mode, measure_function, node_id, context).size
-}
-
 /// Compute the size of a leaf node (node with no children)
-#[allow(clippy::too_many_arguments)]
-pub fn compute<NodeContext, MeasureFunction>(
-    style: &Style,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    sizing_mode: SizingMode,
+pub fn compute_leaf_layout<NodeContext, MeasureFunction>(
     mut measure_function: MeasureFunction,
     node_id: NodeId,
+    inputs: LayoutInput,
+    style: &Style,
     context: Option<&mut NodeContext>,
-) -> SizeBaselinesAndMargins
+) -> LayoutOutput
 where
     MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
 {
+    let LayoutInput { known_dimensions, parent_size, available_space, sizing_mode, .. } = inputs;
+
     // Resolve node's preferred/min/max sizes (width/heights) against the available space (percentages resolve to pixel values)
     // For ContentSize mode, we pretend that the node has no size styles as these should be ignored.
     let (node_size, node_min_size, node_max_size, aspect_ratio) = match sizing_mode {
@@ -124,7 +86,7 @@ where
         let size = Size { width, height }
             .maybe_clamp(node_min_size, node_max_size)
             .maybe_max(padding_border.sum_axes().map(Some));
-        return SizeBaselinesAndMargins {
+        return LayoutOutput {
             size,
             first_baselines: Point::NONE,
             top_margin: CollapsibleMarginSet::ZERO,
@@ -166,7 +128,7 @@ where
         };
         let size = size.maybe_max(padding_border.sum_axes().map(Some));
 
-        return SizeBaselinesAndMargins {
+        return LayoutOutput {
             size,
             first_baselines: Point::NONE,
             top_margin: CollapsibleMarginSet::ZERO,
@@ -197,7 +159,7 @@ where
         height: f32_max(size.height, aspect_ratio.map(|ratio| size.width / ratio).unwrap_or(0.0)),
     };
 
-    SizeBaselinesAndMargins {
+    LayoutOutput {
         size,
         first_baselines: Point::NONE,
         top_margin: CollapsibleMarginSet::ZERO,
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 48946310f..c1e43dcd4 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -3,8 +3,6 @@
 pub(crate) mod common;
 pub(crate) mod leaf;
 
-pub use leaf::compute;
-
 #[cfg(feature = "block_layout")]
 pub(crate) mod block;
 
@@ -14,84 +12,25 @@ pub(crate) mod flexbox;
 #[cfg(feature = "grid")]
 pub(crate) mod grid;
 
-use crate::geometry::{Line, Size};
-use crate::style::AvailableSpace;
-use crate::tree::{Layout, LayoutTree, NodeId, SizeBaselinesAndMargins, SizingMode};
+pub use leaf::compute_leaf_layout;
 
 #[cfg(feature = "block_layout")]
-pub use self::block::BlockAlgorithm;
+pub use self::block::compute_block_layout;
 
 #[cfg(feature = "flexbox")]
-pub use self::flexbox::FlexboxAlgorithm;
+pub use self::flexbox::compute_flexbox_layout;
 
 #[cfg(feature = "grid")]
-pub use self::grid::CssGridAlgorithm;
+pub use self::grid::compute_grid_layout;
 
 #[cfg(feature = "taffy_tree")]
 pub(crate) mod taffy_tree;
 
-/// A common interface that all Taffy layout algorithms conform to
-pub 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: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        sizing_mode: SizingMode,
-        vertical_margins_are_collapsible: Line<bool>,
-    ) -> Size<f32>;
-
-    /// Perform a full layout on the node given the specified constraints
-    fn perform_layout(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        sizing_mode: SizingMode,
-        vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins;
-}
-
-/// The public interface to Taffy's hidden node algorithm implementation
-pub struct HiddenAlgorithm;
-impl LayoutAlgorithm for HiddenAlgorithm {
-    const NAME: &'static str = "NONE";
-
-    fn perform_layout(
-        tree: &mut impl LayoutTree,
-        node: NodeId,
-        _known_dimensions: Size<Option<f32>>,
-        _parent_size: Size<Option<f32>>,
-        _available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        _vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins {
-        perform_hidden_layout(tree, node);
-        SizeBaselinesAndMargins::HIDDEN
-    }
-
-    fn measure_size(
-        _tree: &mut impl LayoutTree,
-        _node: NodeId,
-        _known_dimensions: Size<Option<f32>>,
-        _parent_size: Size<Option<f32>>,
-        _available_space: Size<AvailableSpace>,
-        _sizing_mode: SizingMode,
-        _vertical_margins_are_collapsible: Line<bool>,
-    ) -> Size<f32> {
-        Size::ZERO
-    }
-}
+use crate::tree::{Layout, LayoutOutput, LayoutTree, NodeId};
 
 /// 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: NodeId) {
+pub fn compute_hidden_layout(tree: &mut impl LayoutTree, node: NodeId) -> LayoutOutput {
     /// Recursive function to apply hidden layout to all descendents
     fn perform_hidden_layout_inner(tree: &mut impl LayoutTree, node: NodeId, order: u32) {
         *tree.layout_mut(node) = Layout::with_order(order);
@@ -103,11 +42,13 @@ fn perform_hidden_layout(tree: &mut impl LayoutTree, node: NodeId) {
     for order in 0..tree.child_count(node) {
         perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
     }
+
+    LayoutOutput::HIDDEN
 }
 
 #[cfg(test)]
 mod tests {
-    use super::perform_hidden_layout;
+    use super::compute_hidden_layout;
     use crate::geometry::{Point, Size};
     use crate::style::{Display, Style};
     use crate::tree::TaffyView;
@@ -133,7 +74,7 @@ mod tests {
             )
             .unwrap();
 
-        perform_hidden_layout(
+        compute_hidden_layout(
             &mut TaffyView { taffy: &mut taffy, measure_function: |_, _, _, _| Size::ZERO },
             root.into(),
         );
diff --git a/src/compute/taffy_tree.rs b/src/compute/taffy_tree.rs
index 6339b3914..916b6e3a7 100644
--- a/src/compute/taffy_tree.rs
+++ b/src/compute/taffy_tree.rs
@@ -1,22 +1,19 @@
 //! Computation specific for the default `Taffy` tree implementation
-
-use crate::compute::{leaf, LayoutAlgorithm};
+use crate::compute::leaf::compute_leaf_layout;
 use crate::geometry::{Line, Point, Size};
 use crate::style::{AvailableSpace, Display};
 use crate::tree::{
-    Layout, LayoutTree, NodeId, RunMode, SizeBaselinesAndMargins, SizingMode, Taffy, TaffyError, TaffyView,
+    Layout, LayoutInput, LayoutOutput, LayoutTree, NodeId, RunMode, SizingMode, Taffy, TaffyError, TaffyView,
 };
 use crate::util::debug::{debug_log, debug_log_node, debug_pop_node, debug_push_node};
 use crate::util::sys::round;
 
 #[cfg(feature = "block_layout")]
-use crate::compute::BlockAlgorithm;
-
+use crate::compute::compute_block_layout;
 #[cfg(feature = "flexbox")]
-use crate::compute::FlexboxAlgorithm;
-
+use crate::compute::compute_flexbox_layout;
 #[cfg(feature = "grid")]
-use crate::compute::CssGridAlgorithm;
+use crate::compute::compute_grid_layout;
 
 /// Updates the stored layout of the provided `node` and its children
 pub(crate) fn compute_layout<NodeContext, MeasureFunction>(
@@ -28,14 +25,17 @@ where
     MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
 {
     // Recursively compute node layout
-    let size_and_baselines = perform_node_layout(
+    let size_and_baselines = compute_node_layout(
         taffy_view,
         root,
-        Size::NONE,
-        available_space.into_options(),
-        available_space,
-        SizingMode::InherentSize,
-        Line::FALSE,
+        LayoutInput {
+            known_dimensions: Size::NONE,
+            parent_size: available_space.into_options(),
+            available_space,
+            sizing_mode: SizingMode::InherentSize,
+            run_mode: RunMode::PerformLayout,
+            vertical_margins_are_collapsible: Line::FALSE,
+        },
     );
 
     let layout = Layout { order: 0, size: size_and_baselines.size, location: Point::ZERO };
@@ -49,80 +49,25 @@ where
     Ok(())
 }
 
-/// Perform full layout on a node. Chooses which algorithm to use based on the `display` property.
-pub(crate) fn perform_node_layout<NodeContext, MeasureFunction>(
-    taffy_view: &mut TaffyView<NodeContext, MeasureFunction>,
-    node: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    sizing_mode: SizingMode,
-    vertical_margins_are_collapsible: Line<bool>,
-) -> SizeBaselinesAndMargins
-where
-    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
-{
-    compute_node_layout(
-        taffy_view,
-        node,
-        known_dimensions,
-        parent_size,
-        available_space,
-        RunMode::PerformLayout,
-        sizing_mode,
-        vertical_margins_are_collapsible,
-    )
-}
-
-/// Measure a node's size. Chooses which algorithm to use based on the `display` property.
-pub(crate) fn measure_node_size<NodeContext, MeasureFunction>(
-    taffy_view: &mut TaffyView<NodeContext, MeasureFunction>,
-    node: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    sizing_mode: SizingMode,
-    vertical_margins_are_collapsible: Line<bool>,
-) -> Size<f32>
-where
-    MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
-{
-    compute_node_layout(
-        taffy_view,
-        node,
-        known_dimensions,
-        parent_size,
-        available_space,
-        RunMode::ComputeSize,
-        sizing_mode,
-        vertical_margins_are_collapsible,
-    )
-    .size
-}
-
 /// Updates the stored layout of the provided `node` and its children
-#[allow(clippy::too_many_arguments)]
-fn compute_node_layout<NodeContext, MeasureFunction>(
+pub(crate) fn compute_node_layout<NodeContext, MeasureFunction>(
     taffy_view: &mut TaffyView<NodeContext, MeasureFunction>,
     node: NodeId,
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-    sizing_mode: SizingMode,
-    vertical_margins_are_collapsible: Line<bool>,
-) -> SizeBaselinesAndMargins
+    inputs: LayoutInput,
+) -> LayoutOutput
 where
     MeasureFunction: FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>) -> Size<f32>,
 {
     debug_push_node!(node);
 
+    let LayoutInput { known_dimensions, available_space, run_mode, .. } = inputs;
     let node_key = node.into();
     let has_children = !taffy_view.taffy.children[node_key].is_empty();
 
     // First we check if we have a cached result for the given input
     let cache_run_mode = if !has_children { RunMode::PerformLayout } else { run_mode };
-    let cache_entry = taffy_view.taffy.nodes[node_key].cache.get(known_dimensions, available_space, cache_run_mode);
+    let cache = &taffy_view.taffy.nodes[node_key].cache;
+    let cache_entry = cache.get(known_dimensions, available_space, cache_run_mode);
     if let Some(cached_size_and_baselines) = cache_entry {
         debug_log!("CACHE", dbg:cached_size_and_baselines.size);
         debug_log_node!(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
@@ -130,111 +75,26 @@ where
         return cached_size_and_baselines;
     }
 
+    // Fetch `Display` style (+ debug log)
+    let display_mode = taffy_view.taffy.nodes[node_key].style.display;
+    debug_log!(display_mode);
     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: NodeId,
-        known_dimensions: Size<Option<f32>>,
-        parent_size: Size<Option<f32>>,
-        available_space: Size<AvailableSpace>,
-        run_mode: RunMode,
-        sizing_mode: SizingMode,
-        vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins {
-        debug_log!(Algorithm::NAME);
-
-        match run_mode {
-            RunMode::PerformLayout => Algorithm::perform_layout(
-                tree,
-                node,
-                known_dimensions,
-                parent_size,
-                available_space,
-                sizing_mode,
-                vertical_margins_are_collapsible,
-            ),
-            RunMode::ComputeSize => Algorithm::measure_size(
-                tree,
-                node,
-                known_dimensions,
-                parent_size,
-                available_space,
-                sizing_mode,
-                vertical_margins_are_collapsible,
-            )
-            .into(),
-        }
-    }
-
-    let display_mode = taffy_view.taffy.nodes[node_key].style.display;
     let computed_size_and_baselines = match (display_mode, has_children) {
-        (Display::None, _) => {
-            perform_taffy_tree_hidden_layout(taffy_view.taffy, node);
-            SizeBaselinesAndMargins::HIDDEN
-        }
+        (Display::None, _) => perform_taffy_tree_hidden_layout(taffy_view.taffy, node),
         #[cfg(feature = "block_layout")]
-        (Display::Block, true) => perform_computations::<BlockAlgorithm>(
-            taffy_view,
-            node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            run_mode,
-            sizing_mode,
-            vertical_margins_are_collapsible,
-        ),
+        (Display::Block, true) => compute_block_layout(taffy_view, node, inputs),
         #[cfg(feature = "flexbox")]
-        (Display::Flex, true) => perform_computations::<FlexboxAlgorithm>(
-            taffy_view,
-            node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            run_mode,
-            sizing_mode,
-            vertical_margins_are_collapsible,
-        ),
+        (Display::Flex, true) => compute_flexbox_layout(taffy_view, node, inputs),
         #[cfg(feature = "grid")]
-        (Display::Grid, true) => perform_computations::<CssGridAlgorithm>(
-            taffy_view,
+        (Display::Grid, true) => compute_grid_layout(taffy_view, node, inputs),
+        (_, false) => compute_leaf_layout(
+            &mut taffy_view.measure_function,
             node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            run_mode,
-            sizing_mode,
-            vertical_margins_are_collapsible,
+            inputs,
+            &taffy_view.taffy.nodes[node_key].style,
+            taffy_view.taffy.nodes[node_key].needs_measure.then(|| &mut taffy_view.taffy.node_context_data[node_key]),
         ),
-        (_, false) => match run_mode {
-            RunMode::PerformLayout => leaf::perform_layout(
-                &taffy_view.taffy.nodes[node_key].style,
-                known_dimensions,
-                parent_size,
-                available_space,
-                sizing_mode,
-                &mut taffy_view.measure_function,
-                node,
-                taffy_view.taffy.nodes[node_key]
-                    .needs_measure
-                    .then(|| &mut taffy_view.taffy.node_context_data[node_key]),
-            ),
-            RunMode::ComputeSize => leaf::measure_size(
-                &taffy_view.taffy.nodes[node_key].style,
-                known_dimensions,
-                parent_size,
-                available_space,
-                sizing_mode,
-                &mut taffy_view.measure_function,
-                node,
-                taffy_view.taffy.nodes[node_key]
-                    .needs_measure
-                    .then(|| &mut taffy_view.taffy.node_context_data[node_key]),
-            )
-            .into(),
-        },
     };
 
     // Cache result
@@ -253,7 +113,7 @@ where
 
 /// Creates a layout for this node and its children, recursively.
 /// Each hidden node has zero size and is placed at the origin
-fn perform_taffy_tree_hidden_layout<NodeContext>(tree: &mut Taffy<NodeContext>, node: NodeId) {
+fn perform_taffy_tree_hidden_layout<NodeContext>(tree: &mut Taffy<NodeContext>, node: NodeId) -> LayoutOutput {
     /// Recursive function to apply hidden layout to all descendents
     fn perform_hidden_layout_inner<NodeContext>(tree: &mut Taffy<NodeContext>, node: NodeId, order: u32) {
         let node_key = node.into();
@@ -269,6 +129,8 @@ fn perform_taffy_tree_hidden_layout<NodeContext>(tree: &mut Taffy<NodeContext>,
     for order in 0..tree.children[node.into()].len() {
         perform_hidden_layout_inner(tree, tree.children[node_key][order], order as _);
     }
+
+    LayoutOutput::HIDDEN
 }
 
 /// Rounds the calculated [`Layout`] to exact pixel values
diff --git a/src/lib.rs b/src/lib.rs
index 6c94f468d..3e2376d29 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -27,11 +27,13 @@ pub mod tree;
 #[macro_use]
 pub mod util;
 
+#[cfg(feature = "block_layout")]
+pub use crate::compute::compute_block_layout;
 #[cfg(feature = "flexbox")]
-pub use crate::compute::flexbox::FlexboxAlgorithm;
+pub use crate::compute::compute_flexbox_layout;
 #[cfg(feature = "grid")]
-pub use crate::compute::grid::CssGridAlgorithm;
-pub use crate::compute::LayoutAlgorithm;
+pub use crate::compute::compute_grid_layout;
+pub use crate::compute::compute_leaf_layout;
 pub use crate::tree::LayoutTree;
 #[cfg(feature = "taffy_tree")]
 pub use crate::tree::{Taffy, TaffyError, TaffyResult};
diff --git a/src/style/mod.rs b/src/style/mod.rs
index 125bb5974..80acfd506 100644
--- a/src/style/mod.rs
+++ b/src/style/mod.rs
@@ -66,6 +66,20 @@ impl Display {
     pub const DEFAULT: Display = Display::None;
 }
 
+impl core::fmt::Display for Display {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        match self {
+            Display::None => write!(f, "NONE"),
+            #[cfg(feature = "block_layout")]
+            Display::Block => write!(f, "BLOCK"),
+            #[cfg(feature = "flexbox")]
+            Display::Flex => write!(f, "FLEX"),
+            #[cfg(feature = "grid")]
+            Display::Grid => write!(f, "GRID"),
+        }
+    }
+}
+
 impl Default for Display {
     fn default() -> Self {
         Self::DEFAULT
diff --git a/src/tree/cache.rs b/src/tree/cache.rs
index cb48b5e1b..42e3a9953 100644
--- a/src/tree/cache.rs
+++ b/src/tree/cache.rs
@@ -1,7 +1,7 @@
 //! A cache for storing the results of layout computation
 use crate::geometry::Size;
 use crate::style::AvailableSpace;
-use crate::tree::{RunMode, SizeBaselinesAndMargins};
+use crate::tree::{LayoutOutput, RunMode};
 
 /// The number of cache entries for each node in the tree
 const CACHE_SIZE: usize = 9;
@@ -17,7 +17,7 @@ pub struct CacheEntry {
     run_mode: RunMode,
 
     /// The cached size and baselines of the item
-    cached_size_and_baselines: SizeBaselinesAndMargins,
+    cached_size_and_baselines: LayoutOutput,
 }
 
 /// A cache for caching the results of a sizing a Grid Item or Flexbox Item
@@ -103,7 +103,7 @@ impl Cache {
         known_dimensions: Size<Option<f32>>,
         available_space: Size<AvailableSpace>,
         run_mode: RunMode,
-    ) -> Option<SizeBaselinesAndMargins> {
+    ) -> Option<LayoutOutput> {
         for entry in self.entries.iter().flatten() {
             // Cached ComputeSize results are not valid if we are running in PerformLayout mode
             if entry.run_mode == RunMode::ComputeSize && run_mode == RunMode::PerformLayout {
@@ -134,7 +134,7 @@ impl Cache {
         known_dimensions: Size<Option<f32>>,
         available_space: Size<AvailableSpace>,
         run_mode: RunMode,
-        cached_size_and_baselines: SizeBaselinesAndMargins,
+        cached_size_and_baselines: LayoutOutput,
     ) {
         let cache_slot = Self::compute_cache_slot(known_dimensions, available_space);
         self.entries[cache_slot] =
diff --git a/src/tree/layout.rs b/src/tree/layout.rs
index 8af8f8469..2f0d5ced3 100644
--- a/src/tree/layout.rs
+++ b/src/tree/layout.rs
@@ -1,9 +1,7 @@
 //! Final data structures that represent the high-level UI layout
-
-use crate::{
-    geometry::{Point, Size},
-    util::sys::{f32_max, f32_min},
-};
+use crate::geometry::{Line, Point, Size};
+use crate::style::AvailableSpace;
+use crate::util::sys::{f32_max, f32_min};
 
 /// Whether we are performing a full layout, or we merely need to size the node
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -70,14 +68,40 @@ impl CollapsibleMarginSet {
     }
 }
 
-/// A struct containing both the size of a node and it's first baseline in each dimension (if it has any)
+/// A struct containing the inputs constraints/hints for laying out a node, which are passed in by the parent
+#[derive(Debug, Copy, Clone)]
+pub struct LayoutInput {
+    /// Known dimensions represent dimensions (width/height) which should be taken as fixed when performing layout.
+    /// For example, if known_dimensions.width is set to Some(WIDTH) then this means something like:
+    ///
+    ///    "What would the height of this node be, assuming the width is WIDTH"
+    ///
+    /// Layout functions will be called with both known_dimensions set for final layout. Where the meaning is:
+    ///
+    ///   "The exact size of this node is WIDTHxHEIGHT. Please lay out your children"
+    ///
+    pub known_dimensions: Size<Option<f32>>,
+    /// Parent size dimensions are intended to be used for percentage resolution.
+    pub parent_size: Size<Option<f32>>,
+    /// Available space represents an amount of space to layout into, and is used as a soft constraint
+    /// for the purpose of wrapping.
+    pub available_space: Size<AvailableSpace>,
+    /// Whether a Node's style sizes should be taken into account or ignored
+    pub sizing_mode: SizingMode,
+    /// Whether we only need to know the Node's size, or whe
+    pub run_mode: RunMode,
+    /// Specific to CSS Block layout. Used for correctly computing margin collapsing. You probably want to set this to `Line::FALSE`.
+    pub vertical_margins_are_collapsible: Line<bool>,
+}
+
+/// A struct containing the result of laying a single node, which is returned up to the parent node
 ///
 /// 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 SizeBaselinesAndMargins {
+pub struct LayoutOutput {
     /// The size of the node
     pub size: Size<f32>,
     /// The first baseline of the node in each dimension, if any
@@ -93,8 +117,8 @@ pub struct SizeBaselinesAndMargins {
     pub margins_can_collapse_through: bool,
 }
 
-impl SizeBaselinesAndMargins {
-    /// An all-zero `SizeBaselinesAndMargins` for hidden nodes
+impl LayoutOutput {
+    /// An all-zero `LayoutOutput` for hidden nodes
     pub const HIDDEN: Self = Self {
         size: Size::ZERO,
         first_baselines: Point::NONE,
@@ -103,7 +127,7 @@ impl SizeBaselinesAndMargins {
         margins_can_collapse_through: false,
     };
 
-    /// Constructor to create a `SizeBaselinesAndMargins` from just the size and baselines
+    /// Constructor to create a `LayoutOutput` from just the size and baselines
     pub fn from_size_and_baselines(size: Size<f32>, first_baselines: Point<Option<f32>>) -> Self {
         Self {
             size,
@@ -115,7 +139,7 @@ impl SizeBaselinesAndMargins {
     }
 }
 
-impl From<Size<f32>> for SizeBaselinesAndMargins {
+impl From<Size<f32>> for LayoutOutput {
     fn from(size: Size<f32>) -> Self {
         Self {
             size,
diff --git a/src/tree/mod.rs b/src/tree/mod.rs
index 655911c7a..94751ce85 100644
--- a/src/tree/mod.rs
+++ b/src/tree/mod.rs
@@ -15,7 +15,7 @@ mod taffy_tree;
 #[cfg(feature = "taffy_tree")]
 pub use taffy_tree::{Taffy, TaffyChildIter, TaffyError, TaffyResult, TaffyView};
 mod layout;
-pub use layout::{CollapsibleMarginSet, Layout, RunMode, SizeBaselinesAndMargins, SizingMode};
+pub use layout::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RunMode, SizingMode};
 
 /// Any item that implements the LayoutTree can be layed out using Taffy's algorithms.
 ///
@@ -65,5 +65,5 @@ pub trait LayoutTree {
         available_space: Size<AvailableSpace>,
         sizing_mode: SizingMode,
         vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins;
+    ) -> LayoutOutput;
 }
diff --git a/src/tree/taffy_tree/tree.rs b/src/tree/taffy_tree/tree.rs
index 6ead32954..dcdc55b89 100644
--- a/src/tree/taffy_tree/tree.rs
+++ b/src/tree/taffy_tree/tree.rs
@@ -3,11 +3,11 @@
 //! Layouts are composed of multiple nodes, which live in a tree-like data structure.
 use slotmap::{DefaultKey, SlotMap, SparseSecondaryMap};
 
-use crate::compute::taffy_tree::{compute_layout, measure_node_size, perform_node_layout};
+use crate::compute::taffy_tree::{compute_layout, compute_node_layout};
 use crate::geometry::{Line, Size};
 use crate::prelude::LayoutTree;
 use crate::style::{AvailableSpace, Style};
-use crate::tree::{Layout, NodeData, NodeId, SizeBaselinesAndMargins, SizingMode};
+use crate::tree::{Layout, LayoutInput, LayoutOutput, NodeData, NodeId, RunMode, SizingMode};
 use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec};
 
 use super::{TaffyError, TaffyResult};
@@ -129,15 +129,19 @@ where
         sizing_mode: SizingMode,
         vertical_margins_are_collapsible: Line<bool>,
     ) -> Size<f32> {
-        measure_node_size(
+        compute_node_layout(
             self,
             node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            sizing_mode,
-            vertical_margins_are_collapsible,
+            LayoutInput {
+                known_dimensions,
+                parent_size,
+                available_space,
+                sizing_mode,
+                run_mode: RunMode::ComputeSize,
+                vertical_margins_are_collapsible,
+            },
         )
+        .size
     }
 
     #[inline(always)]
@@ -149,15 +153,18 @@ where
         available_space: Size<AvailableSpace>,
         sizing_mode: SizingMode,
         vertical_margins_are_collapsible: Line<bool>,
-    ) -> SizeBaselinesAndMargins {
-        perform_node_layout(
+    ) -> LayoutOutput {
+        compute_node_layout(
             self,
             node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            sizing_mode,
-            vertical_margins_are_collapsible,
+            LayoutInput {
+                known_dimensions,
+                parent_size,
+                available_space,
+                sizing_mode,
+                run_mode: RunMode::PerformLayout,
+                vertical_margins_are_collapsible,
+            },
         )
     }
 }