1pub(crate) mod common;
4pub(crate) mod leaf;
5
6#[cfg(feature = "block_layout")]
7pub(crate) mod block;
8
9#[cfg(feature = "flexbox")]
10pub(crate) mod flexbox;
11
12#[cfg(feature = "grid")]
13pub(crate) mod grid;
14
15pub use leaf::compute_leaf_layout;
16
17#[cfg(feature = "block_layout")]
18pub use self::block::compute_block_layout;
19
20#[cfg(feature = "flexbox")]
21pub use self::flexbox::compute_flexbox_layout;
22
23#[cfg(feature = "grid")]
24pub use self::grid::compute_grid_layout;
25
26use crate::geometry::{Line, Point, Size};
27use crate::style::{AvailableSpace, Overflow};
28use crate::tree::{
29 Layout, LayoutInput, LayoutOutput, LayoutTree, NodeId, PartialLayoutTree, PartialLayoutTreeExt, SizingMode,
30};
31use crate::util::debug::{debug_log, debug_log_node, debug_pop_node, debug_push_node};
32use crate::util::sys::round;
33use crate::util::ResolveOrZero;
34
35pub fn compute_layout(tree: &mut impl PartialLayoutTree, root: NodeId, available_space: Size<AvailableSpace>) {
37 let output = tree.perform_child_layout(
39 root,
40 Size::NONE,
41 available_space.into_options(),
42 available_space,
43 SizingMode::InherentSize,
44 Line::FALSE,
45 );
46
47 let style = tree.get_style(root);
48 let padding = style.padding.resolve_or_zero(available_space.width.into_option());
49 let border = style.border.resolve_or_zero(available_space.width.into_option());
50 let scrollbar_size = Size {
51 width: if style.overflow.y == Overflow::Scroll { style.scrollbar_width } else { 0.0 },
52 height: if style.overflow.x == Overflow::Scroll { style.scrollbar_width } else { 0.0 },
53 };
54
55 tree.set_unrounded_layout(
56 root,
57 &Layout {
58 order: 0,
59 location: Point::ZERO,
60 size: output.size,
61 #[cfg(feature = "content_size")]
62 content_size: output.content_size,
63 scrollbar_size,
64 padding,
65 border,
66 },
67 );
68}
69
70#[inline(always)]
72pub fn compute_cached_layout<Tree: PartialLayoutTree + ?Sized, ComputeFunction>(
73 tree: &mut Tree,
74 node: NodeId,
75 inputs: LayoutInput,
76 mut compute_uncached: ComputeFunction,
77) -> LayoutOutput
78where
79 ComputeFunction: FnMut(&mut Tree, NodeId, LayoutInput) -> LayoutOutput,
80{
81 debug_push_node!(node);
82 let LayoutInput { known_dimensions, available_space, run_mode, .. } = inputs;
83
84 let cache_entry = tree.get_cache_mut(node).get(known_dimensions, available_space, run_mode);
86 if let Some(cached_size_and_baselines) = cache_entry {
87 debug_log!("CACHE", dbg:cached_size_and_baselines.size);
88 debug_log_node!(known_dimensions, parent_size, available_space, run_mode, sizing_mode);
89 debug_pop_node!();
90 return cached_size_and_baselines;
91 }
92
93 let computed_size_and_baselines = compute_uncached(tree, node, inputs);
94
95 tree.get_cache_mut(node).store(known_dimensions, available_space, run_mode, computed_size_and_baselines);
97
98 debug_log!("RESULT", dbg:computed_size_and_baselines.size);
99 debug_pop_node!();
100
101 computed_size_and_baselines
102}
103
104pub fn round_layout(tree: &mut impl LayoutTree, node_id: NodeId) {
116 return round_layout_inner(tree, node_id, 0.0, 0.0);
117
118 fn round_layout_inner(tree: &mut impl LayoutTree, node_id: NodeId, cumulative_x: f32, cumulative_y: f32) {
120 let unrounded_layout = *tree.get_unrounded_layout(node_id);
121 let mut layout = unrounded_layout;
122
123 let cumulative_x = cumulative_x + unrounded_layout.location.x;
124 let cumulative_y = cumulative_y + unrounded_layout.location.y;
125
126 layout.location.x = round(unrounded_layout.location.x);
127 layout.location.y = round(unrounded_layout.location.y);
128 layout.size.width = round(cumulative_x + unrounded_layout.size.width) - round(cumulative_x);
129 layout.size.height = round(cumulative_y + unrounded_layout.size.height) - round(cumulative_y);
130 layout.scrollbar_size.width = round(unrounded_layout.scrollbar_size.width);
131 layout.scrollbar_size.height = round(unrounded_layout.scrollbar_size.height);
132 layout.border.left = round(cumulative_x + unrounded_layout.border.left) - round(cumulative_x);
133 layout.border.right = round(cumulative_x + unrounded_layout.size.width)
134 - round(cumulative_x + unrounded_layout.size.width - unrounded_layout.border.right);
135 layout.border.top = round(cumulative_y + unrounded_layout.border.top) - round(cumulative_y);
136 layout.border.bottom = round(cumulative_y + unrounded_layout.size.height)
137 - round(cumulative_y + unrounded_layout.size.height - unrounded_layout.border.bottom);
138 layout.padding.left = round(cumulative_x + unrounded_layout.padding.left) - round(cumulative_x);
139 layout.padding.right = round(cumulative_x + unrounded_layout.size.width)
140 - round(cumulative_x + unrounded_layout.size.width - unrounded_layout.padding.right);
141 layout.padding.top = round(cumulative_y + unrounded_layout.padding.top) - round(cumulative_y);
142 layout.padding.bottom = round(cumulative_y + unrounded_layout.size.height)
143 - round(cumulative_y + unrounded_layout.size.height - unrounded_layout.padding.bottom);
144
145 #[cfg(feature = "content_size")]
146 round_content_size(&mut layout, unrounded_layout.content_size, cumulative_x, cumulative_y);
147
148 tree.set_final_layout(node_id, &layout);
149
150 let child_count = tree.child_count(node_id);
151 for index in 0..child_count {
152 let child = tree.get_child_id(node_id, index);
153 round_layout_inner(tree, child, cumulative_x, cumulative_y);
154 }
155 }
156
157 #[cfg(feature = "content_size")]
158 #[inline(always)]
159 fn round_content_size(
162 layout: &mut Layout,
163 unrounded_content_size: Size<f32>,
164 cumulative_x: f32,
165 cumulative_y: f32,
166 ) {
167 layout.content_size.width = round(cumulative_x + unrounded_content_size.width) - round(cumulative_x);
168 layout.content_size.height = round(cumulative_y + unrounded_content_size.height) - round(cumulative_y);
169 }
170}
171
172pub fn compute_hidden_layout(tree: &mut impl PartialLayoutTree, node: NodeId) -> LayoutOutput {
175 tree.get_cache_mut(node).clear();
177 tree.set_unrounded_layout(node, &Layout::with_order(0));
178
179 for index in 0..tree.child_count(node) {
181 let child_id = tree.get_child_id(node, index);
182 tree.compute_child_layout(child_id, LayoutInput::HIDDEN);
183 }
184
185 LayoutOutput::HIDDEN
186}
187
188#[cfg(test)]
189mod tests {
190 use super::compute_hidden_layout;
191 use crate::geometry::{Point, Size};
192 use crate::style::{Display, Style};
193 use crate::TaffyTree;
194
195 #[test]
196 fn hidden_layout_should_hide_recursively() {
197 let mut taffy: TaffyTree<()> = TaffyTree::new();
198
199 let style: Style = Style { display: Display::Flex, size: Size::from_lengths(50.0, 50.0), ..Default::default() };
200
201 let grandchild_00 = taffy.new_leaf(style.clone()).unwrap();
202 let grandchild_01 = taffy.new_leaf(style.clone()).unwrap();
203 let child_00 = taffy.new_with_children(style.clone(), &[grandchild_00, grandchild_01]).unwrap();
204
205 let grandchild_02 = taffy.new_leaf(style.clone()).unwrap();
206 let child_01 = taffy.new_with_children(style.clone(), &[grandchild_02]).unwrap();
207
208 let root = taffy
209 .new_with_children(
210 Style { display: Display::None, size: Size::from_lengths(50.0, 50.0), ..Default::default() },
211 &[child_00, child_01],
212 )
213 .unwrap();
214
215 compute_hidden_layout(&mut taffy.as_layout_tree(), root.into());
216
217 for (node, _) in taffy.nodes.iter().filter(|(node, _)| *node != root.into()) {
220 if let Ok(layout) = taffy.layout(node.into()) {
221 assert_eq!(layout.size, Size::zero());
222 assert_eq!(layout.location, Point::zero());
223 }
224 }
225 }
226}