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