1pub use euclid::Rect;
2use rustc_hash::FxHashMap;
3
4use crate::{
5 custom_measurer::LayoutMeasurer,
6 geometry::{
7 Area,
8 Size2D,
9 },
10 node::Node,
11 prelude::{
12 AlignAxis,
13 Alignment,
14 AlignmentDirection,
15 AreaConverter,
16 AreaModel,
17 AreaOf,
18 Available,
19 AvailableAreaModel,
20 Direction,
21 Inner,
22 LayoutMetadata,
23 Length,
24 Parent,
25 Position,
26 Torin,
27 },
28 size::Size,
29 torin::DirtyReason,
30 tree_adapter::{
31 LayoutNode,
32 NodeKey,
33 TreeAdapter,
34 },
35};
36
37#[derive(Clone, Copy, PartialEq)]
40pub enum Phase {
41 Initial,
42 Final,
43}
44
45pub struct MeasureContext<'a, Key, L, D>
46where
47 Key: NodeKey,
48 L: LayoutMeasurer<Key>,
49 D: TreeAdapter<Key>,
50{
51 pub layout: &'a mut Torin<Key>,
52 pub measurer: &'a mut Option<L>,
53 pub tree_adapter: &'a mut D,
54 pub layout_metadata: LayoutMetadata,
55}
56
57impl<Key, L, D> MeasureContext<'_, Key, L, D>
58where
59 Key: NodeKey,
60 L: LayoutMeasurer<Key>,
61 D: TreeAdapter<Key>,
62{
63 fn recursive_translate(&mut self, node_id: Key, offset_x: Length, offset_y: Length) {
65 let mut buffer = self
66 .tree_adapter
67 .children_of(&node_id)
68 .into_iter()
69 .map(|id| (node_id, id))
70 .collect::<Vec<(Key, Key)>>();
71 while let Some((parent, child)) = buffer.pop() {
72 let node = self
73 .tree_adapter
74 .get_node(&child)
75 .expect("Node does not exist");
76 let translate = match node.position {
77 Position::Global(_) => false,
78 Position::Absolute(_) => parent != node_id,
79 Position::Stacked(_) => true,
80 };
81 if translate {
82 let layout_node = self
83 .layout
84 .get_mut(&child)
85 .expect("Cached node does not exist");
86
87 layout_node.area.origin.x += offset_x.get();
88 layout_node.area.origin.y += offset_y.get();
89 layout_node.inner_area.origin.x += offset_x.get();
90 layout_node.inner_area.origin.y += offset_y.get();
91
92 buffer.extend(
93 self.tree_adapter
94 .children_of(&child)
95 .into_iter()
96 .map(|id| (node_id, id)),
97 );
98 }
99 }
100 }
101
102 #[allow(clippy::too_many_arguments, clippy::missing_panics_doc)]
104 pub fn measure_node(
105 &mut self,
106 node_id: Key,
107 node: &Node,
108 parent_area: AreaOf<Parent>,
109 available_parent_area: AreaOf<Available>,
110 must_cache_children: bool,
112 parent_is_dirty: bool,
114 phase: Phase,
116 ) -> (bool, LayoutNode) {
117 let reason = self.layout.dirty.get(&node_id).copied();
118
119 if let Some(layout_node) = self.layout.get_mut(&node_id)
121 && reason == Some(DirtyReason::InnerLayout)
122 && must_cache_children
123 {
124 let offset_x = node.offset_x - layout_node.offset_x;
126 let offset_y = node.offset_y - layout_node.offset_y;
127
128 layout_node.offset_x = node.offset_x;
129 layout_node.offset_y = node.offset_y;
130
131 let layout_node = layout_node.clone();
132
133 self.recursive_translate(node_id, offset_x, offset_y);
134
135 return (must_cache_children, layout_node);
136 }
137
138 let must_revalidate =
142 parent_is_dirty || reason.is_some() || !self.layout.results.contains_key(&node_id);
143 if must_revalidate {
144 let mut area_size = Size2D::new(node.padding.horizontal(), node.padding.vertical());
146
147 area_size.width = node.width.min_max(
149 area_size.width,
150 parent_area.size.width,
151 available_parent_area.size.width,
152 node.margin.left(),
153 node.margin.horizontal(),
154 &node.minimum_width,
155 &node.maximum_width,
156 self.layout_metadata.root_area.width(),
157 phase,
158 );
159 area_size.height = node.height.min_max(
160 area_size.height,
161 parent_area.size.height,
162 available_parent_area.size.height,
163 node.margin.top(),
164 node.margin.vertical(),
165 &node.minimum_height,
166 &node.maximum_height,
167 self.layout_metadata.root_area.height(),
168 phase,
169 );
170
171 let node_data = if let Some(measurer) = self.measurer {
174 if measurer.should_hook_measurement(node_id) {
175 let available_width =
176 Size::Pixels(Length::new(available_parent_area.size.width)).min_max(
177 area_size.width,
178 parent_area.size.width,
179 available_parent_area.size.width,
180 node.margin.left(),
181 node.margin.horizontal(),
182 &node.minimum_width,
183 &node.maximum_width,
184 self.layout_metadata.root_area.width(),
185 phase,
186 );
187 let available_height =
188 Size::Pixels(Length::new(available_parent_area.size.height)).min_max(
189 area_size.height,
190 parent_area.size.height,
191 available_parent_area.size.height,
192 node.margin.top(),
193 node.margin.vertical(),
194 &node.minimum_height,
195 &node.maximum_height,
196 self.layout_metadata.root_area.height(),
197 phase,
198 );
199 let most_fitting_width = *node
200 .width
201 .most_fitting_size(&area_size.width, &available_width);
202 let most_fitting_height = *node
203 .height
204 .most_fitting_size(&area_size.height, &available_height);
205
206 let most_fitting_area_size =
207 Size2D::new(most_fitting_width, most_fitting_height);
208 let res = measurer.measure(node_id, node, &most_fitting_area_size);
209
210 #[allow(clippy::float_cmp)]
212 if let Some((custom_size, node_data)) = res {
213 if node.width.inner_sized() {
214 area_size.width = node.width.min_max(
215 custom_size.width,
216 parent_area.size.width,
217 available_parent_area.size.width,
218 node.margin.left(),
219 node.margin.horizontal(),
220 &node.minimum_width,
221 &node.maximum_width,
222 self.layout_metadata.root_area.width(),
223 phase,
224 );
225 }
226 if node.height.inner_sized() {
227 area_size.height = node.height.min_max(
228 custom_size.height,
229 parent_area.size.height,
230 available_parent_area.size.height,
231 node.margin.top(),
232 node.margin.vertical(),
233 &node.minimum_height,
234 &node.maximum_height,
235 self.layout_metadata.root_area.height(),
236 phase,
237 );
238 }
239
240 Some(node_data)
242 } else {
243 None
244 }
245 } else {
246 None
247 }
248 } else {
249 None
250 };
251
252 let measure_inner_children = if let Some(measurer) = self.measurer {
253 measurer.should_measure_inner_children(node_id)
254 } else {
255 true
256 };
257
258 let phase_measure_inner_children = if phase == Phase::Initial {
261 node.width.inner_sized() || node.height.inner_sized()
262 } else {
263 true
264 };
265
266 let inner_size = {
268 let mut inner_size = area_size;
269
270 if node.width.inner_sized() {
272 inner_size.width = node.width.min_max(
273 available_parent_area.width(),
274 parent_area.size.width,
275 available_parent_area.width(),
276 node.margin.left(),
277 node.margin.horizontal(),
278 &node.minimum_width,
279 &node.maximum_width,
280 self.layout_metadata.root_area.width(),
281 phase,
282 );
283 }
284 if node.height.inner_sized() {
285 inner_size.height = node.height.min_max(
286 available_parent_area.height(),
287 parent_area.size.height,
288 available_parent_area.height(),
289 node.margin.top(),
290 node.margin.vertical(),
291 &node.minimum_height,
292 &node.maximum_height,
293 self.layout_metadata.root_area.height(),
294 phase,
295 );
296 }
297 inner_size
298 };
299
300 let area_origin = node.position.get_origin(
302 &available_parent_area,
303 &parent_area,
304 area_size,
305 &self.layout_metadata.root_area,
306 );
307 let mut area = Area::new(area_origin, area_size);
308 let mut inner_area = Rect::new(area_origin, inner_size)
309 .without_gaps(&node.padding)
310 .without_gaps(&node.margin)
311 .as_inner();
312
313 let mut inner_sizes = Size2D::default();
314
315 if measure_inner_children && phase_measure_inner_children {
316 let mut available_area = inner_area.as_available();
318
319 available_area.move_with_offsets(&node.offset_x, &node.offset_y);
320
321 let mut parent_area = area.as_parent();
322
323 self.measure_children(
325 &node_id,
326 node,
327 &mut parent_area,
328 &mut inner_area,
329 &mut available_area,
330 &mut inner_sizes,
331 must_cache_children,
332 true,
333 );
334
335 if node.width.inner_sized() {
338 parent_area.size.width = node.width.min_max(
339 parent_area.size.width,
340 parent_area.size.width,
341 available_parent_area.size.width,
342 0.,
343 0.,
344 &node.minimum_width,
345 &node.maximum_width,
346 self.layout_metadata.root_area.width(),
347 phase,
348 );
349 }
350 if node.height.inner_sized() {
351 parent_area.size.height = node.height.min_max(
352 parent_area.size.height,
353 parent_area.size.height,
354 available_parent_area.size.height,
355 0.,
356 0.,
357 &node.minimum_height,
358 &node.maximum_height,
359 self.layout_metadata.root_area.height(),
360 phase,
361 );
362 }
363
364 area = parent_area.cast_unit();
365 }
366
367 let layout_node = LayoutNode {
368 area,
369 margin: node.margin,
370 offset_x: node.offset_x,
371 offset_y: node.offset_y,
372 inner_area,
373 data: node_data,
374 };
375
376 if must_cache_children
378 && phase == Phase::Final
379 && node.has_layout_references
380 && let Some(measurer) = self.measurer
381 {
382 inner_sizes.width += node.padding.horizontal();
383 inner_sizes.height += node.padding.vertical();
384 measurer.notify_layout_references(
385 node_id,
386 layout_node.area,
387 layout_node.visible_area(),
388 inner_sizes,
389 );
390 }
391
392 (must_cache_children, layout_node)
393 } else {
394 let layout_node = self
395 .layout
396 .get(&node_id)
397 .expect("Cached node does not exist")
398 .clone();
399
400 let mut inner_sizes = Size2D::default();
401 let mut available_area = layout_node.inner_area.as_available();
402 let mut area = layout_node.area.as_parent();
403 let mut inner_area = layout_node.inner_area.as_inner();
404
405 available_area.move_with_offsets(&node.offset_x, &node.offset_y);
406
407 let measure_inner_children = if let Some(measurer) = self.measurer {
408 measurer.should_measure_inner_children(node_id)
409 } else {
410 true
411 };
412
413 if measure_inner_children {
414 self.measure_children(
415 &node_id,
416 node,
417 &mut area,
418 &mut inner_area,
419 &mut available_area,
420 &mut inner_sizes,
421 must_cache_children,
422 false,
423 );
424 }
425
426 (false, layout_node)
427 }
428 }
429
430 #[allow(clippy::too_many_arguments)]
432 pub fn measure_children(
433 &mut self,
434 parent_node_id: &Key,
435 parent_node: &Node,
436 parent_area: &mut AreaOf<Parent>,
437 inner_area: &mut AreaOf<Inner>,
438 available_area: &mut AreaOf<Available>,
439 inner_sizes: &mut Size2D,
441 must_cache_children: bool,
443 parent_is_dirty: bool,
445 ) {
446 let children = self.tree_adapter.children_of(parent_node_id);
447
448 let mut initial_phase_flex_grows = FxHashMap::default();
449 let mut initial_phase_sizes = FxHashMap::default();
450 let mut initial_phase_inner_sizes = Size2D::default();
451
452 let (non_absolute_children_len, first_child, last_child) = if parent_node.spacing.get() > 0.
454 {
455 let mut last_child = None;
456 let mut first_child = None;
457 let len = children
458 .iter()
459 .filter(|child_id| {
460 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
461 return false;
462 };
463 let is_stacked = child_data.position.is_stacked();
464 if is_stacked {
465 last_child = Some(**child_id);
466
467 if first_child.is_none() {
468 first_child = Some(**child_id);
469 }
470 }
471 is_stacked
472 })
473 .count();
474 (len, first_child, last_child)
475 } else {
476 (
477 children.len(),
478 children.first().copied(),
479 children.last().copied(),
480 )
481 };
482
483 let needs_initial_phase = parent_node.cross_alignment.is_not_start()
484 || parent_node.main_alignment.is_not_start()
485 || parent_node.content.is_fit()
486 || parent_node.content.is_flex();
487
488 let mut initial_phase_parent_area = *parent_area;
489 let mut initial_phase_inner_area = *inner_area;
490 let mut initial_phase_available_area = *available_area;
491
492 if needs_initial_phase {
495 for child_id in &children {
497 let Some(child_data) = self.tree_adapter.get_node(child_id) else {
498 continue;
499 };
500
501 if !child_data.position.is_stacked() {
504 continue;
505 }
506
507 let is_last_child = last_child == Some(*child_id);
508
509 let inner_area = initial_phase_inner_area;
510
511 let (_, mut child_areas) = self.measure_node(
512 *child_id,
513 &child_data,
514 inner_area.as_parent(),
515 initial_phase_available_area,
516 false,
517 parent_is_dirty,
518 Phase::Initial,
519 );
520
521 child_areas.area.adjust_size(&child_data);
522
523 Self::stack_child(
525 &mut initial_phase_available_area,
526 parent_node,
527 &child_data,
528 &mut initial_phase_parent_area,
529 &mut initial_phase_inner_area,
530 &mut initial_phase_inner_sizes,
531 &child_areas.area,
532 is_last_child,
533 Phase::Initial,
534 );
535
536 if parent_node.cross_alignment.is_not_start()
537 || parent_node.main_alignment.is_spaced()
538 {
539 initial_phase_sizes.insert(*child_id, child_areas.area.size);
540 }
541
542 if parent_node.content.is_flex() {
543 match parent_node.direction {
544 Direction::Vertical => {
545 if let Some(ff) = child_data.height.flex_grow() {
546 initial_phase_flex_grows.insert(*child_id, ff);
547 }
548 }
549 Direction::Horizontal => {
550 if let Some(ff) = child_data.width.flex_grow() {
551 initial_phase_flex_grows.insert(*child_id, ff);
552 }
553 }
554 }
555 }
556 }
557 }
558
559 let initial_available_area = *available_area;
560
561 let flex_grows = initial_phase_flex_grows
562 .values()
563 .copied()
564 .reduce(|acc, v| acc + v)
565 .unwrap_or_default()
566 .max(Length::new(1.0));
567
568 let flex_axis = AlignAxis::new(&parent_node.direction, AlignmentDirection::Main);
569
570 let flex_available_width = initial_available_area.width() - initial_phase_inner_sizes.width;
571 let flex_available_height =
572 initial_available_area.height() - initial_phase_inner_sizes.height;
573
574 let initial_phase_inner_sizes_with_flex =
575 initial_phase_flex_grows
576 .values()
577 .fold(initial_phase_inner_sizes, |mut acc, f| {
578 let flex_grow_per = f.get() / flex_grows.get() * 100.;
579
580 match flex_axis {
581 AlignAxis::Height => {
582 let size = flex_available_height / 100. * flex_grow_per;
583 acc.height += size;
584 }
585 AlignAxis::Width => {
586 let size = flex_available_width / 100. * flex_grow_per;
587 acc.width += size;
588 }
589 }
590
591 acc
592 });
593
594 if needs_initial_phase {
595 if parent_node.main_alignment.is_not_start() {
596 Self::shrink_area_to_fit_when_unbounded(
598 available_area,
599 &initial_phase_parent_area,
600 &mut initial_phase_inner_area,
601 parent_node,
602 AlignmentDirection::Main,
603 );
604
605 Self::align_content(
607 available_area,
608 &initial_phase_inner_area,
609 initial_phase_inner_sizes_with_flex,
610 &parent_node.main_alignment,
611 parent_node.direction,
612 AlignmentDirection::Main,
613 );
614 }
615
616 if parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit() {
617 Self::shrink_area_to_fit_when_unbounded(
619 available_area,
620 &initial_phase_parent_area,
621 &mut initial_phase_inner_area,
622 parent_node,
623 AlignmentDirection::Cross,
624 );
625 }
626 }
627
628 let initial_available_area = *available_area;
629
630 for child_id in children {
632 let Some(child_data) = self.tree_adapter.get_node(&child_id) else {
633 continue;
634 };
635
636 let is_first_child = first_child == Some(child_id);
637 let is_last_child = last_child == Some(child_id);
638
639 let mut adapted_available_area = *available_area;
640
641 if parent_node.content.is_flex() {
642 let flex_grow = initial_phase_flex_grows.get(&child_id);
643
644 if let Some(flex_grow) = flex_grow {
645 let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
646
647 match flex_axis {
648 AlignAxis::Height => {
649 let size = flex_available_height / 100. * flex_grow_per;
650 adapted_available_area.size.height = size;
651 }
652 AlignAxis::Width => {
653 let size = flex_available_width / 100. * flex_grow_per;
654 adapted_available_area.size.width = size;
655 }
656 }
657 }
658 }
659
660 if parent_node.main_alignment.is_spaced() && child_data.position.is_stacked() {
662 Self::align_position(
664 AlignmentDirection::Main,
665 &mut adapted_available_area,
666 &initial_available_area,
667 initial_phase_inner_sizes_with_flex,
668 &parent_node.main_alignment,
669 parent_node.direction,
670 non_absolute_children_len,
671 is_first_child,
672 );
673 }
674
675 if parent_node.cross_alignment.is_not_start() {
676 let initial_phase_size = initial_phase_sizes.get(&child_id);
677
678 if let Some(initial_phase_size) = initial_phase_size {
679 Self::align_content(
681 &mut adapted_available_area,
682 &available_area.as_inner(),
683 *initial_phase_size,
684 &parent_node.cross_alignment,
685 parent_node.direction,
686 AlignmentDirection::Cross,
687 );
688 }
689 }
690
691 let (child_revalidated, mut child_areas) = self.measure_node(
693 child_id,
694 &child_data,
695 inner_area.as_parent(),
696 adapted_available_area,
697 must_cache_children,
698 parent_is_dirty,
699 Phase::Final,
700 );
701
702 child_areas.area.adjust_size(&child_data);
704
705 if child_data.position.is_stacked() {
707 Self::stack_child(
708 available_area,
709 parent_node,
710 &child_data,
711 parent_area,
712 inner_area,
713 inner_sizes,
714 &child_areas.area,
715 is_last_child,
716 Phase::Final,
717 );
718 }
719
720 if child_revalidated && must_cache_children {
722 self.layout.cache_node(child_id, child_areas);
724 }
725 }
726 }
727
728 fn align_content(
730 available_area: &mut AreaOf<Available>,
731 inner_area: &AreaOf<Inner>,
732 contents_size: Size2D,
733 alignment: &Alignment,
734 direction: Direction,
735 alignment_direction: AlignmentDirection,
736 ) {
737 let axis = AlignAxis::new(&direction, alignment_direction);
738
739 match axis {
740 AlignAxis::Height => match alignment {
741 Alignment::Center => {
742 let new_origin_y = (inner_area.height() / 2.0) - (contents_size.height / 2.0);
743 available_area.origin.y = inner_area.min_y() + new_origin_y;
744 }
745 Alignment::End => {
746 available_area.origin.y = inner_area.max_y() - contents_size.height;
747 }
748 _ => {}
749 },
750 AlignAxis::Width => match alignment {
751 Alignment::Center => {
752 let new_origin_x = (inner_area.width() / 2.0) - (contents_size.width / 2.0);
753 available_area.origin.x = inner_area.min_x() + new_origin_x;
754 }
755 Alignment::End => {
756 available_area.origin.x = inner_area.max_x() - contents_size.width;
757 }
758 _ => {}
759 },
760 }
761 }
762
763 #[allow(clippy::too_many_arguments)]
765 fn align_position(
766 alignment_direction: AlignmentDirection,
767 available_area: &mut AreaOf<Available>,
768 initial_available_area: &AreaOf<Available>,
769 inner_sizes: Size2D,
770 alignment: &Alignment,
771 direction: Direction,
772 siblings_len: usize,
773 is_first_sibling: bool,
774 ) {
775 let axis = AlignAxis::new(&direction, alignment_direction);
776
777 match axis {
778 AlignAxis::Height => match alignment {
779 Alignment::SpaceBetween if !is_first_sibling => {
780 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
781 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
782 available_area.origin.y += gap_size;
783 }
784 Alignment::SpaceEvenly => {
785 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
786 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
787 available_area.origin.y += gap_size;
788 }
789 Alignment::SpaceAround => {
790 let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
791 let one_gap_size = all_gaps_sizes / siblings_len as f32;
792 let gap_size = if is_first_sibling {
793 one_gap_size / 2.
794 } else {
795 one_gap_size
796 };
797 available_area.origin.y += gap_size;
798 }
799 _ => {}
800 },
801 AlignAxis::Width => match alignment {
802 Alignment::SpaceBetween if !is_first_sibling => {
803 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
804 let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
805 available_area.origin.x += gap_size;
806 }
807 Alignment::SpaceEvenly => {
808 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
809 let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
810 available_area.origin.x += gap_size;
811 }
812 Alignment::SpaceAround => {
813 let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
814 let one_gap_size = all_gaps_sizes / siblings_len as f32;
815 let gap_size = if is_first_sibling {
816 one_gap_size / 2.
817 } else {
818 one_gap_size
819 };
820 available_area.origin.x += gap_size;
821 }
822 _ => {}
823 },
824 }
825 }
826
827 #[allow(clippy::too_many_arguments)]
829 fn stack_child(
830 available_area: &mut AreaOf<Available>,
831 parent_node: &Node,
832 child_node: &Node,
833 parent_area: &mut AreaOf<Parent>,
834 inner_area: &mut AreaOf<Inner>,
835 inner_sizes: &mut Size2D,
836 child_area: &Area,
837 is_last_sibiling: bool,
838 phase: Phase,
839 ) {
840 let spacing = if is_last_sibiling {
842 Length::default()
843 } else {
844 parent_node.spacing
845 };
846
847 match parent_node.direction {
848 Direction::Horizontal => {
849 available_area.origin.x = child_area.max_x() + spacing.get();
851 available_area.size.width -= child_area.size.width + spacing.get();
852
853 inner_sizes.height = child_area.height().max(inner_sizes.height);
854 inner_sizes.width += spacing.get();
855 if !child_node.width.is_flex() || phase == Phase::Final {
856 inner_sizes.width += child_area.width();
857 }
858
859 if parent_node.height.inner_sized() {
861 parent_area.size.height = parent_area.size.height.max(
862 child_area.size.height
863 + parent_node.padding.vertical()
864 + parent_node.margin.vertical(),
865 );
866 inner_area.size.height = parent_area.size.height
868 - parent_node.padding.vertical()
869 - parent_node.margin.vertical();
870 }
871
872 if parent_node.width.inner_sized() {
874 parent_area.size.width += child_area.size.width + spacing.get();
875 }
876 }
877 Direction::Vertical => {
878 available_area.origin.y = child_area.max_y() + spacing.get();
880 available_area.size.height -= child_area.size.height + spacing.get();
881
882 inner_sizes.width = child_area.width().max(inner_sizes.width);
883 inner_sizes.height += spacing.get();
884 if !child_node.height.is_flex() || phase == Phase::Final {
885 inner_sizes.height += child_area.height();
886 }
887
888 if parent_node.width.inner_sized() {
890 parent_area.size.width = parent_area.size.width.max(
891 child_area.size.width
892 + parent_node.padding.horizontal()
893 + parent_node.margin.horizontal(),
894 );
895 inner_area.size.width = parent_area.size.width
897 - parent_node.padding.horizontal()
898 - parent_node.margin.horizontal();
899 }
900
901 if parent_node.height.inner_sized() {
903 parent_area.size.height += child_area.size.height + spacing.get();
904 }
905 }
906 }
907 }
908
909 fn shrink_area_to_fit_when_unbounded(
915 available_area: &mut AreaOf<Available>,
916 parent_area: &AreaOf<Parent>,
917 inner_area: &mut AreaOf<Inner>,
918 parent_node: &Node,
919 alignment_direction: AlignmentDirection,
920 ) {
921 struct NodeData<'a> {
922 pub inner_origin: &'a mut f32,
923 pub inner_size: &'a mut f32,
924 pub area_origin: f32,
925 pub area_size: f32,
926 pub one_side_padding: f32,
927 pub two_sides_padding: f32,
928 pub one_side_margin: f32,
929 pub two_sides_margin: f32,
930 pub available_size: &'a mut f32,
931 }
932
933 let axis = AlignAxis::new(&parent_node.direction, alignment_direction);
934 let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction {
935 Direction::Vertical => (
936 parent_node.main_alignment.is_not_start(),
937 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
938 ),
939 Direction::Horizontal => (
940 parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
941 parent_node.main_alignment.is_not_start(),
942 ),
943 };
944 let NodeData {
945 inner_origin,
946 inner_size,
947 area_origin,
948 area_size,
949 one_side_padding,
950 two_sides_padding,
951 one_side_margin,
952 two_sides_margin,
953 available_size,
954 } = match axis {
955 AlignAxis::Height if parent_node.height.inner_sized() && is_vertical_not_start => {
956 NodeData {
957 inner_origin: &mut inner_area.origin.y,
958 inner_size: &mut inner_area.size.height,
959 area_origin: parent_area.origin.y,
960 area_size: parent_area.size.height,
961 one_side_padding: parent_node.padding.top(),
962 two_sides_padding: parent_node.padding.vertical(),
963 one_side_margin: parent_node.margin.top(),
964 two_sides_margin: parent_node.margin.vertical(),
965 available_size: &mut available_area.size.height,
966 }
967 }
968 AlignAxis::Width if parent_node.width.inner_sized() && is_horizontal_not_start => {
969 NodeData {
970 inner_origin: &mut inner_area.origin.x,
971 inner_size: &mut inner_area.size.width,
972 area_origin: parent_area.origin.x,
973 area_size: parent_area.size.width,
974 one_side_padding: parent_node.padding.left(),
975 two_sides_padding: parent_node.padding.horizontal(),
976 one_side_margin: parent_node.margin.left(),
977 two_sides_margin: parent_node.margin.horizontal(),
978 available_size: &mut available_area.size.width,
979 }
980 }
981 _ => return,
982 };
983
984 *inner_origin = area_origin + one_side_padding + one_side_margin;
986 *inner_size = area_size - two_sides_padding - two_sides_margin;
988 *available_size = *inner_size;
990 }
991}