tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Sutichaykuna

⎇ 384b60bdadb6ac33f2117cc571e519d738885587 src/compute/leaf.rs Rust · 143 siq'ikuna · 5.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

Remove `cache_mut`, `needs_measure` and `measure_node` methods from `LayoutTree` trait (#431) 384b60bda · Nico Burns ·

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