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/taffy_tree.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/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,
+ },
)
}
}