Add `taffy_tree` feature to opt-out of default Taffy tree (#448)
1//! The layout algorithms themselves
2
3pub(crate) mod common;
4pub(crate) mod leaf;
5
6pub use leaf::compute;
7
8#[cfg(feature = "flexbox")]
9pub(crate) mod flexbox;
10
11#[cfg(feature = "grid")]
12pub(crate) mod grid;
13
14use crate::geometry::{Point, Size};
15use crate::style::AvailableSpace;
16use crate::tree::{Layout, LayoutTree, NodeId, SizeAndBaselines, SizingMode};
17
18#[cfg(feature = "flexbox")]
19pub use self::flexbox::FlexboxAlgorithm;
20
21#[cfg(feature = "grid")]
22pub use self::grid::CssGridAlgorithm;
23
24#[cfg(feature = "taffy_tree")]
25pub(crate) mod taffy_tree;
26
27#[cfg(any(feature = "debug", feature = "profile"))]
28use crate::util::debug::NODE_LOGGER;
29
30/// A common interface that all Taffy layout algorithms conform to
31pub trait LayoutAlgorithm {
32 /// The name of the algorithm (mainly used for debug purposes)
33 const NAME: &'static str;
34
35 /// Compute the size of the node given the specified constraints
36 fn measure_size(
37 tree: &mut impl LayoutTree,
38 node: NodeId,
39 known_dimensions: Size<Option<f32>>,
40 parent_size: Size<Option<f32>>,
41 available_space: Size<AvailableSpace>,
42 sizing_mode: SizingMode,
43 ) -> Size<f32>;
44
45 /// Perform a full layout on the node given the specified constraints
46 fn perform_layout(
47 tree: &mut impl LayoutTree,
48 node: NodeId,
49 known_dimensions: Size<Option<f32>>,
50 parent_size: Size<Option<f32>>,
51 available_space: Size<AvailableSpace>,
52 sizing_mode: SizingMode,
53 ) -> SizeAndBaselines;
54}
55
56#[cfg(feature = "debug")]
57fn debug_log_node(
58 known_dimensions: Size<Option<f32>>,
59 parent_size: Size<Option<f32>>,
60 available_space: Size<AvailableSpace>,
61 run_mode: RunMode,
62 sizing_mode: SizingMode,
63) {
64 NODE_LOGGER.debug_log(run_mode);
65 NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
66 NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
67 NODE_LOGGER.labelled_debug_log("parent_size", parent_size);
68 NODE_LOGGER.labelled_debug_log("available_space", available_space);
69}
70
71/// The public interface to Taffy's hidden node algorithm implementation
72pub struct HiddenAlgorithm;
73impl LayoutAlgorithm for HiddenAlgorithm {
74 const NAME: &'static str = "NONE";
75
76 fn perform_layout(
77 tree: &mut impl LayoutTree,
78 node: NodeId,
79 _known_dimensions: Size<Option<f32>>,
80 _parent_size: Size<Option<f32>>,
81 _available_space: Size<AvailableSpace>,
82 _sizing_mode: SizingMode,
83 ) -> SizeAndBaselines {
84 perform_hidden_layout(tree, node);
85 SizeAndBaselines { size: Size::ZERO, first_baselines: Point::NONE }
86 }
87
88 fn measure_size(
89 _tree: &mut impl LayoutTree,
90 _node: NodeId,
91 _known_dimensions: Size<Option<f32>>,
92 _parent_size: Size<Option<f32>>,
93 _available_space: Size<AvailableSpace>,
94 _sizing_mode: SizingMode,
95 ) -> Size<f32> {
96 Size::ZERO
97 }
98}
99
100/// Creates a layout for this node and its children, recursively.
101/// Each hidden node has zero size and is placed at the origin
102fn perform_hidden_layout(tree: &mut impl LayoutTree, node: NodeId) {
103 /// Recursive function to apply hidden layout to all descendents
104 fn perform_hidden_layout_inner(tree: &mut impl LayoutTree, node: NodeId, order: u32) {
105 *tree.layout_mut(node) = Layout::with_order(order);
106 for order in 0..tree.child_count(node) {
107 perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
108 }
109 }
110
111 for order in 0..tree.child_count(node) {
112 perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::perform_hidden_layout;
119 use crate::geometry::{Point, Size};
120 use crate::style::{Display, Style};
121 use crate::Taffy;
122
123 #[test]
124 fn hidden_layout_should_hide_recursively() {
125 let mut taffy = Taffy::new();
126
127 let style: Style = Style { display: Display::Flex, size: Size::from_points(50.0, 50.0), ..Default::default() };
128
129 let grandchild_00 = taffy.new_leaf(style.clone()).unwrap();
130 let grandchild_01 = taffy.new_leaf(style.clone()).unwrap();
131 let child_00 = taffy.new_with_children(style.clone(), &[grandchild_00, grandchild_01]).unwrap();
132
133 let grandchild_02 = taffy.new_leaf(style.clone()).unwrap();
134 let child_01 = taffy.new_with_children(style.clone(), &[grandchild_02]).unwrap();
135
136 let root = taffy
137 .new_with_children(
138 Style { display: Display::None, size: Size::from_points(50.0, 50.0), ..Default::default() },
139 &[child_00, child_01],
140 )
141 .unwrap();
142
143 perform_hidden_layout(&mut taffy, root.into());
144
145 // Whatever size and display-mode the nodes had previously,
146 // all layouts should resolve to ZERO due to the root's DISPLAY::NONE
147 for (node, _) in taffy.nodes.iter().filter(|(node, _)| *node != root.into()) {
148 if let Ok(layout) = taffy.layout(node.into()) {
149 assert_eq!(layout.size, Size::zero());
150 assert_eq!(layout.location, Point::zero());
151 }
152 }
153 }
154}