taffy/compute/common/
sizing_keyword.rs1use crate::geometry::{AbsoluteAxis, Line, Rect, Size};
4use crate::style::AvailableSpace;
5use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId, SizingMode};
6use crate::util::sys::f32_max;
7use crate::{CompactLength, Dimension};
8
9pub(crate) enum SizingKeywordResolution {
11 Measure(AvailableSpace),
13 Exact(f32),
15}
16
17#[inline]
28pub(crate) fn resolve_sizing_keyword(
29 style: Dimension,
30 stretch_size: Option<f32>,
31 percent_resolution_basis: Option<f32>,
32) -> Option<SizingKeywordResolution> {
33 match style.tag() {
34 CompactLength::MIN_CONTENT_TAG => Some(SizingKeywordResolution::Measure(AvailableSpace::MinContent)),
35 CompactLength::MAX_CONTENT_TAG => Some(SizingKeywordResolution::Measure(AvailableSpace::MaxContent)),
36 CompactLength::FIT_CONTENT_PX_TAG => {
37 Some(SizingKeywordResolution::Measure(AvailableSpace::Definite(style.value())))
38 }
39 CompactLength::FIT_CONTENT_PERCENT_TAG => percent_resolution_basis
40 .map(|basis| SizingKeywordResolution::Measure(AvailableSpace::Definite(basis * style.value()))),
41 CompactLength::FIT_CONTENT_KEYWORD_TAG => {
42 stretch_size.map(|size| SizingKeywordResolution::Measure(AvailableSpace::Definite(size)))
43 }
44 CompactLength::STRETCH_TAG => stretch_size.map(SizingKeywordResolution::Exact),
45 _ => None,
46 }
47}
48
49#[allow(clippy::too_many_arguments)]
58pub(crate) fn resolve_absolute_sizing_keywords(
59 tree: &mut impl LayoutPartialTree,
60 node: NodeId,
61 known_dimensions: &mut Size<Option<f32>>,
62 size_style: Size<Dimension>,
63 area_size: Size<f32>,
64 inset: Rect<Option<f32>>,
65 margin: Rect<Option<f32>>,
66 sizing_mode: SizingMode,
67) {
68 let stretch_size = Size {
69 width: f32_max(
70 area_size.width
71 - inset.left.unwrap_or(0.0)
72 - inset.right.unwrap_or(0.0)
73 - margin.left.unwrap_or(0.0)
74 - margin.right.unwrap_or(0.0),
75 0.0,
76 ),
77 height: f32_max(
78 area_size.height
79 - inset.top.unwrap_or(0.0)
80 - inset.bottom.unwrap_or(0.0)
81 - margin.top.unwrap_or(0.0)
82 - margin.bottom.unwrap_or(0.0),
83 0.0,
84 ),
85 };
86
87 let keyword_width = if known_dimensions.width.is_none() {
88 resolve_sizing_keyword(size_style.width, Some(stretch_size.width), Some(area_size.width))
89 } else {
90 None
91 };
92 let keyword_height = if known_dimensions.height.is_none() {
93 resolve_sizing_keyword(size_style.height, Some(stretch_size.height), Some(area_size.height))
94 } else {
95 None
96 };
97
98 match (keyword_width, keyword_height) {
99 (
101 Some(SizingKeywordResolution::Measure(available_width)),
102 Some(SizingKeywordResolution::Measure(available_height)),
103 ) => {
104 let measured_size = tree.measure_child_size_both(
105 node,
106 Size::NONE,
107 area_size.map(Some),
108 Size { width: available_width, height: available_height },
109 sizing_mode,
110 Line::FALSE,
111 );
112 *known_dimensions = measured_size.map(Some);
113 }
114 (keyword_width, keyword_height) => {
115 if let Some(resolution) = keyword_width {
116 known_dimensions.width = Some(match resolution {
117 SizingKeywordResolution::Exact(width) => width,
118 SizingKeywordResolution::Measure(available_width) => tree.measure_child_size(
119 node,
120 *known_dimensions,
121 area_size.map(Some),
122 Size { width: available_width, height: AvailableSpace::Definite(stretch_size.height) },
123 sizing_mode,
124 AbsoluteAxis::Horizontal,
125 Line::FALSE,
126 ),
127 });
128 }
129 if let Some(resolution) = keyword_height {
130 known_dimensions.height = Some(match resolution {
131 SizingKeywordResolution::Exact(height) => height,
132 SizingKeywordResolution::Measure(available_height) => tree.measure_child_size(
133 node,
134 *known_dimensions,
135 area_size.map(Some),
136 Size {
137 width: known_dimensions
138 .width
139 .map(AvailableSpace::Definite)
140 .unwrap_or(AvailableSpace::Definite(stretch_size.width)),
141 height: available_height,
142 },
143 sizing_mode,
144 AbsoluteAxis::Vertical,
145 Line::FALSE,
146 ),
147 });
148 }
149 }
150 }
151}