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