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.
781    pub fn new(
782        app: &mut App,
783        alignment: AlignmentGeometry,
784        text_direction: Option<TextDirection>,
785        child: Option<AnyRenderBox>,
786    ) -> RenderHandle<Self> {
787        let this = RenderHandle::new_box(
788            app,
789            RenderConstrainedOverflowBox {
790                render_object: RenderObjectData::new(),
791                render_box: RenderBoxData::new(),
792                child: RenderObjectWithChildData::new(),
793                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
794                min_width: None,
795                max_width: None,
796                min_height: None,
797                max_height: None,
798                fit: OverflowBoxFit::Max,
799            },
800        );
801        this.set_child(app, child);
802        this
803    }
804
805    /// The minimum width constraint to give the child. `None` (the default) uses the constraint
806    /// from the parent instead.
807    pub fn min_width(self: RenderHandle<Self>, app: &App) -> Option<f64> {
808        self.get(app).min_width
809    }
810
811    /// Sets [`min_width`](Self::min_width).
812    pub fn set_min_width(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
813        if self.get(app).min_width == value {
814            return;
815        }
816        self.get_mut(app).min_width = value;
817        self.mark_needs_layout(app);
818    }
819
820    /// The maximum width constraint to give the child. `None` (the default) uses the constraint
821    /// from the parent instead.
822    pub fn max_width(self: RenderHandle<Self>, app: &App) -> Option<f64> {
823        self.get(app).max_width
824    }
825
826    /// Sets [`max_width`](Self::max_width).
827    pub fn set_max_width(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
828        if self.get(app).max_width == value {
829            return;
830        }
831        self.get_mut(app).max_width = value;
832        self.mark_needs_layout(app);
833    }
834
835    /// The minimum height constraint to give the child. `None` (the default) uses the constraint
836    /// from the parent instead.
837    pub fn min_height(self: RenderHandle<Self>, app: &App) -> Option<f64> {
838        self.get(app).min_height
839    }
840
841    /// Sets [`min_height`](Self::min_height).
842    pub fn set_min_height(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
843        if self.get(app).min_height == value {
844            return;
845        }
846        self.get_mut(app).min_height = value;
847        self.mark_needs_layout(app);
848    }
849
850    /// The maximum height constraint to give the child. `None` (the default) uses the constraint
851    /// from the parent instead.
852    pub fn max_height(self: RenderHandle<Self>, app: &App) -> Option<f64> {
853        self.get(app).max_height
854    }
855
856    /// Sets [`max_height`](Self::max_height).
857    pub fn set_max_height(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
858        if self.get(app).max_height == value {
859            return;
860        }
861        self.get_mut(app).max_height = value;
862        self.mark_needs_layout(app);
863    }
864
865    /// The way to size the render object.
866    ///
867    /// This only affects the scenario where the child does not indeed overflow. If set to
868    /// [`OverflowBoxFit::DeferToChild`], the render object will size itself to match the size of
869    /// its child within the constraints of its parent, or as small as the parent allows if no
870    /// child is set. If set to [`OverflowBoxFit::Max`] (the default), the render object will size
871    /// itself to be as large as the parent allows.
872    pub fn fit(self: RenderHandle<Self>, app: &App) -> OverflowBoxFit {
873        self.get(app).fit
874    }
875
876    /// Sets [`fit`](Self::fit).
877    pub fn set_fit(self: RenderHandle<Self>, app: &mut App, value: OverflowBoxFit) {
878        if self.get(app).fit == value {
879            return;
880        }
881        self.get_mut(app).fit = value;
882        self.as_object()
883            .mark_needs_layout_for_sized_by_parent_change(app);
884    }
885
886    fn get_inner_constraints(
887        self: RenderHandle<Self>,
888        app: &App,
889        constraints: BoxConstraints,
890    ) -> BoxConstraints {
891        let this = self.get(app);
892        BoxConstraints {
893            min_width: this.min_width.unwrap_or(constraints.min_width),
894            max_width: this.max_width.unwrap_or(constraints.max_width),
895            min_height: this.min_height.unwrap_or(constraints.min_height),
896            max_height: this.max_height.unwrap_or(constraints.max_height),
897        }
898    }
899}
900
901impl RenderObjectWithChildMixin for RenderConstrainedOverflowBox {
902    type ChildType = AnyRenderBox;
903
904    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
905        &self.get(app).child
906    }
907
908    fn child_data_mut(
909        self: RenderHandle<Self>,
910        app: &mut App,
911    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
912        &mut self.get_mut(app).child
913    }
914}
915
916impl RenderShiftedBox for RenderConstrainedOverflowBox {}
917
918impl RenderAligningShiftedBox for RenderConstrainedOverflowBox {
919    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
920        &self.get(app).aligning
921    }
922
923    fn aligning_data_mut(
924        self: RenderHandle<Self>,
925        app: &mut App,
926    ) -> &mut RenderAligningShiftedBoxData {
927        &mut self.get_mut(app).aligning
928    }
929}
930
931impl RenderObject for RenderConstrainedOverflowBox {
932    crate::render_object_accessors!();
933
934    fn sized_by_parent(self: RenderHandle<Self>, app: &App) -> bool {
935        match self.fit(app) {
936            OverflowBoxFit::Max => true,
937            // If defer_to_child, the size will be as small as its child when non-overflowing,
938            // thus it cannot be sized_by_parent.
939            OverflowBoxFit::DeferToChild => false,
940        }
941    }
942
943    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
944        let constraints = self.constraints(app);
945        match self.child(app) {
946            Some(child) => {
947                let inner = self.get_inner_constraints(app, constraints);
948                child.layout(app, inner, true);
949                match self.fit(app) {
950                    OverflowBoxFit::Max => debug_assert!(self.sized_by_parent(app)),
951                    OverflowBoxFit::DeferToChild => {
952                        let size = constraints.constrain(child.size(app));
953                        self.set_size(app, size);
954                    }
955                }
956                self.align_child(app);
957            }
958            None => match self.fit(app) {
959                OverflowBoxFit::Max => debug_assert!(self.sized_by_parent(app)),
960                OverflowBoxFit::DeferToChild => self.set_size(app, constraints.smallest()),
961            },
962        }
963    }
964
965    fn paint(
966        self: RenderHandle<Self>,
967        app: &mut App,
968        context: &mut PaintingContext,
969        offset: Offset,
970    ) {
971        RenderShiftedBox::paint(self, app, context, offset);
972    }
973
974    fn visit_children(
975        self: RenderHandle<Self>,
976        app: &App,
977        visitor: &mut dyn FnMut(AnyRenderObject),
978    ) {
979        if let Some(child) = self.child(app) {
980            visitor(child.as_object());
981        }
982    }
983}
984
985impl RenderBox for RenderConstrainedOverflowBox {
986    crate::render_box_accessors!();
987
988    fn hit_test_children(
989        self: RenderHandle<Self>,
990        app: &mut App,
991        result: &mut BoxHitTestResult<'_>,
992        position: Offset,
993    ) -> bool {
994        RenderShiftedBox::hit_test_children(self, app, result, position)
995    }
996
997    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
998        RenderShiftedBox::compute_min_intrinsic_width(self, app, height)
999    }
1000
1001    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1002        RenderShiftedBox::compute_max_intrinsic_width(self, app, height)
1003    }
1004
1005    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1006        RenderShiftedBox::compute_min_intrinsic_height(self, app, width)
1007    }
1008
1009    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1010        RenderShiftedBox::compute_max_intrinsic_height(self, app, width)
1011    }
1012
1013    fn compute_distance_to_actual_baseline(
1014        self: RenderHandle<Self>,
1015        app: &mut App,
1016        baseline: TextBaseline,
1017    ) -> Option<f64> {
1018        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1019    }
1020
1021    fn compute_dry_layout(
1022        self: RenderHandle<Self>,
1023        app: &mut App,
1024        constraints: BoxConstraints,
1025    ) -> Size {
1026        match self.fit(app) {
1027            OverflowBoxFit::Max => constraints.biggest(),
1028            OverflowBoxFit::DeferToChild => match self.child(app) {
1029                Some(child) => child.get_dry_layout(app, constraints),
1030                None => constraints.smallest(),
1031            },
1032        }
1033    }
1034
1035    fn compute_dry_baseline(
1036        self: RenderHandle<Self>,
1037        app: &mut App,
1038        constraints: BoxConstraints,
1039        baseline: TextBaseline,
1040    ) -> Option<f64> {
1041        let child = self.child(app)?;
1042        let child_constraints = self.get_inner_constraints(app, constraints);
1043        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
1044        let child_size = child.get_dry_layout(app, child_constraints);
1045        let size = self.get_dry_layout(app, constraints);
1046        Some(
1047            result
1048                + self
1049                    .resolved_alignment(app)
1050                    .along_offset(size - child_size)
1051                    .dy(),
1052        )
1053    }
1054}
1055
1056/// A [`RenderBox`] that applies an arbitrary transform to its constraints, and sizes its child
1057/// using the resulting [`BoxConstraints`], optionally clipping, or treating the overflow as an
1058/// error.
1059///
1060/// This [`RenderBox`] sizes its child using a [`BoxConstraints`] created by applying
1061/// [`constraints_transform`](Self::constraints_transform) to this [`RenderBox`]'s own constraints.
1062/// This box will then attempt to adopt the same size, within the limits of its own constraints. If
1063/// it ends up with a different size, it will align the child based on
1064/// [`RenderAligningShiftedBox::alignment`]. If the box cannot expand enough to accommodate the
1065/// entire child, the child will be clipped if
1066/// [`clip_behavior`](Self::clip_behavior) is not [`Clip::None`].
1067///
1068/// When the child is `None`, this [`RenderBox`] takes the smallest possible size and never
1069/// overflows.
1070pub struct RenderConstraintsTransformBox {
1071    render_object: RenderObjectData,
1072    render_box: RenderBoxData,
1073    child: RenderObjectWithChildData<AnyRenderBox>,
1074    aligning: RenderAligningShiftedBoxData,
1075    constraints_transform: BoxConstraintsTransform,
1076    clip_behavior: Clip,
1077    clip_rect_layer: LayerHandle<Handle<ClipRectLayer>>,
1078    overflow_container_rect: Rect,
1079    overflow_child_rect: Rect,
1080    is_overflowing: bool,
1081    child_constraints: Option<BoxConstraints>,
1082}
1083
1084impl RenderConstraintsTransformBox {
1085    /// Creates a [`RenderBox`] that sizes itself to the child and modifies the constraints before
1086    /// passing them down to that child.
1087    pub fn new(
1088        app: &mut App,
1089        alignment: AlignmentGeometry,
1090        text_direction: Option<TextDirection>,
1091        constraints_transform: BoxConstraintsTransform,
1092        child: Option<AnyRenderBox>,
1093    ) -> RenderHandle<Self> {
1094        let this = RenderHandle::new_box(
1095            app,
1096            RenderConstraintsTransformBox {
1097                render_object: RenderObjectData::new(),
1098                render_box: RenderBoxData::new(),
1099                child: RenderObjectWithChildData::new(),
1100                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
1101                constraints_transform,
1102                clip_behavior: Clip::None,
1103                clip_rect_layer: LayerHandle::new(),
1104                overflow_container_rect: Rect::ZERO,
1105                overflow_child_rect: Rect::ZERO,
1106                is_overflowing: false,
1107                child_constraints: None,
1108            },
1109        );
1110        this.set_child(app, child);
1111        this
1112    }
1113
1114    /// The transform this box applies to its own constraints before laying its child out.
1115    pub fn constraints_transform(self: RenderHandle<Self>, app: &App) -> BoxConstraintsTransform {
1116        self.get(app).constraints_transform
1117    }
1118
1119    /// Sets [`constraints_transform`](Self::constraints_transform).
1120    pub fn set_constraints_transform(
1121        self: RenderHandle<Self>,
1122        app: &mut App,
1123        value: BoxConstraintsTransform,
1124    ) {
1125        if std::ptr::fn_addr_eq(self.get(app).constraints_transform, value) {
1126            return;
1127        }
1128        self.get_mut(app).constraints_transform = value;
1129        // The render object only needs layout if the new transform maps the current constraints
1130        // to a different value, or the render object has never been laid out before.
1131        let needs_layout = match self.get(app).child_constraints {
1132            Some(child_constraints) => child_constraints != value(self.constraints(app)),
1133            None => true,
1134        };
1135        if needs_layout {
1136            self.mark_needs_layout(app);
1137        }
1138    }
1139
1140    /// How to clip a child that overflows this box. Defaults to [`Clip::None`].
1141    pub fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
1142        self.get(app).clip_behavior
1143    }
1144
1145    /// Sets [`clip_behavior`](Self::clip_behavior).
1146    pub fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
1147        if self.get(app).clip_behavior == value {
1148            return;
1149        }
1150        self.get_mut(app).clip_behavior = value;
1151        self.mark_needs_paint(app);
1152    }
1153}
1154
1155impl RenderObjectWithChildMixin for RenderConstraintsTransformBox {
1156    type ChildType = AnyRenderBox;
1157
1158    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1159        &self.get(app).child
1160    }
1161
1162    fn child_data_mut(
1163        self: RenderHandle<Self>,
1164        app: &mut App,
1165    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1166        &mut self.get_mut(app).child
1167    }
1168}
1169
1170impl RenderShiftedBox for RenderConstraintsTransformBox {}
1171
1172impl RenderAligningShiftedBox for RenderConstraintsTransformBox {
1173    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
1174        &self.get(app).aligning
1175    }
1176
1177    fn aligning_data_mut(
1178        self: RenderHandle<Self>,
1179        app: &mut App,
1180    ) -> &mut RenderAligningShiftedBoxData {
1181        &mut self.get_mut(app).aligning
1182    }
1183}
1184
1185impl RenderObject for RenderConstraintsTransformBox {
1186    crate::render_object_accessors!();
1187
1188    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1189        let constraints = self.constraints(app);
1190        match self.child(app) {
1191            Some(child) => {
1192                let child_constraints = (self.constraints_transform(app))(constraints);
1193                debug_assert!(
1194                    child_constraints.is_normalized(),
1195                    "{child_constraints} is not normalized"
1196                );
1197                self.get_mut(app).child_constraints = Some(child_constraints);
1198                child.layout(app, child_constraints, true);
1199                let size = constraints.constrain(child.size(app));
1200                self.set_size(app, size);
1201                self.align_child(app);
1202                let child_offset = child
1203                    .as_object()
1204                    .parent_data_of::<BoxParentData>(app)
1205                    .offset;
1206                let child_rect = child_offset & child.size(app);
1207                let this = self.get_mut(app);
1208                this.overflow_container_rect = Offset::ZERO & size;
1209                this.overflow_child_rect = child_rect;
1210            }
1211            None => {
1212                self.set_size(app, constraints.smallest());
1213                let this = self.get_mut(app);
1214                this.overflow_container_rect = Rect::ZERO;
1215                this.overflow_child_rect = Rect::ZERO;
1216            }
1217        }
1218        let this = self.get_mut(app);
1219        this.is_overflowing =
1220            RelativeRect::from_rect(this.overflow_container_rect, this.overflow_child_rect)
1221                .has_insets();
1222    }
1223
1224    fn paint(
1225        self: RenderHandle<Self>,
1226        app: &mut App,
1227        context: &mut PaintingContext,
1228        offset: Offset,
1229    ) {
1230        if self.child(app).is_none() {
1231            return;
1232        }
1233        if !self.get(app).is_overflowing {
1234            RenderShiftedBox::paint(self, app, context, offset);
1235            return;
1236        }
1237        // We have overflow and the clipBehavior isn't none. Clip it.
1238        let clip_rect = Offset::ZERO & self.size(app);
1239        let clip_behavior = self.clip_behavior(app);
1240        let old = self.get(app).clip_rect_layer.layer();
1241        let layer = context.push_clip_rect(
1242            app,
1243            self.as_object().needs_compositing(app),
1244            offset,
1245            clip_rect,
1246            |app, context, offset| RenderShiftedBox::paint(self, app, context, offset),
1247            clip_behavior,
1248            old,
1249        );
1250        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, layer);
1251    }
1252
1253    fn dispose(self: RenderHandle<Self>, app: &mut App) {
1254        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).clip_rect_layer, None);
1255        crate::object::RenderObjectBase::dispose(self, app);
1256    }
1257
1258    fn visit_children(
1259        self: RenderHandle<Self>,
1260        app: &App,
1261        visitor: &mut dyn FnMut(AnyRenderObject),
1262    ) {
1263        if let Some(child) = self.child(app) {
1264            visitor(child.as_object());
1265        }
1266    }
1267}
1268
1269impl RenderBox for RenderConstraintsTransformBox {
1270    crate::render_box_accessors!();
1271
1272    fn hit_test_children(
1273        self: RenderHandle<Self>,
1274        app: &mut App,
1275        result: &mut BoxHitTestResult<'_>,
1276        position: Offset,
1277    ) -> bool {
1278        RenderShiftedBox::hit_test_children(self, app, result, position)
1279    }
1280
1281    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1282        let transformed =
1283            (self.constraints_transform(app))(BoxConstraints::new().max_height(height));
1284        RenderShiftedBox::compute_min_intrinsic_width(self, app, transformed.max_height)
1285    }
1286
1287    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1288        let transformed =
1289            (self.constraints_transform(app))(BoxConstraints::new().max_height(height));
1290        RenderShiftedBox::compute_max_intrinsic_width(self, app, transformed.max_height)
1291    }
1292
1293    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1294        let transformed = (self.constraints_transform(app))(BoxConstraints::new().max_width(width));
1295        RenderShiftedBox::compute_min_intrinsic_height(self, app, transformed.max_width)
1296    }
1297
1298    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1299        let transformed = (self.constraints_transform(app))(BoxConstraints::new().max_width(width));
1300        RenderShiftedBox::compute_max_intrinsic_height(self, app, transformed.max_width)
1301    }
1302
1303    fn compute_distance_to_actual_baseline(
1304        self: RenderHandle<Self>,
1305        app: &mut App,
1306        baseline: TextBaseline,
1307    ) -> Option<f64> {
1308        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1309    }
1310
1311    fn compute_dry_layout(
1312        self: RenderHandle<Self>,
1313        app: &mut App,
1314        constraints: BoxConstraints,
1315    ) -> Size {
1316        match self.child(app) {
1317            Some(child) => {
1318                let child_constraints = (self.constraints_transform(app))(constraints);
1319                let child_size = child.get_dry_layout(app, child_constraints);
1320                constraints.constrain(child_size)
1321            }
1322            None => constraints.smallest(),
1323        }
1324    }
1325
1326    fn compute_dry_baseline(
1327        self: RenderHandle<Self>,
1328        app: &mut App,
1329        constraints: BoxConstraints,
1330        baseline: TextBaseline,
1331    ) -> Option<f64> {
1332        let child = self.child(app)?;
1333        let child_constraints = (self.constraints_transform(app))(constraints);
1334        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
1335        let child_size = child.get_dry_layout(app, child_constraints);
1336        let size = constraints.constrain(child_size);
1337        Some(
1338            result
1339                + self
1340                    .resolved_alignment(app)
1341                    .along_offset(size - child_size)
1342                    .dy(),
1343        )
1344    }
1345}
1346
1347/// A render object that is a specific size but passes its original constraints through to its
1348/// child, which it allows to overflow.
1349///
1350/// If the child's resulting size differs from this render object's size, then the child is aligned
1351/// according to [`RenderAligningShiftedBox::alignment`].
1352pub struct RenderSizedOverflowBox {
1353    render_object: RenderObjectData,
1354    render_box: RenderBoxData,
1355    child: RenderObjectWithChildData<AnyRenderBox>,
1356    aligning: RenderAligningShiftedBoxData,
1357    requested_size: Size,
1358}
1359
1360impl RenderSizedOverflowBox {
1361    /// Creates a render box of a given size that lets its child overflow.
1362    pub fn new(
1363        app: &mut App,
1364        requested_size: Size,
1365        alignment: AlignmentGeometry,
1366        text_direction: Option<TextDirection>,
1367        child: Option<AnyRenderBox>,
1368    ) -> RenderHandle<Self> {
1369        let this = RenderHandle::new_box(
1370            app,
1371            RenderSizedOverflowBox {
1372                render_object: RenderObjectData::new(),
1373                render_box: RenderBoxData::new(),
1374                child: RenderObjectWithChildData::new(),
1375                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
1376                requested_size,
1377            },
1378        );
1379        this.set_child(app, child);
1380        this
1381    }
1382
1383    /// The size this render box should attempt to be.
1384    pub fn requested_size(self: RenderHandle<Self>, app: &App) -> Size {
1385        self.get(app).requested_size
1386    }
1387
1388    /// Sets [`requested_size`](Self::requested_size).
1389    pub fn set_requested_size(self: RenderHandle<Self>, app: &mut App, value: Size) {
1390        if self.get(app).requested_size == value {
1391            return;
1392        }
1393        self.get_mut(app).requested_size = value;
1394        self.mark_needs_layout(app);
1395    }
1396}
1397
1398impl RenderObjectWithChildMixin for RenderSizedOverflowBox {
1399    type ChildType = AnyRenderBox;
1400
1401    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1402        &self.get(app).child
1403    }
1404
1405    fn child_data_mut(
1406        self: RenderHandle<Self>,
1407        app: &mut App,
1408    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1409        &mut self.get_mut(app).child
1410    }
1411}
1412
1413impl RenderShiftedBox for RenderSizedOverflowBox {}
1414
1415impl RenderAligningShiftedBox for RenderSizedOverflowBox {
1416    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
1417        &self.get(app).aligning
1418    }
1419
1420    fn aligning_data_mut(
1421        self: RenderHandle<Self>,
1422        app: &mut App,
1423    ) -> &mut RenderAligningShiftedBoxData {
1424        &mut self.get_mut(app).aligning
1425    }
1426}
1427
1428impl RenderObject for RenderSizedOverflowBox {
1429    crate::render_object_accessors!();
1430
1431    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1432        let constraints = self.constraints(app);
1433        let size = constraints.constrain(self.requested_size(app));
1434        self.set_size(app, size);
1435        if let Some(child) = self.child(app) {
1436            child.layout(app, constraints, true);
1437            self.align_child(app);
1438        }
1439    }
1440
1441    fn paint(
1442        self: RenderHandle<Self>,
1443        app: &mut App,
1444        context: &mut PaintingContext,
1445        offset: Offset,
1446    ) {
1447        RenderShiftedBox::paint(self, app, context, offset);
1448    }
1449
1450    fn visit_children(
1451        self: RenderHandle<Self>,
1452        app: &App,
1453        visitor: &mut dyn FnMut(AnyRenderObject),
1454    ) {
1455        if let Some(child) = self.child(app) {
1456            visitor(child.as_object());
1457        }
1458    }
1459}
1460
1461impl RenderBox for RenderSizedOverflowBox {
1462    crate::render_box_accessors!();
1463
1464    fn hit_test_children(
1465        self: RenderHandle<Self>,
1466        app: &mut App,
1467        result: &mut BoxHitTestResult<'_>,
1468        position: Offset,
1469    ) -> bool {
1470        RenderShiftedBox::hit_test_children(self, app, result, position)
1471    }
1472
1473    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, _height: f64) -> f64 {
1474        self.requested_size(app).width()
1475    }
1476
1477    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, _height: f64) -> f64 {
1478        self.requested_size(app).width()
1479    }
1480
1481    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, _width: f64) -> f64 {
1482        self.requested_size(app).height()
1483    }
1484
1485    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, _width: f64) -> f64 {
1486        self.requested_size(app).height()
1487    }
1488
1489    fn compute_distance_to_actual_baseline(
1490        self: RenderHandle<Self>,
1491        app: &mut App,
1492        baseline: TextBaseline,
1493    ) -> Option<f64> {
1494        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1495    }
1496
1497    fn compute_dry_layout(
1498        self: RenderHandle<Self>,
1499        app: &mut App,
1500        constraints: BoxConstraints,
1501    ) -> Size {
1502        constraints.constrain(self.requested_size(app))
1503    }
1504
1505    fn compute_dry_baseline(
1506        self: RenderHandle<Self>,
1507        app: &mut App,
1508        constraints: BoxConstraints,
1509        baseline: TextBaseline,
1510    ) -> Option<f64> {
1511        let child = self.child(app)?;
1512        let result = child.get_dry_baseline(app, constraints, baseline)?;
1513        let child_size = child.get_dry_layout(app, constraints);
1514        let size = self.get_dry_layout(app, constraints);
1515        Some(
1516            result
1517                + self
1518                    .resolved_alignment(app)
1519                    .along_offset(size - child_size)
1520                    .dy(),
1521        )
1522    }
1523}
1524
1525/// Sizes its child to a fraction of the total available space.
1526///
1527/// For both its width and height, this render object imposes a tight constraint on its child that
1528/// is a multiple (typically less than 1.0) of the maximum constraint it received from its parent
1529/// on that axis. If the factor for a given axis is `None`, then the constraints from the parent
1530/// are just passed through instead.
1531///
1532/// It then tries to size itself to the size of its child. Where this is not possible (e.g. if the
1533/// constraints from the parent are themselves tight), the child is aligned according to
1534/// [`RenderAligningShiftedBox::alignment`].
1535pub struct RenderFractionallySizedOverflowBox {
1536    render_object: RenderObjectData,
1537    render_box: RenderBoxData,
1538    child: RenderObjectWithChildData<AnyRenderBox>,
1539    aligning: RenderAligningShiftedBoxData,
1540    width_factor: Option<f64>,
1541    height_factor: Option<f64>,
1542}
1543
1544impl RenderFractionallySizedOverflowBox {
1545    /// Creates a render box that sizes its child to a fraction of the total available space.
1546    pub fn new(
1547        app: &mut App,
1548        alignment: AlignmentGeometry,
1549        text_direction: Option<TextDirection>,
1550        child: Option<AnyRenderBox>,
1551    ) -> RenderHandle<Self> {
1552        let this = RenderHandle::new_box(
1553            app,
1554            RenderFractionallySizedOverflowBox {
1555                render_object: RenderObjectData::new(),
1556                render_box: RenderBoxData::new(),
1557                child: RenderObjectWithChildData::new(),
1558                aligning: RenderAligningShiftedBoxData::new(alignment, text_direction),
1559                width_factor: None,
1560                height_factor: None,
1561            },
1562        );
1563        this.set_child(app, child);
1564        this
1565    }
1566
1567    /// If non-null, the factor of the incoming width to use.
1568    ///
1569    /// If non-null, the child is given a tight width constraint that is the max incoming width
1570    /// constraint multiplied by this factor. If null, the child is given the incoming width
1571    /// constraints.
1572    pub fn width_factor(self: RenderHandle<Self>, app: &App) -> Option<f64> {
1573        self.get(app).width_factor
1574    }
1575
1576    /// Sets [`width_factor`](Self::width_factor).
1577    pub fn set_width_factor(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
1578        debug_assert!(value.is_none_or(|factor| factor >= 0.0));
1579        if self.get(app).width_factor == value {
1580            return;
1581        }
1582        self.get_mut(app).width_factor = value;
1583        self.mark_needs_layout(app);
1584    }
1585
1586    /// If non-null, the factor of the incoming height to use.
1587    ///
1588    /// If non-null, the child is given a tight height constraint that is the max incoming height
1589    /// constraint multiplied by this factor. If null, the child is given the incoming height
1590    /// constraints.
1591    pub fn height_factor(self: RenderHandle<Self>, app: &App) -> Option<f64> {
1592        self.get(app).height_factor
1593    }
1594
1595    /// Sets [`height_factor`](Self::height_factor).
1596    pub fn set_height_factor(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
1597        debug_assert!(value.is_none_or(|factor| factor >= 0.0));
1598        if self.get(app).height_factor == value {
1599            return;
1600        }
1601        self.get_mut(app).height_factor = value;
1602        self.mark_needs_layout(app);
1603    }
1604
1605    fn get_inner_constraints(
1606        self: RenderHandle<Self>,
1607        app: &App,
1608        constraints: BoxConstraints,
1609    ) -> BoxConstraints {
1610        let (width_factor, height_factor) = {
1611            let this = self.get(app);
1612            (this.width_factor, this.height_factor)
1613        };
1614        let mut min_width = constraints.min_width;
1615        let mut max_width = constraints.max_width;
1616        if let Some(factor) = width_factor {
1617            let width = max_width * factor;
1618            min_width = width;
1619            max_width = width;
1620        }
1621        let mut min_height = constraints.min_height;
1622        let mut max_height = constraints.max_height;
1623        if let Some(factor) = height_factor {
1624            let height = max_height * factor;
1625            min_height = height;
1626            max_height = height;
1627        }
1628        BoxConstraints {
1629            min_width,
1630            max_width,
1631            min_height,
1632            max_height,
1633        }
1634    }
1635}
1636
1637impl RenderObjectWithChildMixin for RenderFractionallySizedOverflowBox {
1638    type ChildType = AnyRenderBox;
1639
1640    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1641        &self.get(app).child
1642    }
1643
1644    fn child_data_mut(
1645        self: RenderHandle<Self>,
1646        app: &mut App,
1647    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1648        &mut self.get_mut(app).child
1649    }
1650}
1651
1652impl RenderShiftedBox for RenderFractionallySizedOverflowBox {}
1653
1654impl RenderAligningShiftedBox for RenderFractionallySizedOverflowBox {
1655    fn aligning_data(self: RenderHandle<Self>, app: &App) -> &RenderAligningShiftedBoxData {
1656        &self.get(app).aligning
1657    }
1658
1659    fn aligning_data_mut(
1660        self: RenderHandle<Self>,
1661        app: &mut App,
1662    ) -> &mut RenderAligningShiftedBoxData {
1663        &mut self.get_mut(app).aligning
1664    }
1665}
1666
1667impl RenderObject for RenderFractionallySizedOverflowBox {
1668    crate::render_object_accessors!();
1669
1670    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1671        let constraints = self.constraints(app);
1672        let inner = self.get_inner_constraints(app, constraints);
1673        match self.child(app) {
1674            Some(child) => {
1675                child.layout(app, inner, true);
1676                let size = constraints.constrain(child.size(app));
1677                self.set_size(app, size);
1678                self.align_child(app);
1679            }
1680            None => {
1681                let size = constraints.constrain(inner.constrain(Size::ZERO));
1682                self.set_size(app, size);
1683            }
1684        }
1685    }
1686
1687    fn paint(
1688        self: RenderHandle<Self>,
1689        app: &mut App,
1690        context: &mut PaintingContext,
1691        offset: Offset,
1692    ) {
1693        RenderShiftedBox::paint(self, app, context, offset);
1694    }
1695
1696    fn visit_children(
1697        self: RenderHandle<Self>,
1698        app: &App,
1699        visitor: &mut dyn FnMut(AnyRenderObject),
1700    ) {
1701        if let Some(child) = self.child(app) {
1702            visitor(child.as_object());
1703        }
1704    }
1705}
1706
1707impl RenderBox for RenderFractionallySizedOverflowBox {
1708    crate::render_box_accessors!();
1709
1710    fn hit_test_children(
1711        self: RenderHandle<Self>,
1712        app: &mut App,
1713        result: &mut BoxHitTestResult<'_>,
1714        position: Offset,
1715    ) -> bool {
1716        RenderShiftedBox::hit_test_children(self, app, result, position)
1717    }
1718
1719    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1720        let (width_factor, height_factor) = {
1721            let this = self.get(app);
1722            (this.width_factor, this.height_factor)
1723        };
1724        let result = match self.child(app) {
1725            // Relies on f64::INFINITY absorption.
1726            Some(child) => {
1727                child.get_min_intrinsic_width(app, height * height_factor.unwrap_or(1.0))
1728            }
1729            None => RenderShiftedBox::compute_min_intrinsic_width(self, app, height),
1730        };
1731        debug_assert!(result.is_finite());
1732        result / width_factor.unwrap_or(1.0)
1733    }
1734
1735    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1736        let (width_factor, height_factor) = {
1737            let this = self.get(app);
1738            (this.width_factor, this.height_factor)
1739        };
1740        let result = match self.child(app) {
1741            Some(child) => {
1742                child.get_max_intrinsic_width(app, height * height_factor.unwrap_or(1.0))
1743            }
1744            None => RenderShiftedBox::compute_max_intrinsic_width(self, app, height),
1745        };
1746        debug_assert!(result.is_finite());
1747        result / width_factor.unwrap_or(1.0)
1748    }
1749
1750    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1751        let (width_factor, height_factor) = {
1752            let this = self.get(app);
1753            (this.width_factor, this.height_factor)
1754        };
1755        let result = match self.child(app) {
1756            Some(child) => child.get_min_intrinsic_height(app, width * width_factor.unwrap_or(1.0)),
1757            None => RenderShiftedBox::compute_min_intrinsic_height(self, app, width),
1758        };
1759        debug_assert!(result.is_finite());
1760        result / height_factor.unwrap_or(1.0)
1761    }
1762
1763    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1764        let (width_factor, height_factor) = {
1765            let this = self.get(app);
1766            (this.width_factor, this.height_factor)
1767        };
1768        let result = match self.child(app) {
1769            Some(child) => child.get_max_intrinsic_height(app, width * width_factor.unwrap_or(1.0)),
1770            None => RenderShiftedBox::compute_max_intrinsic_height(self, app, width),
1771        };
1772        debug_assert!(result.is_finite());
1773        result / height_factor.unwrap_or(1.0)
1774    }
1775
1776    fn compute_distance_to_actual_baseline(
1777        self: RenderHandle<Self>,
1778        app: &mut App,
1779        baseline: TextBaseline,
1780    ) -> Option<f64> {
1781        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
1782    }
1783
1784    fn compute_dry_layout(
1785        self: RenderHandle<Self>,
1786        app: &mut App,
1787        constraints: BoxConstraints,
1788    ) -> Size {
1789        let inner = self.get_inner_constraints(app, constraints);
1790        match self.child(app) {
1791            Some(child) => {
1792                let child_size = child.get_dry_layout(app, inner);
1793                constraints.constrain(child_size)
1794            }
1795            None => constraints.constrain(inner.constrain(Size::ZERO)),
1796        }
1797    }
1798
1799    fn compute_dry_baseline(
1800        self: RenderHandle<Self>,
1801        app: &mut App,
1802        constraints: BoxConstraints,
1803        baseline: TextBaseline,
1804    ) -> Option<f64> {
1805        let child = self.child(app)?;
1806        let child_constraints = self.get_inner_constraints(app, constraints);
1807        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
1808        let child_size = child.get_dry_layout(app, child_constraints);
1809        let size = self.get_dry_layout(app, constraints);
1810        Some(
1811            result
1812                + self
1813                    .resolved_alignment(app)
1814                    .along_offset(size - child_size)
1815                    .dy(),
1816        )
1817    }
1818}
1819
1820/// Shifts the child down such that the child's baseline (or the bottom of the child, if the child
1821/// has no baseline) is [`baseline`](Self::baseline) logical pixels below the top of this box, then
1822/// sizes this box to contain the child.
1823///
1824/// If [`baseline`](Self::baseline) is less than the distance from the top of the child to the
1825/// baseline of the child, then the child will overflow the top of the box. This is typically not
1826/// desirable, in particular, that part of the child will not be found when doing hit tests, so
1827/// the user cannot interact with that part of the child.
1828///
1829/// This box will be sized so that its bottom is coincident with the bottom of the child. This
1830/// means if this box shifts the child down, there will be space between the top of this box and
1831/// the top of the child, but there is never space between the bottom of the child and the bottom
1832/// of the box.
1833pub struct RenderBaseline {
1834    render_object: RenderObjectData,
1835    render_box: RenderBoxData,
1836    child: RenderObjectWithChildData<AnyRenderBox>,
1837    baseline: f64,
1838    baseline_type: TextBaseline,
1839}
1840
1841/// What [`RenderBaseline::compute_sizes`] worked out: Dart's `({Size size, double top})`.
1842struct BaselineSizes {
1843    size: Size,
1844    top: f64,
1845}
1846
1847impl RenderBaseline {
1848    /// Creates a [`RenderBaseline`] object.
1849    pub fn new(
1850        app: &mut App,
1851        baseline: f64,
1852        baseline_type: TextBaseline,
1853        child: Option<AnyRenderBox>,
1854    ) -> RenderHandle<Self> {
1855        let this = RenderHandle::new_box(
1856            app,
1857            RenderBaseline {
1858                render_object: RenderObjectData::new(),
1859                render_box: RenderBoxData::new(),
1860                child: RenderObjectWithChildData::new(),
1861                baseline,
1862                baseline_type,
1863            },
1864        );
1865        this.set_child(app, child);
1866        this
1867    }
1868
1869    /// The number of logical pixels from the top of this box at which to position the child's
1870    /// baseline.
1871    pub fn baseline(self: RenderHandle<Self>, app: &App) -> f64 {
1872        self.get(app).baseline
1873    }
1874
1875    /// Sets [`baseline`](Self::baseline).
1876    pub fn set_baseline(self: RenderHandle<Self>, app: &mut App, value: f64) {
1877        if self.get(app).baseline == value {
1878            return;
1879        }
1880        self.get_mut(app).baseline = value;
1881        self.mark_needs_layout(app);
1882    }
1883
1884    /// The type of baseline to use for positioning the child.
1885    pub fn baseline_type(self: RenderHandle<Self>, app: &App) -> TextBaseline {
1886        self.get(app).baseline_type
1887    }
1888
1889    /// Sets [`baseline_type`](Self::baseline_type).
1890    pub fn set_baseline_type(self: RenderHandle<Self>, app: &mut App, value: TextBaseline) {
1891        if self.get(app).baseline_type == value {
1892            return;
1893        }
1894        self.get_mut(app).baseline_type = value;
1895        self.mark_needs_layout(app);
1896    }
1897
1898    /// Flutter's `_computeSizes`: this box's size and the offset the child is shifted down by.
1899    fn compute_sizes(
1900        self: RenderHandle<Self>,
1901        app: &mut App,
1902        constraints: BoxConstraints,
1903        layout_child: ChildLayouter,
1904        get_baseline: ChildBaselineGetter,
1905    ) -> BaselineSizes {
1906        let Some(child) = self.child(app) else {
1907            return BaselineSizes {
1908                size: constraints.smallest(),
1909                top: 0.0,
1910            };
1911        };
1912        let child_constraints = constraints.loosen();
1913        let child_size = layout_child(app, child, child_constraints);
1914        let baseline_type = self.baseline_type(app);
1915        let child_baseline = get_baseline(app, child, child_constraints, baseline_type)
1916            .unwrap_or(child_size.height());
1917        let top = self.baseline(app) - child_baseline;
1918        BaselineSizes {
1919            size: constraints.constrain(Size::new(child_size.width(), top + child_size.height())),
1920            top,
1921        }
1922    }
1923}
1924
1925impl RenderObjectWithChildMixin for RenderBaseline {
1926    type ChildType = AnyRenderBox;
1927
1928    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1929        &self.get(app).child
1930    }
1931
1932    fn child_data_mut(
1933        self: RenderHandle<Self>,
1934        app: &mut App,
1935    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1936        &mut self.get_mut(app).child
1937    }
1938}
1939
1940impl RenderShiftedBox for RenderBaseline {}
1941
1942impl RenderObject for RenderBaseline {
1943    crate::render_object_accessors!();
1944
1945    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1946        let constraints = self.constraints(app);
1947        let sizes = self.compute_sizes(
1948            app,
1949            constraints,
1950            ChildLayoutHelper::layout_child,
1951            ChildLayoutHelper::get_baseline,
1952        );
1953        self.set_size(app, sizes.size);
1954        if let Some(child) = self.child(app) {
1955            child.parent_data_of_mut::<BoxParentData>(app).offset = Offset::new(0.0, sizes.top);
1956        }
1957    }
1958
1959    fn paint(
1960        self: RenderHandle<Self>,
1961        app: &mut App,
1962        context: &mut PaintingContext,
1963        offset: Offset,
1964    ) {
1965        RenderShiftedBox::paint(self, app, context, offset);
1966    }
1967
1968    fn visit_children(
1969        self: RenderHandle<Self>,
1970        app: &App,
1971        visitor: &mut dyn FnMut(AnyRenderObject),
1972    ) {
1973        if let Some(child) = self.child(app) {
1974            visitor(child.as_object());
1975        }
1976    }
1977}
1978
1979impl RenderBox for RenderBaseline {
1980    crate::render_box_accessors!();
1981
1982    fn hit_test_children(
1983        self: RenderHandle<Self>,
1984        app: &mut App,
1985        result: &mut BoxHitTestResult<'_>,
1986        position: Offset,
1987    ) -> bool {
1988        RenderShiftedBox::hit_test_children(self, app, result, position)
1989    }
1990
1991    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1992        RenderShiftedBox::compute_min_intrinsic_width(self, app, height)
1993    }
1994
1995    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1996        RenderShiftedBox::compute_max_intrinsic_width(self, app, height)
1997    }
1998
1999    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2000        RenderShiftedBox::compute_min_intrinsic_height(self, app, width)
2001    }
2002
2003    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2004        RenderShiftedBox::compute_max_intrinsic_height(self, app, width)
2005    }
2006
2007    fn compute_distance_to_actual_baseline(
2008        self: RenderHandle<Self>,
2009        app: &mut App,
2010        baseline: TextBaseline,
2011    ) -> Option<f64> {
2012        RenderShiftedBox::compute_distance_to_actual_baseline(self, app, baseline)
2013    }
2014
2015    fn compute_dry_layout(
2016        self: RenderHandle<Self>,
2017        app: &mut App,
2018        constraints: BoxConstraints,
2019    ) -> Size {
2020        self.compute_sizes(
2021            app,
2022            constraints,
2023            ChildLayoutHelper::dry_layout_child,
2024            ChildLayoutHelper::get_dry_baseline,
2025        )
2026        .size
2027    }
2028
2029    fn compute_dry_baseline(
2030        self: RenderHandle<Self>,
2031        app: &mut App,
2032        constraints: BoxConstraints,
2033        baseline: TextBaseline,
2034    ) -> Option<f64> {
2035        let child = self.child(app)?;
2036        let child_constraints = constraints.loosen();
2037        let baseline_type = self.baseline_type(app);
2038        let result1 = child.get_dry_baseline(app, child_constraints, baseline)?;
2039        let result2 = child.get_dry_baseline(app, child_constraints, baseline_type)?;
2040        Some(self.baseline(app) + result1 - result2)
2041    }
2042}
2043
2044/// A delegate for computing the layout of a render object with a single child.
2045///
2046/// Used by [`RenderCustomSingleChildLayoutBox`] and `CustomSingleChildLayout` (in the widgets
2047/// library).
2048///
2049/// When asked to layout, [`RenderCustomSingleChildLayoutBox`] first calls
2050/// [`get_size`](Self::get_size) with its incoming constraints to determine its size. It then
2051/// uses [`get_constraints_for_child`](Self::get_constraints_for_child) to determine the
2052/// constraints to apply to the child. After the child completes its layout,
2053/// [`RenderCustomSingleChildLayoutBox`] calls [`get_position_for_child`](Self::get_position_for_child)
2054/// to determine the child's position.
2055///
2056/// The [`relayout`](Self::relayout) listenable causes the layout to update whenever it
2057/// notifies its listeners.
2058pub trait SingleChildLayoutDelegate: Debug + 'static {
2059    /// The [`Listenable`] the layout will update on, Dart's `relayout` constructor argument.
2060    ///
2061    /// Defaults to `None`.
2062    fn relayout(&self) -> Option<&Rc<dyn Listenable>> {
2063        None
2064    }
2065
2066    /// The size of this object given the incoming constraints.
2067    ///
2068    /// Defaults to the biggest size that satisfies the given constraints.
2069    fn get_size(&self, constraints: BoxConstraints) -> Size {
2070        constraints.biggest()
2071    }
2072
2073    /// The constraints for the child given the incoming constraints.
2074    ///
2075    /// During layout, the child is given the layout constraints returned by this function. The
2076    /// child is required to pick a size for itself that satisfies these constraints.
2077    ///
2078    /// Defaults to the given constraints.
2079    fn get_constraints_for_child(&self, constraints: BoxConstraints) -> BoxConstraints {
2080        constraints
2081    }
2082
2083    /// The position where the child should be placed.
2084    ///
2085    /// The `size` argument is the size of the parent, which might be different from the value
2086    /// returned by [`get_size`](Self::get_size) if that size doesn't satisfy the constraints
2087    /// passed to [`get_size`](Self::get_size). The `child_size` argument is the size of the
2088    /// child, which will satisfy the constraints returned by
2089    /// [`get_constraints_for_child`](Self::get_constraints_for_child).
2090    ///
2091    /// Defaults to positioning the child in the upper left corner of the parent.
2092    fn get_position_for_child(&self, size: Size, child_size: Size) -> Offset {
2093        let _ = (size, child_size);
2094        Offset::ZERO
2095    }
2096
2097    /// Called whenever a new instance of the custom layout delegate class is provided to the
2098    /// [`RenderCustomSingleChildLayoutBox`] object, or any time that a new `CustomSingleChildLayout`
2099    /// object is created with a new instance of the custom layout delegate class (which amounts
2100    /// to the same thing, because the latter is implemented in terms of the former).
2101    ///
2102    /// If the new instance represents different information than the old instance, then the
2103    /// method should return true, otherwise it should return false.
2104    ///
2105    /// If the method returns false, then the [`get_size`](Self::get_size),
2106    /// [`get_constraints_for_child`](Self::get_constraints_for_child), and
2107    /// [`get_position_for_child`](Self::get_position_for_child) calls might be optimized away.
2108    ///
2109    /// It's possible that the layout methods will get called even if [`should_relayout`](Self::should_relayout)
2110    /// returns false (e.g. if an ancestor changed its layout). It's also possible that the
2111    /// layout method will get called without [`should_relayout`](Self::should_relayout) being
2112    /// called at all (e.g. if the parent changes size).
2113    ///
2114    /// `old_delegate` is of the same concrete type, Dart's `covariant`: narrow it with
2115    /// [`as_any`](Self::as_any).
2116    fn should_relayout(&self, old_delegate: &dyn SingleChildLayoutDelegate) -> bool;
2117
2118    /// The concrete delegate, for Dart's `runtimeType` comparison and its `covariant`
2119    /// narrowing of [`should_relayout`](Self::should_relayout)'s argument.
2120    fn as_any(&self) -> &dyn Any;
2121}
2122
2123/// Defers the layout of its single child to a delegate.
2124///
2125/// The delegate can determine the layout constraints for the child and can decide where to
2126/// position the child. The delegate can also determine the size of the parent, but the size of
2127/// the parent cannot depend on the size of the child.
2128pub struct RenderCustomSingleChildLayoutBox {
2129    render_object: RenderObjectData,
2130    render_box: RenderBoxData,
2131    child: RenderObjectWithChildData<AnyRenderBox>,
2132    delegate: Rc<dyn SingleChildLayoutDelegate>,
2133}
2134
2135impl RenderCustomSingleChildLayoutBox {
2136    /// Creates a render box that defers its layout to a delegate.
2137    pub fn new(
2138        app: &mut App,
2139        delegate: Rc<dyn SingleChildLayoutDelegate>,
2140        child: Option<AnyRenderBox>,
2141    ) -> RenderHandle<RenderCustomSingleChildLayoutBox> {
2142        let this = RenderHandle::new_box(
2143            app,
2144            RenderCustomSingleChildLayoutBox {
2145                render_object: RenderObjectData::new(),
2146                render_box: RenderBoxData::new(),
2147                child: RenderObjectWithChildData::new(),
2148                delegate,
2149            },
2150        );
2151        this.set_child(app, child);
2152        this
2153    }
2154
2155    /// A delegate that controls this object's layout.
2156    pub fn delegate(self: RenderHandle<Self>, app: &App) -> Rc<dyn SingleChildLayoutDelegate> {
2157        Rc::clone(&self.get(app).delegate)
2158    }
2159
2160    /// Sets [`delegate`](Self::delegate).
2161    pub fn set_delegate(
2162        self: RenderHandle<Self>,
2163        app: &mut App,
2164        new_delegate: Rc<dyn SingleChildLayoutDelegate>,
2165    ) {
2166        let old_delegate = Rc::clone(&self.get(app).delegate);
2167        if Rc::ptr_eq(&old_delegate, &new_delegate) {
2168            return;
2169        }
2170        if new_delegate.as_any().type_id() != old_delegate.as_any().type_id()
2171            || new_delegate.should_relayout(&*old_delegate)
2172        {
2173            self.mark_needs_layout(app);
2174        }
2175        self.get_mut(app).delegate = Rc::clone(&new_delegate);
2176        if self.attached(app) {
2177            if let Some(relayout) = old_delegate.relayout() {
2178                relayout.remove_listener(app, &self.relayout_listener());
2179            }
2180            if let Some(relayout) = new_delegate.relayout() {
2181                relayout.add_listener(app, self.relayout_listener());
2182            }
2183        }
2184    }
2185
2186    /// The `markNeedsLayout` tear-off, equal to itself across registrations.
2187    fn relayout_listener(self: RenderHandle<Self>) -> Listener {
2188        Listener::handle_method(self.handle(), mark_needs_layout_custom_single_child)
2189    }
2190
2191    /// Dart's `_getSize`.
2192    fn get_size(self: RenderHandle<Self>, app: &App, constraints: BoxConstraints) -> Size {
2193        constraints.constrain(self.get(app).delegate.get_size(constraints))
2194    }
2195}
2196
2197fn mark_needs_layout_custom_single_child(
2198    this: Handle<RenderCustomSingleChildLayoutBox>,
2199    app: &mut App,
2200) {
2201    RenderHandle::from_handle(this).mark_needs_layout(app);
2202}
2203
2204impl RenderObjectWithChildMixin for RenderCustomSingleChildLayoutBox {
2205    type ChildType = AnyRenderBox;
2206
2207    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2208        &self.get(app).child
2209    }
2210
2211    fn child_data_mut(
2212        self: RenderHandle<Self>,
2213        app: &mut App,
2214    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2215        &mut self.get_mut(app).child
2216    }
2217}
2218
2219impl RenderShiftedBox for RenderCustomSingleChildLayoutBox {}
2220
2221impl RenderObject for RenderCustomSingleChildLayoutBox {
2222    crate::render_object_accessors!();
2223
2224    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2225        let constraints = self.constraints(app);
2226        let size = self.get_size(app, constraints);
2227        self.set_size(app, size);
2228        if let Some(child) = self.child(app) {
2229            let child_constraints = self
2230                .get(app)
2231                .delegate
2232                .get_constraints_for_child(constraints);
2233            debug_assert!(child_constraints.debug_assert_is_valid(true));
2234            child.layout(app, child_constraints, !child_constraints.is_tight());
2235            let child_size = if child_constraints.is_tight() {
2236                child_constraints.smallest()
2237            } else {
2238                child.size(app)
2239            };
2240            child.parent_data_of_mut::<BoxParentData>(app).offset = self
2241                .get(app)
2242                .delegate
2243                .get_position_for_child(size, child_size);
2244        }
2245    }
2246
2247    fn paint(
2248        self: RenderHandle<Self>,
2249        app: &mut App,
2250        context: &mut PaintingContext,
2251        offset: Offset,
2252    ) {
2253        RenderShiftedBox::paint(self, app, context, offset);
2254    }
2255
2256    fn visit_children(
2257        self: RenderHandle<Self>,
2258        app: &App,
2259        visitor: &mut dyn FnMut(AnyRenderObject),
2260    ) {
2261        if let Some(child) = self.child(app) {
2262            visitor(child.as_object());
2263        }
2264    }
2265
2266    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
2267        if let Some(child) = self.child(app) {
2268            child.as_object().attach(app, owner);
2269        }
2270        if let Some(relayout) = self.delegate(app).relayout() {
2271            relayout.add_listener(app, self.relayout_listener());
2272        }
2273    }
2274
2275    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
2276        if let Some(relayout) = self.delegate(app).relayout() {
2277            relayout.remove_listener(app, &self.relayout_listener());
2278        }
2279        if let Some(child) = self.child(app) {
2280            child.as_object().detach(app);
2281        }
2282    }
2283}
2284
2285impl RenderBox for RenderCustomSingleChildLayoutBox {
2286    crate::render_box_accessors!();
2287
2288    fn hit_test_children(
2289        self: RenderHandle<Self>,
2290        app: &mut App,
2291        result: &mut BoxHitTestResult<'_>,
2292        position: Offset,
2293    ) -> bool {
2294        RenderShiftedBox::hit_test_children(self, app, result, position)
2295    }
2296
2297    // TODO(ianh): It's a bit dubious to be using the getSize function from the delegate to
2298    // figure out the intrinsic dimensions. We really should either not support intrinsics,
2299    // or we should expose intrinsic delegate callbacks and throw if they're not implemented.
2300
2301    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2302        let width = self
2303            .get_size(app, BoxConstraints::tight_for_finite(f64::INFINITY, height))
2304            .width();
2305        if width.is_finite() { width } else { 0.0 }
2306    }
2307
2308    fn compute_max_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_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2316        let height = self
2317            .get_size(app, BoxConstraints::tight_for_finite(width, f64::INFINITY))
2318            .height();
2319        if height.is_finite() { height } else { 0.0 }
2320    }
2321
2322    fn compute_max_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_dry_layout(
2330        self: RenderHandle<Self>,
2331        app: &mut App,
2332        constraints: BoxConstraints,
2333    ) -> Size {
2334        self.get_size(app, constraints)
2335    }
2336
2337    fn compute_dry_baseline(
2338        self: RenderHandle<Self>,
2339        app: &mut App,
2340        constraints: BoxConstraints,
2341        baseline: TextBaseline,
2342    ) -> Option<f64> {
2343        let child = self.child(app)?;
2344        let child_constraints = self
2345            .get(app)
2346            .delegate
2347            .get_constraints_for_child(constraints);
2348        let result = child.get_dry_baseline(app, child_constraints, baseline)?;
2349        let child_size = if child_constraints.is_tight() {
2350            child_constraints.smallest()
2351        } else {
2352            child.get_dry_layout(app, child_constraints)
2353        };
2354        Some(
2355            result
2356                + self
2357                    .get(app)
2358                    .delegate
2359                    .get_position_for_child(self.get_size(app, constraints), child_size)
2360                    .dy(),
2361        )
2362    }
2363}
2364
2365#[cfg(test)]
2366mod tests {
2367    use super::*;
2368    use inset_embedder::Size;
2369    use inset_foundation::AppCell;
2370
2371    use crate::box_::BoxConstraints;
2372    use crate::layer::{ContainerLayer, ErasedLayer, OffsetLayer, PictureLayer};
2373    use crate::pipeline_owner::PipelineOwner;
2374    use crate::proxy_box::{RenderConstrainedBox, RenderRepaintBoundary};
2375    use inset_embedder::valo::Op;
2376
2377    /// `padding_test.dart`: the padding is added to the child's intrinsics, and taken off the
2378    /// extent handed to the child.
2379    #[test]
2380    fn padding_intrinsics_add_the_insets() {
2381        let cell = AppCell::new();
2382        let mut app = cell.borrow_mut();
2383        let child =
2384            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
2385        let padding = RenderPadding::new(
2386            &mut app,
2387            EdgeInsetsGeometry::all(8.0),
2388            None,
2389            Some(child.as_box()),
2390        );
2391        let padded = padding.as_box();
2392        assert_eq!(padded.get_min_intrinsic_width(&mut app, 100.0), 96.0);
2393        assert_eq!(padded.get_max_intrinsic_width(&mut app, 100.0), 96.0);
2394        assert_eq!(padded.get_min_intrinsic_height(&mut app, 100.0), 56.0);
2395        assert_eq!(padded.get_max_intrinsic_height(&mut app, 100.0), 56.0);
2396    }
2397
2398    /// Without a child, the padding is all there is.
2399    #[test]
2400    fn padding_intrinsics_without_a_child_are_the_insets() {
2401        let cell = AppCell::new();
2402        let mut app = cell.borrow_mut();
2403        let padding = RenderPadding::new(&mut app, EdgeInsetsGeometry::all(10.0), None, None);
2404        assert_eq!(
2405            padding.as_box().get_min_intrinsic_width(&mut app, 0.0),
2406            20.0
2407        );
2408        assert_eq!(
2409            padding.as_box().get_max_intrinsic_height(&mut app, 0.0),
2410            20.0
2411        );
2412    }
2413
2414    /// The dry layout of a padding is the size it lays out to.
2415    #[test]
2416    fn padding_dry_layout_matches_its_layout() {
2417        let cell = AppCell::new();
2418        let mut app = cell.borrow_mut();
2419        let child =
2420            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
2421        let padding = RenderPadding::new(
2422            &mut app,
2423            EdgeInsetsGeometry::all(8.0),
2424            None,
2425            Some(child.as_box()),
2426        );
2427        let constraints = BoxConstraints::new().max_width(500.0).max_height(500.0);
2428        let dry = padding.as_box().get_dry_layout(&mut app, constraints);
2429        padding.layout(&mut app, constraints, false);
2430        assert_eq!(dry, padding.size(&app));
2431    }
2432
2433    /// `unconstrained_box_test.dart`: an `UnconstrainedBox` is a
2434    /// `RenderConstraintsTransformBox` whose transform drops every constraint, so the child takes
2435    /// its natural size and is aligned within what the parent allows.
2436    #[test]
2437    fn constraints_transform_box_leaves_the_child_unconstrained_and_aligns_it() {
2438        let cell = AppCell::new();
2439        let mut app = cell.borrow_mut();
2440        let child =
2441            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(50.0, 20.0)), None);
2442        let unconstrained = RenderConstraintsTransformBox::new(
2443            &mut app,
2444            AlignmentGeometry::CENTER,
2445            None,
2446            |_| BoxConstraints::new(),
2447            Some(child.as_box()),
2448        );
2449        unconstrained.layout(
2450            &mut app,
2451            BoxConstraints::tight(Size::new(100.0, 100.0)),
2452            false,
2453        );
2454        assert_eq!(child.size(&app), Size::new(50.0, 20.0));
2455        assert_eq!(unconstrained.size(&app), Size::new(100.0, 100.0));
2456        assert_eq!(
2457            child.as_box().box_parent_data(&app).offset,
2458            Offset::new(25.0, 40.0)
2459        );
2460    }
2461
2462    /// A child that does not fit is clipped when the clip behavior asks for it.
2463    #[test]
2464    fn constraints_transform_box_clips_an_overflowing_child() {
2465        let cell = AppCell::new();
2466        let mut app = cell.borrow_mut();
2467        let child = RenderConstrainedBox::new(
2468            &mut app,
2469            BoxConstraints::tight(Size::new(200.0, 200.0)),
2470            None,
2471        );
2472        let unconstrained = RenderConstraintsTransformBox::new(
2473            &mut app,
2474            AlignmentGeometry::CENTER,
2475            None,
2476            |_| BoxConstraints::new(),
2477            Some(child.as_box()),
2478        );
2479        unconstrained.set_clip_behavior(&mut app, Clip::HardEdge);
2480        let root = RenderRepaintBoundary::new(&mut app, Some(unconstrained.as_box()));
2481        let owner = PipelineOwner::new(&mut app, None, None);
2482        owner.set_root_node(&mut app, Some(root.as_object()));
2483        root.layout(
2484            &mut app,
2485            BoxConstraints::tight(Size::new(100.0, 100.0)),
2486            false,
2487        );
2488        let paint_root = OffsetLayer::new(&mut app, Offset::ZERO);
2489        paint_root
2490            .as_layer()
2491            .attach(&mut app, root.as_object().id());
2492        root.as_object()
2493            .schedule_initial_paint(&mut app, paint_root.as_container_layer());
2494        owner.flush_compositing_bits(&mut app);
2495        owner.flush_paint(&mut app);
2496
2497        assert_eq!(unconstrained.size(&app), Size::new(100.0, 100.0));
2498        let layer = root.as_object().debug_layer(&app).expect("painted");
2499        let clipped = layer
2500            .depth_first_iterate_children(&app)
2501            .into_iter()
2502            .filter_map(|child| {
2503                app.handle::<PictureLayer>(child.id())
2504                    .and_then(|picture| picture.picture(&app).map(|p| p.ops().to_vec()))
2505            })
2506            .flatten()
2507            .any(|op| matches!(op, Op::ClipPath { .. }));
2508        assert!(clipped, "the overflowing child is clipped");
2509    }
2510
2511    /// A `RenderConstrainedOverflowBox` lets its child overflow and keeps the parent's size.
2512    #[test]
2513    fn constrained_overflow_box_sizes_itself_to_the_parent() {
2514        let cell = AppCell::new();
2515        let mut app = cell.borrow_mut();
2516        let child = RenderConstrainedBox::new(&mut app, BoxConstraints::new(), None);
2517        let overflow = RenderConstrainedOverflowBox::new(
2518            &mut app,
2519            AlignmentGeometry::CENTER,
2520            None,
2521            Some(child.as_box()),
2522        );
2523        overflow.set_min_width(&mut app, Some(200.0));
2524        overflow.set_max_width(&mut app, Some(200.0));
2525        overflow.layout(
2526            &mut app,
2527            BoxConstraints::tight(Size::new(100.0, 100.0)),
2528            false,
2529        );
2530        assert_eq!(overflow.size(&app), Size::new(100.0, 100.0));
2531        assert_eq!(child.size(&app).width(), 200.0);
2532        assert_eq!(
2533            child.as_box().box_parent_data(&app).offset.dx(),
2534            -50.0,
2535            "the child is centered, so it overflows both sides"
2536        );
2537    }
2538
2539    /// A `RenderSizedOverflowBox` takes its requested size and passes the original constraints
2540    /// through, and reports the requested size as its intrinsics.
2541    #[test]
2542    fn sized_overflow_box_takes_its_requested_size() {
2543        let cell = AppCell::new();
2544        let mut app = cell.borrow_mut();
2545        let child =
2546            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(30.0, 30.0)), None);
2547        let sized = RenderSizedOverflowBox::new(
2548            &mut app,
2549            Size::new(50.0, 50.0),
2550            AlignmentGeometry::CENTER,
2551            None,
2552            Some(child.as_box()),
2553        );
2554        sized.layout(&mut app, BoxConstraints::new().max_width(100.0), false);
2555        assert_eq!(sized.size(&app), Size::new(50.0, 50.0));
2556        assert_eq!(sized.as_box().get_min_intrinsic_width(&mut app, 0.0), 50.0);
2557        assert_eq!(sized.as_box().get_max_intrinsic_height(&mut app, 0.0), 50.0);
2558    }
2559
2560    /// A `RenderFractionallySizedOverflowBox` tightens the child to a fraction of the incoming
2561    /// maximum, and divides its intrinsics by the factor.
2562    #[test]
2563    fn fractionally_sized_box_tightens_the_child_to_a_fraction() {
2564        let cell = AppCell::new();
2565        let mut app = cell.borrow_mut();
2566        let child = RenderConstrainedBox::new(&mut app, BoxConstraints::new(), None);
2567        let fraction = RenderFractionallySizedOverflowBox::new(
2568            &mut app,
2569            AlignmentGeometry::CENTER,
2570            None,
2571            Some(child.as_box()),
2572        );
2573        fraction.set_width_factor(&mut app, Some(0.5));
2574        fraction.layout(
2575            &mut app,
2576            BoxConstraints::new().max_width(200.0).max_height(80.0),
2577            false,
2578        );
2579        assert_eq!(child.size(&app).width(), 100.0);
2580        assert_eq!(fraction.size(&app).width(), 100.0);
2581    }
2582
2583    /// `baseline_test.dart`: the child is shifted down so that its baseline sits at the given
2584    /// distance from the top.
2585    #[test]
2586    fn baseline_shifts_the_child_down_to_its_baseline() {
2587        let cell = AppCell::new();
2588        let mut app = cell.borrow_mut();
2589        let child =
2590            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)), None);
2591        let baseline = RenderBaseline::new(
2592            &mut app,
2593            30.0,
2594            TextBaseline::Alphabetic,
2595            Some(child.as_box()),
2596        );
2597        baseline.layout(&mut app, BoxConstraints::new(), false);
2598        // The child has no baseline, so its bottom is used: the shift is 30 - 20.
2599        assert_eq!(
2600            child.as_box().box_parent_data(&app).offset,
2601            Offset::new(0.0, 10.0)
2602        );
2603        assert_eq!(baseline.size(&app), Size::new(20.0, 30.0));
2604    }
2605
2606    #[test]
2607    fn padding_around_tight_child() {
2608        let cell = AppCell::new();
2609        let mut app = cell.borrow_mut();
2610        let child =
2611            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
2612        let padding = RenderPadding::new(
2613            &mut app,
2614            EdgeInsetsGeometry::all(8.0),
2615            None,
2616            Some(child.as_box()),
2617        );
2618        padding.layout(&mut app, BoxConstraints::new(), false);
2619        assert_eq!(child.size(&app), Size::new(80.0, 40.0));
2620        assert_eq!(padding.size(&app), Size::new(96.0, 56.0));
2621        assert_eq!(
2622            child.as_box().box_parent_data(&app).offset,
2623            Offset::new(8.0, 8.0)
2624        );
2625    }
2626
2627    #[test]
2628    fn positioned_box_centers_its_child() {
2629        let cell = AppCell::new();
2630        let mut app = cell.borrow_mut();
2631        let child =
2632            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)), None);
2633        let positioned = RenderPositionedBox::new(
2634            &mut app,
2635            AlignmentGeometry::CENTER,
2636            None,
2637            None,
2638            None,
2639            Some(child.as_box()),
2640        );
2641        positioned.layout(
2642            &mut app,
2643            BoxConstraints::tight(Size::new(100.0, 100.0)),
2644            false,
2645        );
2646        assert_eq!(positioned.size(&app), Size::new(100.0, 100.0));
2647        assert_eq!(
2648            child.as_box().box_parent_data(&app).offset,
2649            Offset::new(40.0, 40.0)
2650        );
2651    }
2652
2653    #[test]
2654    fn positioned_box_shrink_wraps_with_a_factor() {
2655        let cell = AppCell::new();
2656        let mut app = cell.borrow_mut();
2657        let child =
2658            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)), None);
2659        let positioned = RenderPositionedBox::new(
2660            &mut app,
2661            AlignmentGeometry::CENTER,
2662            None,
2663            Some(2.0),
2664            None,
2665            Some(child.as_box()),
2666        );
2667        positioned.layout(
2668            &mut app,
2669            BoxConstraints::new().max_width(100.0).max_height(100.0),
2670            false,
2671        );
2672        assert_eq!(positioned.size(&app), Size::new(40.0, 100.0));
2673        assert_eq!(
2674            child.as_box().box_parent_data(&app).offset,
2675            Offset::new(10.0, 40.0)
2676        );
2677    }
2678
2679    #[test]
2680    fn padding_without_child() {
2681        let cell = AppCell::new();
2682        let mut app = cell.borrow_mut();
2683        let padding = RenderPadding::new(&mut app, EdgeInsetsGeometry::all(10.0), None, None);
2684        padding.layout(
2685            &mut app,
2686            BoxConstraints::tight(Size::new(100.0, 100.0)),
2687            false,
2688        );
2689        assert_eq!(padding.size(&app), Size::new(100.0, 100.0));
2690    }
2691
2692    #[derive(Debug)]
2693    struct OffsetDelegate {
2694        offset: Offset,
2695    }
2696
2697    impl SingleChildLayoutDelegate for OffsetDelegate {
2698        fn get_size(&self, constraints: BoxConstraints) -> Size {
2699            constraints.biggest()
2700        }
2701
2702        fn get_constraints_for_child(&self, constraints: BoxConstraints) -> BoxConstraints {
2703            constraints.loosen()
2704        }
2705
2706        fn get_position_for_child(&self, _size: Size, _child_size: Size) -> Offset {
2707            self.offset
2708        }
2709
2710        fn should_relayout(&self, old_delegate: &dyn SingleChildLayoutDelegate) -> bool {
2711            old_delegate
2712                .as_any()
2713                .downcast_ref::<OffsetDelegate>()
2714                .is_none_or(|old| old.offset != self.offset)
2715        }
2716
2717        fn as_any(&self) -> &dyn Any {
2718            self
2719        }
2720    }
2721
2722    #[test]
2723    fn custom_single_child_layout_positions_the_child() {
2724        let cell = AppCell::new();
2725        let mut app = cell.borrow_mut();
2726        let child =
2727            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(20.0, 10.0)), None);
2728        let parent = RenderCustomSingleChildLayoutBox::new(
2729            &mut app,
2730            Rc::new(OffsetDelegate {
2731                offset: Offset::new(8.0, 4.0),
2732            }),
2733            Some(child.as_box()),
2734        );
2735        parent.layout(
2736            &mut app,
2737            BoxConstraints::tight(Size::new(100.0, 50.0)),
2738            false,
2739        );
2740        assert_eq!(parent.size(&app), Size::new(100.0, 50.0));
2741        assert_eq!(
2742            child.as_box().box_parent_data(&app).offset,
2743            Offset::new(8.0, 4.0)
2744        );
2745    }
2746}