1use std::any::{Any, TypeId};
4use std::fmt;
5use std::ops::{Add, Sub};
6
7use inset_embedder::{Clip, Offset, Size, TextBaseline, TextDirection};
8use inset_foundation::{App, Handle, PRECISION_ERROR_TOLERANCE};
9use inset_painting::{Axis, VerticalDirection};
10
11use crate::box_::{
12 AnyRenderBox, BaselineOffset, BoxConstraints, BoxHitTestResult, BoxParentData,
13 ContainerBoxParentData, RenderBox, RenderBoxContainerDefaultsMixin, RenderBoxData,
14};
15use crate::layer::{ClipRectLayer, LayerHandle};
16use crate::layout_helper::{ChildLayoutHelper, ChildLayouter};
17use crate::object::{
18 AnyRenderObject, ContainerParentData, ContainerParentDataMixin, ContainerRenderObjectData,
19 ContainerRenderObjectMixin, ParentData, RenderHandle, RenderObject, RenderObjectData,
20};
21use crate::painting_context::PaintingContext;
22use crate::pipeline_owner::PipelineOwner;
23
24#[derive(Clone, Copy)]
27struct AxisSize(Size);
28
29impl AxisSize {
30 const EMPTY: AxisSize = AxisSize(Size::ZERO);
31
32 fn new(main_axis_extent: f64, cross_axis_extent: f64) -> AxisSize {
33 AxisSize(Size::new(main_axis_extent, cross_axis_extent))
34 }
35
36 fn from_size(size: Size, direction: Axis) -> AxisSize {
37 AxisSize(AxisSize::convert(size, direction))
38 }
39
40 fn convert(size: Size, direction: Axis) -> Size {
41 match direction {
42 Axis::Horizontal => size,
43 Axis::Vertical => size.flipped(),
44 }
45 }
46
47 fn main_axis_extent(self) -> f64 {
48 self.0.width()
49 }
50
51 fn cross_axis_extent(self) -> f64 {
52 self.0.height()
53 }
54
55 fn to_size(self, direction: Axis) -> Size {
56 AxisSize::convert(self.0, direction)
57 }
58
59 fn apply_constraints(self, constraints: BoxConstraints, direction: Axis) -> AxisSize {
60 let effective_constraints = match direction {
61 Axis::Horizontal => constraints,
62 Axis::Vertical => constraints.flipped(),
63 };
64 AxisSize(effective_constraints.constrain(self.0))
65 }
66
67 fn flipped(self) -> AxisSize {
68 AxisSize(self.0.flipped())
69 }
70}
71
72impl Add for AxisSize {
73 type Output = AxisSize;
74
75 fn add(self, other: AxisSize) -> AxisSize {
76 AxisSize(Size::new(
77 self.0.width() + other.0.width(),
78 self.0.height().max(other.0.height()),
79 ))
80 }
81}
82
83impl Sub for AxisSize {
84 type Output = AxisSize;
85
86 fn sub(self, other: AxisSize) -> AxisSize {
87 AxisSize(Size::new(
88 self.0.width() - other.0.width(),
89 self.0.height() - other.0.height(),
90 ))
91 }
92}
93
94#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
99pub enum WrapAlignment {
100 #[default]
108 Start,
109
110 End,
118
119 Center,
121
122 SpaceBetween,
124
125 SpaceAround,
128
129 SpaceEvenly,
132}
133
134impl WrapAlignment {
135 fn distribute_space(
137 self,
138 free_space: f64,
139 item_spacing: f64,
140 item_count: usize,
141 flipped: bool,
142 ) -> (f64, f64) {
143 debug_assert!(item_count > 0);
144 let count = item_count as f64;
145 match self {
146 WrapAlignment::Start => (if flipped { free_space } else { 0.0 }, item_spacing),
147 WrapAlignment::End => WrapAlignment::Start.distribute_space(
148 free_space,
149 item_spacing,
150 item_count,
151 !flipped,
152 ),
153 WrapAlignment::SpaceBetween if item_count < 2 => {
154 WrapAlignment::Start.distribute_space(free_space, item_spacing, item_count, flipped)
155 }
156 WrapAlignment::Center => (free_space / 2.0, item_spacing),
157 WrapAlignment::SpaceBetween => (0.0, free_space / (count - 1.0) + item_spacing),
158 WrapAlignment::SpaceAround => {
159 (free_space / count / 2.0, free_space / count + item_spacing)
160 }
161 WrapAlignment::SpaceEvenly => (
162 free_space / (count + 1.0),
163 free_space / (count + 1.0) + item_spacing,
164 ),
165 }
166 }
167}
168
169#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
171pub enum WrapCrossAlignment {
172 #[default]
180 Start,
181
182 End,
190
191 Center,
193 }
195
196impl WrapCrossAlignment {
197 fn flipped(self) -> WrapCrossAlignment {
198 match self {
199 WrapCrossAlignment::Start => WrapCrossAlignment::End,
200 WrapCrossAlignment::End => WrapCrossAlignment::Start,
201 WrapCrossAlignment::Center => WrapCrossAlignment::Center,
202 }
203 }
204
205 fn alignment(self) -> f64 {
206 match self {
207 WrapCrossAlignment::Start => 0.0,
208 WrapCrossAlignment::End => 1.0,
209 WrapCrossAlignment::Center => 0.5,
210 }
211 }
212}
213
214struct RunMetrics {
216 axis_size: AxisSize,
217 child_count: usize,
218 leading_child: AnyRenderBox,
219}
220
221impl RunMetrics {
222 fn new(leading_child: AnyRenderBox, axis_size: AxisSize) -> RunMetrics {
223 RunMetrics {
224 axis_size,
225 child_count: 1,
226 leading_child,
227 }
228 }
229
230 fn try_adding_new_child(
233 &mut self,
234 child: AnyRenderBox,
235 child_size: AxisSize,
236 flip_main_axis: bool,
237 spacing: f64,
238 max_main_extent: f64,
239 ) -> Option<RunMetrics> {
240 let needs_new_run =
241 self.axis_size.main_axis_extent() + child_size.main_axis_extent() + spacing
242 - max_main_extent
243 > PRECISION_ERROR_TOLERANCE;
244 if needs_new_run {
245 return Some(RunMetrics::new(child, child_size));
246 }
247 self.axis_size = self.axis_size + child_size + AxisSize::new(spacing, 0.0);
248 self.child_count += 1;
249 if flip_main_axis {
250 self.leading_child = child;
251 }
252 None
253 }
254}
255
256#[derive(Debug, Default)]
258pub struct WrapParentData {
259 box_parent_data: BoxParentData,
260 container_parent_data: ContainerParentData<AnyRenderBox>,
261}
262
263impl WrapParentData {
264 pub const fn new() -> WrapParentData {
266 WrapParentData {
267 box_parent_data: BoxParentData::new(),
268 container_parent_data: ContainerParentData::new(),
269 }
270 }
271}
272
273impl ParentData for WrapParentData {
274 fn detach(&mut self) {
275 ContainerParentDataMixin::detach(self);
276 }
277
278 fn provide(&self, id: TypeId) -> Option<&dyn Any> {
279 if id == TypeId::of::<WrapParentData>() {
280 return Some(self);
281 }
282 self.box_parent_data.provide(id)
283 }
284
285 fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
286 if id == TypeId::of::<WrapParentData>() {
287 return Some(self);
288 }
289 self.box_parent_data.provide_mut(id)
290 }
291}
292
293impl ContainerParentDataMixin for WrapParentData {
294 type ChildType = AnyRenderBox;
295
296 fn container_parent_data(&self) -> &ContainerParentData<AnyRenderBox> {
297 &self.container_parent_data
298 }
299
300 fn container_parent_data_mut(&mut self) -> &mut ContainerParentData<AnyRenderBox> {
301 &mut self.container_parent_data
302 }
303}
304
305impl ContainerBoxParentData for WrapParentData {
306 fn box_parent_data(&self) -> &BoxParentData {
307 &self.box_parent_data
308 }
309
310 fn box_parent_data_mut(&mut self) -> &mut BoxParentData {
311 &mut self.box_parent_data
312 }
313}
314
315impl fmt::Display for WrapParentData {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 fmt::Display::fmt(&self.box_parent_data, f)
318 }
319}
320
321pub struct RenderWrap {
335 render_object: RenderObjectData,
336 render_box: RenderBoxData,
337 container: ContainerRenderObjectData<AnyRenderBox>,
338 direction: Axis,
339 alignment: WrapAlignment,
340 spacing: f64,
341 run_alignment: WrapAlignment,
342 run_spacing: f64,
343 cross_axis_alignment: WrapCrossAlignment,
344 text_direction: Option<TextDirection>,
345 vertical_direction: VerticalDirection,
346 clip_behavior: Clip,
347 has_visual_overflow: bool,
348 clip_rect_layer: LayerHandle<Handle<ClipRectLayer>>,
349}
350
351impl RenderWrap {
352 pub fn new(app: &mut App) -> RenderHandle<RenderWrap> {
359 RenderHandle::new_box(
360 app,
361 RenderWrap {
362 render_object: RenderObjectData::new(),
363 render_box: RenderBoxData::new(),
364 container: ContainerRenderObjectData::new(),
365 direction: Axis::Horizontal,
366 alignment: WrapAlignment::Start,
367 spacing: 0.0,
368 run_alignment: WrapAlignment::Start,
369 run_spacing: 0.0,
370 cross_axis_alignment: WrapCrossAlignment::Start,
371 text_direction: None,
372 vertical_direction: VerticalDirection::Down,
373 clip_behavior: Clip::None,
374 has_visual_overflow: false,
375 clip_rect_layer: LayerHandle::new(),
376 },
377 )
378 }
379
380 pub fn direction(self: RenderHandle<Self>, app: &App) -> Axis {
387 self.get(app).direction
388 }
389
390 pub fn set_direction(self: RenderHandle<Self>, app: &mut App, value: Axis) {
392 if self.get(app).direction == value {
393 return;
394 }
395 self.get_mut(app).direction = value;
396 self.mark_needs_layout(app);
397 }
398
399 pub fn alignment(self: RenderHandle<Self>, app: &App) -> WrapAlignment {
413 self.get(app).alignment
414 }
415
416 pub fn set_alignment(self: RenderHandle<Self>, app: &mut App, value: WrapAlignment) {
418 if self.get(app).alignment == value {
419 return;
420 }
421 self.get_mut(app).alignment = value;
422 self.mark_needs_layout(app);
423 }
424
425 pub fn spacing(self: RenderHandle<Self>, app: &App) -> f64 {
436 self.get(app).spacing
437 }
438
439 pub fn set_spacing(self: RenderHandle<Self>, app: &mut App, value: f64) {
441 if self.get(app).spacing == value {
442 return;
443 }
444 self.get_mut(app).spacing = value;
445 self.mark_needs_layout(app);
446 }
447
448 pub fn run_alignment(self: RenderHandle<Self>, app: &App) -> WrapAlignment {
462 self.get(app).run_alignment
463 }
464
465 pub fn set_run_alignment(self: RenderHandle<Self>, app: &mut App, value: WrapAlignment) {
467 if self.get(app).run_alignment == value {
468 return;
469 }
470 self.get_mut(app).run_alignment = value;
471 self.mark_needs_layout(app);
472 }
473
474 pub fn run_spacing(self: RenderHandle<Self>, app: &App) -> f64 {
485 self.get(app).run_spacing
486 }
487
488 pub fn set_run_spacing(self: RenderHandle<Self>, app: &mut App, value: f64) {
490 if self.get(app).run_spacing == value {
491 return;
492 }
493 self.get_mut(app).run_spacing = value;
494 self.mark_needs_layout(app);
495 }
496
497 pub fn cross_axis_alignment(self: RenderHandle<Self>, app: &App) -> WrapCrossAlignment {
513 self.get(app).cross_axis_alignment
514 }
515
516 pub fn set_cross_axis_alignment(
518 self: RenderHandle<Self>,
519 app: &mut App,
520 value: WrapCrossAlignment,
521 ) {
522 if self.get(app).cross_axis_alignment == value {
523 return;
524 }
525 self.get_mut(app).cross_axis_alignment = value;
526 self.mark_needs_layout(app);
527 }
528
529 pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
554 self.get(app).text_direction
555 }
556
557 pub fn set_text_direction(
559 self: RenderHandle<Self>,
560 app: &mut App,
561 value: Option<TextDirection>,
562 ) {
563 if self.get(app).text_direction != value {
564 self.get_mut(app).text_direction = value;
565 self.mark_needs_layout(app);
566 }
567 }
568
569 pub fn vertical_direction(self: RenderHandle<Self>, app: &App) -> VerticalDirection {
582 self.get(app).vertical_direction
583 }
584
585 pub fn set_vertical_direction(
587 self: RenderHandle<Self>,
588 app: &mut App,
589 value: VerticalDirection,
590 ) {
591 if self.get(app).vertical_direction != value {
592 self.get_mut(app).vertical_direction = value;
593 self.mark_needs_layout(app);
594 }
595 }
596
597 pub fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
601 self.get(app).clip_behavior
602 }
603
604 pub fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
606 if value != self.get(app).clip_behavior {
607 self.get_mut(app).clip_behavior = value;
608 self.mark_needs_paint(app);
609 }
610 }
611
612 fn debug_has_necessary_directions(self: RenderHandle<Self>, app: &App) -> bool {
615 let this = self.get(app);
616 let has_text_direction = this.text_direction.is_some();
617 if self.first_child(app).is_some() && self.last_child(app) != self.first_child(app) {
618 if this.direction == Axis::Horizontal {
620 debug_assert!(
621 has_text_direction,
622 "Horizontal RenderWrap with multiple children has a null textDirection, so \
623 the layout order is undefined."
624 );
625 }
626 }
627 let alignment = this.alignment;
628 if matches!(alignment, WrapAlignment::Start | WrapAlignment::End)
629 && this.direction == Axis::Horizontal
630 {
631 debug_assert!(
632 has_text_direction,
633 "Horizontal RenderWrap with alignment {alignment:?} has a null textDirection, so \
634 the alignment cannot be resolved."
635 );
636 }
637 let run_alignment = this.run_alignment;
638 if matches!(run_alignment, WrapAlignment::Start | WrapAlignment::End)
639 && this.direction == Axis::Vertical
640 {
641 debug_assert!(
642 has_text_direction,
643 "Vertical RenderWrap with runAlignment {run_alignment:?} has a null \
644 textDirection, so the alignment cannot be resolved."
645 );
646 }
647 let cross_axis_alignment = this.cross_axis_alignment;
648 if matches!(
649 cross_axis_alignment,
650 WrapCrossAlignment::Start | WrapCrossAlignment::End
651 ) && this.direction == Axis::Vertical
652 {
653 debug_assert!(
654 has_text_direction,
655 "Vertical RenderWrap with crossAxisAlignment {cross_axis_alignment:?} has a \
656 null textDirection, so the alignment cannot be resolved."
657 );
658 }
659 true
660 }
661
662 fn get_main_axis_extent(self: RenderHandle<Self>, app: &App, child_size: Size) -> f64 {
663 match self.direction(app) {
664 Axis::Horizontal => child_size.width(),
665 Axis::Vertical => child_size.height(),
666 }
667 }
668
669 fn get_cross_axis_extent(self: RenderHandle<Self>, app: &App, child_size: Size) -> f64 {
670 match self.direction(app) {
671 Axis::Horizontal => child_size.height(),
672 Axis::Vertical => child_size.width(),
673 }
674 }
675
676 fn get_offset(
677 self: RenderHandle<Self>,
678 app: &App,
679 main_axis_offset: f64,
680 cross_axis_offset: f64,
681 ) -> Offset {
682 match self.direction(app) {
683 Axis::Horizontal => Offset::new(main_axis_offset, cross_axis_offset),
684 Axis::Vertical => Offset::new(cross_axis_offset, main_axis_offset),
685 }
686 }
687
688 fn are_axes_flipped(self: RenderHandle<Self>, app: &App) -> (bool, bool) {
690 let this = self.get(app);
691 let flip_horizontal = match this.text_direction.unwrap_or(TextDirection::Ltr) {
692 TextDirection::Ltr => false,
693 TextDirection::Rtl => true,
694 };
695 let flip_vertical = match this.vertical_direction {
696 VerticalDirection::Down => false,
697 VerticalDirection::Up => true,
698 };
699 match this.direction {
700 Axis::Horizontal => (flip_horizontal, flip_vertical),
701 Axis::Vertical => (flip_vertical, flip_horizontal),
702 }
703 }
704
705 fn child_constraints_and_main_axis_limit(
707 self: RenderHandle<Self>,
708 app: &App,
709 constraints: BoxConstraints,
710 ) -> (BoxConstraints, f64) {
711 match self.direction(app) {
712 Axis::Horizontal => (
713 BoxConstraints::new().max_width(constraints.max_width),
714 constraints.max_width,
715 ),
716 Axis::Vertical => (
717 BoxConstraints::new().max_height(constraints.max_height),
718 constraints.max_height,
719 ),
720 }
721 }
722
723 fn compute_dry_layout_size(
725 self: RenderHandle<Self>,
726 app: &mut App,
727 constraints: BoxConstraints,
728 ) -> Size {
729 let (child_constraints, main_axis_limit) =
730 self.child_constraints_and_main_axis_limit(app, constraints);
731 let (spacing, run_spacing) = (self.spacing(app), self.run_spacing(app));
732
733 let mut main_axis_extent: f64 = 0.0;
734 let mut cross_axis_extent = 0.0;
735 let mut run_main_axis_extent = 0.0;
736 let mut run_cross_axis_extent: f64 = 0.0;
737 let mut child_count = 0;
738 let mut child = self.first_child(app);
739 while let Some(current) = child {
740 let child_size = ChildLayoutHelper::dry_layout_child(app, current, child_constraints);
741 let child_main_axis_extent = self.get_main_axis_extent(app, child_size);
742 let child_cross_axis_extent = self.get_cross_axis_extent(app, child_size);
743 if child_count > 0
745 && run_main_axis_extent + child_main_axis_extent + spacing > main_axis_limit
746 {
747 main_axis_extent = main_axis_extent.max(run_main_axis_extent);
748 cross_axis_extent += run_cross_axis_extent + run_spacing;
749 run_main_axis_extent = 0.0;
750 run_cross_axis_extent = 0.0;
751 child_count = 0;
752 }
753 run_main_axis_extent += child_main_axis_extent;
754 run_cross_axis_extent = run_cross_axis_extent.max(child_cross_axis_extent);
755 if child_count > 0 {
756 run_main_axis_extent += spacing;
757 }
758 child_count += 1;
759 child = self.child_after(app, current);
760 }
761 cross_axis_extent += run_cross_axis_extent;
762 main_axis_extent = main_axis_extent.max(run_main_axis_extent);
763
764 constraints.constrain(match self.direction(app) {
765 Axis::Horizontal => Size::new(main_axis_extent, cross_axis_extent),
766 Axis::Vertical => Size::new(cross_axis_extent, main_axis_extent),
767 })
768 }
769
770 fn compute_runs(
773 self: RenderHandle<Self>,
774 app: &mut App,
775 constraints: BoxConstraints,
776 layout_child: ChildLayouter,
777 ) -> (AxisSize, Vec<RunMetrics>) {
778 debug_assert!(self.first_child(app).is_some());
779 let (child_constraints, main_axis_limit) =
780 self.child_constraints_and_main_axis_limit(app, constraints);
781
782 let (flip_main_axis, _) = self.are_axes_flipped(app);
783 let direction = self.direction(app);
784 let spacing = self.spacing(app);
785 let mut run_metrics: Vec<RunMetrics> = Vec::new();
786
787 let mut children_axis_size = AxisSize::EMPTY;
788 let mut child = self.first_child(app);
789 while let Some(current) = child {
790 let child_size =
791 AxisSize::from_size(layout_child(app, current, child_constraints), direction);
792 let new_run = match run_metrics.last_mut() {
793 None => Some(RunMetrics::new(current, child_size)),
794 Some(current_run) => current_run.try_adding_new_child(
795 current,
796 child_size,
797 flip_main_axis,
798 spacing,
799 main_axis_limit,
800 ),
801 };
802 if let Some(new_run) = new_run {
803 if let Some(current_run) = run_metrics.last() {
804 children_axis_size = children_axis_size + current_run.axis_size.flipped();
805 }
806 run_metrics.push(new_run);
807 }
808 child = self.child_after(app, current);
809 }
810 debug_assert!(!run_metrics.is_empty());
811 let total_run_spacing = self.run_spacing(app) * (run_metrics.len() - 1) as f64;
812 let current_run = run_metrics.last().expect("at least one run");
813 children_axis_size = children_axis_size
814 + (AxisSize::new(total_run_spacing, 0.0) + current_run.axis_size.flipped());
815 (children_axis_size.flipped(), run_metrics)
816 }
817
818 fn position_children(
821 self: RenderHandle<Self>,
822 app: &mut App,
823 run_metrics: &[RunMetrics],
824 free_axis_size: AxisSize,
825 container_axis_size: AxisSize,
826 position_child: &mut dyn FnMut(&mut App, Offset, AnyRenderBox),
827 get_child_size: &mut dyn FnMut(&mut App, AnyRenderBox) -> Size,
828 ) {
829 debug_assert!(!run_metrics.is_empty());
830
831 let direction = self.direction(app);
832 let spacing = self.spacing(app);
833
834 let cross_axis_free_space = free_axis_size.cross_axis_extent().max(0.0);
835
836 let (flip_main_axis, flip_cross_axis) = self.are_axes_flipped(app);
837 let cross_axis_alignment = self.cross_axis_alignment(app);
838 let effective_cross_alignment = if flip_cross_axis {
839 cross_axis_alignment.flipped()
840 } else {
841 cross_axis_alignment
842 };
843 let (run_leading_space, run_between_space) = self.run_alignment(app).distribute_space(
844 cross_axis_free_space,
845 self.run_spacing(app),
846 run_metrics.len(),
847 flip_cross_axis,
848 );
849 let alignment = self.alignment(app);
850
851 let mut run_cross_axis_offset = run_leading_space;
852 let runs: Box<dyn Iterator<Item = &RunMetrics>> = if flip_cross_axis {
853 Box::new(run_metrics.iter().rev())
854 } else {
855 Box::new(run_metrics.iter())
856 };
857 for run in runs {
858 let run_cross_axis_extent = run.axis_size.cross_axis_extent();
859 let child_count = run.child_count;
860
861 let main_axis_free_space = (container_axis_size.main_axis_extent()
862 - run.axis_size.main_axis_extent())
863 .max(0.0);
864 let (child_leading_space, child_between_space) = alignment.distribute_space(
865 main_axis_free_space,
866 spacing,
867 child_count,
868 flip_main_axis,
869 );
870
871 let mut child_main_axis_offset = child_leading_space;
872
873 let mut remaining_child_count = run.child_count;
874 let mut child = Some(run.leading_child);
875 while let Some(current) = child
876 && remaining_child_count > 0
877 {
878 let child_axis_size = AxisSize::from_size(get_child_size(app, current), direction);
879 let child_cross_axis_offset = effective_cross_alignment.alignment()
880 * (run_cross_axis_extent - child_axis_size.cross_axis_extent());
881 let offset = self.get_offset(
882 app,
883 child_main_axis_offset,
884 run_cross_axis_offset + child_cross_axis_offset,
885 );
886 position_child(app, offset, current);
887 child_main_axis_offset += child_axis_size.main_axis_extent() + child_between_space;
888 child = if flip_main_axis {
889 self.child_before(app, current)
890 } else {
891 self.child_after(app, current)
892 };
893 remaining_child_count -= 1;
894 }
895 run_cross_axis_offset += run_cross_axis_extent + run_between_space;
896 }
897 }
898}
899
900impl ContainerRenderObjectMixin for RenderWrap {
901 type ChildType = AnyRenderBox;
902 type ParentDataType = WrapParentData;
903
904 fn container_data(
905 self: RenderHandle<Self>,
906 app: &App,
907 ) -> &ContainerRenderObjectData<AnyRenderBox> {
908 &self.get(app).container
909 }
910
911 fn container_data_mut(
912 self: RenderHandle<Self>,
913 app: &mut App,
914 ) -> &mut ContainerRenderObjectData<AnyRenderBox> {
915 &mut self.get_mut(app).container
916 }
917}
918
919impl RenderBoxContainerDefaultsMixin for RenderWrap {}
920
921impl RenderObject for RenderWrap {
922 crate::render_object_accessors!();
923
924 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
925 let constraints = self.constraints(app);
926 debug_assert!(self.debug_has_necessary_directions(app));
927 if self.first_child(app).is_none() {
928 self.set_size(app, constraints.smallest());
929 self.get_mut(app).has_visual_overflow = false;
930 return;
931 }
932
933 let direction = self.direction(app);
934 let (children_axis_size, run_metrics) =
935 self.compute_runs(app, constraints, ChildLayoutHelper::layout_child);
936 let container_axis_size = children_axis_size.apply_constraints(constraints, direction);
937 self.set_size(app, container_axis_size.to_size(direction));
938 let free_axis_size = container_axis_size - children_axis_size;
939 self.get_mut(app).has_visual_overflow =
940 free_axis_size.main_axis_extent() < 0.0 || free_axis_size.cross_axis_extent() < 0.0;
941 self.position_children(
942 app,
943 &run_metrics,
944 free_axis_size,
945 container_axis_size,
946 &mut |app, offset, child| {
947 child
948 .parent_data_of_mut::<WrapParentData>(app)
949 .set_offset(offset);
950 },
951 &mut |app, child| child.size(app),
952 );
953 }
954
955 fn visit_children(
956 self: RenderHandle<Self>,
957 app: &App,
958 visitor: &mut dyn FnMut(AnyRenderObject),
959 ) {
960 ContainerRenderObjectMixin::visit_children(self, app, visitor)
961 }
962
963 fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
964 ContainerRenderObjectMixin::did_attach(self, app, owner)
965 }
966
967 fn did_detach(self: RenderHandle<Self>, app: &mut App) {
968 ContainerRenderObjectMixin::did_detach(self, app)
969 }
970
971 fn redepth_children(self: RenderHandle<Self>, app: &mut App) {
972 ContainerRenderObjectMixin::redepth_children(self, app)
973 }
974
975 fn paint(
978 self: RenderHandle<Self>,
979 app: &mut App,
980 context: &mut PaintingContext,
981 offset: Offset,
982 ) {
983 let clip_behavior = self.clip_behavior(app);
986 if self.get(app).has_visual_overflow && clip_behavior != Clip::None {
987 let size = self.size(app);
988 let old = self.get(app).clip_rect_layer.layer();
989 let layer = context.push_clip_rect(
990 app,
991 self.as_object().needs_compositing(app),
992 offset,
993 Offset::ZERO & size,
994 |app, context, offset| self.default_paint(app, context, offset),
995 clip_behavior,
996 old,
997 );
998 LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, layer);
999 } else {
1000 LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, None);
1001 self.default_paint(app, context, offset);
1002 }
1003 }
1004
1005 fn dispose(self: RenderHandle<Self>, app: &mut App) {
1007 LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, None);
1008 crate::object::RenderObjectBase::dispose(self, app);
1009 }
1010}
1011
1012impl RenderBox for RenderWrap {
1013 crate::render_box_accessors!();
1014
1015 fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1016 if !child.parent_data_is::<WrapParentData>(app) {
1017 child.set_parent_data(app, WrapParentData::new());
1018 }
1019 }
1020
1021 fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1022 match self.direction(app) {
1023 Axis::Horizontal => {
1024 let mut width: f64 = 0.0;
1025 let mut child = self.first_child(app);
1026 while let Some(current) = child {
1027 width = width.max(current.get_min_intrinsic_width(app, f64::INFINITY));
1028 child = self.child_after(app, current);
1029 }
1030 width
1031 }
1032 Axis::Vertical => self
1033 .get_dry_layout(app, BoxConstraints::new().max_height(height))
1034 .width(),
1035 }
1036 }
1037
1038 fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1039 match self.direction(app) {
1040 Axis::Horizontal => {
1041 let mut width = 0.0;
1042 let mut child = self.first_child(app);
1043 while let Some(current) = child {
1044 width += current.get_max_intrinsic_width(app, f64::INFINITY);
1045 child = self.child_after(app, current);
1046 }
1047 width
1048 }
1049 Axis::Vertical => self
1050 .get_dry_layout(app, BoxConstraints::new().max_height(height))
1051 .width(),
1052 }
1053 }
1054
1055 fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1056 match self.direction(app) {
1057 Axis::Horizontal => self
1058 .get_dry_layout(app, BoxConstraints::new().max_width(width))
1059 .height(),
1060 Axis::Vertical => {
1061 let mut height: f64 = 0.0;
1062 let mut child = self.first_child(app);
1063 while let Some(current) = child {
1064 height = height.max(current.get_min_intrinsic_height(app, f64::INFINITY));
1065 child = self.child_after(app, current);
1066 }
1067 height
1068 }
1069 }
1070 }
1071
1072 fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1073 match self.direction(app) {
1074 Axis::Horizontal => self
1075 .get_dry_layout(app, BoxConstraints::new().max_width(width))
1076 .height(),
1077 Axis::Vertical => {
1078 let mut height = 0.0;
1079 let mut child = self.first_child(app);
1080 while let Some(current) = child {
1081 height += current.get_max_intrinsic_height(app, f64::INFINITY);
1082 child = self.child_after(app, current);
1083 }
1084 height
1085 }
1086 }
1087 }
1088
1089 fn compute_distance_to_actual_baseline(
1090 self: RenderHandle<Self>,
1091 app: &mut App,
1092 baseline: TextBaseline,
1093 ) -> Option<f64> {
1094 self.default_compute_distance_to_highest_actual_baseline(app, baseline)
1095 }
1096
1097 fn compute_dry_baseline(
1098 self: RenderHandle<Self>,
1099 app: &mut App,
1100 constraints: BoxConstraints,
1101 baseline: TextBaseline,
1102 ) -> Option<f64> {
1103 self.first_child(app)?;
1104 let child_constraints = match self.direction(app) {
1105 Axis::Horizontal => BoxConstraints::new().max_width(constraints.max_width),
1106 Axis::Vertical => BoxConstraints::new().max_height(constraints.max_height),
1107 };
1108
1109 let (children_axis_size, run_metrics) =
1110 self.compute_runs(app, constraints, ChildLayoutHelper::dry_layout_child);
1111 let container_axis_size =
1112 children_axis_size.apply_constraints(constraints, self.direction(app));
1113
1114 let mut baseline_offset = BaselineOffset::NO_BASELINE;
1115 self.position_children(
1116 app,
1117 &run_metrics,
1118 children_axis_size,
1119 container_axis_size,
1120 &mut |app, offset, child| {
1121 baseline_offset = baseline_offset.min_of(
1122 BaselineOffset(child.get_dry_baseline(app, child_constraints, baseline))
1123 + offset.dy(),
1124 );
1125 },
1126 &mut |app, child| child.get_dry_layout(app, child_constraints),
1127 );
1128 baseline_offset.offset()
1129 }
1130
1131 fn compute_dry_layout(
1132 self: RenderHandle<Self>,
1133 app: &mut App,
1134 constraints: BoxConstraints,
1135 ) -> Size {
1136 self.compute_dry_layout_size(app, constraints)
1137 }
1138
1139 fn hit_test_children(
1140 self: RenderHandle<Self>,
1141 app: &mut App,
1142 result: &mut BoxHitTestResult<'_>,
1143 position: Offset,
1144 ) -> bool {
1145 self.default_hit_test_children(app, result, position)
1146 }
1147}
1148
1149#[cfg(test)]
1150mod tests {
1151 use inset_embedder::valo::Op;
1152 use inset_foundation::AppCell;
1153
1154 use super::*;
1155 use crate::layer::{ContainerLayer, ErasedLayer, OffsetLayer, PictureLayer};
1156 use crate::proxy_box::{RenderConstrainedBox, RenderRepaintBoundary};
1157
1158 fn box_80(app: &mut App) -> AnyRenderBox {
1160 let at_least = BoxConstraints::new().min_width(80.0).min_height(80.0);
1161 RenderConstrainedBox::new(app, at_least, None).as_box()
1162 }
1163
1164 fn wrap_of_three(app: &mut App, direction: Axis, spacing: f64) -> RenderHandle<RenderWrap> {
1166 let wrap = RenderWrap::new(app);
1167 let children = vec![box_80(app), box_80(app), box_80(app)];
1168 wrap.add_all(app, Some(children));
1169 wrap.set_spacing(app, spacing);
1170 wrap.set_run_spacing(app, spacing);
1171 wrap.set_direction(app, direction);
1172 wrap
1173 }
1174
1175 #[test]
1177 fn a_horizontal_wrap_is_as_tall_as_its_runs() {
1178 let cell = AppCell::new();
1179 let mut app = cell.borrow_mut();
1180 let wrap = wrap_of_three(&mut app, Axis::Horizontal, 5.0);
1181 for (width, height) in [(245.0, 165.0), (250.0, 80.0), (80.0, 250.0), (79.0, 250.0)] {
1182 assert_eq!(wrap.compute_max_intrinsic_height(&mut app, width), height);
1183 assert_eq!(wrap.compute_min_intrinsic_height(&mut app, width), height);
1184 }
1185 }
1186
1187 #[test]
1189 fn a_vertical_wrap_is_as_wide_as_its_runs() {
1190 let cell = AppCell::new();
1191 let mut app = cell.borrow_mut();
1192 let wrap = wrap_of_three(&mut app, Axis::Vertical, 5.0);
1193 for (height, width) in [(245.0, 165.0), (250.0, 80.0), (80.0, 250.0), (79.0, 250.0)] {
1194 assert_eq!(wrap.compute_max_intrinsic_width(&mut app, height), width);
1195 assert_eq!(wrap.compute_min_intrinsic_width(&mut app, height), width);
1196 }
1197 }
1198
1199 #[test]
1201 fn one_child_makes_one_run_whatever_the_width() {
1202 let cell = AppCell::new();
1203 let mut app = cell.borrow_mut();
1204 let wrap = RenderWrap::new(&mut app);
1205 let child = box_80(&mut app);
1206 wrap.add(&mut app, child);
1207 wrap.set_spacing(&mut app, 5.0);
1208 wrap.set_run_spacing(&mut app, 5.0);
1209 for width in [100.0, 79.0, 80.0] {
1210 assert_eq!(wrap.compute_max_intrinsic_height(&mut app, width), 80.0);
1211 assert_eq!(wrap.compute_min_intrinsic_height(&mut app, width), 80.0);
1212 }
1213 }
1214
1215 fn offsets(app: &App, wrap: RenderHandle<RenderWrap>) -> Vec<Offset> {
1216 let mut offsets = Vec::new();
1217 let mut child = wrap.first_child(app);
1218 while let Some(current) = child {
1219 offsets.push(current.box_parent_data(app).offset);
1220 child = wrap.child_after(app, current);
1221 }
1222 offsets
1223 }
1224
1225 #[test]
1226 fn children_that_overflow_a_run_start_the_next_one() {
1227 let cell = AppCell::new();
1228 let mut app = cell.borrow_mut();
1229 let wrap = wrap_of_three(&mut app, Axis::Horizontal, 10.0);
1230 wrap.set_text_direction(&mut app, Some(TextDirection::Ltr));
1231 wrap.as_box()
1232 .layout(&mut app, BoxConstraints::new().max_width(200.0), true);
1233 assert_eq!(wrap.size(&app), Size::new(170.0, 170.0));
1234 assert_eq!(
1235 offsets(&app, wrap),
1236 [
1237 Offset::new(0.0, 0.0),
1238 Offset::new(90.0, 0.0),
1239 Offset::new(0.0, 90.0)
1240 ]
1241 );
1242 }
1243
1244 #[test]
1245 fn a_right_to_left_wrap_places_its_runs_from_the_right() {
1246 let cell = AppCell::new();
1247 let mut app = cell.borrow_mut();
1248 let wrap = wrap_of_three(&mut app, Axis::Horizontal, 10.0);
1249 wrap.set_text_direction(&mut app, Some(TextDirection::Rtl));
1250 wrap.set_alignment(&mut app, WrapAlignment::Start);
1251 wrap.as_box().layout(
1252 &mut app,
1253 BoxConstraints::tight(Size::new(200.0, 200.0)),
1254 true,
1255 );
1256 assert_eq!(
1258 offsets(&app, wrap),
1259 [
1260 Offset::new(120.0, 0.0),
1261 Offset::new(30.0, 0.0),
1262 Offset::new(120.0, 90.0)
1263 ]
1264 );
1265 }
1266
1267 #[test]
1268 fn alignments_spread_the_free_space() {
1269 let cell = AppCell::new();
1270 let mut app = cell.borrow_mut();
1271 let wrap = wrap_of_three(&mut app, Axis::Horizontal, 0.0);
1272 wrap.set_text_direction(&mut app, Some(TextDirection::Ltr));
1273 wrap.set_alignment(&mut app, WrapAlignment::SpaceBetween);
1274 wrap.set_run_alignment(&mut app, WrapAlignment::End);
1275 wrap.set_cross_axis_alignment(&mut app, WrapCrossAlignment::Center);
1276 wrap.as_box().layout(
1277 &mut app,
1278 BoxConstraints::tight(Size::new(300.0, 100.0)),
1279 true,
1280 );
1281 assert_eq!(
1282 offsets(&app, wrap),
1283 [
1284 Offset::new(0.0, 20.0),
1285 Offset::new(110.0, 20.0),
1286 Offset::new(220.0, 20.0)
1287 ]
1288 );
1289 assert_eq!(
1290 WrapAlignment::SpaceEvenly.distribute_space(40.0, 0.0, 3, false),
1291 (10.0, 10.0)
1292 );
1293 assert_eq!(
1294 WrapAlignment::SpaceAround.distribute_space(60.0, 5.0, 3, false),
1295 (10.0, 25.0)
1296 );
1297 }
1298
1299 #[test]
1300 fn a_wrap_measures_dry_as_it_lays_out() {
1301 let cell = AppCell::new();
1302 let mut app = cell.borrow_mut();
1303 let wrap = wrap_of_three(&mut app, Axis::Horizontal, 10.0);
1304 wrap.set_text_direction(&mut app, Some(TextDirection::Ltr));
1305 let constraints = BoxConstraints::new().max_width(200.0);
1306 let dry = wrap.get_dry_layout(&mut app, constraints);
1307 wrap.as_box().layout(&mut app, constraints, true);
1308 assert_eq!(dry, wrap.size(&app));
1309 }
1310
1311 fn schedule_root_paint(app: &mut App, node: AnyRenderObject) {
1312 let root = OffsetLayer::new(app, Offset::ZERO);
1313 root.as_layer().attach(app, node.id());
1314 node.schedule_initial_paint(app, root.as_container_layer());
1315 }
1316
1317 fn first_frame(
1319 app: &mut App,
1320 root: AnyRenderBox,
1321 constraints: BoxConstraints,
1322 ) -> Handle<PipelineOwner> {
1323 let owner = PipelineOwner::new(app, None, None);
1324 owner.set_root_node(app, Some(root.as_object()));
1325 root.layout(app, constraints, false);
1326 schedule_root_paint(app, root.as_object());
1327 owner.flush_compositing_bits(app);
1328 owner.flush_paint(app);
1329 owner
1330 }
1331
1332 fn picture_has_clip(app: &App, boundary: AnyRenderObject) -> bool {
1333 let layer = boundary.debug_layer(app).expect("painted");
1334 layer
1335 .depth_first_iterate_children(app)
1336 .into_iter()
1337 .filter_map(|child| {
1338 app.handle::<PictureLayer>(child.id())
1339 .and_then(|picture| picture.picture(app).map(|p| p.ops().to_vec()))
1340 })
1341 .flatten()
1342 .any(|op| matches!(op, Op::ClipPath { .. }))
1343 }
1344
1345 #[test]
1347 fn an_overflowing_wrap_clips_only_when_asked() {
1348 for (clip_behavior, clips) in [(None, false), (Some(Clip::HardEdge), true)] {
1349 let cell = AppCell::new();
1350 let mut app = cell.borrow_mut();
1351 let child = RenderConstrainedBox::new(
1352 &mut app,
1353 BoxConstraints::tight(Size::square(200.0)),
1354 None,
1355 );
1356 let wrap = RenderWrap::new(&mut app);
1357 wrap.set_text_direction(&mut app, Some(TextDirection::Ltr));
1358 if let Some(clip_behavior) = clip_behavior {
1359 wrap.set_clip_behavior(&mut app, clip_behavior);
1360 }
1361 wrap.add(&mut app, child.as_box());
1362 let root = RenderRepaintBoundary::new(&mut app, Some(wrap.as_box()));
1363
1364 let owner = first_frame(
1365 &mut app,
1366 root.as_box(),
1367 BoxConstraints::new().max_width(100.0).max_height(100.0),
1368 );
1369
1370 assert_eq!(
1371 picture_has_clip(&app, root.as_object()),
1372 clips,
1373 "{clip_behavior:?}"
1374 );
1375 let _ = owner;
1376 }
1377 }
1378}