Skip to main content

inset_rendering/
shifted_box.rs

1//! Flutter counterpart: `rendering/shifted_box.dart` (`BoxConstraintsTransform`,
2//! `RenderShiftedBox`, `RenderPadding`, `RenderAligningShiftedBox`, `RenderPositionedBox`,
3//! `OverflowBoxFit`, `RenderConstrainedOverflowBox`, `RenderConstraintsTransformBox`,
4//! `RenderSizedOverflowBox`, `RenderFractionallySizedOverflowBox`,
5//! `RenderCustomSingleChildLayoutBox`, `SingleChildLayoutDelegate`, `RenderBaseline`).
6
7use std::any::Any;
8use std::fmt::Debug;
9use std::rc::Rc;
10
11use inset_embedder::{Clip, Offset, Rect, Size, TextBaseline};
12use inset_foundation::{App, Handle, Listenable, Listener};
13use inset_painting::{Alignment, AlignmentGeometry, EdgeInsets, EdgeInsetsGeometry, TextDirection};
14
15use crate::box_::{
16    AnyRenderBox, BoxConstraints, BoxHitTestResult, BoxParentData, RenderBox, RenderBoxData,
17};
18use crate::layer::{ClipRectLayer, LayerHandle};
19use crate::layout_helper::{ChildBaselineGetter, ChildLayoutHelper, ChildLayouter};
20use crate::object::{
21    AnyRenderObject, Constraints, RenderHandle, RenderObject, RenderObjectData,
22    RenderObjectWithChildData, RenderObjectWithChildMixin,
23};
24use crate::painting_context::PaintingContext;
25use crate::pipeline_owner::PipelineOwner;
26use crate::stack::RelativeRect;
27
28/// Signature for a function that transforms a [`BoxConstraints`] to another [`BoxConstraints`].
29///
30/// Used by [`RenderConstraintsTransformBox`]. Typically the caller requires the returned
31/// [`BoxConstraints`] to be [`Constraints::is_normalized`].
32pub type BoxConstraintsTransform = fn(BoxConstraints) -> BoxConstraints;
33
34/// Abstract class for one-child-layout render boxes that provide control over
35/// the child's position.
36///
37/// Flutter's `RenderShiftedBox`: the shared bodies. A leaf implements the marker and calls
38/// these where Dart would run the inherited method: `RenderShiftedBox::paint(self, …)`.
39pub trait RenderShiftedBox:
40    RenderObjectWithChildMixin<ChildType = AnyRenderBox> + RenderBox
41{
42    /// The child's minimum intrinsic width, or 0 without a child.
43    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
44        match self.child(app) {
45            Some(child) => child.get_min_intrinsic_width(app, height),
46            None => 0.0,
47        }
48    }
49
50    /// The child's maximum intrinsic width, or 0 without a child.
51    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
52        match self.child(app) {
53            Some(child) => child.get_max_intrinsic_width(app, height),
54            None => 0.0,
55        }
56    }
57
58    /// The child's minimum intrinsic height, or 0 without a child.
59    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
60        match self.child(app) {
61            Some(child) => child.get_min_intrinsic_height(app, width),
62            None => 0.0,
63        }
64    }
65
66    /// The child's maximum intrinsic height, or 0 without a child.
67    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
68        match self.child(app) {
69            Some(child) => child.get_max_intrinsic_height(app, width),
70            None => 0.0,
71        }
72    }
73
74    /// The child's baseline shifted by the child's paint offset, or none without a child.
75    fn compute_distance_to_actual_baseline(
76        self: RenderHandle<Self>,
77        app: &mut App,
78        baseline: TextBaseline,
79    ) -> Option<f64> {
80        debug_assert!(!self.as_object().debug_needs_layout(app));
81        let child = self.child(app)?;
82        debug_assert!(!child.as_object().debug_needs_layout(app));
83        let result = child.get_distance_to_actual_baseline(app, baseline)?;
84        let offset = child
85            .as_object()
86            .parent_data_of::<BoxParentData>(app)
87            .offset;
88        Some(result + offset.dy())
89    }
90
91    /// The child's dry baseline at this box's constraints. The base applies no transform;
92    /// subclasses override to add their offset.
93    fn compute_dry_baseline(
94        self: RenderHandle<Self>,
95        app: &mut App,
96        constraints: BoxConstraints,
97        baseline: TextBaseline,
98    ) -> Option<f64> {
99        self.child(app)
100            .and_then(|child| child.get_dry_baseline(app, constraints, baseline))
101    }
102
103    /// Hit tests the child at its parent-data offset.
104    fn hit_test_children(
105        self: RenderHandle<Self>,
106        app: &mut App,
107        result: &mut BoxHitTestResult<'_>,
108        position: Offset,
109    ) -> bool {
110        let Some(child) = self.child(app) else {
111            return false;
112        };
113        let child_offset = child
114            .as_object()
115            .parent_data_of::<BoxParentData>(app)
116            .offset;
117        result.add_with_paint_offset(Some(child_offset), position, |result, transformed| {
118            debug_assert_eq!(transformed, position - child_offset);
119            child.hit_test(app, result, transformed)
120        })
121    }
122
123    /// Paints the child at its parent-data offset.
124    fn paint(
125        self: RenderHandle<Self>,
126        app: &mut App,
127        context: &mut PaintingContext,
128        offset: Offset,
129    ) {
130        if let Some(child) = self.child(app) {
131            let child_offset = child
132                .as_object()
133                .parent_data_of::<BoxParentData>(app)
134                .offset;
135            context.paint_child(app, child.as_object(), child_offset + offset);
136        }
137    }
138}
139
140/// Insets its child by the given padding.
141pub struct RenderPadding {
142    render_object: RenderObjectData,
143    render_box: RenderBoxData,
144    child: RenderObjectWithChildData<AnyRenderBox>,
145    resolved_padding_cache: Option<EdgeInsets>,
146    padding: EdgeInsetsGeometry,
147    text_direction: Option<TextDirection>,
148}
149
150impl RenderPadding {
151    /// Creates a render object that insets its child.
152    ///
153    /// `padding` must have non-negative insets.
154    pub fn new(
155        app: &mut App,
156        padding: EdgeInsetsGeometry,
157        text_direction: Option<TextDirection>,
158        child: Option<AnyRenderBox>,
159    ) -> RenderHandle<RenderPadding> {
160        debug_assert!(padding.is_non_negative());
161        let this = RenderHandle::new_box(
162            app,
163            RenderPadding {
164                render_object: RenderObjectData::new(),
165                render_box: RenderBoxData::new(),
166                child: RenderObjectWithChildData::new(),
167                resolved_padding_cache: None,
168                padding,
169                text_direction,
170            },
171        );
172        this.set_child(app, child);
173        this
174    }
175
176    /// The amount to pad the child in each dimension.
177    pub fn padding(self: RenderHandle<Self>, app: &App) -> EdgeInsetsGeometry {
178        self.get(app).padding
179    }
180
181    /// Sets [`padding`](Self::padding).
182    pub fn set_padding(self: RenderHandle<Self>, app: &mut App, value: EdgeInsetsGeometry) {
183        debug_assert!(value.is_non_negative());
184        if self.get(app).padding == value {
185            return;
186        }
187        self.get_mut(app).padding = value;
188        self.mark_need_resolution(app);
189    }
190
191    /// The text direction with which to resolve [`padding`](Self::padding).
192    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
193        self.get(app).text_direction
194    }
195
196    /// Sets [`text_direction`](Self::text_direction).
197    pub fn set_text_direction(
198        self: RenderHandle<Self>,
199        app: &mut App,
200        value: Option<TextDirection>,
201    ) {
202        if self.get(app).text_direction == value {
203            return;
204        }
205        self.get_mut(app).text_direction = value;
206        self.mark_need_resolution(app);
207    }
208
209    fn resolved_padding(&mut self) -> EdgeInsets {
210        if let Some(cached) = self.resolved_padding_cache {
211            return cached;
212        }
213        let resolved = self.padding.resolve(self.text_direction);
214        debug_assert!(resolved.is_non_negative());
215        self.resolved_padding_cache = Some(resolved);
216        resolved
217    }
218
219    fn mark_need_resolution(self: RenderHandle<Self>, app: &mut App) {
220        self.get_mut(app).resolved_padding_cache = None;
221        self.mark_needs_layout(app);
222    }
223}
224
225impl RenderObjectWithChildMixin for RenderPadding {
226    type ChildType = AnyRenderBox;
227
228    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
229        &self.get(app).child
230    }
231
232    fn child_data_mut(
233        self: RenderHandle<Self>,
234        app: &mut App,
235    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
236        &mut self.get_mut(app).child
237    }
238}
239
240impl RenderShiftedBox for RenderPadding {}
241
242impl RenderObject for RenderPadding {
243    crate::render_object_accessors!();
244
245    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
246        let constraints = self.constraints(app);
247        let padding = self.get_mut(app).resolved_padding();
248        let child = self.child(app);
249        if child.is_none() {
250            self.set_size(
251                app,
252                constraints.constrain(Size::new(padding.horizontal(), padding.vertical())),
253            );
254            return;
255        }
256        let child = child.expect("checked");
257        let inner_constraints = constraints.deflate(EdgeInsetsGeometry::Insets(padding));
258        child.layout(app, inner_constraints, true);
259        child.parent_data_of_mut::<BoxParentData>(app).offset =
260            Offset::new(padding.left, padding.top);
261        self.set_size(
262            app,
263            constraints.constrain(Size::new(
264                padding.horizontal() + child.size(app).width(),
265                padding.vertical() + child.size(app).height(),
266            )),
267        );
268    }
269
270    fn paint(
271        self: RenderHandle<Self>,
272        app: &mut App,
273        context: &mut PaintingContext,
274        offset: Offset,
275    ) {
276        RenderShiftedBox::paint(self, app, context, offset);
277    }
278
279    fn visit_children(
280        self: RenderHandle<Self>,
281        app: &App,
282        visitor: &mut dyn FnMut(AnyRenderObject),
283    ) {
284        if let Some(child) = self.child(app) {
285            visitor(child.as_object());
286        }
287    }
288}
289
290impl RenderBox for RenderPadding {
291    crate::render_box_accessors!();
292
293    fn hit_test_children(
294        self: RenderHandle<Self>,
295        app: &mut App,
296        result: &mut BoxHitTestResult<'_>,
297        position: Offset,
298    ) -> bool {
299        RenderShiftedBox::hit_test_children(self, app, result, position)
300    }
301
302    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
303        let padding = self.get_mut(app).resolved_padding();
304        match self.child(app) {
305            // Relies on f64::INFINITY absorption.
306            Some(child) => {
307                child.get_min_intrinsic_width(app, (height - padding.vertical()).max(0.0))
308                    + padding.horizontal()
309            }
310            None => padding.horizontal(),
311        }
312    }
313
314    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
315        let padding = self.get_mut(app).resolved_padding();
316        match self.child(app) {
317            Some(child) => {
318                child.get_max_intrinsic_width(app, (height - padding.vertical()).max(0.0))
319                    + padding.horizontal()
320            }
321            None => padding.horizontal(),
322        }
323    }
324
325    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
326        let padding = self.get_mut(app).resolved_padding();
327        match self.child(app) {
328            Some(child) => {
329                child.get_min_intrinsic_height(app, (width - padding.horizontal()).max(0.0))
330                    + padding.vertical()
331            }
332            None => padding.vertical(),
333        }
334    }
335
336    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
337        let padding = self.get_mut(app).resolved_padding();
338        match self.child(app) {
339            Some(child) => {
340                child.get_max_intrinsic_height(app, (width - padding.horizontal()).max(0.0))
341                    + padding.vertical()
342            }
343            None => padding.vertical(),
344        }
345    }
346
347    fn compute_distance_to_actual_baseline(
348        self: RenderHandle<Self>,
349        app: &mut App,
350        baseline: TextBaseline,
351    ) -> Option<f64> {
352        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
353    }
354
355    fn compute_dry_baseline(
356        self: RenderHandle<Self>,
357        app: &mut App,
358        constraints: BoxConstraints,
359        baseline: TextBaseline,
360    ) -> Option<f64> {
361        let child = self.child(app)?;
362        let padding = self.get_mut(app).resolved_padding();
363        let inner_constraints = constraints.deflate(EdgeInsetsGeometry::Insets(padding));
364        let child_baseline = child.get_dry_baseline(app, inner_constraints, baseline)?;
365        Some(child_baseline + padding.top)
366    }
367
368    fn compute_dry_layout(
369        self: RenderHandle<Self>,
370        app: &mut App,
371        constraints: BoxConstraints,
372    ) -> Size {
373        let padding = self.get_mut(app).resolved_padding();
374        let Some(child) = self.child(app) else {
375            return constraints.constrain(Size::new(padding.horizontal(), padding.vertical()));
376        };
377        let inner_constraints = constraints.deflate(EdgeInsetsGeometry::Insets(padding));
378        let child_size = child.get_dry_layout(app, inner_constraints);
379        constraints.constrain(Size::new(
380            padding.horizontal() + child_size.width(),
381            padding.vertical() + child_size.height(),
382        ))
383    }
384}
385
386/// The mixin fields of [`RenderAligningShiftedBox`].
387pub struct RenderAligningShiftedBoxData {
388    resolved_alignment: Option<Alignment>,
389    alignment: AlignmentGeometry,
390    text_direction: Option<TextDirection>,
391}
392
393impl RenderAligningShiftedBoxData {
394    /// Flutter's constructor arguments; `alignment` defaults to center.
395    pub const fn new(
396        alignment: AlignmentGeometry,
397        text_direction: Option<TextDirection>,
398    ) -> RenderAligningShiftedBoxData {
399        RenderAligningShiftedBoxData {
400            resolved_alignment: None,
401            alignment,
402            text_direction,
403        }
404    }
405}
406
407/// Abstract class for one-child-layout render boxes that use a
408/// [`AlignmentGeometry`] to align their children.
409pub trait RenderAligningShiftedBox: RenderShiftedBox {
410    /// Mixin field access.
411    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData;
412
413    /// See [`aligning_data`](Self::aligning_data).
414    fn aligning_data_mut(
415        self: RenderHandle<Self>,
416        app: &mut App,
417    ) -> &mut RenderAligningShiftedBoxData;
418
419    /// The [`alignment`](Self::alignment) resolved against [`text_direction`](Self::text_direction).
420    fn resolved_alignment(self: RenderHandle<Self>, app: &mut App) -> Alignment {
421        let data = self.aligning_data(app);
422        if let Some(resolved) = data.resolved_alignment {
423            return resolved;
424        }
425        let resolved = data.alignment.resolve(data.text_direction);
426        self.aligning_data_mut(app).resolved_alignment = Some(resolved);
427        resolved
428    }
429
430    fn mark_need_resolution(self: RenderHandle<Self>, app: &mut App) {
431        self.aligning_data_mut(app).resolved_alignment = None;
432        self.mark_needs_layout(app);
433    }
434
435    /// How to align the child.
436    ///
437    /// The x and y values of the alignment control the horizontal and vertical
438    /// alignment, respectively. An x value of -1.0 means that the left edge of
439    /// the child is aligned with the left edge of the parent whereas an x value
440    /// of 1.0 means that the right edge of the child is aligned with the right
441    /// edge of the parent. Other values interpolate (and extrapolate) linearly.
442    fn alignment(self: RenderHandle<Self>, app: &App) -> AlignmentGeometry {
443        self.aligning_data(app).alignment
444    }
445
446    /// Sets [`alignment`](Self::alignment).
447    fn set_alignment(self: RenderHandle<Self>, app: &mut App, value: AlignmentGeometry) {
448        if self.aligning_data(app).alignment == value {
449            return;
450        }
451        self.aligning_data_mut(app).alignment = value;
452        self.mark_need_resolution(app);
453    }
454
455    /// The text direction with which to resolve [`alignment`](Self::alignment).
456    fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
457        self.aligning_data(app).text_direction
458    }
459
460    /// Sets [`text_direction`](Self::text_direction).
461    fn set_text_direction(self: RenderHandle<Self>, app: &mut App, value: Option<TextDirection>) {
462        if self.aligning_data(app).text_direction == value {
463            return;
464        }
465        self.aligning_data_mut(app).text_direction = value;
466        self.mark_need_resolution(app);
467    }
468
469    /// Apply the current [`alignment`](Self::alignment) to the child.
470    ///
471    /// Subclasses should call this method if they have a child, to have this
472    /// class perform the actual alignment. If they don't have a child, they
473    /// should not call this method.
474    fn align_child(self: RenderHandle<Self>, app: &mut App) {
475        let child = self.child(app).expect("align_child requires a child");
476        debug_assert!(!child.as_object().debug_needs_layout(app));
477        let offset = self
478            .resolved_alignment(app)
479            .along_offset(self.size(app) - child.size(app));
480        child
481            .as_object()
482            .parent_data_of_mut::<BoxParentData>(app)
483            .offset = offset;
484    }
485}
486
487/// Positions its child using an [`AlignmentGeometry`].
488///
489/// For example, to align a box at the bottom right, you would pass this box a
490/// tight constraint that is bigger than the child's natural size, with an
491/// alignment of `Alignment::BOTTOM_RIGHT`.
492///
493/// By default, sizes to be as big as possible in both axes. If either axis is
494/// unconstrained, then in that direction it will be sized to fit the child's
495/// dimensions. Using `width_factor` and `height_factor` you can force this
496/// latter behavior in all cases.
497pub struct RenderPositionedBox {
498    render_object: RenderObjectData,
499    render_box: RenderBoxData,
500    child: RenderObjectWithChildData<AnyRenderBox>,
501    aligning: RenderAligningShiftedBoxData,
502    width_factor: Option<f64>,
503    height_factor: Option<f64>,
504}
505
506impl RenderPositionedBox {
507    /// Creates a render object that positions its child.
508    ///
509    /// `width_factor` and `height_factor` must be non-negative when given.
510    pub fn new(
511        app: &mut App,
512        alignment: AlignmentGeometry,
513        text_direction: Option<TextDirection>,
514        width_factor: Option<f64>,
515        height_factor: Option<f64>,
516        child: Option<AnyRenderBox>,
517    ) -> RenderHandle<Self> {
518        debug_assert!(width_factor.is_none_or(|factor| factor >= 0.0));
519        debug_assert!(height_factor.is_none_or(|factor| factor >= 0.0));
520        let this = RenderHandle::new_box(
521            app,
522            RenderPositionedBox {
523                render_object: RenderObjectData::new(),
524                render_box: RenderBoxData::new(),
525                child: RenderObjectWithChildData::new(),
526                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
527                width_factor,
528                height_factor,
529            },
530        );
531        this.set_child(app, child);
532        this
533    }
534
535    /// If non-null, sets its width to the child's width multiplied by this factor.
536    ///
537    /// Can be both greater and less than 1.0 but must be positive.
538    pub fn width_factor(self: RenderHandle<Self>, app: &App) -> Option<f64> {
539        self.get(app).width_factor
540    }
541
542    /// Sets [`width_factor`](Self::width_factor).
543    pub fn set_width_factor(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
544        debug_assert!(value.is_none_or(|factor| factor >= 0.0));
545        if self.get(app).width_factor == value {
546            return;
547        }
548        self.get_mut(app).width_factor = value;
549        self.mark_needs_layout(app);
550    }
551
552    /// If non-null, sets its height to the child's height multiplied by this factor.
553    ///
554    /// Can be both greater and less than 1.0 but must be positive.
555    pub fn height_factor(self: RenderHandle<Self>, app: &App) -> Option<f64> {
556        self.get(app).height_factor
557    }
558
559    /// Sets [`height_factor`](Self::height_factor).
560    pub fn set_height_factor(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
561        debug_assert!(value.is_none_or(|factor| factor >= 0.0));
562        if self.get(app).height_factor == value {
563            return;
564        }
565        self.get_mut(app).height_factor = value;
566        self.mark_needs_layout(app);
567    }
568}
569
570impl RenderObjectWithChildMixin for RenderPositionedBox {
571    type ChildType = AnyRenderBox;
572
573    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
574        &self.get(app).child
575    }
576
577    fn child_data_mut(
578        self: RenderHandle<Self>,
579        app: &mut App,
580    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
581        &mut self.get_mut(app).child
582    }
583}
584
585impl RenderShiftedBox for RenderPositionedBox {}
586
587impl RenderAligningShiftedBox for RenderPositionedBox {
588    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
589        &self.get(app).aligning
590    }
591
592    fn aligning_data_mut(
593        self: RenderHandle<Self>,
594        app: &mut App,
595    ) -> &mut RenderAligningShiftedBoxData {
596        &mut self.get_mut(app).aligning
597    }
598}
599
600impl RenderPositionedBox {
601    /// Dart's sizing line of `performLayout` / `computeDryLayout`: shrink-wrap an axis when it
602    /// has a factor or is unbounded, and `child_size` is zero without a child.
603    fn size_for_child(
604        self: RenderHandle<Self>,
605        app: &App,
606        constraints: BoxConstraints,
607        child_size: Size,
608    ) -> Size {
609        let (width_factor, height_factor) = {
610            let this = self.get(app);
611            (this.width_factor, this.height_factor)
612        };
613        let shrink_wrap_width = width_factor.is_some() || constraints.max_width == f64::INFINITY;
614        let shrink_wrap_height = height_factor.is_some() || constraints.max_height == f64::INFINITY;
615        constraints.constrain(Size::new(
616            if shrink_wrap_width {
617                child_size.width() * width_factor.unwrap_or(1.0)
618            } else {
619                f64::INFINITY
620            },
621            if shrink_wrap_height {
622                child_size.height() * height_factor.unwrap_or(1.0)
623            } else {
624                f64::INFINITY
625            },
626        ))
627    }
628}
629
630impl RenderObject for RenderPositionedBox {
631    crate::render_object_accessors!();
632
633    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
634        let constraints = self.constraints(app);
635        match self.child(app) {
636            Some(child) => {
637                child.layout(app, constraints.loosen(), true);
638                let child_size = child.size(app);
639                let size = self.size_for_child(app, constraints, child_size);
640                self.set_size(app, size);
641                self.align_child(app);
642            }
643            None => {
644                let size = self.size_for_child(app, constraints, Size::ZERO);
645                self.set_size(app, size);
646            }
647        }
648    }
649
650    fn paint(
651        self: RenderHandle<Self>,
652        app: &mut App,
653        context: &mut PaintingContext,
654        offset: Offset,
655    ) {
656        RenderShiftedBox::paint(self, app, context, offset);
657    }
658
659    fn visit_children(
660        self: RenderHandle<Self>,
661        app: &App,
662        visitor: &mut dyn FnMut(AnyRenderObject),
663    ) {
664        if let Some(child) = self.child(app) {
665            visitor(child.as_object());
666        }
667    }
668}
669
670impl RenderBox for RenderPositionedBox {
671    crate::render_box_accessors!();
672
673    fn hit_test_children(
674        self: RenderHandle<Self>,
675        app: &mut App,
676        result: &mut BoxHitTestResult<'_>,
677        position: Offset,
678    ) -> bool {
679        RenderShiftedBox::hit_test_children(self, app, result, position)
680    }
681
682    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
683        let factor = self.get(app).width_factor.unwrap_or(1.0);
684        RenderShiftedBox::compute_min_intrinsic_width(self, app, height) * factor
685    }
686
687    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
688        let factor = self.get(app).width_factor.unwrap_or(1.0);
689        RenderShiftedBox::compute_max_intrinsic_width(self, app, height) * factor
690    }
691
692    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
693        let factor = self.get(app).height_factor.unwrap_or(1.0);
694        RenderShiftedBox::compute_min_intrinsic_height(self, app, width) * factor
695    }
696
697    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
698        let factor = self.get(app).height_factor.unwrap_or(1.0);
699        RenderShiftedBox::compute_max_intrinsic_height(self, app, width) * factor
700    }
701
702    fn compute_distance_to_actual_baseline(
703        self: RenderHandle<Self>,
704        app: &mut App,
705        baseline: TextBaseline,
706    ) -> Option<f64> {
707        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
708    }
709
710    fn compute_dry_baseline(
711        self: RenderHandle<Self>,
712        app: &mut App,
713        constraints: BoxConstraints,
714        baseline: TextBaseline,
715    ) -> Option<f64> {
716        let child = self.child(app)?;
717        let child_constraints = constraints.loosen();
718        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
719        let child_size = child.get_dry_layout(app, child_constraints);
720        let size = self.size_for_child(app, constraints, child_size);
721        let child_offset = self.resolved_alignment(app).along_offset(size - child_size);
722        Some(result + child_offset.dy())
723    }
724
725    fn compute_dry_layout(
726        self: RenderHandle<Self>,
727        app: &mut App,
728        constraints: BoxConstraints,
729    ) -> Size {
730        match self.child(app) {
731            Some(child) => {
732                let child_size = child.get_dry_layout(app, constraints.loosen());
733                self.size_for_child(app, constraints, child_size)
734            }
735            None => self.size_for_child(app, constraints, Size::ZERO),
736        }
737    }
738}
739
740/// How much space should be occupied by the [`RenderConstrainedOverflowBox`] when it is not
741/// overflowing.
742#[derive(Clone, Copy, Debug, PartialEq, Eq)]
743pub enum OverflowBoxFit {
744    /// The widget will size itself to be as large as the parent allows.
745    Max,
746
747    /// The widget will follow the child's size.
748    ///
749    /// More specifically, the render object will size itself to match the size of its child
750    /// within the constraints of its parent, or as small as the parent allows if no child is
751    /// set.
752    DeferToChild,
753}
754
755/// A render object that imposes different constraints on its child than it gets from its parent,
756/// possibly allowing the child to overflow the parent.
757///
758/// A render overflow box proxies most functions in the render box protocol to its child, except
759/// that when laying out its child, it passes constraints based on the `min_width`, `max_width`,
760/// `min_height`, and `max_height` fields instead of just passing the parent's constraints in.
761/// Specifically, it overrides any of the equivalent fields on the constraints given by the parent
762/// with the constraints given by these fields, as long as those values are not null. If a value is
763/// null, then the original constraint is used.
764///
765/// Additionally, this render object allows the child to overflow the bounds of this box. If the
766/// child overflows, this box will not clip the overflowing part.
767pub struct RenderConstrainedOverflowBox {
768    render_object: RenderObjectData,
769    render_box: RenderBoxData,
770    child: RenderObjectWithChildData<AnyRenderBox>,
771    aligning: RenderAligningShiftedBoxData,
772    min_width: Option<f64>,
773    max_width: Option<f64>,
774    min_height: Option<f64>,
775    max_height: Option<f64>,
776    fit: OverflowBoxFit,
777}
778
779impl RenderConstrainedOverflowBox {
780    /// Creates a render object that lets its child overflow itself; `None` constraints use the
781    /// parent's, and Dart's default `fit` is [`OverflowBoxFit::Max`].
782    #[allow(clippy::too_many_arguments)]
783    pub fn new(
784        app: &mut App,
785        min_width: Option<f64>,
786        max_width: Option<f64>,
787        min_height: Option<f64>,
788        max_height: Option<f64>,
789        fit: OverflowBoxFit,
790        alignment: AlignmentGeometry,
791        text_direction: Option<TextDirection>,
792        child: Option<AnyRenderBox>,
793    ) -> RenderHandle<Self> {
794        let this = RenderHandle::new_box(
795            app,
796            RenderConstrainedOverflowBox {
797                render_object: RenderObjectData::new(),
798                render_box: RenderBoxData::new(),
799                child: RenderObjectWithChildData::new(),
800                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
801                min_width,
802                max_width,
803                min_height,
804                max_height,
805                fit,
806            },
807        );
808        this.set_child(app, child);
809        this
810    }
811
812    /// The minimum width constraint to give the child. `None` (the default) uses the constraint
813    /// from the parent instead.
814    pub fn min_width(self: RenderHandle<Self>, app: &App) -> Option<f64> {
815        self.get(app).min_width
816    }
817
818    /// Sets [`min_width`](Self::min_width).
819    pub fn set_min_width(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
820        if self.get(app).min_width == value {
821            return;
822        }
823        self.get_mut(app).min_width = value;
824        self.mark_needs_layout(app);
825    }
826
827    /// The maximum width constraint to give the child. `None` (the default) uses the constraint
828    /// from the parent instead.
829    pub fn max_width(self: RenderHandle<Self>, app: &App) -> Option<f64> {
830        self.get(app).max_width
831    }
832
833    /// Sets [`max_width`](Self::max_width).
834    pub fn set_max_width(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
835        if self.get(app).max_width == value {
836            return;
837        }
838        self.get_mut(app).max_width = value;
839        self.mark_needs_layout(app);
840    }
841
842    /// The minimum height constraint to give the child. `None` (the default) uses the constraint
843    /// from the parent instead.
844    pub fn min_height(self: RenderHandle<Self>, app: &App) -> Option<f64> {
845        self.get(app).min_height
846    }
847
848    /// Sets [`min_height`](Self::min_height).
849    pub fn set_min_height(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
850        if self.get(app).min_height == value {
851            return;
852        }
853        self.get_mut(app).min_height = value;
854        self.mark_needs_layout(app);
855    }
856
857    /// The maximum height constraint to give the child. `None` (the default) uses the constraint
858    /// from the parent instead.
859    pub fn max_height(self: RenderHandle<Self>, app: &App) -> Option<f64> {
860        self.get(app).max_height
861    }
862
863    /// Sets [`max_height`](Self::max_height).
864    pub fn set_max_height(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
865        if self.get(app).max_height == value {
866            return;
867        }
868        self.get_mut(app).max_height = value;
869        self.mark_needs_layout(app);
870    }
871
872    /// The way to size the render object.
873    ///
874    /// This only affects the scenario where the child does not indeed overflow. If set to
875    /// [`OverflowBoxFit::DeferToChild`], the render object will size itself to match the size of
876    /// its child within the constraints of its parent, or as small as the parent allows if no
877    /// child is set. If set to [`OverflowBoxFit::Max`] (the default), the render object will size
878    /// itself to be as large as the parent allows.
879    pub fn fit(self: RenderHandle<Self>, app: &App) -> OverflowBoxFit {
880        self.get(app).fit
881    }
882
883    /// Sets [`fit`](Self::fit).
884    pub fn set_fit(self: RenderHandle<Self>, app: &mut App, value: OverflowBoxFit) {
885        if self.get(app).fit == value {
886            return;
887        }
888        self.get_mut(app).fit = value;
889        self.as_object()
890            .mark_needs_layout_for_sized_by_parent_change(app);
891    }
892
893    fn get_inner_constraints(
894        self: RenderHandle<Self>,
895        app: &App,
896        constraints: BoxConstraints,
897    ) -> BoxConstraints {
898        let this = self.get(app);
899        BoxConstraints {
900            min_width: this.min_width.unwrap_or(constraints.min_width),
901            max_width: this.max_width.unwrap_or(constraints.max_width),
902            min_height: this.min_height.unwrap_or(constraints.min_height),
903            max_height: this.max_height.unwrap_or(constraints.max_height),
904        }
905    }
906}
907
908impl RenderObjectWithChildMixin for RenderConstrainedOverflowBox {
909    type ChildType = AnyRenderBox;
910
911    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
912        &self.get(app).child
913    }
914
915    fn child_data_mut(
916        self: RenderHandle<Self>,
917        app: &mut App,
918    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
919        &mut self.get_mut(app).child
920    }
921}
922
923impl RenderShiftedBox for RenderConstrainedOverflowBox {}
924
925impl RenderAligningShiftedBox for RenderConstrainedOverflowBox {
926    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
927        &self.get(app).aligning
928    }
929
930    fn aligning_data_mut(
931        self: RenderHandle<Self>,
932        app: &mut App,
933    ) -> &mut RenderAligningShiftedBoxData {
934        &mut self.get_mut(app).aligning
935    }
936}
937
938impl RenderObject for RenderConstrainedOverflowBox {
939    crate::render_object_accessors!();
940
941    fn sized_by_parent(self: RenderHandle<Self>, app: &App) -> bool {
942        match self.fit(app) {
943            OverflowBoxFit::Max => true,
944            // If defer_to_child, the size will be as small as its child when non-overflowing,
945            // thus it cannot be sized_by_parent.
946            OverflowBoxFit::DeferToChild => false,
947        }
948    }
949
950    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
951        let constraints = self.constraints(app);
952        match self.child(app) {
953            Some(child) => {
954                let inner = self.get_inner_constraints(app, constraints);
955                child.layout(app, inner, true);
956                match self.fit(app) {
957                    OverflowBoxFit::Max => debug_assert!(self.sized_by_parent(app)),
958                    OverflowBoxFit::DeferToChild => {
959                        let size = constraints.constrain(child.size(app));
960                        self.set_size(app, size);
961                    }
962                }
963                self.align_child(app);
964            }
965            None => match self.fit(app) {
966                OverflowBoxFit::Max => debug_assert!(self.sized_by_parent(app)),
967                OverflowBoxFit::DeferToChild => self.set_size(app, constraints.smallest()),
968            },
969        }
970    }
971
972    fn paint(
973        self: RenderHandle<Self>,
974        app: &mut App,
975        context: &mut PaintingContext,
976        offset: Offset,
977    ) {
978        RenderShiftedBox::paint(self, app, context, offset);
979    }
980
981    fn visit_children(
982        self: RenderHandle<Self>,
983        app: &App,
984        visitor: &mut dyn FnMut(AnyRenderObject),
985    ) {
986        if let Some(child) = self.child(app) {
987            visitor(child.as_object());
988        }
989    }
990}
991
992impl RenderBox for RenderConstrainedOverflowBox {
993    crate::render_box_accessors!();
994
995    fn hit_test_children(
996        self: RenderHandle<Self>,
997        app: &mut App,
998        result: &mut BoxHitTestResult<'_>,
999        position: Offset,
1000    ) -> bool {
1001        RenderShiftedBox::hit_test_children(self, app, result, position)
1002    }
1003
1004    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1005        RenderShiftedBox::compute_min_intrinsic_width(self, app, height)
1006    }
1007
1008    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1009        RenderShiftedBox::compute_max_intrinsic_width(self, app, height)
1010    }
1011
1012    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1013        RenderShiftedBox::compute_min_intrinsic_height(self, app, width)
1014    }
1015
1016    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1017        RenderShiftedBox::compute_max_intrinsic_height(self, app, width)
1018    }
1019
1020    fn compute_distance_to_actual_baseline(
1021        self: RenderHandle<Self>,
1022        app: &mut App,
1023        baseline: TextBaseline,
1024    ) -> Option<f64> {
1025        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1026    }
1027
1028    fn compute_dry_layout(
1029        self: RenderHandle<Self>,
1030        app: &mut App,
1031        constraints: BoxConstraints,
1032    ) -> Size {
1033        match self.fit(app) {
1034            OverflowBoxFit::Max => constraints.biggest(),
1035            OverflowBoxFit::DeferToChild => match self.child(app) {
1036                Some(child) => child.get_dry_layout(app, constraints),
1037                None => constraints.smallest(),
1038            },
1039        }
1040    }
1041
1042    fn compute_dry_baseline(
1043        self: RenderHandle<Self>,
1044        app: &mut App,
1045        constraints: BoxConstraints,
1046        baseline: TextBaseline,
1047    ) -> Option<f64> {
1048        let child = self.child(app)?;
1049        let child_constraints = self.get_inner_constraints(app, constraints);
1050        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
1051        let child_size = child.get_dry_layout(app, child_constraints);
1052        let size = self.get_dry_layout(app, constraints);
1053        Some(
1054            result
1055                + self
1056                    .resolved_alignment(app)
1057                    .along_offset(size - child_size)
1058                    .dy(),
1059        )
1060    }
1061}
1062
1063/// A [`RenderBox`] that applies an arbitrary transform to its constraints, and sizes its child
1064/// using the resulting [`BoxConstraints`], optionally clipping, or treating the overflow as an
1065/// error.
1066///
1067/// This [`RenderBox`] sizes its child using a [`BoxConstraints`] created by applying
1068/// [`constraints_transform`](Self::constraints_transform) to this [`RenderBox`]'s own constraints.
1069/// This box will then attempt to adopt the same size, within the limits of its own constraints. If
1070/// it ends up with a different size, it will align the child based on
1071/// [`RenderAligningShiftedBox::alignment`]. If the box cannot expand enough to accommodate the
1072/// entire child, the child will be clipped if
1073/// [`clip_behavior`](Self::clip_behavior) is not [`Clip::None`].
1074///
1075/// When the child is `None`, this [`RenderBox`] takes the smallest possible size and never
1076/// overflows.
1077pub struct RenderConstraintsTransformBox {
1078    render_object: RenderObjectData,
1079    render_box: RenderBoxData,
1080    child: RenderObjectWithChildData<AnyRenderBox>,
1081    aligning: RenderAligningShiftedBoxData,
1082    constraints_transform: BoxConstraintsTransform,
1083    clip_behavior: Clip,
1084    clip_rect_layer: LayerHandle<Handle<ClipRectLayer>>,
1085    overflow_container_rect: Rect,
1086    overflow_child_rect: Rect,
1087    is_overflowing: bool,
1088    child_constraints: Option<BoxConstraints>,
1089}
1090
1091impl RenderConstraintsTransformBox {
1092    /// Creates a [`RenderBox`] that sizes itself to the child and modifies the constraints before
1093    /// passing them down to that child.
1094    pub fn new(
1095        app: &mut App,
1096        alignment: AlignmentGeometry,
1097        text_direction: Option<TextDirection>,
1098        constraints_transform: BoxConstraintsTransform,
1099        child: Option<AnyRenderBox>,
1100    ) -> RenderHandle<Self> {
1101        let this = RenderHandle::new_box(
1102            app,
1103            RenderConstraintsTransformBox {
1104                render_object: RenderObjectData::new(),
1105                render_box: RenderBoxData::new(),
1106                child: RenderObjectWithChildData::new(),
1107                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
1108                constraints_transform,
1109                clip_behavior: Clip::None,
1110                clip_rect_layer: LayerHandle::new(),
1111                overflow_container_rect: Rect::ZERO,
1112                overflow_child_rect: Rect::ZERO,
1113                is_overflowing: false,
1114                child_constraints: None,
1115            },
1116        );
1117        this.set_child(app, child);
1118        this
1119    }
1120
1121    /// The transform this box applies to its own constraints before laying its child out.
1122    pub fn constraints_transform(self: RenderHandle<Self>, app: &App) -> BoxConstraintsTransform {
1123        self.get(app).constraints_transform
1124    }
1125
1126    /// Sets [`constraints_transform`](Self::constraints_transform).
1127    pub fn set_constraints_transform(
1128        self: RenderHandle<Self>,
1129        app: &mut App,
1130        value: BoxConstraintsTransform,
1131    ) {
1132        if std::ptr::fn_addr_eq(self.get(app).constraints_transform, value) {
1133            return;
1134        }
1135        self.get_mut(app).constraints_transform = value;
1136        // The render object only needs layout if the new transform maps the current constraints
1137        // to a different value, or the render object has never been laid out before.
1138        let needs_layout = match self.get(app).child_constraints {
1139            Some(child_constraints) => child_constraints != value(self.constraints(app)),
1140            None => true,
1141        };
1142        if needs_layout {
1143            self.mark_needs_layout(app);
1144        }
1145    }
1146
1147    /// How to clip a child that overflows this box. Defaults to [`Clip::None`].
1148    pub fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
1149        self.get(app).clip_behavior
1150    }
1151
1152    /// Sets [`clip_behavior`](Self::clip_behavior).
1153    pub fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
1154        if self.get(app).clip_behavior == value {
1155            return;
1156        }
1157        self.get_mut(app).clip_behavior = value;
1158        self.mark_needs_paint(app);
1159    }
1160}
1161
1162impl RenderObjectWithChildMixin for RenderConstraintsTransformBox {
1163    type ChildType = AnyRenderBox;
1164
1165    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1166        &self.get(app).child
1167    }
1168
1169    fn child_data_mut(
1170        self: RenderHandle<Self>,
1171        app: &mut App,
1172    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1173        &mut self.get_mut(app).child
1174    }
1175}
1176
1177impl RenderShiftedBox for RenderConstraintsTransformBox {}
1178
1179impl RenderAligningShiftedBox for RenderConstraintsTransformBox {
1180    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
1181        &self.get(app).aligning
1182    }
1183
1184    fn aligning_data_mut(
1185        self: RenderHandle<Self>,
1186        app: &mut App,
1187    ) -> &mut RenderAligningShiftedBoxData {
1188        &mut self.get_mut(app).aligning
1189    }
1190}
1191
1192impl RenderObject for RenderConstraintsTransformBox {
1193    crate::render_object_accessors!();
1194
1195    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1196        let constraints = self.constraints(app);
1197        match self.child(app) {
1198            Some(child) => {
1199                let child_constraints = (self.constraints_transform(app))(constraints);
1200                debug_assert!(
1201                    child_constraints.is_normalized(),
1202                    "{child_constraints} is not normalized"
1203                );
1204                self.get_mut(app).child_constraints = Some(child_constraints);
1205                child.layout(app, child_constraints, true);
1206                let size = constraints.constrain(child.size(app));
1207                self.set_size(app, size);
1208                self.align_child(app);
1209                let child_offset = child
1210                    .as_object()
1211                    .parent_data_of::<BoxParentData>(app)
1212                    .offset;
1213                let child_rect = child_offset & child.size(app);
1214                let this = self.get_mut(app);
1215                this.overflow_container_rect = Offset::ZERO & size;
1216                this.overflow_child_rect = child_rect;
1217            }
1218            None => {
1219                self.set_size(app, constraints.smallest());
1220                let this = self.get_mut(app);
1221                this.overflow_container_rect = Rect::ZERO;
1222                this.overflow_child_rect = Rect::ZERO;
1223            }
1224        }
1225        let this = self.get_mut(app);
1226        this.is_overflowing =
1227            RelativeRect::from_rect(this.overflow_container_rect, this.overflow_child_rect)
1228                .has_insets();
1229    }
1230
1231    fn paint(
1232        self: RenderHandle<Self>,
1233        app: &mut App,
1234        context: &mut PaintingContext,
1235        offset: Offset,
1236    ) {
1237        if self.child(app).is_none() {
1238            return;
1239        }
1240        if !self.get(app).is_overflowing {
1241            RenderShiftedBox::paint(self, app, context, offset);
1242            return;
1243        }
1244        // We have overflow and the clipBehavior isn't none. Clip it.
1245        let clip_rect = Offset::ZERO & self.size(app);
1246        let clip_behavior = self.clip_behavior(app);
1247        let old = self.get(app).clip_rect_layer.layer();
1248        let layer = context.push_clip_rect(
1249            app,
1250            self.as_object().needs_compositing(app),
1251            offset,
1252            clip_rect,
1253            |app, context, offset| RenderShiftedBox::paint(self, app, context, offset),
1254            clip_behavior,
1255            old,
1256        );
1257        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, layer);
1258    }
1259
1260    fn dispose(self: RenderHandle<Self>, app: &mut App) {
1261        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, None);
1262        crate::object::RenderObjectBase::dispose(self, app);
1263    }
1264
1265    fn visit_children(
1266        self: RenderHandle<Self>,
1267        app: &App,
1268        visitor: &mut dyn FnMut(AnyRenderObject),
1269    ) {
1270        if let Some(child) = self.child(app) {
1271            visitor(child.as_object());
1272        }
1273    }
1274}
1275
1276impl RenderBox for RenderConstraintsTransformBox {
1277    crate::render_box_accessors!();
1278
1279    fn hit_test_children(
1280        self: RenderHandle<Self>,
1281        app: &mut App,
1282        result: &mut BoxHitTestResult<'_>,
1283        position: Offset,
1284    ) -> bool {
1285        RenderShiftedBox::hit_test_children(self, app, result, position)
1286    }
1287
1288    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1289        let transformed =
1290            (self.constraints_transform(app))(BoxConstraints::new().max_height(height));
1291        RenderShiftedBox::compute_min_intrinsic_width(self, app, transformed.max_height)
1292    }
1293
1294    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1295        let transformed =
1296            (self.constraints_transform(app))(BoxConstraints::new().max_height(height));
1297        RenderShiftedBox::compute_max_intrinsic_width(self, app, transformed.max_height)
1298    }
1299
1300    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1301        let transformed = (self.constraints_transform(app))(BoxConstraints::new().max_width(width));
1302        RenderShiftedBox::compute_min_intrinsic_height(self, app, transformed.max_width)
1303    }
1304
1305    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1306        let transformed = (self.constraints_transform(app))(BoxConstraints::new().max_width(width));
1307        RenderShiftedBox::compute_max_intrinsic_height(self, app, transformed.max_width)
1308    }
1309
1310    fn compute_distance_to_actual_baseline(
1311        self: RenderHandle<Self>,
1312        app: &mut App,
1313        baseline: TextBaseline,
1314    ) -> Option<f64> {
1315        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1316    }
1317
1318    fn compute_dry_layout(
1319        self: RenderHandle<Self>,
1320        app: &mut App,
1321        constraints: BoxConstraints,
1322    ) -> Size {
1323        match self.child(app) {
1324            Some(child) => {
1325                let child_constraints = (self.constraints_transform(app))(constraints);
1326                let child_size = child.get_dry_layout(app, child_constraints);
1327                constraints.constrain(child_size)
1328            }
1329            None => constraints.smallest(),
1330        }
1331    }
1332
1333    fn compute_dry_baseline(
1334        self: RenderHandle<Self>,
1335        app: &mut App,
1336        constraints: BoxConstraints,
1337        baseline: TextBaseline,
1338    ) -> Option<f64> {
1339        let child = self.child(app)?;
1340        let child_constraints = (self.constraints_transform(app))(constraints);
1341        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
1342        let child_size = child.get_dry_layout(app, child_constraints);
1343        let size = constraints.constrain(child_size);
1344        Some(
1345            result
1346                + self
1347                    .resolved_alignment(app)
1348                    .along_offset(size - child_size)
1349                    .dy(),
1350        )
1351    }
1352}
1353
1354/// A render object that is a specific size but passes its original constraints through to its
1355/// child, which it allows to overflow.
1356///
1357/// If the child's resulting size differs from this render object's size, then the child is aligned
1358/// according to [`RenderAligningShiftedBox::alignment`].
1359pub struct RenderSizedOverflowBox {
1360    render_object: RenderObjectData,
1361    render_box: RenderBoxData,
1362    child: RenderObjectWithChildData<AnyRenderBox>,
1363    aligning: RenderAligningShiftedBoxData,
1364    requested_size: Size,
1365}
1366
1367impl RenderSizedOverflowBox {
1368    /// Creates a render box of a given size that lets its child overflow.
1369    pub fn new(
1370        app: &mut App,
1371        requested_size: Size,
1372        alignment: AlignmentGeometry,
1373        text_direction: Option<TextDirection>,
1374        child: Option<AnyRenderBox>,
1375    ) -> RenderHandle<Self> {
1376        let this = RenderHandle::new_box(
1377            app,
1378            RenderSizedOverflowBox {
1379                render_object: RenderObjectData::new(),
1380                render_box: RenderBoxData::new(),
1381                child: RenderObjectWithChildData::new(),
1382                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
1383                requested_size,
1384            },
1385        );
1386        this.set_child(app, child);
1387        this
1388    }
1389
1390    /// The size this render box should attempt to be.
1391    pub fn requested_size(self: RenderHandle<Self>, app: &App) -> Size {
1392        self.get(app).requested_size
1393    }
1394
1395    /// Sets [`requested_size`](Self::requested_size).
1396    pub fn set_requested_size(self: RenderHandle<Self>, app: &mut App, value: Size) {
1397        if self.get(app).requested_size == value {
1398            return;
1399        }
1400        self.get_mut(app).requested_size = value;
1401        self.mark_needs_layout(app);
1402    }
1403}
1404
1405impl RenderObjectWithChildMixin for RenderSizedOverflowBox {
1406    type ChildType = AnyRenderBox;
1407
1408    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1409        &self.get(app).child
1410    }
1411
1412    fn child_data_mut(
1413        self: RenderHandle<Self>,
1414        app: &mut App,
1415    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1416        &mut self.get_mut(app).child
1417    }
1418}
1419
1420impl RenderShiftedBox for RenderSizedOverflowBox {}
1421
1422impl RenderAligningShiftedBox for RenderSizedOverflowBox {
1423    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
1424        &self.get(app).aligning
1425    }
1426
1427    fn aligning_data_mut(
1428        self: RenderHandle<Self>,
1429        app: &mut App,
1430    ) -> &mut RenderAligningShiftedBoxData {
1431        &mut self.get_mut(app).aligning
1432    }
1433}
1434
1435impl RenderObject for RenderSizedOverflowBox {
1436    crate::render_object_accessors!();
1437
1438    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1439        let constraints = self.constraints(app);
1440        let size = constraints.constrain(self.requested_size(app));
1441        self.set_size(app, size);
1442        if let Some(child) = self.child(app) {
1443            child.layout(app, constraints, true);
1444            self.align_child(app);
1445        }
1446    }
1447
1448    fn paint(
1449        self: RenderHandle<Self>,
1450        app: &mut App,
1451        context: &mut PaintingContext,
1452        offset: Offset,
1453    ) {
1454        RenderShiftedBox::paint(self, app, context, offset);
1455    }
1456
1457    fn visit_children(
1458        self: RenderHandle<Self>,
1459        app: &App,
1460        visitor: &mut dyn FnMut(AnyRenderObject),
1461    ) {
1462        if let Some(child) = self.child(app) {
1463            visitor(child.as_object());
1464        }
1465    }
1466}
1467
1468impl RenderBox for RenderSizedOverflowBox {
1469    crate::render_box_accessors!();
1470
1471    fn hit_test_children(
1472        self: RenderHandle<Self>,
1473        app: &mut App,
1474        result: &mut BoxHitTestResult<'_>,
1475        position: Offset,
1476    ) -> bool {
1477        RenderShiftedBox::hit_test_children(self, app, result, position)
1478    }
1479
1480    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, _height: f64) -> f64 {
1481        self.requested_size(app).width()
1482    }
1483
1484    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, _height: f64) -> f64 {
1485        self.requested_size(app).width()
1486    }
1487
1488    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, _width: f64) -> f64 {
1489        self.requested_size(app).height()
1490    }
1491
1492    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, _width: f64) -> f64 {
1493        self.requested_size(app).height()
1494    }
1495
1496    fn compute_distance_to_actual_baseline(
1497        self: RenderHandle<Self>,
1498        app: &mut App,
1499        baseline: TextBaseline,
1500    ) -> Option<f64> {
1501        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1502    }
1503
1504    fn compute_dry_layout(
1505        self: RenderHandle<Self>,
1506        app: &mut App,
1507        constraints: BoxConstraints,
1508    ) -> Size {
1509        constraints.constrain(self.requested_size(app))
1510    }
1511
1512    fn compute_dry_baseline(
1513        self: RenderHandle<Self>,
1514        app: &mut App,
1515        constraints: BoxConstraints,
1516        baseline: TextBaseline,
1517    ) -> Option<f64> {
1518        let child = self.child(app)?;
1519        let result = child.get_dry_baseline(app, constraints, baseline)?;
1520        let child_size = child.get_dry_layout(app, constraints);
1521        let size = self.get_dry_layout(app, constraints);
1522        Some(
1523            result
1524                + self
1525                    .resolved_alignment(app)
1526                    .along_offset(size - child_size)
1527                    .dy(),
1528        )
1529    }
1530}
1531
1532/// Sizes its child to a fraction of the total available space.
1533///
1534/// For both its width and height, this render object imposes a tight constraint on its child that
1535/// is a multiple (typically less than 1.0) of the maximum constraint it received from its parent
1536/// on that axis. If the factor for a given axis is `None`, then the constraints from the parent
1537/// are just passed through instead.
1538///
1539/// It then tries to size itself to the size of its child. Where this is not possible (e.g. if the
1540/// constraints from the parent are themselves tight), the child is aligned according to
1541/// [`RenderAligningShiftedBox::alignment`].
1542pub struct RenderFractionallySizedOverflowBox {
1543    render_object: RenderObjectData,
1544    render_box: RenderBoxData,
1545    child: RenderObjectWithChildData<AnyRenderBox>,
1546    aligning: RenderAligningShiftedBoxData,
1547    width_factor: Option<f64>,
1548    height_factor: Option<f64>,
1549}
1550
1551impl RenderFractionallySizedOverflowBox {
1552    /// Creates a render box that sizes its child to a fraction of the total available space.
1553    pub fn new(
1554        app: &mut App,
1555        alignment: AlignmentGeometry,
1556        text_direction: Option<TextDirection>,
1557        child: Option<AnyRenderBox>,
1558    ) -> RenderHandle<Self> {
1559        let this = RenderHandle::new_box(
1560            app,
1561            RenderFractionallySizedOverflowBox {
1562                render_object: RenderObjectData::new(),
1563                render_box: RenderBoxData::new(),
1564                child: RenderObjectWithChildData::new(),
1565                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
1566                width_factor: None,
1567                height_factor: None,
1568            },
1569        );
1570        this.set_child(app, child);
1571        this
1572    }
1573
1574    /// If non-null, the factor of the incoming width to use.
1575    ///
1576    /// If non-null, the child is given a tight width constraint that is the max incoming width
1577    /// constraint multiplied by this factor. If null, the child is given the incoming width
1578    /// constraints.
1579    pub fn width_factor(self: RenderHandle<Self>, app: &App) -> Option<f64> {
1580        self.get(app).width_factor
1581    }
1582
1583    /// Sets [`width_factor`](Self::width_factor).
1584    pub fn set_width_factor(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
1585        debug_assert!(value.is_none_or(|factor| factor >= 0.0));
1586        if self.get(app).width_factor == value {
1587            return;
1588        }
1589        self.get_mut(app).width_factor = value;
1590        self.mark_needs_layout(app);
1591    }
1592
1593    /// If non-null, the factor of the incoming height to use.
1594    ///
1595    /// If non-null, the child is given a tight height constraint that is the max incoming height
1596    /// constraint multiplied by this factor. If null, the child is given the incoming height
1597    /// constraints.
1598    pub fn height_factor(self: RenderHandle<Self>, app: &App) -> Option<f64> {
1599        self.get(app).height_factor
1600    }
1601
1602    /// Sets [`height_factor`](Self::height_factor).
1603    pub fn set_height_factor(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
1604        debug_assert!(value.is_none_or(|factor| factor >= 0.0));
1605        if self.get(app).height_factor == value {
1606            return;
1607        }
1608        self.get_mut(app).height_factor = value;
1609        self.mark_needs_layout(app);
1610    }
1611
1612    fn get_inner_constraints(
1613        self: RenderHandle<Self>,
1614        app: &App,
1615        constraints: BoxConstraints,
1616    ) -> BoxConstraints {
1617        let (width_factor, height_factor) = {
1618            let this = self.get(app);
1619            (this.width_factor, this.height_factor)
1620        };
1621        let mut min_width = constraints.min_width;
1622        let mut max_width = constraints.max_width;
1623        if let Some(factor) = width_factor {
1624            let width = max_width * factor;
1625            min_width = width;
1626            max_width = width;
1627        }
1628        let mut min_height = constraints.min_height;
1629        let mut max_height = constraints.max_height;
1630        if let Some(factor) = height_factor {
1631            let height = max_height * factor;
1632            min_height = height;
1633            max_height = height;
1634        }
1635        BoxConstraints {
1636            min_width,
1637            max_width,
1638            min_height,
1639            max_height,
1640        }
1641    }
1642}
1643
1644impl RenderObjectWithChildMixin for RenderFractionallySizedOverflowBox {
1645    type ChildType = AnyRenderBox;
1646
1647    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1648        &self.get(app).child
1649    }
1650
1651    fn child_data_mut(
1652        self: RenderHandle<Self>,
1653        app: &mut App,
1654    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1655        &mut self.get_mut(app).child
1656    }
1657}
1658
1659impl RenderShiftedBox for RenderFractionallySizedOverflowBox {}
1660
1661impl RenderAligningShiftedBox for RenderFractionallySizedOverflowBox {
1662    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
1663        &self.get(app).aligning
1664    }
1665
1666    fn aligning_data_mut(
1667        self: RenderHandle<Self>,
1668        app: &mut App,
1669    ) -> &mut RenderAligningShiftedBoxData {
1670        &mut self.get_mut(app).aligning
1671    }
1672}
1673
1674impl RenderObject for RenderFractionallySizedOverflowBox {
1675    crate::render_object_accessors!();
1676
1677    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1678        let constraints = self.constraints(app);
1679        let inner = self.get_inner_constraints(app, constraints);
1680        match self.child(app) {
1681            Some(child) => {
1682                child.layout(app, inner, true);
1683                let size = constraints.constrain(child.size(app));
1684                self.set_size(app, size);
1685                self.align_child(app);
1686            }
1687            None => {
1688                let size = constraints.constrain(inner.constrain(Size::ZERO));
1689                self.set_size(app, size);
1690            }
1691        }
1692    }
1693
1694    fn paint(
1695        self: RenderHandle<Self>,
1696        app: &mut App,
1697        context: &mut PaintingContext,
1698        offset: Offset,
1699    ) {
1700        RenderShiftedBox::paint(self, app, context, offset);
1701    }
1702
1703    fn visit_children(
1704        self: RenderHandle<Self>,
1705        app: &App,
1706        visitor: &mut dyn FnMut(AnyRenderObject),
1707    ) {
1708        if let Some(child) = self.child(app) {
1709            visitor(child.as_object());
1710        }
1711    }
1712}
1713
1714impl RenderBox for RenderFractionallySizedOverflowBox {
1715    crate::render_box_accessors!();
1716
1717    fn hit_test_children(
1718        self: RenderHandle<Self>,
1719        app: &mut App,
1720        result: &mut BoxHitTestResult<'_>,
1721        position: Offset,
1722    ) -> bool {
1723        RenderShiftedBox::hit_test_children(self, app, result, position)
1724    }
1725
1726    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1727        let (width_factor, height_factor) = {
1728            let this = self.get(app);
1729            (this.width_factor, this.height_factor)
1730        };
1731        let result = match self.child(app) {
1732            // Relies on f64::INFINITY absorption.
1733            Some(child) => {
1734                child.get_min_intrinsic_width(app, height * height_factor.unwrap_or(1.0))
1735            }
1736            None => RenderShiftedBox::compute_min_intrinsic_width(self, app, height),
1737        };
1738        debug_assert!(result.is_finite());
1739        result / width_factor.unwrap_or(1.0)
1740    }
1741
1742    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1743        let (width_factor, height_factor) = {
1744            let this = self.get(app);
1745            (this.width_factor, this.height_factor)
1746        };
1747        let result = match self.child(app) {
1748            Some(child) => {
1749                child.get_max_intrinsic_width(app, height * height_factor.unwrap_or(1.0))
1750            }
1751            None => RenderShiftedBox::compute_max_intrinsic_width(self, app, height),
1752        };
1753        debug_assert!(result.is_finite());
1754        result / width_factor.unwrap_or(1.0)
1755    }
1756
1757    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1758        let (width_factor, height_factor) = {
1759            let this = self.get(app);
1760            (this.width_factor, this.height_factor)
1761        };
1762        let result = match self.child(app) {
1763            Some(child) => child.get_min_intrinsic_height(app, width * width_factor.unwrap_or(1.0)),
1764            None => RenderShiftedBox::compute_min_intrinsic_height(self, app, width),
1765        };
1766        debug_assert!(result.is_finite());
1767        result / height_factor.unwrap_or(1.0)
1768    }
1769
1770    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1771        let (width_factor, height_factor) = {
1772            let this = self.get(app);
1773            (this.width_factor, this.height_factor)
1774        };
1775        let result = match self.child(app) {
1776            Some(child) => child.get_max_intrinsic_height(app, width * width_factor.unwrap_or(1.0)),
1777            None => RenderShiftedBox::compute_max_intrinsic_height(self, app, width),
1778        };
1779        debug_assert!(result.is_finite());
1780        result / height_factor.unwrap_or(1.0)
1781    }
1782
1783    fn compute_distance_to_actual_baseline(
1784        self: RenderHandle<Self>,
1785        app: &mut App,
1786        baseline: TextBaseline,
1787    ) -> Option<f64> {
1788        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1789    }
1790
1791    fn compute_dry_layout(
1792        self: RenderHandle<Self>,
1793        app: &mut App,
1794        constraints: BoxConstraints,
1795    ) -> Size {
1796        let inner = self.get_inner_constraints(app, constraints);
1797        match self.child(app) {
1798            Some(child) => {
1799                let child_size = child.get_dry_layout(app, inner);
1800                constraints.constrain(child_size)
1801            }
1802            None => constraints.constrain(inner.constrain(Size::ZERO)),
1803        }
1804    }
1805
1806    fn compute_dry_baseline(
1807        self: RenderHandle<Self>,
1808        app: &mut App,
1809        constraints: BoxConstraints,
1810        baseline: TextBaseline,
1811    ) -> Option<f64> {
1812        let child = self.child(app)?;
1813        let child_constraints = self.get_inner_constraints(app, constraints);
1814        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
1815        let child_size = child.get_dry_layout(app, child_constraints);
1816        let size = self.get_dry_layout(app, constraints);
1817        Some(
1818            result
1819                + self
1820                    .resolved_alignment(app)
1821                    .along_offset(size - child_size)
1822                    .dy(),
1823        )
1824    }
1825}
1826
1827/// Shifts the child down such that the child's baseline (or the bottom of the child, if the child
1828/// has no baseline) is [`baseline`](Self::baseline) logical pixels below the top of this box, then
1829/// sizes this box to contain the child.
1830///
1831/// If [`baseline`](Self::baseline) is less than the distance from the top of the child to the
1832/// baseline of the child, then the child will overflow the top of the box. This is typically not
1833/// desirable, in particular, that part of the child will not be found when doing hit tests, so
1834/// the user cannot interact with that part of the child.
1835///
1836/// This box will be sized so that its bottom is coincident with the bottom of the child. This
1837/// means if this box shifts the child down, there will be space between the top of this box and
1838/// the top of the child, but there is never space between the bottom of the child and the bottom
1839/// of the box.
1840pub struct RenderBaseline {
1841    render_object: RenderObjectData,
1842    render_box: RenderBoxData,
1843    child: RenderObjectWithChildData<AnyRenderBox>,
1844    baseline: f64,
1845    baseline_type: TextBaseline,
1846}
1847
1848/// What [`RenderBaseline::compute_sizes`] worked out: Dart's `({Size size, double top})`.
1849struct BaselineSizes {
1850    size: Size,
1851    top: f64,
1852}
1853
1854impl RenderBaseline {
1855    /// Creates a [`RenderBaseline`] object.
1856    pub fn new(
1857        app: &mut App,
1858        baseline: f64,
1859        baseline_type: TextBaseline,
1860        child: Option<AnyRenderBox>,
1861    ) -> RenderHandle<Self> {
1862        let this = RenderHandle::new_box(
1863            app,
1864            RenderBaseline {
1865                render_object: RenderObjectData::new(),
1866                render_box: RenderBoxData::new(),
1867                child: RenderObjectWithChildData::new(),
1868                baseline,
1869                baseline_type,
1870            },
1871        );
1872        this.set_child(app, child);
1873        this
1874    }
1875
1876    /// The number of logical pixels from the top of this box at which to position the child's
1877    /// baseline.
1878    pub fn baseline(self: RenderHandle<Self>, app: &App) -> f64 {
1879        self.get(app).baseline
1880    }
1881
1882    /// Sets [`baseline`](Self::baseline).
1883    pub fn set_baseline(self: RenderHandle<Self>, app: &mut App, value: f64) {
1884        if self.get(app).baseline == value {
1885            return;
1886        }
1887        self.get_mut(app).baseline = value;
1888        self.mark_needs_layout(app);
1889    }
1890
1891    /// The type of baseline to use for positioning the child.
1892    pub fn baseline_type(self: RenderHandle<Self>, app: &App) -> TextBaseline {
1893        self.get(app).baseline_type
1894    }
1895
1896    /// Sets [`baseline_type`](Self::baseline_type).
1897    pub fn set_baseline_type(self: RenderHandle<Self>, app: &mut App, value: TextBaseline) {
1898        if self.get(app).baseline_type == value {
1899            return;
1900        }
1901        self.get_mut(app).baseline_type = value;
1902        self.mark_needs_layout(app);
1903    }
1904
1905    /// Flutter's `_computeSizes`: this box's size and the offset the child is shifted down by.
1906    fn compute_sizes(
1907        self: RenderHandle<Self>,
1908        app: &mut App,
1909        constraints: BoxConstraints,
1910        layout_child: ChildLayouter,
1911        get_baseline: ChildBaselineGetter,
1912    ) -> BaselineSizes {
1913        let Some(child) = self.child(app) else {
1914            return BaselineSizes {
1915                size: constraints.smallest(),
1916                top: 0.0,
1917            };
1918        };
1919        let child_constraints = constraints.loosen();
1920        let child_size = layout_child(app, child, child_constraints);
1921        let baseline_type = self.baseline_type(app);
1922        let child_baseline = get_baseline(app, child, child_constraints, baseline_type)
1923            .unwrap_or(child_size.height());
1924        let top = self.baseline(app) - child_baseline;
1925        BaselineSizes {
1926            size: constraints.constrain(Size::new(child_size.width(), top + child_size.height())),
1927            top,
1928        }
1929    }
1930}
1931
1932impl RenderObjectWithChildMixin for RenderBaseline {
1933    type ChildType = AnyRenderBox;
1934
1935    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1936        &self.get(app).child
1937    }
1938
1939    fn child_data_mut(
1940        self: RenderHandle<Self>,
1941        app: &mut App,
1942    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1943        &mut self.get_mut(app).child
1944    }
1945}
1946
1947impl RenderShiftedBox for RenderBaseline {}
1948
1949impl RenderObject for RenderBaseline {
1950    crate::render_object_accessors!();
1951
1952    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1953        let constraints = self.constraints(app);
1954        let sizes = self.compute_sizes(
1955            app,
1956            constraints,
1957            ChildLayoutHelper::layout_child,
1958            ChildLayoutHelper::get_baseline,
1959        );
1960        self.set_size(app, sizes.size);
1961        if let Some(child) = self.child(app) {
1962            child.parent_data_of_mut::<BoxParentData>(app).offset = Offset::new(0.0, sizes.top);
1963        }
1964    }
1965
1966    fn paint(
1967        self: RenderHandle<Self>,
1968        app: &mut App,
1969        context: &mut PaintingContext,
1970        offset: Offset,
1971    ) {
1972        RenderShiftedBox::paint(self, app, context, offset);
1973    }
1974
1975    fn visit_children(
1976        self: RenderHandle<Self>,
1977        app: &App,
1978        visitor: &mut dyn FnMut(AnyRenderObject),
1979    ) {
1980        if let Some(child) = self.child(app) {
1981            visitor(child.as_object());
1982        }
1983    }
1984}
1985
1986impl RenderBox for RenderBaseline {
1987    crate::render_box_accessors!();
1988
1989    fn hit_test_children(
1990        self: RenderHandle<Self>,
1991        app: &mut App,
1992        result: &mut BoxHitTestResult<'_>,
1993        position: Offset,
1994    ) -> bool {
1995        RenderShiftedBox::hit_test_children(self, app, result, position)
1996    }
1997
1998    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1999        RenderShiftedBox::compute_min_intrinsic_width(self, app, height)
2000    }
2001
2002    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2003        RenderShiftedBox::compute_max_intrinsic_width(self, app, height)
2004    }
2005
2006    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2007        RenderShiftedBox::compute_min_intrinsic_height(self, app, width)
2008    }
2009
2010    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2011        RenderShiftedBox::compute_max_intrinsic_height(self, app, width)
2012    }
2013
2014    fn compute_distance_to_actual_baseline(
2015        self: RenderHandle<Self>,
2016        app: &mut App,
2017        baseline: TextBaseline,
2018    ) -> Option<f64> {
2019        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
2020    }
2021
2022    fn compute_dry_layout(
2023        self: RenderHandle<Self>,
2024        app: &mut App,
2025        constraints: BoxConstraints,
2026    ) -> Size {
2027        self.compute_sizes(
2028            app,
2029            constraints,
2030            ChildLayoutHelper::dry_layout_child,
2031            ChildLayoutHelper::get_dry_baseline,
2032        )
2033        .size
2034    }
2035
2036    fn compute_dry_baseline(
2037        self: RenderHandle<Self>,
2038        app: &mut App,
2039        constraints: BoxConstraints,
2040        baseline: TextBaseline,
2041    ) -> Option<f64> {
2042        let child = self.child(app)?;
2043        let child_constraints = constraints.loosen();
2044        let baseline_type = self.baseline_type(app);
2045        let result1 = child.get_dry_baseline(app, child_constraints, baseline)?;
2046        let result2 = child.get_dry_baseline(app, child_constraints, baseline_type)?;
2047        Some(self.baseline(app) + result1 - result2)
2048    }
2049}
2050
2051/// A delegate for computing the layout of a render object with a single child.
2052///
2053/// Used by [`RenderCustomSingleChildLayoutBox`] and `CustomSingleChildLayout` (in the widgets
2054/// library).
2055///
2056/// When asked to layout, [`RenderCustomSingleChildLayoutBox`] first calls
2057/// [`get_size`](Self::get_size) with its incoming constraints to determine its size. It then
2058/// uses [`get_constraints_for_child`](Self::get_constraints_for_child) to determine the
2059/// constraints to apply to the child. After the child completes its layout,
2060/// [`RenderCustomSingleChildLayoutBox`] calls [`get_position_for_child`](Self::get_position_for_child)
2061/// to determine the child's position.
2062///
2063/// The [`relayout`](Self::relayout) listenable causes the layout to update whenever it
2064/// notifies its listeners.
2065pub trait SingleChildLayoutDelegate: Debug + 'static {
2066    /// The [`Listenable`] the layout will update on, Dart's `relayout` constructor argument.
2067    ///
2068    /// Defaults to `None`.
2069    fn relayout(&self) -> Option<&Rc<dyn Listenable>> {
2070        None
2071    }
2072
2073    /// The size of this object given the incoming constraints.
2074    ///
2075    /// Defaults to the biggest size that satisfies the given constraints.
2076    fn get_size(&self, constraints: BoxConstraints) -> Size {
2077        constraints.biggest()
2078    }
2079
2080    /// The constraints for the child given the incoming constraints.
2081    ///
2082    /// During layout, the child is given the layout constraints returned by this function. The
2083    /// child is required to pick a size for itself that satisfies these constraints.
2084    ///
2085    /// Defaults to the given constraints.
2086    fn get_constraints_for_child(&self, constraints: BoxConstraints) -> BoxConstraints {
2087        constraints
2088    }
2089
2090    /// The position where the child should be placed.
2091    ///
2092    /// The `size` argument is the size of the parent, which might be different from the value
2093    /// returned by [`get_size`](Self::get_size) if that size doesn't satisfy the constraints
2094    /// passed to [`get_size`](Self::get_size). The `child_size` argument is the size of the
2095    /// child, which will satisfy the constraints returned by
2096    /// [`get_constraints_for_child`](Self::get_constraints_for_child).
2097    ///
2098    /// Defaults to positioning the child in the upper left corner of the parent.
2099    fn get_position_for_child(&self, size: Size, child_size: Size) -> Offset {
2100        let _ = (size, child_size);
2101        Offset::ZERO
2102    }
2103
2104    /// Called whenever a new instance of the custom layout delegate class is provided to the
2105    /// [`RenderCustomSingleChildLayoutBox`] object, or any time that a new `CustomSingleChildLayout`
2106    /// object is created with a new instance of the custom layout delegate class (which amounts
2107    /// to the same thing, because the latter is implemented in terms of the former).
2108    ///
2109    /// If the new instance represents different information than the old instance, then the
2110    /// method should return true, otherwise it should return false.
2111    ///
2112    /// If the method returns false, then the [`get_size`](Self::get_size),
2113    /// [`get_constraints_for_child`](Self::get_constraints_for_child), and
2114    /// [`get_position_for_child`](Self::get_position_for_child) calls might be optimized away.
2115    ///
2116    /// It's possible that the layout methods will get called even if [`should_relayout`](Self::should_relayout)
2117    /// returns false (e.g. if an ancestor changed its layout). It's also possible that the
2118    /// layout method will get called without [`should_relayout`](Self::should_relayout) being
2119    /// called at all (e.g. if the parent changes size).
2120    ///
2121    /// `old_delegate` is of the same concrete type, Dart's `covariant`: narrow it with
2122    /// [`as_any`](Self::as_any).
2123    fn should_relayout(&self, old_delegate: &dyn SingleChildLayoutDelegate) -> bool;
2124
2125    /// The concrete delegate, for Dart's `runtimeType` comparison and its `covariant`
2126    /// narrowing of [`should_relayout`](Self::should_relayout)'s argument.
2127    fn as_any(&self) -> &dyn Any;
2128}
2129
2130/// Defers the layout of its single child to a delegate.
2131///
2132/// The delegate can determine the layout constraints for the child and can decide where to
2133/// position the child. The delegate can also determine the size of the parent, but the size of
2134/// the parent cannot depend on the size of the child.
2135pub struct RenderCustomSingleChildLayoutBox {
2136    render_object: RenderObjectData,
2137    render_box: RenderBoxData,
2138    child: RenderObjectWithChildData<AnyRenderBox>,
2139    delegate: Rc<dyn SingleChildLayoutDelegate>,
2140}
2141
2142impl RenderCustomSingleChildLayoutBox {
2143    /// Creates a render box that defers its layout to a delegate.
2144    pub fn new(
2145        app: &mut App,
2146        delegate: Rc<dyn SingleChildLayoutDelegate>,
2147        child: Option<AnyRenderBox>,
2148    ) -> RenderHandle<RenderCustomSingleChildLayoutBox> {
2149        let this = RenderHandle::new_box(
2150            app,
2151            RenderCustomSingleChildLayoutBox {
2152                render_object: RenderObjectData::new(),
2153                render_box: RenderBoxData::new(),
2154                child: RenderObjectWithChildData::new(),
2155                delegate,
2156            },
2157        );
2158        this.set_child(app, child);
2159        this
2160    }
2161
2162    /// A delegate that controls this object's layout.
2163    pub fn delegate(self: RenderHandle<Self>, app: &App) -> Rc<dyn SingleChildLayoutDelegate> {
2164        Rc::clone(&self.get(app).delegate)
2165    }
2166
2167    /// Sets [`delegate`](Self::delegate).
2168    pub fn set_delegate(
2169        self: RenderHandle<Self>,
2170        app: &mut App,
2171        new_delegate: Rc<dyn SingleChildLayoutDelegate>,
2172    ) {
2173        let old_delegate = Rc::clone(&self.get(app).delegate);
2174        if Rc::ptr_eq(&old_delegate, &new_delegate) {
2175            return;
2176        }
2177        if new_delegate.as_any().type_id() != old_delegate.as_any().type_id()
2178            || new_delegate.should_relayout(&*old_delegate)
2179        {
2180            self.mark_needs_layout(app);
2181        }
2182        self.get_mut(app).delegate = Rc::clone(&new_delegate);
2183        if self.attached(app) {
2184            if let Some(relayout) = old_delegate.relayout() {
2185                relayout.remove_listener(app, &self.relayout_listener());
2186            }
2187            if let Some(relayout) = new_delegate.relayout() {
2188                relayout.add_listener(app, self.relayout_listener());
2189            }
2190        }
2191    }
2192
2193    /// The `markNeedsLayout` tear-off, equal to itself across registrations.
2194    fn relayout_listener(self: RenderHandle<Self>) -> Listener {
2195        Listener::handle_method(self.handle(), mark_needs_layout_custom_single_child)
2196    }
2197
2198    /// Dart's `_getSize`.
2199    fn get_size(self: RenderHandle<Self>, app: &App, constraints: BoxConstraints) -> Size {
2200        constraints.constrain(self.get(app).delegate.get_size(constraints))
2201    }
2202}
2203
2204fn mark_needs_layout_custom_single_child(
2205    this: Handle<RenderCustomSingleChildLayoutBox>,
2206    app: &mut App,
2207) {
2208    RenderHandle::from_handle(this).mark_needs_layout(app);
2209}
2210
2211impl RenderObjectWithChildMixin for RenderCustomSingleChildLayoutBox {
2212    type ChildType = AnyRenderBox;
2213
2214    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2215        &self.get(app).child
2216    }
2217
2218    fn child_data_mut(
2219        self: RenderHandle<Self>,
2220        app: &mut App,
2221    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2222        &mut self.get_mut(app).child
2223    }
2224}
2225
2226impl RenderShiftedBox for RenderCustomSingleChildLayoutBox {}
2227
2228impl RenderObject for RenderCustomSingleChildLayoutBox {
2229    crate::render_object_accessors!();
2230
2231    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2232        let constraints = self.constraints(app);
2233        let size = self.get_size(app, constraints);
2234        self.set_size(app, size);
2235        if let Some(child) = self.child(app) {
2236            let child_constraints = self
2237                .get(app)
2238                .delegate
2239                .get_constraints_for_child(constraints);
2240            debug_assert!(child_constraints.debug_assert_is_valid(true));
2241            child.layout(app, child_constraints, !child_constraints.is_tight());
2242            let child_size = if child_constraints.is_tight() {
2243                child_constraints.smallest()
2244            } else {
2245                child.size(app)
2246            };
2247            child.parent_data_of_mut::<BoxParentData>(app).offset = self
2248                .get(app)
2249                .delegate
2250                .get_position_for_child(size, child_size);
2251        }
2252    }
2253
2254    fn paint(
2255        self: RenderHandle<Self>,
2256        app: &mut App,
2257        context: &mut PaintingContext,
2258        offset: Offset,
2259    ) {
2260        RenderShiftedBox::paint(self, app, context, offset);
2261    }
2262
2263    fn visit_children(
2264        self: RenderHandle<Self>,
2265        app: &App,
2266        visitor: &mut dyn FnMut(AnyRenderObject),
2267    ) {
2268        if let Some(child) = self.child(app) {
2269            visitor(child.as_object());
2270        }
2271    }
2272
2273    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
2274        if let Some(child) = self.child(app) {
2275            child.as_object().attach(app, owner);
2276        }
2277        if let Some(relayout) = self.delegate(app).relayout() {
2278            relayout.add_listener(app, self.relayout_listener());
2279        }
2280    }
2281
2282    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
2283        if let Some(relayout) = self.delegate(app).relayout() {
2284            relayout.remove_listener(app, &self.relayout_listener());
2285        }
2286        if let Some(child) = self.child(app) {
2287            child.as_object().detach(app);
2288        }
2289    }
2290}
2291
2292impl RenderBox for RenderCustomSingleChildLayoutBox {
2293    crate::render_box_accessors!();
2294
2295    fn hit_test_children(
2296        self: RenderHandle<Self>,
2297        app: &mut App,
2298        result: &mut BoxHitTestResult<'_>,
2299        position: Offset,
2300    ) -> bool {
2301        RenderShiftedBox::hit_test_children(self, app, result, position)
2302    }
2303
2304    // TODO(ianh): It's a bit dubious to be using the getSize function from the delegate to
2305    // figure out the intrinsic dimensions. We really should either not support intrinsics,
2306    // or we should expose intrinsic delegate callbacks and throw if they're not implemented.
2307
2308    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2309        let width = self
2310            .get_size(app, BoxConstraints::tight_for_finite(f64::INFINITY, height))
2311            .width();
2312        if width.is_finite() { width } else { 0.0 }
2313    }
2314
2315    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2316        let width = self
2317            .get_size(app, BoxConstraints::tight_for_finite(f64::INFINITY, height))
2318            .width();
2319        if width.is_finite() { width } else { 0.0 }
2320    }
2321
2322    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2323        let height = self
2324            .get_size(app, BoxConstraints::tight_for_finite(width, f64::INFINITY))
2325            .height();
2326        if height.is_finite() { height } else { 0.0 }
2327    }
2328
2329    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2330        let height = self
2331            .get_size(app, BoxConstraints::tight_for_finite(width, f64::INFINITY))
2332            .height();
2333        if height.is_finite() { height } else { 0.0 }
2334    }
2335
2336    fn compute_dry_layout(
2337        self: RenderHandle<Self>,
2338        app: &mut App,
2339        constraints: BoxConstraints,
2340    ) -> Size {
2341        self.get_size(app, constraints)
2342    }
2343
2344    fn compute_dry_baseline(
2345        self: RenderHandle<Self>,
2346        app: &mut App,
2347        constraints: BoxConstraints,
2348        baseline: TextBaseline,
2349    ) -> Option<f64> {
2350        let child = self.child(app)?;
2351        let child_constraints = self
2352            .get(app)
2353            .delegate
2354            .get_constraints_for_child(constraints);
2355        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
2356        let child_size = if child_constraints.is_tight() {
2357            child_constraints.smallest()
2358        } else {
2359            child.get_dry_layout(app, child_constraints)
2360        };
2361        Some(
2362            result
2363                + self
2364                    .get(app)
2365                    .delegate
2366                    .get_position_for_child(self.get_size(app, constraints), child_size)
2367                    .dy(),
2368        )
2369    }
2370}
2371
2372#[cfg(test)]
2373mod tests {
2374    use super::*;
2375    use inset_embedder::Size;
2376    use inset_foundation::AppCell;
2377
2378    use crate::box_::BoxConstraints;
2379    use crate::layer::{ContainerLayer, ErasedLayer, OffsetLayer, PictureLayer};
2380    use crate::pipeline_owner::PipelineOwner;
2381    use crate::proxy_box::{RenderConstrainedBox, RenderRepaintBoundary};
2382    use inset_embedder::valo::Op;
2383
2384    /// `padding_test.dart`: the padding is added to the child's intrinsics, and taken off the
2385    /// extent handed to the child.
2386    #[test]
2387    fn padding_intrinsics_add_the_insets() {
2388        let cell = AppCell::new();
2389        let mut app = cell.borrow_mut();
2390        let child =
2391            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
2392        let padding = RenderPadding::new(
2393            &mut app,
2394            EdgeInsetsGeometry::all(8.0),
2395            None,
2396            Some(child.as_box()),
2397        );
2398        let padded = padding.as_box();
2399        assert_eq!(padded.get_min_intrinsic_width(&mut app, 100.0), 96.0);
2400        assert_eq!(padded.get_max_intrinsic_width(&mut app, 100.0), 96.0);
2401        assert_eq!(padded.get_min_intrinsic_height(&mut app, 100.0), 56.0);
2402        assert_eq!(padded.get_max_intrinsic_height(&mut app, 100.0), 56.0);
2403    }
2404
2405    /// Without a child, the padding is all there is.
2406    #[test]
2407    fn padding_intrinsics_without_a_child_are_the_insets() {
2408        let cell = AppCell::new();
2409        let mut app = cell.borrow_mut();
2410        let padding = RenderPadding::new(&mut app, EdgeInsetsGeometry::all(10.0), None, None);
2411        assert_eq!(
2412            padding.as_box().get_min_intrinsic_width(&mut app, 0.0),
2413            20.0
2414        );
2415        assert_eq!(
2416            padding.as_box().get_max_intrinsic_height(&mut app, 0.0),
2417            20.0
2418        );
2419    }
2420
2421    /// The dry layout of a padding is the size it lays out to.
2422    #[test]
2423    fn padding_dry_layout_matches_its_layout() {
2424        let cell = AppCell::new();
2425        let mut app = cell.borrow_mut();
2426        let child =
2427            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
2428        let padding = RenderPadding::new(
2429            &mut app,
2430            EdgeInsetsGeometry::all(8.0),
2431            None,
2432            Some(child.as_box()),
2433        );
2434        let constraints = BoxConstraints::new().max_width(500.0).max_height(500.0);
2435        let dry = padding.as_box().get_dry_layout(&mut app, constraints);
2436        padding.layout(&mut app, constraints, false);
2437        assert_eq!(dry, padding.size(&app));
2438    }
2439
2440    /// `unconstrained_box_test.dart`: an `UnconstrainedBox` is a
2441    /// `RenderConstraintsTransformBox` whose transform drops every constraint, so the child takes
2442    /// its natural size and is aligned within what the parent allows.
2443    #[test]
2444    fn constraints_transform_box_leaves_the_child_unconstrained_and_aligns_it() {
2445        let cell = AppCell::new();
2446        let mut app = cell.borrow_mut();
2447        let child =
2448            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(50.0, 20.0)), None);
2449        let unconstrained = RenderConstraintsTransformBox::new(
2450            &mut app,
2451            AlignmentGeometry::CENTER,
2452            None,
2453            |_| BoxConstraints::new(),
2454            Some(child.as_box()),
2455        );
2456        unconstrained.layout(
2457            &mut app,
2458            BoxConstraints::tight(Size::new(100.0, 100.0)),
2459            false,
2460        );
2461        assert_eq!(child.size(&app), Size::new(50.0, 20.0));
2462        assert_eq!(unconstrained.size(&app), Size::new(100.0, 100.0));
2463        assert_eq!(
2464            child.as_box().box_parent_data(&app).offset,
2465            Offset::new(25.0, 40.0)
2466        );
2467    }
2468
2469    /// A child that does not fit is clipped when the clip behavior asks for it.
2470    #[test]
2471    fn constraints_transform_box_clips_an_overflowing_child() {
2472        let cell = AppCell::new();
2473        let mut app = cell.borrow_mut();
2474        let child = RenderConstrainedBox::new(
2475            &mut app,
2476            BoxConstraints::tight(Size::new(200.0, 200.0)),
2477            None,
2478        );
2479        let unconstrained = RenderConstraintsTransformBox::new(
2480            &mut app,
2481            AlignmentGeometry::CENTER,
2482            None,
2483            |_| BoxConstraints::new(),
2484            Some(child.as_box()),
2485        );
2486        unconstrained.set_clip_behavior(&mut app, Clip::HardEdge);
2487        let root = RenderRepaintBoundary::new(&mut app, Some(unconstrained.as_box()));
2488        let owner = PipelineOwner::new(&mut app, None, None);
2489        owner.set_root_node(&mut app, Some(root.as_object()));
2490        root.layout(
2491            &mut app,
2492            BoxConstraints::tight(Size::new(100.0, 100.0)),
2493            false,
2494        );
2495        let paint_root = OffsetLayer::new(&mut app, Offset::ZERO);
2496        paint_root
2497            .as_layer()
2498            .attach(&mut app, root.as_object().id());
2499        root.as_object()
2500            .schedule_initial_paint(&mut app, paint_root.as_container_layer());
2501        owner.flush_compositing_bits(&mut app);
2502        owner.flush_paint(&mut app);
2503
2504        assert_eq!(unconstrained.size(&app), Size::new(100.0, 100.0));
2505        let layer = root.as_object().debug_layer(&app).expect("painted");
2506        let clipped = layer
2507            .depth_first_iterate_children(&app)
2508            .into_iter()
2509            .filter_map(|child| {
2510                app.handle::<PictureLayer>(child.id())
2511                    .and_then(|picture| picture.picture(&app).map(|p| p.ops().to_vec()))
2512            })
2513            .flatten()
2514            .any(|op| matches!(op, Op::ClipPath { .. }));
2515        assert!(clipped, "the overflowing child is clipped");
2516    }
2517
2518    /// A `RenderConstrainedOverflowBox` lets its child overflow and keeps the parent's size.
2519    #[test]
2520    fn constrained_overflow_box_sizes_itself_to_the_parent() {
2521        let cell = AppCell::new();
2522        let mut app = cell.borrow_mut();
2523        let child = RenderConstrainedBox::new(&mut app, BoxConstraints::new(), None);
2524        let overflow = RenderConstrainedOverflowBox::new(
2525            &mut app,
2526            Some(200.0),
2527            Some(200.0),
2528            None,
2529            None,
2530            OverflowBoxFit::Max,
2531            AlignmentGeometry::CENTER,
2532            None,
2533            Some(child.as_box()),
2534        );
2535        overflow.layout(
2536            &mut app,
2537            BoxConstraints::tight(Size::new(100.0, 100.0)),
2538            false,
2539        );
2540        assert_eq!(overflow.size(&app), Size::new(100.0, 100.0));
2541        assert_eq!(child.size(&app).width(), 200.0);
2542        assert_eq!(
2543            child.as_box().box_parent_data(&app).offset.dx(),
2544            -50.0,
2545            "the child is centered, so it overflows both sides"
2546        );
2547    }
2548
2549    /// A `RenderSizedOverflowBox` takes its requested size and passes the original constraints
2550    /// through, and reports the requested size as its intrinsics.
2551    #[test]
2552    fn sized_overflow_box_takes_its_requested_size() {
2553        let cell = AppCell::new();
2554        let mut app = cell.borrow_mut();
2555        let child =
2556            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(30.0, 30.0)), None);
2557        let sized = RenderSizedOverflowBox::new(
2558            &mut app,
2559            Size::new(50.0, 50.0),
2560            AlignmentGeometry::CENTER,
2561            None,
2562            Some(child.as_box()),
2563        );
2564        sized.layout(&mut app, BoxConstraints::new().max_width(100.0), false);
2565        assert_eq!(sized.size(&app), Size::new(50.0, 50.0));
2566        assert_eq!(sized.as_box().get_min_intrinsic_width(&mut app, 0.0), 50.0);
2567        assert_eq!(sized.as_box().get_max_intrinsic_height(&mut app, 0.0), 50.0);
2568    }
2569
2570    /// A `RenderFractionallySizedOverflowBox` tightens the child to a fraction of the incoming
2571    /// maximum, and divides its intrinsics by the factor.
2572    #[test]
2573    fn fractionally_sized_box_tightens_the_child_to_a_fraction() {
2574        let cell = AppCell::new();
2575        let mut app = cell.borrow_mut();
2576        let child = RenderConstrainedBox::new(&mut app, BoxConstraints::new(), None);
2577        let fraction = RenderFractionallySizedOverflowBox::new(
2578            &mut app,
2579            AlignmentGeometry::CENTER,
2580            None,
2581            Some(child.as_box()),
2582        );
2583        fraction.set_width_factor(&mut app, Some(0.5));
2584        fraction.layout(
2585            &mut app,
2586            BoxConstraints::new().max_width(200.0).max_height(80.0),
2587            false,
2588        );
2589        assert_eq!(child.size(&app).width(), 100.0);
2590        assert_eq!(fraction.size(&app).width(), 100.0);
2591    }
2592
2593    /// `baseline_test.dart`: the child is shifted down so that its baseline sits at the given
2594    /// distance from the top.
2595    #[test]
2596    fn baseline_shifts_the_child_down_to_its_baseline() {
2597        let cell = AppCell::new();
2598        let mut app = cell.borrow_mut();
2599        let child =
2600            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)), None);
2601        let baseline = RenderBaseline::new(
2602            &mut app,
2603            30.0,
2604            TextBaseline::Alphabetic,
2605            Some(child.as_box()),
2606        );
2607        baseline.layout(&mut app, BoxConstraints::new(), false);
2608        // The child has no baseline, so its bottom is used: the shift is 30 - 20.
2609        assert_eq!(
2610            child.as_box().box_parent_data(&app).offset,
2611            Offset::new(0.0, 10.0)
2612        );
2613        assert_eq!(baseline.size(&app), Size::new(20.0, 30.0));
2614    }
2615
2616    #[test]
2617    fn padding_around_tight_child() {
2618        let cell = AppCell::new();
2619        let mut app = cell.borrow_mut();
2620        let child =
2621            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
2622        let padding = RenderPadding::new(
2623            &mut app,
2624            EdgeInsetsGeometry::all(8.0),
2625            None,
2626            Some(child.as_box()),
2627        );
2628        padding.layout(&mut app, BoxConstraints::new(), false);
2629        assert_eq!(child.size(&app), Size::new(80.0, 40.0));
2630        assert_eq!(padding.size(&app), Size::new(96.0, 56.0));
2631        assert_eq!(
2632            child.as_box().box_parent_data(&app).offset,
2633            Offset::new(8.0, 8.0)
2634        );
2635    }
2636
2637    #[test]
2638    fn positioned_box_centers_its_child() {
2639        let cell = AppCell::new();
2640        let mut app = cell.borrow_mut();
2641        let child =
2642            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)), None);
2643        let positioned = RenderPositionedBox::new(
2644            &mut app,
2645            AlignmentGeometry::CENTER,
2646            None,
2647            None,
2648            None,
2649            Some(child.as_box()),
2650        );
2651        positioned.layout(
2652            &mut app,
2653            BoxConstraints::tight(Size::new(100.0, 100.0)),
2654            false,
2655        );
2656        assert_eq!(positioned.size(&app), Size::new(100.0, 100.0));
2657        assert_eq!(
2658            child.as_box().box_parent_data(&app).offset,
2659            Offset::new(40.0, 40.0)
2660        );
2661    }
2662
2663    #[test]
2664    fn positioned_box_shrink_wraps_with_a_factor() {
2665        let cell = AppCell::new();
2666        let mut app = cell.borrow_mut();
2667        let child =
2668            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)), None);
2669        let positioned = RenderPositionedBox::new(
2670            &mut app,
2671            AlignmentGeometry::CENTER,
2672            None,
2673            Some(2.0),
2674            None,
2675            Some(child.as_box()),
2676        );
2677        positioned.layout(
2678            &mut app,
2679            BoxConstraints::new().max_width(100.0).max_height(100.0),
2680            false,
2681        );
2682        assert_eq!(positioned.size(&app), Size::new(40.0, 100.0));
2683        assert_eq!(
2684            child.as_box().box_parent_data(&app).offset,
2685            Offset::new(10.0, 40.0)
2686        );
2687    }
2688
2689    #[test]
2690    fn padding_without_child() {
2691        let cell = AppCell::new();
2692        let mut app = cell.borrow_mut();
2693        let padding = RenderPadding::new(&mut app, EdgeInsetsGeometry::all(10.0), None, None);
2694        padding.layout(
2695            &mut app,
2696            BoxConstraints::tight(Size::new(100.0, 100.0)),
2697            false,
2698        );
2699        assert_eq!(padding.size(&app), Size::new(100.0, 100.0));
2700    }
2701
2702    #[derive(Debug)]
2703    struct OffsetDelegate {
2704        offset: Offset,
2705    }
2706
2707    impl SingleChildLayoutDelegate for OffsetDelegate {
2708        fn get_size(&self, constraints: BoxConstraints) -> Size {
2709            constraints.biggest()
2710        }
2711
2712        fn get_constraints_for_child(&self, constraints: BoxConstraints) -> BoxConstraints {
2713            constraints.loosen()
2714        }
2715
2716        fn get_position_for_child(&self, _size: Size, _child_size: Size) -> Offset {
2717            self.offset
2718        }
2719
2720        fn should_relayout(&self, old_delegate: &dyn SingleChildLayoutDelegate) -> bool {
2721            old_delegate
2722                .as_any()
2723                .downcast_ref::<OffsetDelegate>()
2724                .is_none_or(|old| old.offset != self.offset)
2725        }
2726
2727        fn as_any(&self) -> &dyn Any {
2728            self
2729        }
2730    }
2731
2732    #[test]
2733    fn custom_single_child_layout_positions_the_child() {
2734        let cell = AppCell::new();
2735        let mut app = cell.borrow_mut();
2736        let child =
2737            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 10.0)), None);
2738        let parent = RenderCustomSingleChildLayoutBox::new(
2739            &mut app,
2740            Rc::new(OffsetDelegate {
2741                offset: Offset::new(8.0, 4.0),
2742            }),
2743            Some(child.as_box()),
2744        );
2745        parent.layout(
2746            &mut app,
2747            BoxConstraints::tight(Size::new(100.0, 50.0)),
2748            false,
2749        );
2750        assert_eq!(parent.size(&app), Size::new(100.0, 50.0));
2751        assert_eq!(
2752            child.as_box().box_parent_data(&app).offset,
2753            Offset::new(8.0, 4.0)
2754        );
2755    }
2756}