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