Call measure function on leaf nodes even if the node does not have context (#598)
1#[cfg(test)]
2mod measure {
3 use taffy::prelude::*;
4
5 #[derive(Debug, Clone, Copy)]
6 struct FixedMeasure {
7 width: f32,
8 height: f32,
9 }
10 fn fixed_measure_function(
11 known_dimensions: Size<Option<f32>>,
12 _available_space: Size<AvailableSpace>,
13 _node_id: NodeId,
14 node_context: Option<&mut FixedMeasure>,
15 ) -> taffy::geometry::Size<f32> {
16 let size = node_context.copied().unwrap_or(FixedMeasure { width: 0.0, height: 0.0 });
17 Size {
18 width: known_dimensions.width.unwrap_or(size.width),
19 height: known_dimensions.height.unwrap_or(size.height),
20 }
21 }
22
23 struct AspectRatioMeasure {
24 width: f32,
25 height_ratio: f32,
26 }
27 fn aspect_ratio_measure_function(
28 known_dimensions: Size<Option<f32>>,
29 _available_space: Size<AvailableSpace>,
30 _node_id: NodeId,
31 node_context: Option<&mut AspectRatioMeasure>,
32 ) -> taffy::geometry::Size<f32> {
33 let Some(node_context) = node_context else { return Size::ZERO };
34 let width = known_dimensions.width.unwrap_or(node_context.width);
35 let height = known_dimensions.height.unwrap_or(width * node_context.height_ratio);
36 Size { width, height }
37 }
38
39 #[test]
40 fn measure_root() {
41 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
42 let node = taffy.new_leaf_with_context(Style::default(), FixedMeasure { width: 100.0, height: 100.0 }).unwrap();
43 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
44
45 assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
46 assert_eq!(taffy.layout(node).unwrap().size.height, 100.0);
47 }
48
49 #[test]
50 fn measure_child() {
51 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
52
53 let child =
54 taffy.new_leaf_with_context(Style::default(), FixedMeasure { width: 100.0, height: 100.0 }).unwrap();
55
56 let node = taffy.new_with_children(Style::default(), &[child]).unwrap();
57 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
58
59 assert_eq!(taffy.layout(node).unwrap().size.width, 100.0);
60 assert_eq!(taffy.layout(node).unwrap().size.height, 100.0);
61
62 assert_eq!(taffy.layout(child).unwrap().size.width, 100.0);
63 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
64 }
65
66 #[test]
67 fn measure_child_constraint() {
68 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
69 let child =
70 taffy.new_leaf_with_context(Style::default(), FixedMeasure { width: 100.0, height: 100.0 }).unwrap();
71
72 let node = taffy
73 .new_with_children(
74 Style { size: Size { width: Dimension::Length(50.0), height: auto() }, ..Default::default() },
75 &[child],
76 )
77 .unwrap();
78
79 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
80
81 // Parent
82 assert_eq!(taffy.layout(node).unwrap().size.width, 50.0);
83 assert_eq!(taffy.layout(node).unwrap().size.height, 100.0);
84 // Child
85 assert_eq!(taffy.layout(child).unwrap().size.width, 100.0);
86 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
87 }
88
89 #[test]
90 fn measure_child_constraint_padding_parent() {
91 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
92 let child =
93 taffy.new_leaf_with_context(Style::default(), FixedMeasure { width: 100.0, height: 100.0 }).unwrap();
94
95 let node = taffy
96 .new_with_children(
97 Style {
98 size: Size { width: Dimension::Length(50.0), height: auto() },
99 padding: Rect {
100 left: LengthPercentage::Length(10.0),
101 right: LengthPercentage::Length(10.0),
102 top: LengthPercentage::Length(10.0),
103 bottom: LengthPercentage::Length(10.0),
104 },
105 ..Default::default()
106 },
107 &[child],
108 )
109 .unwrap();
110 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
111
112 assert_eq!(taffy.layout(node).unwrap().location.x, 0.0);
113 assert_eq!(taffy.layout(node).unwrap().location.y, 0.0);
114 assert_eq!(taffy.layout(node).unwrap().size.width, 50.0);
115 assert_eq!(taffy.layout(node).unwrap().size.height, 120.0);
116
117 assert_eq!(taffy.layout(child).unwrap().location.x, 10.0);
118 assert_eq!(taffy.layout(child).unwrap().location.y, 10.0);
119 assert_eq!(taffy.layout(child).unwrap().size.width, 100.0);
120 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
121 }
122
123 #[test]
124 fn measure_child_with_flex_grow() {
125 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
126 let child0 = taffy
127 .new_leaf(Style {
128 size: Size { width: Dimension::Length(50.0), height: Dimension::Length(50.0) },
129 ..Default::default()
130 })
131 .unwrap();
132
133 let child1 = taffy
134 .new_leaf_with_context(
135 Style { flex_grow: 1.0, ..Default::default() },
136 FixedMeasure { width: 10.0, height: 50.0 },
137 )
138 .unwrap();
139
140 let node = taffy
141 .new_with_children(
142 Style { size: Size { width: Dimension::Length(100.0), height: auto() }, ..Default::default() },
143 &[child0, child1],
144 )
145 .unwrap();
146
147 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
148
149 assert_eq!(taffy.layout(child1).unwrap().size.width, 50.0);
150 assert_eq!(taffy.layout(child1).unwrap().size.height, 50.0);
151 }
152
153 #[test]
154 fn measure_child_with_flex_shrink() {
155 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
156 let child0 = taffy
157 .new_leaf(Style {
158 size: Size { width: Dimension::Length(50.0), height: Dimension::Length(50.0) },
159 flex_shrink: 0.0,
160 ..Default::default()
161 })
162 .unwrap();
163
164 let child1 =
165 taffy.new_leaf_with_context(Style::default(), FixedMeasure { width: 100.0, height: 50.0 }).unwrap();
166
167 let node = taffy
168 .new_with_children(
169 Style { size: Size { width: Dimension::Length(100.0), height: auto() }, ..Default::default() },
170 &[child0, child1],
171 )
172 .unwrap();
173
174 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
175
176 assert_eq!(taffy.layout(child1).unwrap().size.width, 100.0);
177 assert_eq!(taffy.layout(child1).unwrap().size.height, 50.0);
178 }
179
180 #[test]
181 fn remeasure_child_after_growing() {
182 let mut taffy: TaffyTree<AspectRatioMeasure> = TaffyTree::new();
183 let child0 = taffy
184 .new_leaf(Style {
185 size: Size { width: Dimension::Length(50.0), height: Dimension::Length(50.0) },
186 ..Default::default()
187 })
188 .unwrap();
189
190 let child1 = taffy
191 .new_leaf_with_context(
192 Style { flex_grow: 1.0, ..Default::default() },
193 AspectRatioMeasure { width: 10.0, height_ratio: 2.0 },
194 )
195 .unwrap();
196
197 let node = taffy
198 .new_with_children(
199 Style {
200 size: Size { width: Dimension::Length(100.0), height: auto() },
201 align_items: Some(AlignItems::Start),
202 ..Default::default()
203 },
204 &[child0, child1],
205 )
206 .unwrap();
207
208 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, aspect_ratio_measure_function).unwrap();
209
210 assert_eq!(taffy.layout(child1).unwrap().size.width, 50.0);
211 assert_eq!(taffy.layout(child1).unwrap().size.height, 100.0);
212 }
213
214 #[test]
215 fn remeasure_child_after_shrinking() {
216 let mut taffy: TaffyTree<AspectRatioMeasure> = TaffyTree::new();
217
218 let child0 = taffy
219 .new_leaf(Style {
220 size: Size { width: Dimension::Length(50.0), height: Dimension::Length(50.0) },
221 flex_shrink: 0.0,
222 ..Default::default()
223 })
224 .unwrap();
225
226 let child1 = taffy
227 .new_leaf_with_context(Style::default(), AspectRatioMeasure { width: 100.0, height_ratio: 2.0 })
228 .unwrap();
229
230 let node = taffy
231 .new_with_children(
232 Style {
233 size: Size { width: Dimension::Length(100.0), height: auto() },
234 align_items: Some(AlignItems::Start),
235 ..Default::default()
236 },
237 &[child0, child1],
238 )
239 .unwrap();
240
241 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, aspect_ratio_measure_function).unwrap();
242
243 assert_eq!(taffy.layout(child1).unwrap().size.width, 100.0);
244 assert_eq!(taffy.layout(child1).unwrap().size.height, 200.0);
245 }
246
247 #[test]
248 fn remeasure_child_after_stretching() {
249 let mut taffy: TaffyTree<()> = TaffyTree::new();
250
251 fn custom_measure_function(
252 known_dimensions: Size<Option<f32>>,
253 _available_space: Size<AvailableSpace>,
254 _node_id: NodeId,
255 _node_context: Option<&mut ()>,
256 ) -> taffy::geometry::Size<f32> {
257 let height = known_dimensions.height.unwrap_or(50.0);
258 let width = known_dimensions.width.unwrap_or(height);
259 Size { width, height }
260 }
261
262 let child = taffy.new_leaf_with_context(Style::default(), ()).unwrap();
263
264 let node = taffy
265 .new_with_children(
266 Style {
267 size: Size { width: Dimension::Length(100.0), height: Dimension::Length(100.0) },
268 ..Default::default()
269 },
270 &[child],
271 )
272 .unwrap();
273
274 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, custom_measure_function).unwrap();
275
276 assert_eq!(taffy.layout(child).unwrap().size.width, 100.0);
277 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
278 }
279
280 #[test]
281 fn width_overrides_measure() {
282 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
283 let child = taffy
284 .new_leaf_with_context(
285 Style { size: Size { width: Dimension::Length(50.0), height: auto() }, ..Default::default() },
286 FixedMeasure { width: 100.0, height: 100.0 },
287 )
288 .unwrap();
289
290 let node = taffy.new_with_children(Style::default(), &[child]).unwrap();
291 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
292
293 assert_eq!(taffy.layout(child).unwrap().size.width, 50.0);
294 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
295 }
296
297 #[test]
298 fn height_overrides_measure() {
299 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
300 let child = taffy
301 .new_leaf_with_context(
302 Style { size: Size { width: auto(), height: Dimension::Length(50.0) }, ..Default::default() },
303 FixedMeasure { width: 100.0, height: 100.0 },
304 )
305 .unwrap();
306
307 let node = taffy.new_with_children(Style::default(), &[child]).unwrap();
308 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
309
310 assert_eq!(taffy.layout(child).unwrap().size.width, 100.0);
311 assert_eq!(taffy.layout(child).unwrap().size.height, 50.0);
312 }
313
314 #[test]
315 fn flex_basis_overrides_measure() {
316 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
317 let child0 = taffy
318 .new_leaf(Style { flex_basis: Dimension::Length(50.0), flex_grow: 1.0, ..Default::default() })
319 .unwrap();
320
321 let child1 = taffy
322 .new_leaf_with_context(
323 Style { flex_basis: Dimension::Length(50.0), flex_grow: 1.0, ..Default::default() },
324 FixedMeasure { width: 100.0, height: 100.0 },
325 )
326 .unwrap();
327
328 let node = taffy
329 .new_with_children(
330 Style {
331 size: Size { width: Dimension::Length(200.0), height: Dimension::Length(100.0) },
332 ..Default::default()
333 },
334 &[child0, child1],
335 )
336 .unwrap();
337
338 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
339
340 assert_eq!(taffy.layout(child0).unwrap().size.width, 100.0);
341 assert_eq!(taffy.layout(child0).unwrap().size.height, 100.0);
342 assert_eq!(taffy.layout(child1).unwrap().size.width, 100.0);
343 assert_eq!(taffy.layout(child1).unwrap().size.height, 100.0);
344 }
345
346 #[test]
347 fn stretch_overrides_measure() {
348 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
349 let child = taffy.new_leaf_with_context(Style::default(), FixedMeasure { width: 50.0, height: 50.0 }).unwrap();
350
351 let node = taffy
352 .new_with_children(
353 Style {
354 size: Size { width: Dimension::Length(100.0), height: Dimension::Length(100.0) },
355 ..Default::default()
356 },
357 &[child],
358 )
359 .unwrap();
360
361 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
362
363 assert_eq!(taffy.layout(child).unwrap().size.width, 50.0);
364 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
365 }
366
367 #[test]
368 fn measure_absolute_child() {
369 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
370 let child = taffy
371 .new_leaf_with_context(
372 Style { position: Position::Absolute, ..Default::default() },
373 FixedMeasure { width: 50.0, height: 50.0 },
374 )
375 .unwrap();
376
377 let node = taffy
378 .new_with_children(
379 Style {
380 size: Size { width: Dimension::Length(100.0), height: Dimension::Length(100.0) },
381 ..Default::default()
382 },
383 &[child],
384 )
385 .unwrap();
386
387 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
388
389 assert_eq!(taffy.layout(child).unwrap().size.width, 50.0);
390 assert_eq!(taffy.layout(child).unwrap().size.height, 50.0);
391 }
392
393 #[test]
394 fn ignore_invalid_measure() {
395 let mut taffy: TaffyTree<FixedMeasure> = TaffyTree::new();
396 let child = taffy.new_leaf(Style { flex_grow: 1.0, ..Default::default() }).unwrap();
397
398 let node = taffy
399 .new_with_children(
400 Style {
401 size: Size { width: Dimension::Length(100.0), height: Dimension::Length(100.0) },
402 ..Default::default()
403 },
404 &[child],
405 )
406 .unwrap();
407
408 taffy.compute_layout_with_measure(node, Size::MAX_CONTENT, fixed_measure_function).unwrap();
409
410 assert_eq!(taffy.layout(child).unwrap().size.width, 100.0);
411 assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
412 }
413}