tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 707HTML 660Markdown 12TOML 62344 Definiciones

⎇ 77a309162f0011d9ddb563f435f3cbafc5b1775f src/compute/leaf.rs Rust · 146 líneas · 6.0 KB Historia Quién tocó qué crudo

Use `struct NodeId(u64)` instead of `slotmap::DefaultKey` in all public APIs (#426) e997fa3f4 · Nico Burns ·

1//! Computes size using styles and measure functions
2
3use crate::compute::LayoutAlgorithm;
4use crate::geometry::{Point, Size};
5use crate::layout::{SizeAndBaselines, SizingMode};
6use crate::math::MaybeMath;
7use crate::resolve::{MaybeResolve, ResolveOrZero};
8use crate::style::AvailableSpace;
9use crate::sys::f32_max;
10use crate::tree::{LayoutTree, NodeId};
11
12#[cfg(feature = "debug")]
13use crate::debug::NODE_LOGGER;
14
15/// The public interface to Taffy's leaf node algorithm implementation
16pub(crate) struct LeafAlgorithm;
17impl LayoutAlgorithm for LeafAlgorithm {
18    const NAME: &'static str = "LEAF";
19
20    fn perform_layout(
21        tree: &mut impl LayoutTree,
22        node: NodeId,
23        known_dimensions: Size<Option<f32>>,
24        parent_size: Size<Option<f32>>,
25        available_space: Size<AvailableSpace>,
26        sizing_mode: SizingMode,
27    ) -> SizeAndBaselines {
28        compute(tree, node, known_dimensions, parent_size, available_space, sizing_mode)
29    }
30
31    fn measure_size(
32        tree: &mut impl LayoutTree,
33        node: NodeId,
34        known_dimensions: Size<Option<f32>>,
35        parent_size: Size<Option<f32>>,
36        available_space: Size<AvailableSpace>,
37        sizing_mode: SizingMode,
38    ) -> Size<f32> {
39        compute(tree, node, known_dimensions, parent_size, available_space, sizing_mode).size
40    }
41}
42
43/// Compute the size of a leaf node (node with no children)
44pub(crate) fn compute(
45    tree: &mut impl LayoutTree,
46    node: NodeId,
47    known_dimensions: Size<Option<f32>>,
48    parent_size: Size<Option<f32>>,
49    available_space: Size<AvailableSpace>,
50    sizing_mode: SizingMode,
51) -> SizeAndBaselines {
52    let style = tree.style(node);
53
54    // Resolve node's preferred/min/max sizes (width/heights) against the available space (percentages resolve to pixel values)
55    // For ContentSize mode, we pretend that the node has no size styles as these should be ignored.
56    let (node_size, node_min_size, node_max_size, aspect_ratio) = match sizing_mode {
57        SizingMode::ContentSize => {
58            let node_size = known_dimensions;
59            let node_min_size = Size::NONE;
60            let node_max_size = Size::NONE;
61            (node_size, node_min_size, node_max_size, None)
62        }
63        SizingMode::InherentSize => {
64            let aspect_ratio = style.aspect_ratio;
65            let style_size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
66            let style_min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
67            let style_max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
68
69            let node_size = known_dimensions.or(style_size);
70            (node_size, style_min_size, style_max_size, aspect_ratio)
71        }
72    };
73
74    // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width).
75    // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values)
76    let padding = style.padding.resolve_or_zero(parent_size.width);
77    let border = style.border.resolve_or_zero(parent_size.width);
78    let padding_border = padding + border;
79
80    #[cfg(feature = "debug")]
81    NODE_LOGGER.log("LEAF");
82    #[cfg(feature = "debug")]
83    NODE_LOGGER.labelled_debug_log("node_size", node_size);
84    #[cfg(feature = "debug")]
85    NODE_LOGGER.labelled_debug_log("min_size ", node_min_size);
86    #[cfg(feature = "debug")]
87    NODE_LOGGER.labelled_debug_log("max_size ", node_max_size);
88
89    // Return early if both width and height are known
90    if let Size { width: Some(width), height: Some(height) } = node_size {
91        let size = Size { width, height }
92            .maybe_clamp(node_min_size, node_max_size)
93            .maybe_max(padding_border.sum_axes().map(Some));
94        return SizeAndBaselines { size, first_baselines: Point::NONE };
95    };
96
97    if tree.needs_measure(node) {
98        // Compute available space
99        let available_space = Size {
100            width: available_space
101                .width
102                .maybe_set(node_size.width)
103                .maybe_set(node_max_size.width)
104                .map_definite_value(|size| size.maybe_clamp(node_min_size.width, node_max_size.width)),
105            height: available_space
106                .height
107                .maybe_set(node_size.height)
108                .maybe_set(node_max_size.height)
109                .map_definite_value(|size| size.maybe_clamp(node_min_size.height, node_max_size.height)),
110        };
111
112        // Measure node
113        let measured_size = tree.measure_node(node, known_dimensions, available_space);
114
115        let measured_size = Size {
116            width: measured_size.width,
117            height: f32_max(measured_size.height, aspect_ratio.map(|ratio| measured_size.width / ratio).unwrap_or(0.0)),
118        };
119
120        let size = node_size.unwrap_or(measured_size).maybe_clamp(node_min_size, node_max_size);
121        let size = size.maybe_max(padding_border.sum_axes().map(Some));
122        return SizeAndBaselines { size, first_baselines: Point::NONE };
123    }
124
125    let size = Size {
126        width: node_size
127            .width
128            // .unwrap_or(0.0) + padding.horizontal_axis_sum() + border.horizontal_axis_sum(), // content-box
129            .unwrap_or(0.0) // border-box
130            .maybe_clamp(node_min_size.width, node_max_size.width)
131            .maybe_max(padding_border.horizontal_axis_sum().into()),
132        height: node_size
133            .height
134            // .unwrap_or(0.0) + padding.vertical_axis_sum() + border.vertical_axis_sum(), // content-box
135            .unwrap_or(0.0) // border-box
136            .maybe_clamp(node_min_size.height, node_max_size.height)
137            .maybe_max(padding_border.vertical_axis_sum().into()),
138    };
139
140    let size = Size {
141        width: f32_max(size.width, aspect_ratio.map(|ratio| size.height * ratio).unwrap_or(0.0)),
142        height: f32_max(size.height, aspect_ratio.map(|ratio| size.width / ratio).unwrap_or(0.0)),
143    };
144
145    SizeAndBaselines { size, first_baselines: Point::NONE }
146}