• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The abstractions that make up the core of Taffy's low-level API
2 //!
3 //! ## Examples
4 //!
5 //! The following examples demonstrate end-to-end implementation of Taffy's traits and usage of the low-level compute APIs:
6 //!
7 //!   - [custom_tree_vec](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_vec.rs) which implements a custom Taffy tree using a `Vec` as an arena with NodeId's being index's into the Vec.
8 //!   - [custom_tree_owned_partial](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_owned_partial.rs) which implements a custom Taffy tree using directly owned children with NodeId's being index's into vec on parent node.
9 //!   - [custom_tree_owned_unsafe](https://github.com/DioxusLabs/taffy/blob/main/examples/custom_tree_owned_unsafe.rs) which implements a custom Taffy tree using directly owned children with NodeId's being pointers.
10 //!
11 //! ## Overview
12 //!
13 //! ### Trait dependency tree
14 //!
15 //! The tree below illustrates which traits depend on which other traits.
16 //!
17 //! ```text
18 //! TraversePartialTree     - Access a node's children
19 //! ├──  LayoutPartialTree  - Run layout algorithms on a node and it's direct children
20 //! └──  TraverseTree       - Recursively access a node's descendants
21 //!     ├──  RoundTree      - Round a float-valued`  layout to integer pixels
22 //!     └──  PrintTree      - Print a debug representation of a node tree
23 //! ```
24 //!
25 //! ### A table of traits
26 //!
27 //! | Trait                 | Requires                | Enables                                                                                                                                                                                                                                                                                                                                                                                                                   |
28 //! | ---                   | ---                     | ---                                                                                                                                                                                                                                                                                                                                                                                                                       |
29 //! | [`LayoutPartialTree`] | [`TraversePartialTree`] | [`compute_flexbox_layout`](crate::compute_flexbox_layout)<br />[`compute_grid_layout`](crate::compute_grid_layout)<br />[`compute_block_layout`](crate::compute_block_layout)<br />[`compute_root_layout`](crate::compute_root_layout)<br />[`compute_leaf_layout`](crate::compute_leaf_layout)<br />[`compute_hidden_layout`](crate::compute_hidden_layout)<br />[`compute_cached_layout`](crate::compute_cached_layout) |
30 //! | [`RoundTree`]         | [`TraverseTree`]        | [`round_layout`](crate::round_layout)                                                                                                                                                                                                                                                                                                                                                                                     |
31 //! | [`PrintTree`]         | [`TraverseTree`]        | [`print_tree`](crate::print_tree)                                                                                                                                                                                                                                                                                                                                                                                         |
32 //!
33 //! ## All of the traits on one page
34 //!
35 //! ### TraversePartialTree and TraverseTree
36 //! These traits are Taffy's abstraction for downward tree traversal:
37 //!  - [`TraversePartialTree`] allows access to a single container node, and it's immediate children. This is the only "traverse" trait that is required
38 //!     for use of Taffy's core layout algorithms (flexbox, grid, etc).
39 //!  - [`TraverseTree`] is a marker trait which uses the same API signature as `TraversePartialTree`, but extends it with a guarantee that the child/children methods can be used to recurse
40 //!     infinitely down the tree. It is required by the `RoundTree` and
41 //!     the `PrintTree` traits.
42 //! ```rust
43 //! # use taffy::*;
44 //! pub trait TraversePartialTree {
45 //!     /// Type representing an iterator of the children of a node
46 //!     type ChildIter<'a>: Iterator<Item = NodeId>
47 //!     where
48 //!         Self: 'a;
49 //!
50 //!     /// Get the list of children IDs for the given node
51 //!     fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>;
52 //!
53 //!     /// Get the number of children for the given node
54 //!     fn child_count(&self, parent_node_id: NodeId) -> usize;
55 //!
56 //!     /// Get a specific child of a node, where the index represents the nth child
57 //!     fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId;
58 //! }
59 //!
60 //! pub trait TraverseTree: TraversePartialTree {}
61 //! ```
62 //!
63 //! You must implement [`TraversePartialTree`] to access any of Taffy's low-level API. If your tree implementation allows you to implement [`TraverseTree`] with
64 //! the correct semantics (full recursive traversal is available) then you should.
65 //!
66 //! ### LayoutPartialTree
67 //!
68 //! **Requires:** `TraversePartialTree`<br />
69 //! **Enables:** Flexbox, Grid, Block and Leaf layout algorithms from the [`crate::compute`] module
70 //!
71 //! Any type that implements [`LayoutPartialTree`] can be laid out using [Taffy's algorithms](crate::compute)
72 //!
73 //! Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single
74 //! node that only has access to it's immediate children.
75 //!
76 //! ```rust
77 //! # use taffy::*;
78 //! pub trait LayoutPartialTree: TraversePartialTree {
79 //!     /// Get a reference to the [`Style`] for this node.
80 //!     fn get_style(&self, node_id: NodeId) -> &Style;
81 //!
82 //!     /// Set the node's unrounded layout
83 //!     fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
84 //!
85 //!     /// Get a mutable reference to the [`Cache`] for this node.
86 //!     fn get_cache_mut(&mut self, node_id: NodeId) -> &mut Cache;
87 //!
88 //!     /// Compute the specified node's size or full layout given the specified constraints
89 //!     fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
90 //! }
91 //! ```
92 //!
93 //! ### RoundTree
94 //!
95 //! **Requires:** `TraverseTree`
96 //!
97 //! Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
98 //! rounding to snap the values to the pixel grid.
99 //!
100 //! As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
101 //!
102 //! ```rust
103 //! # use taffy::*;
104 //! pub trait RoundTree: TraverseTree {
105 //!     /// Get the node's unrounded layout
106 //!     fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout;
107 //!     /// Get a reference to the node's final layout
108 //!     fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout);
109 //! }
110 //! ```
111 //!
112 //! ### PrintTree
113 //!
114 //! **Requires:** `TraverseTree`
115 //!
116 //! ```rust
117 //! /// Trait used by the `print_tree` method which prints a debug representation
118 //! ///
119 //! /// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
120 //! # use taffy::*;
121 //! pub trait PrintTree: TraverseTree {
122 //!     /// Get a debug label for the node (typically the type of node: flexbox, grid, text, image, etc)
123 //!     fn get_debug_label(&self, node_id: NodeId) -> &'static str;
124 //!     /// Get a reference to the node's final layout
125 //!     fn get_final_layout(&self, node_id: NodeId) -> &Layout;
126 //! }
127 //! ```
128 //!
129 use super::{Layout, LayoutInput, LayoutOutput, NodeId, RequestedAxis, RunMode, SizingMode};
130 #[cfg(feature = "detailed_layout_info")]
131 use crate::debug::debug_log;
132 use crate::geometry::{AbsoluteAxis, Line, Size};
133 use crate::style::{AvailableSpace, CoreStyle};
134 #[cfg(feature = "flexbox")]
135 use crate::style::{FlexboxContainerStyle, FlexboxItemStyle};
136 #[cfg(feature = "grid")]
137 use crate::style::{GridContainerStyle, GridItemStyle};
138 #[cfg(feature = "block_layout")]
139 use crate::{BlockContainerStyle, BlockItemStyle};
140 
141 #[cfg(all(feature = "grid", feature = "detailed_layout_info"))]
142 use crate::compute::grid::DetailedGridInfo;
143 
144 /// Taffy's abstraction for downward tree traversal.
145 ///
146 /// However, this trait does *not* require access to any node's other than a single container node's immediate children unless you also intend to implement `TraverseTree`.
147 pub trait TraversePartialTree {
148     /// Type representing an iterator of the children of a node
149     type ChildIter<'a>: Iterator<Item = NodeId>
150     where
151         Self: 'a;
152 
153     /// Get the list of children IDs for the given node
child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>154     fn child_ids(&self, parent_node_id: NodeId) -> Self::ChildIter<'_>;
155 
156     /// Get the number of children for the given node
child_count(&self, parent_node_id: NodeId) -> usize157     fn child_count(&self, parent_node_id: NodeId) -> usize;
158 
159     /// Get a specific child of a node, where the index represents the nth child
get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId160     fn get_child_id(&self, parent_node_id: NodeId, child_index: usize) -> NodeId;
161 }
162 
163 /// A marker trait which extends `TraversePartialTree`
164 ///
165 /// Implementing this trait implies the additional guarantee that the child/children methods can be used to recurse
166 /// infinitely down the tree. Is required by the `RoundTree` and the `PrintTree` traits.
167 pub trait TraverseTree: TraversePartialTree {}
168 
169 /// Any type that implements [`LayoutPartialTree`] can be laid out using [Taffy's algorithms](crate::compute)
170 ///
171 /// Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single
172 /// node that only has access to it's immediate children.
173 pub trait LayoutPartialTree: TraversePartialTree {
174     /// The style type representing the core container styles that all containers should have
175     /// Used when laying out the root node of a tree
176     type CoreContainerStyle<'a>: CoreStyle
177     where
178         Self: 'a;
179 
180     /// Get core style
get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>181     fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>;
182 
183     /// Set the node's unrounded layout
set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout)184     fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
185 
186     /// Compute the specified node's size or full layout given the specified constraints
compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput187     fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput;
188 }
189 
190 /// Trait used by the `compute_cached_layout` method which allows cached layout results to be stored and retrieved.
191 ///
192 /// The `Cache` struct implements a per-node cache that is compatible with this trait.
193 pub trait CacheTree {
194     /// Try to retrieve a cached result from the cache
cache_get( &self, node_id: NodeId, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>, run_mode: RunMode, ) -> Option<LayoutOutput>195     fn cache_get(
196         &self,
197         node_id: NodeId,
198         known_dimensions: Size<Option<f32>>,
199         available_space: Size<AvailableSpace>,
200         run_mode: RunMode,
201     ) -> Option<LayoutOutput>;
202 
203     /// Store a computed size in the cache
cache_store( &mut self, node_id: NodeId, known_dimensions: Size<Option<f32>>, available_space: Size<AvailableSpace>, run_mode: RunMode, layout_output: LayoutOutput, )204     fn cache_store(
205         &mut self,
206         node_id: NodeId,
207         known_dimensions: Size<Option<f32>>,
208         available_space: Size<AvailableSpace>,
209         run_mode: RunMode,
210         layout_output: LayoutOutput,
211     );
212 
213     /// Clear all cache entries for the node
cache_clear(&mut self, node_id: NodeId)214     fn cache_clear(&mut self, node_id: NodeId);
215 }
216 
217 /// Trait used by the `round_layout` method which takes a tree of unrounded float-valued layouts and performs
218 /// rounding to snap the values to the pixel grid.
219 ///
220 /// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
221 pub trait RoundTree: TraverseTree {
222     /// Get the node's unrounded layout
get_unrounded_layout(&self, node_id: NodeId) -> &Layout223     fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout;
224     /// Get a reference to the node's final layout
set_final_layout(&mut self, node_id: NodeId, layout: &Layout)225     fn set_final_layout(&mut self, node_id: NodeId, layout: &Layout);
226 }
227 
228 /// Trait used by the `print_tree` method which prints a debug representation
229 ///
230 /// As indicated by it's dependence on `TraverseTree`, it required full recursive access to the tree.
231 pub trait PrintTree: TraverseTree {
232     /// Get a debug label for the node (typically the type of node: flexbox, grid, text, image, etc)
get_debug_label(&self, node_id: NodeId) -> &'static str233     fn get_debug_label(&self, node_id: NodeId) -> &'static str;
234     /// Get a reference to the node's final layout
get_final_layout(&self, node_id: NodeId) -> &Layout235     fn get_final_layout(&self, node_id: NodeId) -> &Layout;
236 }
237 
238 #[cfg(feature = "flexbox")]
239 /// Extends [`LayoutPartialTree`] with getters for the styles required for Flexbox layout
240 pub trait LayoutFlexboxContainer: LayoutPartialTree {
241     /// The style type representing the Flexbox container's styles
242     type FlexboxContainerStyle<'a>: FlexboxContainerStyle
243     where
244         Self: 'a;
245     /// The style type representing each Flexbox item's styles
246     type FlexboxItemStyle<'a>: FlexboxItemStyle
247     where
248         Self: 'a;
249 
250     /// Get the container's styles
get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_>251     fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_>;
252 
253     /// Get the child's styles
get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_>254     fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_>;
255 }
256 
257 #[cfg(feature = "grid")]
258 /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout
259 pub trait LayoutGridContainer: LayoutPartialTree {
260     /// The style type representing the CSS Grid container's styles
261     type GridContainerStyle<'a>: GridContainerStyle
262     where
263         Self: 'a;
264 
265     /// The style type representing each CSS Grid item's styles
266     type GridItemStyle<'a>: GridItemStyle
267     where
268         Self: 'a;
269 
270     /// Get the container's styles
get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_>271     fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_>;
272 
273     /// Get the child's styles
get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_>274     fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_>;
275 
276     /// Set the node's detailed grid information
277     ///
278     /// Implementing this method is optional. Doing so allows you to access details about the the grid such as
279     /// the computed size of each grid track and the computed placement of each grid item.
280     #[cfg(feature = "detailed_layout_info")]
set_detailed_grid_info(&mut self, _node_id: NodeId, _detailed_grid_info: DetailedGridInfo)281     fn set_detailed_grid_info(&mut self, _node_id: NodeId, _detailed_grid_info: DetailedGridInfo) {
282         debug_log!("LayoutGridContainer::set_detailed_grid_info called");
283     }
284 }
285 
286 #[cfg(feature = "block_layout")]
287 /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Block layout
288 pub trait LayoutBlockContainer: LayoutPartialTree {
289     /// The style type representing the CSS Block container's styles
290     type BlockContainerStyle<'a>: BlockContainerStyle
291     where
292         Self: 'a;
293     /// The style type representing each CSS Block item's styles
294     type BlockItemStyle<'a>: BlockItemStyle
295     where
296         Self: 'a;
297 
298     /// Get the container's styles
get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_>299     fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_>;
300 
301     /// Get the child's styles
get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_>302     fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_>;
303 }
304 
305 // --- PRIVATE TRAITS
306 
307 /// A private trait which allows us to add extra convenience methods to types which implement
308 /// LayoutTree without making those methods public.
309 pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
310     /// Compute the size of the node given the specified constraints
311     #[inline(always)]
312     #[allow(clippy::too_many_arguments)]
measure_child_size( &mut self, node_id: NodeId, known_dimensions: Size<Option<f32>>, parent_size: Size<Option<f32>>, available_space: Size<AvailableSpace>, sizing_mode: SizingMode, axis: AbsoluteAxis, vertical_margins_are_collapsible: Line<bool>, ) -> f32313     fn measure_child_size(
314         &mut self,
315         node_id: NodeId,
316         known_dimensions: Size<Option<f32>>,
317         parent_size: Size<Option<f32>>,
318         available_space: Size<AvailableSpace>,
319         sizing_mode: SizingMode,
320         axis: AbsoluteAxis,
321         vertical_margins_are_collapsible: Line<bool>,
322     ) -> f32 {
323         self.compute_child_layout(
324             node_id,
325             LayoutInput {
326                 known_dimensions,
327                 parent_size,
328                 available_space,
329                 sizing_mode,
330                 axis: axis.into(),
331                 run_mode: RunMode::ComputeSize,
332                 vertical_margins_are_collapsible,
333             },
334         )
335         .size
336         .get_abs(axis)
337     }
338 
339     /// Perform a full layout on the node given the specified constraints
340     #[inline(always)]
perform_child_layout( &mut self, node_id: NodeId, known_dimensions: Size<Option<f32>>, parent_size: Size<Option<f32>>, available_space: Size<AvailableSpace>, sizing_mode: SizingMode, vertical_margins_are_collapsible: Line<bool>, ) -> LayoutOutput341     fn perform_child_layout(
342         &mut self,
343         node_id: NodeId,
344         known_dimensions: Size<Option<f32>>,
345         parent_size: Size<Option<f32>>,
346         available_space: Size<AvailableSpace>,
347         sizing_mode: SizingMode,
348         vertical_margins_are_collapsible: Line<bool>,
349     ) -> LayoutOutput {
350         self.compute_child_layout(
351             node_id,
352             LayoutInput {
353                 known_dimensions,
354                 parent_size,
355                 available_space,
356                 sizing_mode,
357                 axis: RequestedAxis::Both,
358                 run_mode: RunMode::PerformLayout,
359                 vertical_margins_are_collapsible,
360             },
361         )
362     }
363 }
364 
365 impl<T: LayoutPartialTree> LayoutPartialTreeExt for T {}
366