torin/
measure.rs

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/// Some layout strategies require two-phase measurements
38/// Example: Alignments or content-fit.
39#[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    /// Translate all the children of the given Node by the specified X and Y offsets.
64    fn recursive_translate(&mut self, node_id: Key, offset_x: Length, offset_y: Length) {
65        let mut buffer = self.tree_adapter.children_of(&node_id);
66        while let Some(child) = buffer.pop() {
67            let node = self
68                .tree_adapter
69                .get_node(&child)
70                .expect("Node does not exist");
71
72            let translate = match node.position {
73                Position::Global(_) => false,
74                Position::Stacked(_) | Position::Absolute(_) => true,
75            };
76
77            if translate {
78                let layout_node = self
79                    .layout
80                    .get_mut(&child)
81                    .expect("Cached node does not exist");
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                if let Some(measurer) = self.measurer {
88                    measurer.notify_layout_references(
89                        child,
90                        layout_node.area,
91                        layout_node.visible_area(),
92                        layout_node.inner_sizes,
93                    );
94                }
95
96                buffer.extend(self.tree_adapter.children_of(&child));
97            }
98        }
99    }
100
101    /// Measure a Node and all its children.
102    #[allow(clippy::too_many_arguments, clippy::missing_panics_doc)]
103    pub fn measure_node(
104        &mut self,
105        node_id: Key,
106        node: &Node,
107        // Area occupied by it's parent
108        parent_area: AreaOf<Parent>,
109        // Initial area occupied by it's parent
110        initial_parent_area: AreaOf<Parent>,
111        // Area that is available to use by the children of the parent
112        available_parent_area: AreaOf<Available>,
113        // Whether to cache the measurements of this Node's children
114        must_cache_children: bool,
115        // Parent Node is dirty.
116        parent_is_dirty: bool,
117        // Current phase of measurement
118        phase: Phase,
119    ) -> (bool, LayoutNode) {
120        let reason = self.layout.dirty.get(&node_id).copied();
121
122        // If possible translate all this Node's descendants to avoid relayout
123        if let Some(layout_node) = self.layout.get_mut(&node_id)
124            && reason == Some(DirtyReason::InnerLayout)
125            && must_cache_children
126        {
127            // Get the offset difference since the last layout
128            let offset_x = node.offset_x - layout_node.offset_x;
129            let offset_y = node.offset_y - layout_node.offset_y;
130
131            layout_node.offset_x = node.offset_x;
132            layout_node.offset_y = node.offset_y;
133
134            let layout_node = layout_node.clone();
135
136            self.recursive_translate(node_id, offset_x, offset_y);
137
138            return (must_cache_children, layout_node);
139        }
140
141        // 1. If parent is dirty
142        // 2. If this Node has been marked as dirty
143        // 3. If there is no know cached data about this Node.
144        let must_revalidate =
145            parent_is_dirty || reason.is_some() || !self.layout.results.contains_key(&node_id);
146        if must_revalidate {
147            // Create the initial Node area size
148            let mut area_size = Size2D::new(node.padding.horizontal(), node.padding.vertical());
149
150            // Compute the width and height given the size, the minimum size, the maximum size and margins
151            area_size.width = node.width.min_max(
152                area_size.width,
153                initial_parent_area.size.width,
154                available_parent_area.size.width,
155                node.margin.left(),
156                node.margin.horizontal(),
157                &node.minimum_width,
158                &node.maximum_width,
159                self.layout_metadata.root_area.width(),
160                phase,
161            );
162            area_size.height = node.height.min_max(
163                area_size.height,
164                initial_parent_area.size.height,
165                available_parent_area.size.height,
166                node.margin.top(),
167                node.margin.vertical(),
168                &node.minimum_height,
169                &node.maximum_height,
170                self.layout_metadata.root_area.height(),
171                phase,
172            );
173
174            // If available, run a custom layout measure function
175            // This is useful when you use third-party libraries (e.g. rust-skia, cosmic-text) to measure text layouts
176            let node_data = if let Some(measurer) = self.measurer {
177                if measurer.should_hook_measurement(node_id) {
178                    let available_width =
179                        Size::Pixels(Length::new(available_parent_area.size.width)).min_max(
180                            area_size.width,
181                            initial_parent_area.size.width,
182                            available_parent_area.size.width,
183                            node.margin.left(),
184                            node.margin.horizontal(),
185                            &node.minimum_width,
186                            &node.maximum_width,
187                            self.layout_metadata.root_area.width(),
188                            phase,
189                        );
190                    let available_height =
191                        Size::Pixels(Length::new(available_parent_area.size.height)).min_max(
192                            area_size.height,
193                            initial_parent_area.size.height,
194                            available_parent_area.size.height,
195                            node.margin.top(),
196                            node.margin.vertical(),
197                            &node.minimum_height,
198                            &node.maximum_height,
199                            self.layout_metadata.root_area.height(),
200                            phase,
201                        );
202                    let most_fitting_width = *node
203                        .width
204                        .most_fitting_size(&area_size.width, &available_width);
205                    let most_fitting_height = *node
206                        .height
207                        .most_fitting_size(&area_size.height, &available_height);
208
209                    let most_fitting_area_size =
210                        Size2D::new(most_fitting_width, most_fitting_height);
211                    let res = measurer.measure(node_id, node, &most_fitting_area_size);
212
213                    // Compute the width and height again using the new custom area sizes
214                    #[allow(clippy::float_cmp)]
215                    if let Some((custom_size, node_data)) = res {
216                        if node.width.inner_sized() {
217                            area_size.width = node.width.min_max(
218                                custom_size.width,
219                                initial_parent_area.size.width,
220                                available_parent_area.size.width,
221                                node.margin.left(),
222                                node.margin.horizontal(),
223                                &node.minimum_width,
224                                &node.maximum_width,
225                                self.layout_metadata.root_area.width(),
226                                phase,
227                            );
228                        }
229                        if node.height.inner_sized() {
230                            area_size.height = node.height.min_max(
231                                custom_size.height,
232                                initial_parent_area.size.height,
233                                available_parent_area.size.height,
234                                node.margin.top(),
235                                node.margin.vertical(),
236                                &node.minimum_height,
237                                &node.maximum_height,
238                                self.layout_metadata.root_area.height(),
239                                phase,
240                            );
241                        }
242
243                        // Do not measure inner children
244                        Some(node_data)
245                    } else {
246                        None
247                    }
248                } else {
249                    None
250                }
251            } else {
252                None
253            };
254
255            let measure_inner_children = if let Some(measurer) = self.measurer {
256                measurer.should_measure_inner_children(node_id)
257            } else {
258                true
259            };
260
261            // There is no need to measure inner children in the initial phase if this Node size
262            // isn't decided by his children
263            let phase_measure_inner_children = if phase == Phase::Initial {
264                node.width.inner_sized() || node.height.inner_sized()
265            } else {
266                true
267            };
268
269            // Compute the inner size of the Node, which is basically the size inside the margins and paddings
270            let inner_size = {
271                let mut inner_size = area_size;
272
273                // When having an unsized bound we set it to whatever is still available in the parent's area
274                if node.width.inner_sized() {
275                    inner_size.width = node.width.min_max(
276                        available_parent_area.width(),
277                        initial_parent_area.size.width,
278                        available_parent_area.width(),
279                        node.margin.left(),
280                        node.margin.horizontal(),
281                        &node.minimum_width,
282                        &node.maximum_width,
283                        self.layout_metadata.root_area.width(),
284                        phase,
285                    );
286                }
287                if node.height.inner_sized() {
288                    inner_size.height = node.height.min_max(
289                        available_parent_area.height(),
290                        initial_parent_area.size.height,
291                        available_parent_area.height(),
292                        node.margin.top(),
293                        node.margin.vertical(),
294                        &node.minimum_height,
295                        &node.maximum_height,
296                        self.layout_metadata.root_area.height(),
297                        phase,
298                    );
299                }
300                inner_size
301            };
302
303            // Create the areas
304            let area_origin = node.position.get_origin(
305                &available_parent_area,
306                &parent_area,
307                area_size,
308                &self.layout_metadata.root_area,
309            );
310            let mut area = Area::new(area_origin, area_size);
311            let mut inner_area = Rect::new(area_origin, inner_size)
312                .without_gaps(&node.padding)
313                .without_gaps(&node.margin)
314                .as_inner();
315
316            let mut inner_sizes = Size2D::default();
317
318            if measure_inner_children && phase_measure_inner_children {
319                // Create an area containing the available space inside the inner area
320                let mut available_area = inner_area.as_available();
321
322                available_area.move_with_offsets(&node.offset_x, &node.offset_y);
323
324                let mut parent_area = area.as_parent();
325
326                // Measure the layout of this Node's children
327                self.measure_children(
328                    &node_id,
329                    node,
330                    &mut parent_area,
331                    &mut inner_area,
332                    &mut available_area,
333                    &mut inner_sizes,
334                    must_cache_children,
335                    true,
336                );
337
338                // Re apply min max values after measuring with inner sized
339                // Margins are set to 0 because area.size already contains the margins
340                if node.width.inner_sized() {
341                    parent_area.size.width = node.width.min_max(
342                        parent_area.size.width,
343                        parent_area.size.width,
344                        available_parent_area.size.width,
345                        0.,
346                        0.,
347                        &node.minimum_width,
348                        &node.maximum_width,
349                        self.layout_metadata.root_area.width(),
350                        phase,
351                    );
352                }
353                if node.height.inner_sized() {
354                    parent_area.size.height = node.height.min_max(
355                        parent_area.size.height,
356                        parent_area.size.height,
357                        available_parent_area.size.height,
358                        0.,
359                        0.,
360                        &node.minimum_height,
361                        &node.maximum_height,
362                        self.layout_metadata.root_area.height(),
363                        phase,
364                    );
365                }
366
367                area = parent_area.cast_unit();
368            }
369
370            let layout_node = LayoutNode {
371                area,
372                margin: node.margin,
373                offset_x: node.offset_x,
374                offset_y: node.offset_y,
375                inner_area,
376                data: node_data,
377                inner_sizes,
378            };
379
380            // In case of any layout listener, notify it with the new areas.
381            if must_cache_children
382                && phase == Phase::Final
383                && node.has_layout_references
384                && let Some(measurer) = self.measurer
385            {
386                inner_sizes.width += node.padding.horizontal();
387                inner_sizes.height += node.padding.vertical();
388                measurer.notify_layout_references(
389                    node_id,
390                    layout_node.area,
391                    layout_node.visible_area(),
392                    inner_sizes,
393                );
394            }
395
396            (must_cache_children, layout_node)
397        } else {
398            let layout_node = self
399                .layout
400                .get(&node_id)
401                .expect("Cached node does not exist")
402                .clone();
403
404            let mut inner_sizes = Size2D::default();
405            let mut available_area = layout_node.inner_area.as_available();
406            let mut area = layout_node.area.as_parent();
407            let mut inner_area = layout_node.inner_area.as_inner();
408
409            available_area.move_with_offsets(&node.offset_x, &node.offset_y);
410
411            let measure_inner_children = if let Some(measurer) = self.measurer {
412                measurer.should_measure_inner_children(node_id)
413            } else {
414                true
415            };
416
417            if measure_inner_children {
418                self.measure_children(
419                    &node_id,
420                    node,
421                    &mut area,
422                    &mut inner_area,
423                    &mut available_area,
424                    &mut inner_sizes,
425                    must_cache_children,
426                    false,
427                );
428            }
429
430            (false, layout_node)
431        }
432    }
433
434    /// Measure the children layouts of a Node.
435    #[allow(clippy::too_many_arguments)]
436    pub fn measure_children(
437        &mut self,
438        parent_node_id: &Key,
439        parent_node: &Node,
440        parent_area: &mut AreaOf<Parent>,
441        inner_area: &mut AreaOf<Inner>,
442        available_area: &mut AreaOf<Available>,
443        // Accumulated sizes in both axis in the Node
444        inner_sizes: &mut Size2D,
445        // Whether to cache the measurements of this Node's children
446        must_cache_children: bool,
447        // Parent Node is dirty.
448        parent_is_dirty: bool,
449    ) {
450        let children = self.tree_adapter.children_of(parent_node_id);
451
452        let initial_area = *inner_area;
453
454        let mut initial_phase_flex_grows = FxHashMap::default();
455        let mut initial_phase_sizes = FxHashMap::default();
456        let mut initial_phase_inner_sizes = Size2D::default();
457
458        // Used to calculate the spacing and some alignments
459        let (non_absolute_children_len, first_child, last_child) = if parent_node.spacing.get() > 0.
460        {
461            let mut last_child = None;
462            let mut first_child = None;
463            let len = children
464                .iter()
465                .filter(|child_id| {
466                    let Some(child_data) = self.tree_adapter.get_node(child_id) else {
467                        return false;
468                    };
469                    let is_stacked = child_data.position.is_stacked();
470                    if is_stacked {
471                        last_child = Some(**child_id);
472
473                        if first_child.is_none() {
474                            first_child = Some(**child_id);
475                        }
476                    }
477                    is_stacked
478                })
479                .count();
480            (len, first_child, last_child)
481        } else {
482            (
483                children.len(),
484                children.first().copied(),
485                children.last().copied(),
486            )
487        };
488
489        let needs_initial_phase = parent_node.cross_alignment.is_not_start()
490            || parent_node.main_alignment.is_not_start()
491            || parent_node.content.is_fit()
492            || parent_node.content.is_flex()
493            || parent_node.content.is_wrap();
494
495        let mut initial_phase_parent_area = *parent_area;
496        let mut initial_phase_inner_area = *inner_area;
497        let mut initial_phase_available_area = *available_area;
498
499        // Initial phase: Measure the size and position of the children if the parent has a
500        // non-start cross alignment, non-start main alignment of a fit-content.
501        if needs_initial_phase {
502            //  Measure the children
503            for child_id in &children {
504                let Some(child_data) = self.tree_adapter.get_node(child_id) else {
505                    continue;
506                };
507
508                // No need to consider this Node for a two-phasing
509                // measurements as it will float on its own.
510                if !child_data.position.is_stacked() {
511                    continue;
512                }
513
514                let is_last_child = last_child == Some(*child_id);
515
516                let inner_area = initial_phase_inner_area;
517
518                let (_, mut child_areas) = self.measure_node(
519                    *child_id,
520                    &child_data,
521                    inner_area.as_parent(),
522                    initial_area.as_parent(),
523                    initial_phase_available_area,
524                    false,
525                    parent_is_dirty,
526                    Phase::Initial,
527                );
528
529                child_areas.area.adjust_size(&child_data);
530
531                // Stack this child into the parent
532                Self::stack_child(
533                    &mut initial_phase_available_area,
534                    parent_node,
535                    &child_data,
536                    &mut initial_phase_parent_area,
537                    &mut initial_phase_inner_area,
538                    &mut initial_phase_inner_sizes,
539                    &child_areas.area,
540                    is_last_child,
541                    Phase::Initial,
542                );
543
544                if parent_node.cross_alignment.is_not_start()
545                    || parent_node.main_alignment.is_spaced()
546                    || parent_node.content.is_wrap()
547                {
548                    initial_phase_sizes.insert(*child_id, child_areas.area.size);
549                }
550
551                if parent_node.content.is_flex() {
552                    match parent_node.direction {
553                        Direction::Vertical => {
554                            if let Some(ff) = child_data.height.flex_grow() {
555                                initial_phase_flex_grows.insert(*child_id, ff);
556                            }
557                        }
558                        Direction::Horizontal => {
559                            if let Some(ff) = child_data.width.flex_grow() {
560                                initial_phase_flex_grows.insert(*child_id, ff);
561                            }
562                        }
563                    }
564                }
565            }
566        }
567
568        let flex_grows = initial_phase_flex_grows
569            .values()
570            .copied()
571            .reduce(|acc, v| acc + v)
572            .unwrap_or_default()
573            .max(Length::new(1.0));
574
575        let flex_axis = AlignAxis::new(&parent_node.direction, AlignmentDirection::Main);
576
577        let flex_available_width = available_area.width() - initial_phase_inner_sizes.width;
578        let flex_available_height = available_area.height() - initial_phase_inner_sizes.height;
579
580        if parent_node.content.is_flex() {
581            initial_phase_inner_sizes =
582                initial_phase_flex_grows
583                    .values()
584                    .fold(initial_phase_inner_sizes, |mut acc, f| {
585                        let flex_grow_per = f.get() / flex_grows.get() * 100.;
586
587                        match flex_axis {
588                            AlignAxis::Height => {
589                                let size = flex_available_height / 100. * flex_grow_per;
590                                acc.height += size;
591                            }
592                            AlignAxis::Width => {
593                                let size = flex_available_width / 100. * flex_grow_per;
594                                acc.width += size;
595                            }
596                        }
597
598                        acc
599                    });
600        }
601
602        if needs_initial_phase {
603            if parent_node.content.is_wrap() {
604                Self::wrap_adjust_initial(
605                    &children,
606                    parent_node,
607                    &initial_phase_sizes,
608                    &mut initial_phase_inner_sizes,
609                    &mut initial_phase_available_area,
610                    &mut initial_phase_parent_area,
611                    &mut initial_phase_inner_area,
612                );
613            }
614
615            if parent_node.main_alignment.is_not_start() && parent_node.content.allows_alignments()
616            {
617                // Adjust the available and inner areas of the Main axis
618                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::Main,
624                );
625
626                // Align the Main axis
627                Self::align_content(
628                    available_area,
629                    &initial_phase_inner_area,
630                    initial_phase_inner_sizes,
631                    &parent_node.main_alignment,
632                    parent_node.direction,
633                    AlignmentDirection::Main,
634                );
635            }
636
637            if (parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit())
638                && parent_node.content.allows_alignments()
639            {
640                // Adjust the available and inner areas of the Cross axis
641                Self::shrink_area_to_fit_when_unbounded(
642                    available_area,
643                    &initial_phase_parent_area,
644                    &mut initial_phase_inner_area,
645                    parent_node,
646                    AlignmentDirection::Cross,
647                );
648            }
649        }
650
651        let initial_available_area = *available_area;
652
653        // Final phase: measure the children with all the axis and sizes adjusted
654        for child_id in children {
655            let Some(child_data) = self.tree_adapter.get_node(&child_id) else {
656                continue;
657            };
658
659            let is_first_child = first_child == Some(child_id);
660            let is_last_child = last_child == Some(child_id);
661
662            let mut adapted_available_area = *available_area;
663
664            if parent_node.content.is_flex() {
665                let flex_grow = initial_phase_flex_grows.get(&child_id);
666
667                if let Some(flex_grow) = flex_grow {
668                    let flex_grow_per = flex_grow.get() / flex_grows.get() * 100.;
669
670                    match flex_axis {
671                        AlignAxis::Height => {
672                            let size = flex_available_height / 100. * flex_grow_per;
673                            adapted_available_area.size.height = size;
674                        }
675                        AlignAxis::Width => {
676                            let size = flex_available_width / 100. * flex_grow_per;
677                            adapted_available_area.size.width = size;
678                        }
679                    }
680                }
681            }
682
683            // Only the stacked children will be aligned
684            if parent_node.main_alignment.is_spaced()
685                && child_data.position.is_stacked()
686                && parent_node.content.allows_alignments()
687            {
688                // Align the Main axis if necessary
689                Self::align_position(
690                    AlignmentDirection::Main,
691                    &mut adapted_available_area,
692                    &initial_available_area,
693                    initial_phase_inner_sizes,
694                    &parent_node.main_alignment,
695                    parent_node.direction,
696                    non_absolute_children_len,
697                    is_first_child,
698                );
699            }
700
701            if parent_node.cross_alignment.is_not_start() && parent_node.content.allows_alignments()
702            {
703                let initial_phase_size = initial_phase_sizes.get(&child_id);
704
705                if let Some(initial_phase_size) = initial_phase_size {
706                    // Align the Cross axis if necessary
707                    Self::align_content(
708                        &mut adapted_available_area,
709                        &available_area.as_inner(),
710                        *initial_phase_size,
711                        &parent_node.cross_alignment,
712                        parent_node.direction,
713                        AlignmentDirection::Cross,
714                    );
715                }
716            }
717
718            if parent_node.content.is_wrap() {
719                let initial_phase_size = initial_phase_sizes.get(&child_id);
720                Self::wrap_handle_final(
721                    parent_node,
722                    initial_phase_size,
723                    &initial_available_area,
724                    available_area,
725                    &mut adapted_available_area,
726                    *inner_sizes,
727                );
728            }
729
730            // Final measurement
731            let (child_revalidated, mut child_areas) = self.measure_node(
732                child_id,
733                &child_data,
734                inner_area.as_parent(),
735                initial_area.as_parent(),
736                adapted_available_area,
737                must_cache_children,
738                parent_is_dirty,
739                Phase::Final,
740            );
741
742            // Adjust the size of the area if needed
743            child_areas.area.adjust_size(&child_data);
744
745            // Stack this child into the parent
746            if child_data.position.is_stacked() {
747                Self::stack_child(
748                    available_area,
749                    parent_node,
750                    &child_data,
751                    parent_area,
752                    inner_area,
753                    inner_sizes,
754                    &child_areas.area,
755                    is_last_child,
756                    Phase::Final,
757                );
758            }
759
760            // Cache the child layout if it was mutated and children must be cached
761            if child_revalidated && must_cache_children {
762                // Finally cache this node areas into Torin
763                self.layout.cache_node(child_id, child_areas);
764            }
765        }
766    }
767
768    // In order to make the elements wrap in the second phase we need to
769    // update the available area to have the proper width/height as if nodes had been wrapped already
770    fn wrap_adjust_initial(
771        children: &[Key],
772        parent_node: &Node,
773        initial_phase_sizes: &FxHashMap<Key, Size2D>,
774        initial_phase_inner_sizes: &mut Size2D,
775        available_area: &mut AreaOf<Available>,
776        parent_area: &mut AreaOf<Parent>,
777        _initial_phase_inner_area: &mut AreaOf<Inner>,
778    ) {
779        let mut used_area = Area::zero();
780        let break_size = *initial_phase_inner_sizes;
781        for child_id in children {
782            let initial_phase_size = initial_phase_sizes.get(child_id);
783            if let Some(initial_phase_size) = initial_phase_size {
784                match parent_node.direction {
785                    Direction::Vertical => {
786                        if available_area.height() - used_area.height() - initial_phase_size.height
787                            < 0.
788                        {
789                            // Break the line if there is no enough space
790                            used_area.size.height = initial_phase_size.height;
791                            available_area.size.width += break_size.width;
792                            // Keep increasing for every break
793                            initial_phase_inner_sizes.width += break_size.width;
794                            if parent_node.width.inner_sized() {
795                                parent_area.size.width += break_size.width;
796                            }
797                        } else {
798                            // Otherwise just keep adding each child size
799                            used_area.size.height += initial_phase_size.height;
800                        }
801                    }
802                    Direction::Horizontal => {
803                        if available_area.width() - used_area.width() - initial_phase_size.width
804                            < 0.
805                        {
806                            // Break the line if there is no enough space
807                            used_area.size.width = initial_phase_size.width;
808                            available_area.size.height += break_size.height;
809                            // Keep increasing for every break
810                            initial_phase_inner_sizes.height += break_size.height;
811                            if parent_node.height.inner_sized() {
812                                parent_area.size.height += break_size.height;
813                            }
814                        } else {
815                            // Otherwise just keep adding each child size
816                            used_area.size.width += initial_phase_size.width;
817                        }
818                    }
819                }
820            }
821        }
822    }
823
824    /// Handle wrapping adjustments for a single child during the final phase.
825    fn wrap_handle_final(
826        parent_node: &Node,
827        initial_phase_size: Option<&Size2D>,
828        initial_available_area: &AreaOf<Available>,
829        available_area: &mut AreaOf<Available>,
830        adapted_available_area: &mut AreaOf<Available>,
831        inner_sizes: Size2D,
832    ) {
833        if let Some(initial_phase_size) = initial_phase_size {
834            match parent_node.direction {
835                Direction::Vertical => {
836                    if adapted_available_area.height() - initial_phase_size.height < 0. {
837                        available_area.origin.y = initial_available_area.origin.y;
838                        available_area.size.height = initial_available_area.size.height;
839                        available_area.origin.x += inner_sizes.width;
840                        adapted_available_area.origin.y = initial_available_area.origin.y;
841                        adapted_available_area.size.height = initial_available_area.size.height;
842                        adapted_available_area.origin.x += inner_sizes.width;
843                    }
844                }
845                Direction::Horizontal => {
846                    if adapted_available_area.width() - initial_phase_size.width < 0. {
847                        available_area.origin.x = initial_available_area.origin.x;
848                        available_area.size.width = initial_available_area.size.width;
849                        available_area.origin.y += inner_sizes.height;
850                        adapted_available_area.origin.x = initial_available_area.origin.x;
851                        adapted_available_area.size.width = initial_available_area.size.width;
852                        adapted_available_area.origin.y += inner_sizes.height;
853                    }
854                }
855            }
856        }
857    }
858
859    /// Align the content of this node.
860    fn align_content(
861        available_area: &mut AreaOf<Available>,
862        inner_area: &AreaOf<Inner>,
863        contents_size: Size2D,
864        alignment: &Alignment,
865        direction: Direction,
866        alignment_direction: AlignmentDirection,
867    ) {
868        let axis = AlignAxis::new(&direction, alignment_direction);
869
870        match axis {
871            AlignAxis::Height => match alignment {
872                Alignment::Center => {
873                    let new_origin_y = (inner_area.height() / 2.0) - (contents_size.height / 2.0);
874                    available_area.origin.y = inner_area.min_y() + new_origin_y;
875                }
876                Alignment::End => {
877                    available_area.origin.y = inner_area.max_y() - contents_size.height;
878                }
879                _ => {}
880            },
881            AlignAxis::Width => match alignment {
882                Alignment::Center => {
883                    let new_origin_x = (inner_area.width() / 2.0) - (contents_size.width / 2.0);
884                    available_area.origin.x = inner_area.min_x() + new_origin_x;
885                }
886                Alignment::End => {
887                    available_area.origin.x = inner_area.max_x() - contents_size.width;
888                }
889                _ => {}
890            },
891        }
892    }
893
894    /// Align the position of this node.
895    #[allow(clippy::too_many_arguments)]
896    fn align_position(
897        alignment_direction: AlignmentDirection,
898        available_area: &mut AreaOf<Available>,
899        initial_available_area: &AreaOf<Available>,
900        inner_sizes: Size2D,
901        alignment: &Alignment,
902        direction: Direction,
903        siblings_len: usize,
904        is_first_sibling: bool,
905    ) {
906        let axis = AlignAxis::new(&direction, alignment_direction);
907
908        match axis {
909            AlignAxis::Height => match alignment {
910                Alignment::SpaceBetween if !is_first_sibling => {
911                    let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
912                    let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
913                    available_area.origin.y += gap_size;
914                }
915                Alignment::SpaceEvenly => {
916                    let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
917                    let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
918                    available_area.origin.y += gap_size;
919                }
920                Alignment::SpaceAround => {
921                    let all_gaps_sizes = initial_available_area.height() - inner_sizes.height;
922                    let one_gap_size = all_gaps_sizes / siblings_len as f32;
923                    let gap_size = if is_first_sibling {
924                        one_gap_size / 2.
925                    } else {
926                        one_gap_size
927                    };
928                    available_area.origin.y += gap_size;
929                }
930                _ => {}
931            },
932            AlignAxis::Width => match alignment {
933                Alignment::SpaceBetween if !is_first_sibling => {
934                    let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
935                    let gap_size = all_gaps_sizes / (siblings_len - 1) as f32;
936                    available_area.origin.x += gap_size;
937                }
938                Alignment::SpaceEvenly => {
939                    let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
940                    let gap_size = all_gaps_sizes / (siblings_len + 1) as f32;
941                    available_area.origin.x += gap_size;
942                }
943                Alignment::SpaceAround => {
944                    let all_gaps_sizes = initial_available_area.width() - inner_sizes.width;
945                    let one_gap_size = all_gaps_sizes / siblings_len as f32;
946                    let gap_size = if is_first_sibling {
947                        one_gap_size / 2.
948                    } else {
949                        one_gap_size
950                    };
951                    available_area.origin.x += gap_size;
952                }
953                _ => {}
954            },
955        }
956    }
957
958    /// Stack a child Node into its parent
959    #[allow(clippy::too_many_arguments)]
960    fn stack_child(
961        available_area: &mut AreaOf<Available>,
962        parent_node: &Node,
963        child_node: &Node,
964        parent_area: &mut AreaOf<Parent>,
965        inner_area: &mut AreaOf<Inner>,
966        inner_sizes: &mut Size2D,
967        child_area: &Area,
968        is_last_sibilin: bool,
969        phase: Phase,
970    ) {
971        // Only apply the spacing to elements after `i > 0` and `i < len - 1`
972        let spacing = if is_last_sibilin {
973            Length::default()
974        } else {
975            parent_node.spacing
976        };
977
978        match parent_node.direction {
979            Direction::Horizontal => {
980                // Move the available area
981                available_area.origin.x = child_area.max_x() + spacing.get();
982                available_area.size.width -= child_area.size.width + spacing.get();
983
984                inner_sizes.height = child_area.height().max(inner_sizes.height);
985                inner_sizes.width += spacing.get();
986                if !child_node.width.is_flex() || phase == Phase::Final {
987                    inner_sizes.width += child_area.width();
988                }
989
990                // Keep the biggest height
991                if parent_node.height.inner_sized() {
992                    parent_area.size.height = parent_area.size.height.max(
993                        child_area.size.height
994                            + parent_node.padding.vertical()
995                            + parent_node.margin.vertical(),
996                    );
997                    // Keep the inner area in sync
998                    inner_area.size.height = parent_area.size.height
999                        - parent_node.padding.vertical()
1000                        - parent_node.margin.vertical();
1001                }
1002
1003                // Accumulate width
1004                if parent_node.width.inner_sized() {
1005                    parent_area.size.width += child_area.size.width + spacing.get();
1006                }
1007            }
1008            Direction::Vertical => {
1009                // Move the available area
1010                available_area.origin.y = child_area.max_y() + spacing.get();
1011                available_area.size.height -= child_area.size.height + spacing.get();
1012
1013                inner_sizes.width = child_area.width().max(inner_sizes.width);
1014                inner_sizes.height += spacing.get();
1015                if !child_node.height.is_flex() || phase == Phase::Final {
1016                    inner_sizes.height += child_area.height();
1017                }
1018
1019                // Keep the biggest width
1020                if parent_node.width.inner_sized() {
1021                    parent_area.size.width = parent_area.size.width.max(
1022                        child_area.size.width
1023                            + parent_node.padding.horizontal()
1024                            + parent_node.margin.horizontal(),
1025                    );
1026                    // Keep the inner area in sync
1027                    inner_area.size.width = parent_area.size.width
1028                        - parent_node.padding.horizontal()
1029                        - parent_node.margin.horizontal();
1030                }
1031
1032                // Accumulate height
1033                if parent_node.height.inner_sized() {
1034                    parent_area.size.height += child_area.size.height + spacing.get();
1035                }
1036            }
1037        }
1038    }
1039
1040    /// Shrink the available area and inner area of a parent node when for example height is set to "auto",
1041    /// direction is vertical and main_alignment is set to "center" or "end" or the content is set to "fit".
1042    /// The intended usage is to call this after the first measurement and before the second,
1043    /// this way the second measurement will align the content relatively to the parent element instead
1044    /// of overflowing due to being aligned relatively to the upper parent element
1045    fn shrink_area_to_fit_when_unbounded(
1046        available_area: &mut AreaOf<Available>,
1047        parent_area: &AreaOf<Parent>,
1048        inner_area: &mut AreaOf<Inner>,
1049        parent_node: &Node,
1050        alignment_direction: AlignmentDirection,
1051    ) {
1052        struct NodeData<'a> {
1053            pub inner_origin: &'a mut f32,
1054            pub inner_size: &'a mut f32,
1055            pub area_origin: f32,
1056            pub area_size: f32,
1057            pub one_side_padding: f32,
1058            pub two_sides_padding: f32,
1059            pub one_side_margin: f32,
1060            pub two_sides_margin: f32,
1061            pub available_size: &'a mut f32,
1062        }
1063
1064        let axis = AlignAxis::new(&parent_node.direction, alignment_direction);
1065        let (is_vertical_not_start, is_horizontal_not_start) = match parent_node.direction {
1066            Direction::Vertical => (
1067                parent_node.main_alignment.is_not_start(),
1068                parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1069            ),
1070            Direction::Horizontal => (
1071                parent_node.cross_alignment.is_not_start() || parent_node.content.is_fit(),
1072                parent_node.main_alignment.is_not_start(),
1073            ),
1074        };
1075        let NodeData {
1076            inner_origin,
1077            inner_size,
1078            area_origin,
1079            area_size,
1080            one_side_padding,
1081            two_sides_padding,
1082            one_side_margin,
1083            two_sides_margin,
1084            available_size,
1085        } = match axis {
1086            AlignAxis::Height if parent_node.height.inner_sized() && is_vertical_not_start => {
1087                NodeData {
1088                    inner_origin: &mut inner_area.origin.y,
1089                    inner_size: &mut inner_area.size.height,
1090                    area_origin: parent_area.origin.y,
1091                    area_size: parent_area.size.height,
1092                    one_side_padding: parent_node.padding.top(),
1093                    two_sides_padding: parent_node.padding.vertical(),
1094                    one_side_margin: parent_node.margin.top(),
1095                    two_sides_margin: parent_node.margin.vertical(),
1096                    available_size: &mut available_area.size.height,
1097                }
1098            }
1099            AlignAxis::Width if parent_node.width.inner_sized() && is_horizontal_not_start => {
1100                NodeData {
1101                    inner_origin: &mut inner_area.origin.x,
1102                    inner_size: &mut inner_area.size.width,
1103                    area_origin: parent_area.origin.x,
1104                    area_size: parent_area.size.width,
1105                    one_side_padding: parent_node.padding.left(),
1106                    two_sides_padding: parent_node.padding.horizontal(),
1107                    one_side_margin: parent_node.margin.left(),
1108                    two_sides_margin: parent_node.margin.horizontal(),
1109                    available_size: &mut available_area.size.width,
1110                }
1111            }
1112            _ => return,
1113        };
1114
1115        // Set the origin of the inner area to the origin of the area plus the padding and margin for the given axis
1116        *inner_origin = area_origin + one_side_padding + one_side_margin;
1117        // Set the size of the inner area to the size of the area minus the padding and margin for the given axis
1118        *inner_size = area_size - two_sides_padding - two_sides_margin;
1119        // Set the same available size as the inner area for the given axis
1120        *available_size = *inner_size;
1121    }
1122}