//! The layout algorithms themselves
pub(crate) mod common;
pub(crate) mod leaf;
pub use leaf::compute;
#[cfg(feature = "flexbox")]
pub(crate) mod flexbox;
#[cfg(feature = "grid")]
pub(crate) mod grid;
use crate::geometry::{Point, Size};
use crate::style::AvailableSpace;
use crate::tree::{Layout, LayoutTree, NodeId, SizeAndBaselines, SizingMode};
#[cfg(feature = "flexbox")]
pub use self::flexbox::FlexboxAlgorithm;
#[cfg(feature = "grid")]
pub use self::grid::CssGridAlgorithm;
#[cfg(feature = "taffy_tree")]
pub(crate) mod taffy_tree;
#[cfg(any(feature = "debug", feature = "profile"))]
use crate::util::debug::NODE_LOGGER;
/// 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>,
parent_size: Size >,
available_space: Size,
sizing_mode: SizingMode,
) -> Size;
/// Perform a full layout on the node given the specified constraints
fn perform_layout(
tree: &mut impl LayoutTree,
node: NodeId,
known_dimensions: Size>,
parent_size: Size >,
available_space: Size,
sizing_mode: SizingMode,
) -> SizeAndBaselines;
}
#[cfg(feature = "debug")]
fn debug_log_node(
known_dimensions: Size>,
parent_size: Size >,
available_space: Size,
run_mode: RunMode,
sizing_mode: SizingMode,
) {
NODE_LOGGER.debug_log(run_mode);
NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
NODE_LOGGER.labelled_debug_log("parent_size", parent_size);
NODE_LOGGER.labelled_debug_log("available_space", available_space);
}
/// 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>,
_parent_size: Size >,
_available_space: Size,
_sizing_mode: SizingMode,
) -> SizeAndBaselines {
perform_hidden_layout(tree, node);
SizeAndBaselines { size: Size::ZERO, first_baselines: Point::NONE }
}
fn measure_size(
_tree: &mut impl LayoutTree,
_node: NodeId,
_known_dimensions: Size>,
_parent_size: Size >,
_available_space: Size,
_sizing_mode: SizingMode,
) -> Size {
Size::ZERO
}
}
/// 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) {
/// 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);
for order in 0..tree.child_count(node) {
perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
}
}
for order in 0..tree.child_count(node) {
perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
}
}
#[cfg(test)]
mod tests {
use super::perform_hidden_layout;
use crate::geometry::{Point, Size};
use crate::style::{Display, Style};
use crate::Taffy;
#[test]
fn hidden_layout_should_hide_recursively() {
let mut taffy = Taffy::new();
let style: Style = Style { display: Display::Flex, size: Size::from_points(50.0, 50.0), ..Default::default() };
let grandchild_00 = taffy.new_leaf(style.clone()).unwrap();
let grandchild_01 = taffy.new_leaf(style.clone()).unwrap();
let child_00 = taffy.new_with_children(style.clone(), &[grandchild_00, grandchild_01]).unwrap();
let grandchild_02 = taffy.new_leaf(style.clone()).unwrap();
let child_01 = taffy.new_with_children(style.clone(), &[grandchild_02]).unwrap();
let root = taffy
.new_with_children(
Style { display: Display::None, size: Size::from_points(50.0, 50.0), ..Default::default() },
&[child_00, child_01],
)
.unwrap();
perform_hidden_layout(&mut taffy, root.into());
// Whatever size and display-mode the nodes had previously,
// all layouts should resolve to ZERO due to the root's DISPLAY::NONE
for (node, _) in taffy.nodes.iter().filter(|(node, _)| *node != root.into()) {
if let Ok(layout) = taffy.layout(node.into()) {
assert_eq!(layout.size, Size::zero());
assert_eq!(layout.location, Point::zero());
}
}
}
}