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 calc_resolver: impl Fn(*const (), f32) -> f32,
33) -> Option<SizingKeywordResolution> {
34 #[cfg(not(feature = "calc"))]
35 let _ = &calc_resolver;
36 match style.tag() {
37 CompactLength::MIN_CONTENT_TAG => Some(SizingKeywordResolution::Measure(AvailableSpace::MinContent)),
38 CompactLength::MAX_CONTENT_TAG => Some(SizingKeywordResolution::Measure(AvailableSpace::MaxContent)),
39 CompactLength::FIT_CONTENT_PX_TAG => {
40 Some(SizingKeywordResolution::Measure(AvailableSpace::Definite(style.value())))
41 }
42 CompactLength::FIT_CONTENT_PERCENT_TAG => percent_resolution_basis
43 .map(|basis| SizingKeywordResolution::Measure(AvailableSpace::Definite(basis * style.value()))),
44 CompactLength::FIT_CONTENT_KEYWORD_TAG => {
45 stretch_size.map(|size| SizingKeywordResolution::Measure(AvailableSpace::Definite(size)))
46 }
47 #[cfg(feature = "calc")]
48 _ if style.is_fit_content_calc() => percent_resolution_basis.map(|basis| {
49 SizingKeywordResolution::Measure(AvailableSpace::Definite(calc_resolver(style.calc_value(), basis)))
50 }),
51 CompactLength::STRETCH_TAG => stretch_size.map(SizingKeywordResolution::Exact),
52 _ => None,
53 }
54}
55
56#[allow(clippy::too_many_arguments)]
65pub(crate) fn resolve_absolute_sizing_keywords(
66 tree: &mut impl LayoutPartialTree,
67 node: NodeId,
68 known_dimensions: &mut Size<Option<f32>>,
69 size_style: Size<Dimension>,
70 area_size: Size<f32>,
71 inset: Rect<Option<f32>>,
72 margin: Rect<Option<f32>>,
73 sizing_mode: SizingMode,
74) {
75 let stretch_size = Size {
76 width: f32_max(
77 area_size.width
78 - inset.left.unwrap_or(0.0)
79 - inset.right.unwrap_or(0.0)
80 - margin.left.unwrap_or(0.0)
81 - margin.right.unwrap_or(0.0),
82 0.0,
83 ),
84 height: f32_max(
85 area_size.height
86 - inset.top.unwrap_or(0.0)
87 - inset.bottom.unwrap_or(0.0)
88 - margin.top.unwrap_or(0.0)
89 - margin.bottom.unwrap_or(0.0),
90 0.0,
91 ),
92 };
93
94 let keyword_width = if known_dimensions.width.is_none() {
95 resolve_sizing_keyword(size_style.width, Some(stretch_size.width), Some(area_size.width), |val, basis| {
96 tree.calc(val, basis)
97 })
98 } else {
99 None
100 };
101 let keyword_height = if known_dimensions.height.is_none() {
102 resolve_sizing_keyword(size_style.height, Some(stretch_size.height), Some(area_size.height), |val, basis| {
103 tree.calc(val, basis)
104 })
105 } else {
106 None
107 };
108
109 match (keyword_width, keyword_height) {
110 (
112 Some(SizingKeywordResolution::Measure(available_width)),
113 Some(SizingKeywordResolution::Measure(available_height)),
114 ) => {
115 let measured_size = tree.measure_child_size_both(
116 node,
117 Size::NONE,
118 area_size.map(Some),
119 Size { width: available_width, height: available_height },
120 sizing_mode,
121 Line::FALSE,
122 );
123 *known_dimensions = measured_size.map(Some);
124 }
125 (keyword_width, keyword_height) => {
126 if let Some(resolution) = keyword_width {
127 known_dimensions.width = Some(match resolution {
128 SizingKeywordResolution::Exact(width) => width,
129 SizingKeywordResolution::Measure(available_width) => tree.measure_child_size(
130 node,
131 *known_dimensions,
132 area_size.map(Some),
133 Size { width: available_width, height: AvailableSpace::Definite(stretch_size.height) },
134 sizing_mode,
135 AbsoluteAxis::Horizontal,
136 Line::FALSE,
137 ),
138 });
139 }
140 if let Some(resolution) = keyword_height {
141 known_dimensions.height = Some(match resolution {
142 SizingKeywordResolution::Exact(height) => height,
143 SizingKeywordResolution::Measure(available_height) => tree.measure_child_size(
144 node,
145 *known_dimensions,
146 area_size.map(Some),
147 Size {
148 width: known_dimensions
149 .width
150 .map(AvailableSpace::Definite)
151 .unwrap_or(AvailableSpace::Definite(stretch_size.width)),
152 height: available_height,
153 },
154 sizing_mode,
155 AbsoluteAxis::Vertical,
156 Line::FALSE,
157 ),
158 });
159 }
160 }
161 }
162}