Skip to main content

inset_rendering/
proxy_box.rs

1//! Flutter counterpart: `rendering/proxy_box.dart` (`RenderProxyBoxMixin`,
2//! `HitTestBehavior`, `RenderConstrainedBox`, `RenderLimitedBox`, `RenderOpacity`,
3//! `RenderAnimatedOpacityMixin`, `RenderAnimatedOpacity`, `CustomClipper`,
4//! `RenderCustomClip`, `RenderClipRect`, `RenderClipRRect`, `RenderPointerListener`,
5//! `DecorationPosition`, `RenderDecoratedBox`, `RenderTransform`,
6//! `RenderFractionalTranslation`, `RenderRepaintBoundary`, `RenderMouseRegion`,
7//! `RenderIgnorePointer`, `RenderOffstage`, `RenderAbsorbPointer`, `RenderAnnotatedRegion`),
8//! plus
9//! `widgets/basic.dart`'s `_RenderColoredBox`.
10//!
11//! Intrinsics wait.
12
13use std::any::Any;
14use std::rc::Rc;
15use std::sync::Arc;
16
17use inset_animation::AnyAnimation;
18use inset_embedder::{
19    BlendMode, Clip, Color, FillRule, ImageFilter, Matrix4, Offset, Paint, Path, PathBuilder,
20    RRect, RSuperellipse, Rect, Size, TextBaseline, rsuperellipse_radii_elliptical, valo::Point,
21};
22use inset_foundation::{App, Handle, Listenable, Listener};
23use inset_gestures::{
24    PointerCancelEventListener, PointerDownEventListener, PointerEnterEventListener, PointerEvent,
25    PointerExitEventListener, PointerHoverEventListener, PointerMoveEventListener,
26    PointerPanZoomEndEventListener, PointerPanZoomStartEventListener,
27    PointerPanZoomUpdateEventListener, PointerSignalEventListener, PointerUpEventListener,
28};
29use inset_painting::{
30    Alignment, AlignmentGeometry, BorderRadiusGeometry, BoxFit, BoxPainter, ClipContext,
31    Decoration, ImageConfiguration, ShapeBorder, TextDirection, apply_box_fit, get_as_translation,
32};
33use inset_services::{MouseCursor, MouseCursorRef, MouseTrackerAnnotation};
34
35use crate::box_::{
36    AnyRenderBox, BoxConstraints, BoxHitTestEntry, BoxHitTestResult, RenderBox, RenderBoxBase,
37    RenderBoxData,
38};
39use crate::image_filter_config::{ImageFilterConfig, ImageFilterContext};
40use crate::layer::{
41    AnnotatedRegionLayer, BackdropFilterLayer, BackdropKey, ClipPathLayer, ClipRRectLayer,
42    ClipRectLayer, ContainerLayer, FollowerLayer, LayerHandle, LayerLink, LeaderLayer,
43    OffsetLayerMixin, OpacityLayer, TransformLayer,
44};
45use crate::layout_helper::{ChildLayoutHelper, ChildLayouter};
46use crate::object::{
47    AnyRenderObject, Constraints, EmptyParentData, RenderHandle, RenderObject, RenderObjectData,
48    RenderObjectWithChildData, RenderObjectWithChildMixin,
49};
50use crate::painting_context::PaintingContext;
51use crate::pipeline_owner::PipelineOwner;
52
53/// A base class for render boxes that resemble their children.
54///
55/// Flutter's `RenderProxyBoxMixin`: the shared bodies of a proxy box. A leaf implements the
56/// marker and calls these where Dart would run the inherited method:
57/// `RenderProxyBoxMixin::perform_layout(self, app)`.
58pub trait RenderProxyBoxMixin:
59    RenderObjectWithChildMixin<ChildType = AnyRenderBox> + RenderBox
60{
61    /// A proxy child gets plain parent data, not [`crate::BoxParentData`].
62    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
63        if child.parent_data(app).is_none() {
64            child.set_parent_data(app, EmptyParentData);
65        }
66    }
67
68    /// A proxy paints its child at its own offset: no transform to apply.
69    fn apply_paint_transform(
70        self: RenderHandle<Self>,
71        app: &App,
72        child: AnyRenderObject,
73        transform: &mut Matrix4,
74    ) {
75        let _ = (app, child, transform);
76    }
77
78    /// The child's minimum intrinsic width, or 0 without a child.
79    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
80        match self.child(app) {
81            Some(child) => child.get_min_intrinsic_width(app, height),
82            None => 0.0,
83        }
84    }
85
86    /// The child's maximum intrinsic width, or 0 without a child.
87    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
88        match self.child(app) {
89            Some(child) => child.get_max_intrinsic_width(app, height),
90            None => 0.0,
91        }
92    }
93
94    /// The child's minimum intrinsic height, or 0 without a child.
95    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
96        match self.child(app) {
97            Some(child) => child.get_min_intrinsic_height(app, width),
98            None => 0.0,
99        }
100    }
101
102    /// The child's maximum intrinsic height, or 0 without a child.
103    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
104        match self.child(app) {
105            Some(child) => child.get_max_intrinsic_height(app, width),
106            None => 0.0,
107        }
108    }
109
110    /// The child's baseline, or none without a child.
111    fn compute_distance_to_actual_baseline(
112        self: RenderHandle<Self>,
113        app: &mut App,
114        baseline: TextBaseline,
115    ) -> Option<f64> {
116        self.child(app)
117            .and_then(|child| child.get_distance_to_actual_baseline(app, baseline))
118    }
119
120    /// The child's dry baseline, or none without a child.
121    fn compute_dry_baseline(
122        self: RenderHandle<Self>,
123        app: &mut App,
124        constraints: BoxConstraints,
125        baseline: TextBaseline,
126    ) -> Option<f64> {
127        self.child(app)
128            .and_then(|child| child.get_dry_baseline(app, constraints, baseline))
129    }
130
131    /// The child's dry layout at this box's constraints, or
132    /// [`compute_size_for_no_child`](Self::compute_size_for_no_child).
133    fn compute_dry_layout(
134        self: RenderHandle<Self>,
135        app: &mut App,
136        constraints: BoxConstraints,
137    ) -> Size {
138        match self.child(app) {
139            Some(child) => child.get_dry_layout(app, constraints),
140            None => self.compute_size_for_no_child(app, constraints),
141        }
142    }
143
144    /// Lays the child out with this box's constraints and takes its size.
145    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
146        let constraints = self.constraints(app);
147        let size = match self.child(app) {
148            Some(child) => {
149                child.layout(app, constraints, true);
150                child.size(app)
151            }
152            None => self.compute_size_for_no_child(app, constraints),
153        };
154        self.set_size(app, size);
155    }
156
157    /// Calculate the size the proxy box would have when it has no child.
158    fn compute_size_for_no_child(
159        self: RenderHandle<Self>,
160        _app: &App,
161        constraints: BoxConstraints,
162    ) -> Size {
163        constraints.smallest()
164    }
165
166    /// Hit tests the child at this box's position.
167    fn hit_test_children(
168        self: RenderHandle<Self>,
169        app: &mut App,
170        result: &mut BoxHitTestResult<'_>,
171        position: Offset,
172    ) -> bool {
173        match self.child(app) {
174            Some(child) => child.hit_test(app, result, position),
175            None => false,
176        }
177    }
178
179    /// Paints the child at this box's offset.
180    fn paint(
181        self: RenderHandle<Self>,
182        app: &mut App,
183        context: &mut PaintingContext,
184        offset: Offset,
185    ) {
186        let Some(child) = self.child(app) else {
187            return;
188        };
189        context.paint_child(app, child.as_object(), offset);
190    }
191}
192
193/// A [`RenderProxyBoxMixin`] that allows customizing its hit-test behavior.
194///
195/// Flutter's `RenderProxyBoxWithHitTestBehavior`. A leaf stores the [`HitTestBehavior`] and
196/// wires `hit_test` / `hit_test_self` to these.
197pub trait RenderProxyBoxWithHitTestBehavior: RenderProxyBoxMixin {
198    /// How to behave during hit testing when deciding how the hit test propagates to children
199    /// and whether to consider targets behind this one.
200    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior;
201
202    /// Flutter's `hitTest`: a translucent box is added even when nothing was hit.
203    fn hit_test(
204        self: RenderHandle<Self>,
205        app: &mut App,
206        result: &mut BoxHitTestResult<'_>,
207        position: Offset,
208    ) -> bool {
209        let mut hit_target = false;
210        if self.size(app).contains(position) {
211            hit_target = RenderBox::hit_test_children(self, app, result, position)
212                || RenderBox::hit_test_self(self, app, position);
213            if hit_target || self.behavior(app) == HitTestBehavior::Translucent {
214                result.add(BoxHitTestEntry::new(self.as_box(), position).into());
215            }
216        }
217        hit_target
218    }
219
220    /// Flutter's `hitTestSelf`: an opaque box is hit by itself.
221    fn hit_test_self(self: RenderHandle<Self>, app: &App, _position: Offset) -> bool {
222        self.behavior(app) == HitTestBehavior::Opaque
223    }
224}
225
226/// How to behave during hit tests.
227#[derive(Debug, Clone, Copy, PartialEq, Eq)]
228pub enum HitTestBehavior {
229    /// Targets that defer to their children receive events within their bounds
230    /// only if one of their children is hit by the hit test.
231    DeferToChild,
232
233    /// Opaque targets can be hit by hit tests, causing them to both receive
234    /// events within their bounds and prevent targets visually behind them from
235    /// also receiving events.
236    Opaque,
237
238    /// Translucent targets both receive events within their bounds and permit
239    /// targets visually behind them to also receive events.
240    Translucent,
241}
242
243/// Imposes additional constraints on its child.
244pub struct RenderConstrainedBox {
245    render_object: RenderObjectData,
246    render_box: RenderBoxData,
247    child: RenderObjectWithChildData<AnyRenderBox>,
248    additional_constraints: BoxConstraints,
249}
250
251impl RenderConstrainedBox {
252    /// Creates a render box that constrains its child.
253    ///
254    /// `additional_constraints` must be valid.
255    pub fn new(
256        app: &mut App,
257        additional_constraints: BoxConstraints,
258        child: Option<AnyRenderBox>,
259    ) -> RenderHandle<RenderConstrainedBox> {
260        debug_assert!(additional_constraints.debug_assert_is_valid(false));
261        let this = RenderHandle::new_box(
262            app,
263            RenderConstrainedBox {
264                render_object: RenderObjectData::new(),
265                render_box: RenderBoxData::new(),
266                child: RenderObjectWithChildData::new(),
267                additional_constraints,
268            },
269        );
270        this.set_child(app, child);
271        this
272    }
273
274    /// Additional constraints to apply to the child during layout.
275    pub fn additional_constraints(self: RenderHandle<Self>, app: &App) -> BoxConstraints {
276        self.get(app).additional_constraints
277    }
278
279    /// Sets [`additional_constraints`](Self::additional_constraints).
280    pub fn set_additional_constraints(
281        self: RenderHandle<Self>,
282        app: &mut App,
283        value: BoxConstraints,
284    ) {
285        debug_assert!(value.debug_assert_is_valid(false));
286        if self.get(app).additional_constraints == value {
287            return;
288        }
289        self.get_mut(app).additional_constraints = value;
290        self.mark_needs_layout(app);
291    }
292}
293
294impl RenderObjectWithChildMixin for RenderConstrainedBox {
295    type ChildType = AnyRenderBox;
296
297    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
298        &self.get(app).child
299    }
300
301    fn child_data_mut(
302        self: RenderHandle<Self>,
303        app: &mut App,
304    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
305        &mut self.get_mut(app).child
306    }
307}
308
309impl RenderProxyBoxMixin for RenderConstrainedBox {}
310
311impl RenderObject for RenderConstrainedBox {
312    crate::render_object_accessors!();
313
314    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
315        let constraints = self.constraints(app);
316        let additional = self.get(app).additional_constraints;
317        if let Some(child) = self.child(app) {
318            child.layout(app, additional.enforce(constraints), true);
319            self.set_size(app, child.size(app));
320        } else {
321            self.set_size(app, additional.enforce(constraints).constrain(Size::ZERO));
322        }
323    }
324
325    fn paint(
326        self: RenderHandle<Self>,
327        app: &mut App,
328        context: &mut PaintingContext,
329        offset: Offset,
330    ) {
331        RenderProxyBoxMixin::paint(self, app, context, offset);
332    }
333
334    fn visit_children(
335        self: RenderHandle<Self>,
336        app: &App,
337        visitor: &mut dyn FnMut(AnyRenderObject),
338    ) {
339        if let Some(child) = self.child(app) {
340            visitor(child.as_object());
341        }
342    }
343}
344
345impl RenderBox for RenderConstrainedBox {
346    crate::render_box_accessors!();
347
348    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
349        RenderProxyBoxMixin::setup_parent_data(self, app, child);
350    }
351
352    fn apply_paint_transform(
353        self: RenderHandle<Self>,
354        app: &App,
355        child: AnyRenderObject,
356        transform: &mut Matrix4,
357    ) {
358        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
359    }
360
361    fn hit_test_children(
362        self: RenderHandle<Self>,
363        app: &mut App,
364        result: &mut BoxHitTestResult<'_>,
365        position: Offset,
366    ) -> bool {
367        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
368    }
369
370    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
371        let additional = self.get(app).additional_constraints;
372        if additional.has_bounded_width() && additional.has_tight_width() {
373            return additional.min_width;
374        }
375        let width = RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height);
376        debug_assert!(width.is_finite());
377        if additional.has_infinite_width() {
378            width
379        } else {
380            additional.constrain_width(width)
381        }
382    }
383
384    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
385        let additional = self.get(app).additional_constraints;
386        if additional.has_bounded_width() && additional.has_tight_width() {
387            return additional.min_width;
388        }
389        let width = RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height);
390        debug_assert!(width.is_finite());
391        if additional.has_infinite_width() {
392            width
393        } else {
394            additional.constrain_width(width)
395        }
396    }
397
398    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
399        let additional = self.get(app).additional_constraints;
400        if additional.has_bounded_height() && additional.has_tight_height() {
401            return additional.min_height;
402        }
403        let height = RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width);
404        debug_assert!(height.is_finite());
405        if additional.has_infinite_height() {
406            height
407        } else {
408            additional.constrain_height(height)
409        }
410    }
411
412    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
413        let additional = self.get(app).additional_constraints;
414        if additional.has_bounded_height() && additional.has_tight_height() {
415            return additional.min_height;
416        }
417        let height = RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width);
418        debug_assert!(height.is_finite());
419        if additional.has_infinite_height() {
420            height
421        } else {
422            additional.constrain_height(height)
423        }
424    }
425
426    fn compute_distance_to_actual_baseline(
427        self: RenderHandle<Self>,
428        app: &mut App,
429        baseline: TextBaseline,
430    ) -> Option<f64> {
431        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
432    }
433
434    fn compute_dry_baseline(
435        self: RenderHandle<Self>,
436        app: &mut App,
437        constraints: BoxConstraints,
438        baseline: TextBaseline,
439    ) -> Option<f64> {
440        let additional = self.get(app).additional_constraints;
441        self.child(app).and_then(|child| {
442            child.get_dry_baseline(app, additional.enforce(constraints), baseline)
443        })
444    }
445
446    fn compute_dry_layout(
447        self: RenderHandle<Self>,
448        app: &mut App,
449        constraints: BoxConstraints,
450    ) -> Size {
451        let additional = self.get(app).additional_constraints;
452        match self.child(app) {
453            Some(child) => child.get_dry_layout(app, additional.enforce(constraints)),
454            None => additional.enforce(constraints).constrain(Size::ZERO),
455        }
456    }
457}
458
459/// Makes its child partially transparent.
460///
461/// This class paints its child into an intermediate buffer and then blends the
462/// child back into the scene partially transparent.
463///
464/// For values of opacity other than 0.0 and 1.0, this class is relatively
465/// expensive because it requires painting the child into an intermediate
466/// buffer. For the value 0.0, the child is not painted at all. For the
467/// value 1.0, the child is painted immediately without an intermediate buffer.
468pub struct RenderOpacity {
469    render_object: RenderObjectData,
470    render_box: RenderBoxData,
471    child: RenderObjectWithChildData<AnyRenderBox>,
472    alpha: i32,
473    opacity: f64,
474}
475
476impl RenderOpacity {
477    /// Creates a partially transparent render object.
478    ///
479    /// The `opacity` argument must be between 0.0 and 1.0, inclusive.
480    pub fn new(app: &mut App, opacity: f64, child: Option<AnyRenderBox>) -> RenderHandle<Self> {
481        debug_assert!((0.0..=1.0).contains(&opacity));
482        let this = RenderHandle::new_box(
483            app,
484            RenderOpacity {
485                render_object: RenderObjectData::new(),
486                render_box: RenderBoxData::new(),
487                child: RenderObjectWithChildData::new(),
488                alpha: Color::get_alpha_from_opacity(opacity),
489                opacity,
490            },
491        );
492        this.set_child(app, child);
493        this
494    }
495
496    /// The fraction to scale the child's alpha value.
497    ///
498    /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent
499    /// (i.e., invisible).
500    ///
501    /// Values 1.0 and 0.0 are painted with a fast path. Other values
502    /// require painting the child into an intermediate buffer, which is
503    /// expensive.
504    pub fn opacity(self: RenderHandle<Self>, app: &App) -> f64 {
505        self.get(app).opacity
506    }
507
508    /// Sets [`opacity`](Self::opacity).
509    pub fn set_opacity(self: RenderHandle<Self>, app: &mut App, value: f64) {
510        debug_assert!((0.0..=1.0).contains(&value));
511        if self.get(app).opacity == value {
512            return;
513        }
514        let did_need_compositing = self.always_needs_compositing(app);
515        let this = self.get_mut(app);
516        this.opacity = value;
517        this.alpha = Color::get_alpha_from_opacity(value);
518        if did_need_compositing != self.always_needs_compositing(app) {
519            self.mark_needs_compositing_bits_update(app);
520        }
521        self.mark_needs_composited_layer_update(app);
522    }
523}
524
525impl RenderObjectWithChildMixin for RenderOpacity {
526    type ChildType = AnyRenderBox;
527
528    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
529        &self.get(app).child
530    }
531
532    fn child_data_mut(
533        self: RenderHandle<Self>,
534        app: &mut App,
535    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
536        &mut self.get_mut(app).child
537    }
538}
539
540impl RenderProxyBoxMixin for RenderOpacity {}
541
542impl RenderObject for RenderOpacity {
543    crate::render_object_accessors!();
544
545    fn always_needs_compositing(self: RenderHandle<Self>, app: &App) -> bool {
546        self.child(app).is_some() && self.get(app).alpha > 0
547    }
548
549    fn is_repaint_boundary(self: RenderHandle<Self>, app: &App) -> bool {
550        self.always_needs_compositing(app)
551    }
552
553    fn update_composited_layer(
554        self: RenderHandle<Self>,
555        app: &mut App,
556        old_layer: Option<crate::AnyOffsetLayer>,
557    ) -> crate::AnyOffsetLayer {
558        let layer = match old_layer {
559            Some(old) => app
560                .handle::<OpacityLayer>(old.id())
561                .expect("RenderOpacity reuses an OpacityLayer"),
562            None => OpacityLayer::new(app),
563        };
564        layer.set_alpha(app, self.get(app).alpha);
565        layer.as_offset_layer()
566    }
567
568    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
569        RenderProxyBoxMixin::perform_layout(self, app);
570    }
571
572    fn paint(
573        self: RenderHandle<Self>,
574        app: &mut App,
575        context: &mut PaintingContext,
576        offset: Offset,
577    ) {
578        if self.child(app).is_none() || self.get(app).alpha == 0 {
579            return;
580        }
581        RenderProxyBoxMixin::paint(self, app, context, offset);
582    }
583
584    fn visit_children(
585        self: RenderHandle<Self>,
586        app: &App,
587        visitor: &mut dyn FnMut(AnyRenderObject),
588    ) {
589        if let Some(child) = self.child(app) {
590            visitor(child.as_object());
591        }
592    }
593}
594
595impl RenderBox for RenderOpacity {
596    crate::render_box_accessors!();
597
598    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
599        RenderProxyBoxMixin::setup_parent_data(self, app, child);
600    }
601
602    fn apply_paint_transform(
603        self: RenderHandle<Self>,
604        app: &App,
605        child: AnyRenderObject,
606        transform: &mut Matrix4,
607    ) {
608        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
609    }
610
611    fn hit_test_children(
612        self: RenderHandle<Self>,
613        app: &mut App,
614        result: &mut BoxHitTestResult<'_>,
615        position: Offset,
616    ) -> bool {
617        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
618    }
619
620    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
621        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
622    }
623
624    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
625        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
626    }
627
628    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
629        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
630    }
631
632    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
633        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
634    }
635
636    fn compute_distance_to_actual_baseline(
637        self: RenderHandle<Self>,
638        app: &mut App,
639        baseline: TextBaseline,
640    ) -> Option<f64> {
641        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
642    }
643
644    fn compute_dry_baseline(
645        self: RenderHandle<Self>,
646        app: &mut App,
647        constraints: BoxConstraints,
648        baseline: TextBaseline,
649    ) -> Option<f64> {
650        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
651    }
652
653    fn compute_dry_layout(
654        self: RenderHandle<Self>,
655        app: &mut App,
656        constraints: BoxConstraints,
657    ) -> Size {
658        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
659    }
660}
661
662/// Provides an anchor for a [`RenderFollowerLayer`].
663///
664/// Flutter's `RenderLeaderLayer`: paints its child through a leader item that records where the
665/// child lands for the link's followers.
666pub struct RenderLeaderLayer {
667    render_object: RenderObjectData,
668    render_box: RenderBoxData,
669    child: RenderObjectWithChildData<AnyRenderBox>,
670    link: Handle<LayerLink>,
671    /// The size of the last layout, which `link.leader_size` reports.
672    previous_layout_size: Option<Size>,
673}
674
675impl RenderLeaderLayer {
676    pub fn new(
677        app: &mut App,
678        link: Handle<LayerLink>,
679        child: Option<AnyRenderBox>,
680    ) -> RenderHandle<Self> {
681        let this = RenderHandle::new_box(
682            app,
683            RenderLeaderLayer {
684                render_object: RenderObjectData::new(),
685                render_box: RenderBoxData::new(),
686                child: RenderObjectWithChildData::new(),
687                link,
688                previous_layout_size: None,
689            },
690        );
691        this.set_child(app, child);
692        this
693    }
694
695    /// The link object that connects this [`RenderLeaderLayer`] with one or more
696    /// [`RenderFollowerLayer`]s.
697    pub fn link(self: RenderHandle<Self>, app: &App) -> Handle<LayerLink> {
698        self.get(app).link
699    }
700
701    /// Sets [`link`](Self::link).
702    pub fn set_link(self: RenderHandle<Self>, app: &mut App, value: Handle<LayerLink>) {
703        let link = self.get(app).link;
704        if link == value {
705            return;
706        }
707        let old = app.get_mut(link);
708        old.leader_size = None;
709        self.get_mut(app).link = value;
710        if let Some(size) = self.get(app).previous_layout_size {
711            app.get_mut(value).leader_size = Some(size);
712        }
713        self.mark_needs_paint(app);
714    }
715}
716
717impl RenderObjectWithChildMixin for RenderLeaderLayer {
718    type ChildType = AnyRenderBox;
719
720    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
721        &self.get(app).child
722    }
723
724    fn child_data_mut(
725        self: RenderHandle<Self>,
726        app: &mut App,
727    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
728        &mut self.get_mut(app).child
729    }
730}
731
732impl RenderProxyBoxMixin for RenderLeaderLayer {}
733
734impl RenderObject for RenderLeaderLayer {
735    crate::render_object_accessors!();
736
737    fn always_needs_compositing(self: RenderHandle<Self>, _app: &App) -> bool {
738        true
739    }
740
741    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
742        RenderProxyBoxMixin::perform_layout(self, app);
743        let size = self.size(app);
744        self.get_mut(app).previous_layout_size = Some(size);
745        let link = self.get(app).link;
746        app.get_mut(link).leader_size = Some(size);
747    }
748
749    fn paint(
750        self: RenderHandle<Self>,
751        app: &mut App,
752        context: &mut PaintingContext,
753        offset: Offset,
754    ) {
755        let link = self.get(app).link;
756        let layer = match self.as_object().layer_as::<LeaderLayer>(app) {
757            None => {
758                let layer = LeaderLayer::new(app, link);
759                layer.set_offset(app, offset);
760                self.as_object()
761                    .set_layer(app, Some(layer.as_container_layer()));
762                layer
763            }
764            Some(layer) => {
765                layer.set_link(app, link);
766                layer.set_offset(app, offset);
767                layer
768            }
769        };
770        context.push_layer(
771            app,
772            layer.as_container_layer(),
773            |app, context, offset| {
774                RenderProxyBoxMixin::paint(self, app, context, offset);
775            },
776            Offset::ZERO,
777            None,
778        );
779    }
780
781    fn visit_children(
782        self: RenderHandle<Self>,
783        app: &App,
784        visitor: &mut dyn FnMut(AnyRenderObject),
785    ) {
786        if let Some(child) = self.child(app) {
787            visitor(child.as_object());
788        }
789    }
790}
791
792impl RenderBox for RenderLeaderLayer {
793    crate::render_box_accessors!();
794
795    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
796        RenderProxyBoxMixin::setup_parent_data(self, app, child);
797    }
798
799    fn apply_paint_transform(
800        self: RenderHandle<Self>,
801        app: &App,
802        child: AnyRenderObject,
803        transform: &mut Matrix4,
804    ) {
805        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
806    }
807
808    fn hit_test_children(
809        self: RenderHandle<Self>,
810        app: &mut App,
811        result: &mut BoxHitTestResult<'_>,
812        position: Offset,
813    ) -> bool {
814        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
815    }
816
817    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
818        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
819    }
820
821    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
822        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
823    }
824
825    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
826        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
827    }
828
829    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
830        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
831    }
832
833    fn compute_distance_to_actual_baseline(
834        self: RenderHandle<Self>,
835        app: &mut App,
836        baseline: TextBaseline,
837    ) -> Option<f64> {
838        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
839    }
840
841    fn compute_dry_baseline(
842        self: RenderHandle<Self>,
843        app: &mut App,
844        constraints: BoxConstraints,
845        baseline: TextBaseline,
846    ) -> Option<f64> {
847        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
848    }
849
850    fn compute_dry_layout(
851        self: RenderHandle<Self>,
852        app: &mut App,
853        constraints: BoxConstraints,
854    ) -> Size {
855        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
856    }
857}
858
859/// Transforms its child using a transform matrix computed at composite time from the link's
860/// [`RenderLeaderLayer`]: the child paints where the leader is, whatever lies between them.
861///
862/// Flutter's `RenderFollowerLayer`.
863pub struct RenderFollowerLayer {
864    render_object: RenderObjectData,
865    render_box: RenderBoxData,
866    child: RenderObjectWithChildData<AnyRenderBox>,
867    link: Handle<LayerLink>,
868    show_when_unlinked: bool,
869    offset: Offset,
870    leader_anchor: Alignment,
871    follower_anchor: Alignment,
872}
873
874impl RenderFollowerLayer {
875    pub fn new(
876        app: &mut App,
877        link: Handle<LayerLink>,
878        show_when_unlinked: bool,
879        offset: Offset,
880        leader_anchor: Alignment,
881        follower_anchor: Alignment,
882        child: Option<AnyRenderBox>,
883    ) -> RenderHandle<Self> {
884        let this = RenderHandle::new_box(
885            app,
886            RenderFollowerLayer {
887                render_object: RenderObjectData::new(),
888                render_box: RenderBoxData::new(),
889                child: RenderObjectWithChildData::new(),
890                link,
891                show_when_unlinked,
892                offset,
893                leader_anchor,
894                follower_anchor,
895            },
896        );
897        this.set_child(app, child);
898        this
899    }
900
901    /// The link object that connects this [`RenderFollowerLayer`] with a [`RenderLeaderLayer`].
902    pub fn link(self: RenderHandle<Self>, app: &App) -> Handle<LayerLink> {
903        self.get(app).link
904    }
905
906    /// Sets [`link`](Self::link).
907    pub fn set_link(self: RenderHandle<Self>, app: &mut App, value: Handle<LayerLink>) {
908        if self.get(app).link == value {
909            return;
910        }
911        self.get_mut(app).link = value;
912        self.mark_needs_paint(app);
913    }
914
915    /// Whether to show the render object's contents when there is no corresponding
916    /// [`RenderLeaderLayer`].
917    pub fn show_when_unlinked(self: RenderHandle<Self>, app: &App) -> bool {
918        self.get(app).show_when_unlinked
919    }
920
921    /// Sets [`show_when_unlinked`](Self::show_when_unlinked).
922    pub fn set_show_when_unlinked(self: RenderHandle<Self>, app: &mut App, value: bool) {
923        if self.get(app).show_when_unlinked == value {
924            return;
925        }
926        self.get_mut(app).show_when_unlinked = value;
927        self.mark_needs_paint(app);
928    }
929
930    /// The offset to apply to the origin of the linked [`RenderLeaderLayer`] to obtain this
931    /// render object's origin.
932    pub fn offset(self: RenderHandle<Self>, app: &App) -> Offset {
933        self.get(app).offset
934    }
935
936    /// Sets [`offset`](Self::offset).
937    pub fn set_offset(self: RenderHandle<Self>, app: &mut App, value: Offset) {
938        if self.get(app).offset == value {
939            return;
940        }
941        self.get_mut(app).offset = value;
942        self.mark_needs_paint(app);
943    }
944
945    /// The anchor point on the linked [`RenderLeaderLayer`] that [`follower_anchor`] lines up
946    /// with.
947    ///
948    /// [`follower_anchor`]: Self::follower_anchor
949    pub fn leader_anchor(self: RenderHandle<Self>, app: &App) -> Alignment {
950        self.get(app).leader_anchor
951    }
952
953    /// Sets [`leader_anchor`](Self::leader_anchor).
954    pub fn set_leader_anchor(self: RenderHandle<Self>, app: &mut App, value: Alignment) {
955        if self.get(app).leader_anchor == value {
956            return;
957        }
958        self.get_mut(app).leader_anchor = value;
959        self.mark_needs_paint(app);
960    }
961
962    /// The anchor point on this render object that lines up with [`leader_anchor`].
963    ///
964    /// [`leader_anchor`]: Self::leader_anchor
965    pub fn follower_anchor(self: RenderHandle<Self>, app: &App) -> Alignment {
966        self.get(app).follower_anchor
967    }
968
969    /// Sets [`follower_anchor`](Self::follower_anchor).
970    pub fn set_follower_anchor(self: RenderHandle<Self>, app: &mut App, value: Alignment) {
971        if self.get(app).follower_anchor == value {
972            return;
973        }
974        self.get_mut(app).follower_anchor = value;
975        self.mark_needs_paint(app);
976    }
977
978    /// The transform that was used during the last composite, from this render object's
979    /// children to its own coordinates, or the identity when there was none.
980    ///
981    /// Flutter's `getCurrentTransform`.
982    pub fn current_transform(self: RenderHandle<Self>, app: &App) -> Matrix4 {
983        self.as_object()
984            .layer_as::<FollowerLayer>(app)
985            .and_then(|layer| layer.get_last_transform(app))
986            .unwrap_or(Matrix4::IDENTITY)
987    }
988}
989
990impl RenderObjectWithChildMixin for RenderFollowerLayer {
991    type ChildType = AnyRenderBox;
992
993    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
994        &self.get(app).child
995    }
996
997    fn child_data_mut(
998        self: RenderHandle<Self>,
999        app: &mut App,
1000    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1001        &mut self.get_mut(app).child
1002    }
1003}
1004
1005impl RenderProxyBoxMixin for RenderFollowerLayer {}
1006
1007impl RenderObject for RenderFollowerLayer {
1008    crate::render_object_accessors!();
1009
1010    fn always_needs_compositing(self: RenderHandle<Self>, _app: &App) -> bool {
1011        true
1012    }
1013
1014    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1015        RenderProxyBoxMixin::perform_layout(self, app);
1016    }
1017
1018    /// Flutter's `detach`: `layer = null`.
1019    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
1020        self.as_object().set_layer(app, None);
1021        if let Some(child) = self.child(app) {
1022            child.as_object().detach(app);
1023        }
1024    }
1025
1026    fn paint(
1027        self: RenderHandle<Self>,
1028        app: &mut App,
1029        context: &mut PaintingContext,
1030        offset: Offset,
1031    ) {
1032        let link = self.get(app).link;
1033        let leader_size = app.get(link).leader_size;
1034        debug_assert!(
1035            leader_size.is_some()
1036                || link.leader(app).is_none()
1037                || self.get(app).leader_anchor == Alignment::TOP_LEFT,
1038            "a leader size is required when leader_anchor is not Alignment::TOP_LEFT"
1039        );
1040        let this = self.get(app);
1041        let effective_linked_offset = match leader_size {
1042            None => this.offset,
1043            Some(leader_size) => {
1044                this.leader_anchor.along_size(leader_size)
1045                    - this.follower_anchor.along_size(self.size(app))
1046                    + this.offset
1047            }
1048        };
1049        let show_when_unlinked = this.show_when_unlinked;
1050        let layer = match self.as_object().layer_as::<FollowerLayer>(app) {
1051            None => {
1052                let layer = FollowerLayer::new(app, link);
1053                layer.set_show_when_unlinked(app, show_when_unlinked);
1054                layer.set_linked_offset(app, effective_linked_offset);
1055                layer.set_unlinked_offset(app, offset);
1056                self.as_object()
1057                    .set_layer(app, Some(layer.as_container_layer()));
1058                layer
1059            }
1060            Some(layer) => {
1061                layer.set_link(app, link);
1062                layer.set_show_when_unlinked(app, show_when_unlinked);
1063                layer.set_linked_offset(app, effective_linked_offset);
1064                layer.set_unlinked_offset(app, offset);
1065                layer
1066            }
1067        };
1068        context.push_layer(
1069            app,
1070            layer.as_container_layer(),
1071            |app, context, offset| {
1072                RenderProxyBoxMixin::paint(self, app, context, offset);
1073            },
1074            Offset::ZERO,
1075            Some(Rect::from_ltrb(
1076                f64::NEG_INFINITY,
1077                f64::NEG_INFINITY,
1078                f64::INFINITY,
1079                f64::INFINITY,
1080            )),
1081        );
1082    }
1083
1084    fn visit_children(
1085        self: RenderHandle<Self>,
1086        app: &App,
1087        visitor: &mut dyn FnMut(AnyRenderObject),
1088    ) {
1089        if let Some(child) = self.child(app) {
1090            visitor(child.as_object());
1091        }
1092    }
1093}
1094
1095impl RenderBox for RenderFollowerLayer {
1096    crate::render_box_accessors!();
1097
1098    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1099        RenderProxyBoxMixin::setup_parent_data(self, app, child);
1100    }
1101
1102    fn apply_paint_transform(
1103        self: RenderHandle<Self>,
1104        app: &App,
1105        _child: AnyRenderObject,
1106        transform: &mut Matrix4,
1107    ) {
1108        *transform = transform.then(&self.current_transform(app));
1109    }
1110
1111    /// Disables the hit testing if this render object is hidden. A follower does not check
1112    /// whether it is itself hit: the untransformed size and the child's transformed position
1113    /// do not relate.
1114    fn hit_test(
1115        self: RenderHandle<Self>,
1116        app: &mut App,
1117        result: &mut BoxHitTestResult<'_>,
1118        position: Offset,
1119    ) -> bool {
1120        let link = self.get(app).link;
1121        if link.leader(app).is_none() && !self.get(app).show_when_unlinked {
1122            return false;
1123        }
1124        RenderBox::hit_test_children(self, app, result, position)
1125    }
1126
1127    fn hit_test_children(
1128        self: RenderHandle<Self>,
1129        app: &mut App,
1130        result: &mut BoxHitTestResult<'_>,
1131        position: Offset,
1132    ) -> bool {
1133        let transform = self.current_transform(app);
1134        result.add_with_paint_transform(Some(transform), position, |result, position| {
1135            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
1136        })
1137    }
1138
1139    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1140        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
1141    }
1142
1143    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1144        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
1145    }
1146
1147    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1148        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
1149    }
1150
1151    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1152        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
1153    }
1154
1155    fn compute_distance_to_actual_baseline(
1156        self: RenderHandle<Self>,
1157        app: &mut App,
1158        baseline: TextBaseline,
1159    ) -> Option<f64> {
1160        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
1161    }
1162
1163    fn compute_dry_baseline(
1164        self: RenderHandle<Self>,
1165        app: &mut App,
1166        constraints: BoxConstraints,
1167        baseline: TextBaseline,
1168    ) -> Option<f64> {
1169        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
1170    }
1171
1172    fn compute_dry_layout(
1173        self: RenderHandle<Self>,
1174        app: &mut App,
1175        constraints: BoxConstraints,
1176    ) -> Size {
1177        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
1178    }
1179}
1180
1181/// The mixin fields of [`RenderAnimatedOpacityMixin`].
1182pub struct RenderAnimatedOpacityData {
1183    alpha: Option<i32>,
1184    currently_is_repaint_boundary: Option<bool>,
1185    opacity: Option<AnyAnimation<f64>>,
1186}
1187
1188impl RenderAnimatedOpacityData {
1189    /// No animation yet; the host sets one in its constructor.
1190    pub const fn new() -> RenderAnimatedOpacityData {
1191        RenderAnimatedOpacityData {
1192            alpha: None,
1193            currently_is_repaint_boundary: None,
1194            opacity: None,
1195        }
1196    }
1197}
1198
1199impl Default for RenderAnimatedOpacityData {
1200    fn default() -> RenderAnimatedOpacityData {
1201        RenderAnimatedOpacityData::new()
1202    }
1203}
1204
1205/// Implementation of [`RenderAnimatedOpacity`] and `RenderSliverAnimatedOpacity`.
1206///
1207/// This mixin allows the logic of animating opacity to be used with different
1208/// layout models, e.g. the way that [`RenderAnimatedOpacity`] uses it for
1209/// [`RenderBox`] and `RenderSliverAnimatedOpacity` uses it for `RenderSliver`.
1210///
1211/// The host wires the virtuals: `is_repaint_boundary`, `update_composited_layer`, `did_attach`,
1212/// `did_detach`, and `paint` call the same-named functions here.
1213pub trait RenderAnimatedOpacityMixin:
1214    RenderObjectWithChildMixin<ChildType = AnyRenderBox> + RenderBox
1215{
1216    /// Mixin field access.
1217    fn animated_opacity_data(self: RenderHandle<Self>, app: &App) -> &RenderAnimatedOpacityData;
1218
1219    /// See [`animated_opacity_data`](Self::animated_opacity_data).
1220    fn animated_opacity_data_mut(
1221        self: RenderHandle<Self>,
1222        app: &mut App,
1223    ) -> &mut RenderAnimatedOpacityData;
1224
1225    /// Flutter's `isRepaintBoundary`.
1226    fn is_repaint_boundary(self: RenderHandle<Self>, app: &App) -> bool {
1227        self.child(app).is_some()
1228            && self
1229                .animated_opacity_data(app)
1230                .currently_is_repaint_boundary
1231                .expect("set by the opacity setter")
1232    }
1233
1234    /// Flutter's `updateCompositedLayer`.
1235    fn update_composited_layer(
1236        self: RenderHandle<Self>,
1237        app: &mut App,
1238        old_layer: Option<crate::AnyOffsetLayer>,
1239    ) -> crate::AnyOffsetLayer {
1240        let alpha = self
1241            .animated_opacity_data(app)
1242            .alpha
1243            .expect("set by the opacity setter");
1244        let layer = match old_layer {
1245            Some(old) => app
1246                .handle::<OpacityLayer>(old.id())
1247                .expect("RenderAnimatedOpacity reuses an OpacityLayer"),
1248            None => OpacityLayer::new(app),
1249        };
1250        layer.set_alpha(app, alpha);
1251        layer.as_offset_layer()
1252    }
1253
1254    /// The animation that drives this render object's opacity.
1255    ///
1256    /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent
1257    /// (i.e., invisible).
1258    fn opacity(self: RenderHandle<Self>, app: &App) -> AnyAnimation<f64> {
1259        self.animated_opacity_data(app)
1260            .opacity
1261            .expect("set by the constructor")
1262    }
1263
1264    /// Sets [`opacity`](Self::opacity).
1265    fn set_opacity(self: RenderHandle<Self>, app: &mut App, value: AnyAnimation<f64>) {
1266        if self.animated_opacity_data(app).opacity == Some(value) {
1267            return;
1268        }
1269        if self.attached(app)
1270            && let Some(opacity) = self.animated_opacity_data(app).opacity
1271        {
1272            opacity.remove_listener(app, &self.opacity_listener());
1273        }
1274        self.animated_opacity_data_mut(app).opacity = Some(value);
1275        if self.attached(app) {
1276            value.add_listener(app, self.opacity_listener());
1277        }
1278        self.update_opacity(app);
1279    }
1280
1281    /// Flutter's `attach` after `super.attach(owner)`.
1282    fn did_attach(self: RenderHandle<Self>, app: &mut App) {
1283        self.opacity(app).add_listener(app, self.opacity_listener());
1284        self.update_opacity(app); // in case it changed while we weren't listening
1285    }
1286
1287    /// Flutter's `detach` before `super.detach()`.
1288    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
1289        self.opacity(app)
1290            .remove_listener(app, &self.opacity_listener());
1291    }
1292
1293    /// The `_updateOpacity` tear-off, equal to itself across registrations.
1294    fn opacity_listener(self: RenderHandle<Self>) -> Listener {
1295        Listener::handle_method(self.handle(), update_opacity::<Self>)
1296    }
1297
1298    /// Flutter's `_updateOpacity`.
1299    fn update_opacity(self: RenderHandle<Self>, app: &mut App) {
1300        let old_alpha = self.animated_opacity_data(app).alpha;
1301        let alpha = Color::get_alpha_from_opacity(self.opacity(app).value(app));
1302        self.animated_opacity_data_mut(app).alpha = Some(alpha);
1303        if old_alpha != Some(alpha) {
1304            let was_repaint_boundary = self
1305                .animated_opacity_data(app)
1306                .currently_is_repaint_boundary;
1307            self.animated_opacity_data_mut(app)
1308                .currently_is_repaint_boundary = Some(alpha > 0);
1309            // Flutter: `markNeedsCompositingBitsUpdate`, whose effect on a boundary change is a repaint.
1310            if self.child(app).is_some() && was_repaint_boundary != Some(alpha > 0) {
1311                self.mark_needs_compositing_bits_update(app);
1312            }
1313            self.mark_needs_composited_layer_update(app);
1314        }
1315    }
1316
1317    /// Flutter's `paint`: nothing when fully transparent, else the proxy paint.
1318    fn paint(self: RenderHandle<Self>, app: &mut App, context: &mut PaintingContext, offset: Offset)
1319    where
1320        Self: RenderProxyBoxMixin,
1321    {
1322        if self.animated_opacity_data(app).alpha == Some(0) {
1323            return;
1324        }
1325        RenderProxyBoxMixin::paint(self, app, context, offset);
1326    }
1327}
1328
1329fn update_opacity<T: RenderAnimatedOpacityMixin>(this: Handle<T>, app: &mut App) {
1330    RenderAnimatedOpacityMixin::update_opacity(RenderHandle::from_handle(this), app);
1331}
1332
1333/// Makes its child partially transparent, driven from an [`AnyAnimation`].
1334///
1335/// This is a variant of [`RenderOpacity`] that uses an [`AnyAnimation<f64>`]
1336/// rather than a `f64` to control the opacity.
1337pub struct RenderAnimatedOpacity {
1338    render_object: RenderObjectData,
1339    render_box: RenderBoxData,
1340    child: RenderObjectWithChildData<AnyRenderBox>,
1341    animated_opacity: RenderAnimatedOpacityData,
1342}
1343
1344impl RenderAnimatedOpacity {
1345    /// Creates a partially transparent render object.
1346    pub fn new(
1347        app: &mut App,
1348        opacity: AnyAnimation<f64>,
1349        child: Option<AnyRenderBox>,
1350    ) -> RenderHandle<Self> {
1351        let this = RenderHandle::new_box(
1352            app,
1353            RenderAnimatedOpacity {
1354                render_object: RenderObjectData::new(),
1355                render_box: RenderBoxData::new(),
1356                child: RenderObjectWithChildData::new(),
1357                animated_opacity: RenderAnimatedOpacityData::new(),
1358            },
1359        );
1360        this.set_child(app, child);
1361        this.set_opacity(app, opacity);
1362        this
1363    }
1364}
1365
1366impl RenderObjectWithChildMixin for RenderAnimatedOpacity {
1367    type ChildType = AnyRenderBox;
1368
1369    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1370        &self.get(app).child
1371    }
1372
1373    fn child_data_mut(
1374        self: RenderHandle<Self>,
1375        app: &mut App,
1376    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1377        &mut self.get_mut(app).child
1378    }
1379}
1380
1381impl RenderProxyBoxMixin for RenderAnimatedOpacity {}
1382
1383impl RenderAnimatedOpacityMixin for RenderAnimatedOpacity {
1384    fn animated_opacity_data(self: RenderHandle<Self>, app: &App) -> &RenderAnimatedOpacityData {
1385        &self.get(app).animated_opacity
1386    }
1387
1388    fn animated_opacity_data_mut(
1389        self: RenderHandle<Self>,
1390        app: &mut App,
1391    ) -> &mut RenderAnimatedOpacityData {
1392        &mut self.get_mut(app).animated_opacity
1393    }
1394}
1395
1396impl RenderObject for RenderAnimatedOpacity {
1397    crate::render_object_accessors!();
1398
1399    fn is_repaint_boundary(self: RenderHandle<Self>, app: &App) -> bool {
1400        RenderAnimatedOpacityMixin::is_repaint_boundary(self, app)
1401    }
1402
1403    fn update_composited_layer(
1404        self: RenderHandle<Self>,
1405        app: &mut App,
1406        old_layer: Option<crate::AnyOffsetLayer>,
1407    ) -> crate::AnyOffsetLayer {
1408        RenderAnimatedOpacityMixin::update_composited_layer(self, app, old_layer)
1409    }
1410
1411    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<crate::PipelineOwner>) {
1412        if let Some(child) = self.child(app) {
1413            child.as_object().attach(app, owner);
1414        }
1415        RenderAnimatedOpacityMixin::did_attach(self, app);
1416    }
1417
1418    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
1419        RenderAnimatedOpacityMixin::did_detach(self, app);
1420        if let Some(child) = self.child(app) {
1421            child.as_object().detach(app);
1422        }
1423    }
1424
1425    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1426        RenderProxyBoxMixin::perform_layout(self, app);
1427    }
1428
1429    fn paint(
1430        self: RenderHandle<Self>,
1431        app: &mut App,
1432        context: &mut PaintingContext,
1433        offset: Offset,
1434    ) {
1435        RenderAnimatedOpacityMixin::paint(self, app, context, offset);
1436    }
1437
1438    fn visit_children(
1439        self: RenderHandle<Self>,
1440        app: &App,
1441        visitor: &mut dyn FnMut(AnyRenderObject),
1442    ) {
1443        if let Some(child) = self.child(app) {
1444            visitor(child.as_object());
1445        }
1446    }
1447}
1448
1449impl RenderBox for RenderAnimatedOpacity {
1450    crate::render_box_accessors!();
1451
1452    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1453        RenderProxyBoxMixin::setup_parent_data(self, app, child);
1454    }
1455
1456    fn apply_paint_transform(
1457        self: RenderHandle<Self>,
1458        app: &App,
1459        child: AnyRenderObject,
1460        transform: &mut Matrix4,
1461    ) {
1462        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
1463    }
1464
1465    fn hit_test_children(
1466        self: RenderHandle<Self>,
1467        app: &mut App,
1468        result: &mut BoxHitTestResult<'_>,
1469        position: Offset,
1470    ) -> bool {
1471        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
1472    }
1473
1474    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1475        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
1476    }
1477
1478    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1479        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
1480    }
1481
1482    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1483        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
1484    }
1485
1486    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1487        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
1488    }
1489
1490    fn compute_distance_to_actual_baseline(
1491        self: RenderHandle<Self>,
1492        app: &mut App,
1493        baseline: TextBaseline,
1494    ) -> Option<f64> {
1495        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
1496    }
1497
1498    fn compute_dry_baseline(
1499        self: RenderHandle<Self>,
1500        app: &mut App,
1501        constraints: BoxConstraints,
1502        baseline: TextBaseline,
1503    ) -> Option<f64> {
1504        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
1505    }
1506
1507    fn compute_dry_layout(
1508        self: RenderHandle<Self>,
1509        app: &mut App,
1510        constraints: BoxConstraints,
1511    ) -> Size {
1512        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
1513    }
1514}
1515
1516/// Calls callbacks in response to common pointer events.
1517///
1518/// It responds to events that can indicate the location of a pointer, such as when the pointer
1519/// presses down, moves, releases, or is cancelled.
1520///
1521/// It does not respond to events that are exclusive to mouse, such as when the mouse enters and
1522/// exits a region without pressing any buttons. For these events, use `RenderMouseRegion`.
1523///
1524/// If it has a child, defers to the child for sizing behavior.
1525///
1526/// If it does not have a child, grows to fit the parent-provided constraints.
1527pub struct RenderPointerListener {
1528    render_object: RenderObjectData,
1529    render_box: RenderBoxData,
1530    child: RenderObjectWithChildData<AnyRenderBox>,
1531    on_pointer_down: Option<PointerDownEventListener>,
1532    on_pointer_move: Option<PointerMoveEventListener>,
1533    on_pointer_up: Option<PointerUpEventListener>,
1534    on_pointer_hover: Option<PointerHoverEventListener>,
1535    on_pointer_cancel: Option<PointerCancelEventListener>,
1536    on_pointer_pan_zoom_start: Option<PointerPanZoomStartEventListener>,
1537    on_pointer_pan_zoom_update: Option<PointerPanZoomUpdateEventListener>,
1538    on_pointer_pan_zoom_end: Option<PointerPanZoomEndEventListener>,
1539    on_pointer_signal: Option<PointerSignalEventListener>,
1540    behavior: HitTestBehavior,
1541}
1542
1543macro_rules! pointer_listener_field {
1544    ($get:ident, $set:ident, $ty:ty, $doc:expr) => {
1545        #[doc = $doc]
1546        pub fn $get(self: RenderHandle<Self>, app: &App) -> Option<$ty> {
1547            self.get(app).$get.clone()
1548        }
1549
1550        #[doc = concat!("Sets [`", stringify!($get), "`](Self::", stringify!($get), ").")]
1551        pub fn $set(self: RenderHandle<Self>, app: &mut App, value: Option<$ty>) {
1552            self.get_mut(app).$get = value;
1553        }
1554    };
1555}
1556
1557impl RenderPointerListener {
1558    /// Creates a render object that forwards pointer events to callbacks.
1559    ///
1560    /// The callbacks are set afterwards; Flutter's constructor takes them as optional named
1561    /// arguments, all `null` by default.
1562    pub fn new(
1563        app: &mut App,
1564        behavior: HitTestBehavior,
1565        child: Option<AnyRenderBox>,
1566    ) -> RenderHandle<Self> {
1567        let this = RenderHandle::new_box(
1568            app,
1569            RenderPointerListener {
1570                render_object: RenderObjectData::new(),
1571                render_box: RenderBoxData::new(),
1572                child: RenderObjectWithChildData::new(),
1573                on_pointer_down: None,
1574                on_pointer_move: None,
1575                on_pointer_up: None,
1576                on_pointer_hover: None,
1577                on_pointer_cancel: None,
1578                on_pointer_pan_zoom_start: None,
1579                on_pointer_pan_zoom_update: None,
1580                on_pointer_pan_zoom_end: None,
1581                on_pointer_signal: None,
1582                behavior,
1583            },
1584        );
1585        this.set_child(app, child);
1586        this
1587    }
1588
1589    pointer_listener_field!(
1590        on_pointer_down,
1591        set_on_pointer_down,
1592        PointerDownEventListener,
1593        "Called when a pointer comes into contact with the screen (for touch pointers), or has its button pressed (for mouse pointers) at this widget's location."
1594    );
1595    pointer_listener_field!(
1596        on_pointer_move,
1597        set_on_pointer_move,
1598        PointerMoveEventListener,
1599        "Called when a pointer that triggered an `on_pointer_down` changes position."
1600    );
1601    pointer_listener_field!(
1602        on_pointer_up,
1603        set_on_pointer_up,
1604        PointerUpEventListener,
1605        "Called when a pointer that triggered an `on_pointer_down` is no longer in contact with the screen."
1606    );
1607    pointer_listener_field!(
1608        on_pointer_hover,
1609        set_on_pointer_hover,
1610        PointerHoverEventListener,
1611        "Called when a pointer that has not an `on_pointer_down` changes position."
1612    );
1613    pointer_listener_field!(
1614        on_pointer_cancel,
1615        set_on_pointer_cancel,
1616        PointerCancelEventListener,
1617        "Called when the input from a pointer that triggered an `on_pointer_down` is no longer directed towards this receiver."
1618    );
1619    pointer_listener_field!(
1620        on_pointer_pan_zoom_start,
1621        set_on_pointer_pan_zoom_start,
1622        PointerPanZoomStartEventListener,
1623        "Called when a pan/zoom begins such as from a trackpad gesture."
1624    );
1625    pointer_listener_field!(
1626        on_pointer_pan_zoom_update,
1627        set_on_pointer_pan_zoom_update,
1628        PointerPanZoomUpdateEventListener,
1629        "Called when a pan/zoom is updated."
1630    );
1631    pointer_listener_field!(
1632        on_pointer_pan_zoom_end,
1633        set_on_pointer_pan_zoom_end,
1634        PointerPanZoomEndEventListener,
1635        "Called when a pan/zoom finishes."
1636    );
1637    pointer_listener_field!(
1638        on_pointer_signal,
1639        set_on_pointer_signal,
1640        PointerSignalEventListener,
1641        "Called when a pointer signal occurs over this object."
1642    );
1643
1644    /// Sets [`behavior`](RenderProxyBoxWithHitTestBehavior::behavior).
1645    pub fn set_behavior(self: RenderHandle<Self>, app: &mut App, value: HitTestBehavior) {
1646        self.get_mut(app).behavior = value;
1647    }
1648}
1649
1650impl RenderObjectWithChildMixin for RenderPointerListener {
1651    type ChildType = AnyRenderBox;
1652
1653    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1654        &self.get(app).child
1655    }
1656
1657    fn child_data_mut(
1658        self: RenderHandle<Self>,
1659        app: &mut App,
1660    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1661        &mut self.get_mut(app).child
1662    }
1663}
1664
1665impl RenderProxyBoxMixin for RenderPointerListener {
1666    fn compute_size_for_no_child(
1667        self: RenderHandle<Self>,
1668        _app: &App,
1669        constraints: BoxConstraints,
1670    ) -> Size {
1671        constraints.biggest()
1672    }
1673}
1674
1675impl RenderProxyBoxWithHitTestBehavior for RenderPointerListener {
1676    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
1677        self.get(app).behavior
1678    }
1679}
1680
1681impl RenderObject for RenderPointerListener {
1682    crate::render_object_accessors!();
1683
1684    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1685        RenderProxyBoxMixin::perform_layout(self, app);
1686    }
1687
1688    fn paint(
1689        self: RenderHandle<Self>,
1690        app: &mut App,
1691        context: &mut PaintingContext,
1692        offset: Offset,
1693    ) {
1694        RenderProxyBoxMixin::paint(self, app, context, offset);
1695    }
1696
1697    fn visit_children(
1698        self: RenderHandle<Self>,
1699        app: &App,
1700        visitor: &mut dyn FnMut(AnyRenderObject),
1701    ) {
1702        if let Some(child) = self.child(app) {
1703            visitor(child.as_object());
1704        }
1705    }
1706}
1707
1708impl RenderBox for RenderPointerListener {
1709    crate::render_box_accessors!();
1710
1711    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1712        RenderProxyBoxMixin::setup_parent_data(self, app, child);
1713    }
1714
1715    fn apply_paint_transform(
1716        self: RenderHandle<Self>,
1717        app: &App,
1718        child: AnyRenderObject,
1719        transform: &mut Matrix4,
1720    ) {
1721        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
1722    }
1723
1724    fn handle_event(
1725        self: RenderHandle<Self>,
1726        app: &mut App,
1727        event: &PointerEvent,
1728        _entry: &BoxHitTestEntry,
1729    ) {
1730        match event {
1731            PointerEvent::Down(event) => {
1732                if let Some(callback) = self.get(app).on_pointer_down.clone() {
1733                    callback(app, event.clone());
1734                }
1735            }
1736            PointerEvent::Move(event) => {
1737                if let Some(callback) = self.get(app).on_pointer_move.clone() {
1738                    callback(app, event.clone());
1739                }
1740            }
1741            PointerEvent::Up(event) => {
1742                if let Some(callback) = self.get(app).on_pointer_up.clone() {
1743                    callback(app, event.clone());
1744                }
1745            }
1746            PointerEvent::Hover(event) => {
1747                if let Some(callback) = self.get(app).on_pointer_hover.clone() {
1748                    callback(app, event.clone());
1749                }
1750            }
1751            PointerEvent::Cancel(event) => {
1752                if let Some(callback) = self.get(app).on_pointer_cancel.clone() {
1753                    callback(app, event.clone());
1754                }
1755            }
1756            PointerEvent::PanZoomStart(event) => {
1757                if let Some(callback) = self.get(app).on_pointer_pan_zoom_start.clone() {
1758                    callback(app, event.clone());
1759                }
1760            }
1761            PointerEvent::PanZoomUpdate(event) => {
1762                if let Some(callback) = self.get(app).on_pointer_pan_zoom_update.clone() {
1763                    callback(app, event.clone());
1764                }
1765            }
1766            PointerEvent::PanZoomEnd(event) => {
1767                if let Some(callback) = self.get(app).on_pointer_pan_zoom_end.clone() {
1768                    callback(app, event.clone());
1769                }
1770            }
1771            PointerEvent::Scroll(_)
1772            | PointerEvent::ScrollInertiaCancel(_)
1773            | PointerEvent::Scale(_) => {
1774                if let Some(callback) = self.get(app).on_pointer_signal.clone() {
1775                    callback(app, event.clone());
1776                }
1777            }
1778            PointerEvent::Added(_)
1779            | PointerEvent::Removed(_)
1780            | PointerEvent::Enter(_)
1781            | PointerEvent::Exit(_) => {}
1782        }
1783    }
1784
1785    fn hit_test(
1786        self: RenderHandle<Self>,
1787        app: &mut App,
1788        result: &mut BoxHitTestResult<'_>,
1789        position: Offset,
1790    ) -> bool {
1791        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
1792    }
1793
1794    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
1795        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
1796    }
1797
1798    fn hit_test_children(
1799        self: RenderHandle<Self>,
1800        app: &mut App,
1801        result: &mut BoxHitTestResult<'_>,
1802        position: Offset,
1803    ) -> bool {
1804        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
1805    }
1806
1807    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1808        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
1809    }
1810
1811    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
1812        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
1813    }
1814
1815    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1816        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
1817    }
1818
1819    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
1820        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
1821    }
1822
1823    fn compute_distance_to_actual_baseline(
1824        self: RenderHandle<Self>,
1825        app: &mut App,
1826        baseline: TextBaseline,
1827    ) -> Option<f64> {
1828        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
1829    }
1830
1831    fn compute_dry_baseline(
1832        self: RenderHandle<Self>,
1833        app: &mut App,
1834        constraints: BoxConstraints,
1835        baseline: TextBaseline,
1836    ) -> Option<f64> {
1837        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
1838    }
1839
1840    fn compute_dry_layout(
1841        self: RenderHandle<Self>,
1842        app: &mut App,
1843        constraints: BoxConstraints,
1844    ) -> Size {
1845        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
1846    }
1847}
1848
1849/// Where to paint a box decoration.
1850#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1851pub enum DecorationPosition {
1852    /// Paint the box decoration behind the children.
1853    Background,
1854
1855    /// Paint the box decoration in front of the children.
1856    Foreground,
1857}
1858
1859/// Paints a [`Decoration`] either before or after its child paints.
1860pub struct RenderDecoratedBox {
1861    render_object: RenderObjectData,
1862    render_box: RenderBoxData,
1863    child: RenderObjectWithChildData<AnyRenderBox>,
1864    painter: Option<Box<dyn BoxPainter>>,
1865    decoration: Box<dyn Decoration>,
1866    position: DecorationPosition,
1867    configuration: ImageConfiguration,
1868}
1869
1870impl RenderDecoratedBox {
1871    /// Creates a decorated box.
1872    ///
1873    /// The `configuration` is normally obtained from `createLocalImageConfiguration`.
1874    pub fn new(
1875        app: &mut App,
1876        decoration: Box<dyn Decoration>,
1877        position: DecorationPosition,
1878        configuration: ImageConfiguration,
1879        child: Option<AnyRenderBox>,
1880    ) -> RenderHandle<Self> {
1881        let this = RenderHandle::new_box(
1882            app,
1883            RenderDecoratedBox {
1884                render_object: RenderObjectData::new(),
1885                render_box: RenderBoxData::new(),
1886                child: RenderObjectWithChildData::new(),
1887                painter: None,
1888                decoration,
1889                position,
1890                configuration,
1891            },
1892        );
1893        this.set_child(app, child);
1894        this
1895    }
1896
1897    /// What decoration to paint.
1898    pub fn decoration(self: RenderHandle<Self>, app: &App) -> &dyn Decoration {
1899        &*self.get(app).decoration
1900    }
1901
1902    /// Sets [`decoration`](Self::decoration).
1903    pub fn set_decoration(self: RenderHandle<Self>, app: &mut App, value: Box<dyn Decoration>) {
1904        if value.eq_decoration(&*self.get(app).decoration) {
1905            return;
1906        }
1907        let this = self.get_mut(app);
1908        if let Some(mut painter) = this.painter.take() {
1909            painter.dispose();
1910        }
1911        this.decoration = value;
1912        self.mark_needs_paint(app);
1913    }
1914
1915    /// Whether to paint the box decoration behind or in front of the child.
1916    pub fn position(self: RenderHandle<Self>, app: &App) -> DecorationPosition {
1917        self.get(app).position
1918    }
1919
1920    /// Sets [`position`](Self::position).
1921    pub fn set_position(self: RenderHandle<Self>, app: &mut App, value: DecorationPosition) {
1922        if self.get(app).position == value {
1923            return;
1924        }
1925        self.get_mut(app).position = value;
1926        self.mark_needs_paint(app);
1927    }
1928
1929    /// The settings to pass to the decoration when painting, so that it can
1930    /// resolve images appropriately. See [`ImageConfiguration`].
1931    pub fn configuration(self: RenderHandle<Self>, app: &App) -> &ImageConfiguration {
1932        &self.get(app).configuration
1933    }
1934
1935    /// Sets [`configuration`](Self::configuration).
1936    pub fn set_configuration(self: RenderHandle<Self>, app: &mut App, value: ImageConfiguration) {
1937        if self.get(app).configuration == value {
1938            return;
1939        }
1940        self.get_mut(app).configuration = value;
1941        self.mark_needs_paint(app);
1942    }
1943
1944    fn paint_decoration(
1945        self: RenderHandle<Self>,
1946        app: &mut App,
1947        context: &mut PaintingContext,
1948        offset: Offset,
1949        configuration: &ImageConfiguration,
1950    ) {
1951        let debug_save_count = context.canvas().save_count();
1952        let is_complex = {
1953            let this = self.get_mut(app);
1954            let painter = this.painter.get_or_insert_with(|| {
1955                this.decoration
1956                    .create_box_painter(Some(Rc::new(move |app| self.mark_needs_paint(app))))
1957            });
1958            painter.paint(context.canvas(), offset, configuration);
1959            this.decoration.is_complex()
1960        };
1961        debug_assert_eq!(
1962            debug_save_count,
1963            context.canvas().save_count(),
1964            "the decoration's painter had mismatching save and restore calls"
1965        );
1966        if is_complex {
1967            context.set_is_complex_hint();
1968        }
1969    }
1970}
1971
1972impl RenderObjectWithChildMixin for RenderDecoratedBox {
1973    type ChildType = AnyRenderBox;
1974
1975    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1976        &self.get(app).child
1977    }
1978
1979    fn child_data_mut(
1980        self: RenderHandle<Self>,
1981        app: &mut App,
1982    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1983        &mut self.get_mut(app).child
1984    }
1985}
1986
1987impl RenderProxyBoxMixin for RenderDecoratedBox {}
1988
1989impl RenderObject for RenderDecoratedBox {
1990    crate::render_object_accessors!();
1991
1992    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
1993        if let Some(mut painter) = self.get_mut(app).painter.take() {
1994            painter.dispose();
1995        }
1996        if let Some(child) = self.child(app) {
1997            child.as_object().detach(app);
1998        }
1999        self.mark_needs_paint(app);
2000    }
2001
2002    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2003        RenderProxyBoxMixin::perform_layout(self, app);
2004    }
2005
2006    fn paint(
2007        self: RenderHandle<Self>,
2008        app: &mut App,
2009        context: &mut PaintingContext,
2010        offset: Offset,
2011    ) {
2012        let size = self.size(app);
2013        let filled_configuration =
2014            self.get(app)
2015                .configuration
2016                .copy_with(None, None, None, None, Some(size), None);
2017        if self.get(app).position == DecorationPosition::Background {
2018            self.paint_decoration(app, context, offset, &filled_configuration);
2019        }
2020        RenderProxyBoxMixin::paint(self, app, context, offset);
2021        if self.get(app).position == DecorationPosition::Foreground {
2022            self.paint_decoration(app, context, offset, &filled_configuration);
2023        }
2024    }
2025
2026    fn visit_children(
2027        self: RenderHandle<Self>,
2028        app: &App,
2029        visitor: &mut dyn FnMut(AnyRenderObject),
2030    ) {
2031        if let Some(child) = self.child(app) {
2032            visitor(child.as_object());
2033        }
2034    }
2035}
2036
2037impl RenderBox for RenderDecoratedBox {
2038    crate::render_box_accessors!();
2039
2040    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
2041        let this = self.get(app);
2042        this.decoration
2043            .hit_test(self.size(app), position, this.configuration.text_direction)
2044    }
2045
2046    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2047        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2048    }
2049
2050    fn apply_paint_transform(
2051        self: RenderHandle<Self>,
2052        app: &App,
2053        child: AnyRenderObject,
2054        transform: &mut Matrix4,
2055    ) {
2056        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2057    }
2058
2059    fn hit_test_children(
2060        self: RenderHandle<Self>,
2061        app: &mut App,
2062        result: &mut BoxHitTestResult<'_>,
2063        position: Offset,
2064    ) -> bool {
2065        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2066    }
2067
2068    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2069        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2070    }
2071
2072    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2073        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2074    }
2075
2076    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2077        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2078    }
2079
2080    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2081        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2082    }
2083
2084    fn compute_distance_to_actual_baseline(
2085        self: RenderHandle<Self>,
2086        app: &mut App,
2087        baseline: TextBaseline,
2088    ) -> Option<f64> {
2089        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2090    }
2091
2092    fn compute_dry_baseline(
2093        self: RenderHandle<Self>,
2094        app: &mut App,
2095        constraints: BoxConstraints,
2096        baseline: TextBaseline,
2097    ) -> Option<f64> {
2098        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2099    }
2100
2101    fn compute_dry_layout(
2102        self: RenderHandle<Self>,
2103        app: &mut App,
2104        constraints: BoxConstraints,
2105    ) -> Size {
2106        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
2107    }
2108}
2109
2110/// Creates a separate display list for its child.
2111///
2112/// This render object creates a separate display list for its child, which
2113/// can improve performance if the subtree repaints at different times than
2114/// the surrounding parts of the tree.
2115pub struct RenderRepaintBoundary {
2116    render_object: RenderObjectData,
2117    render_box: RenderBoxData,
2118    child: RenderObjectWithChildData<AnyRenderBox>,
2119}
2120
2121impl RenderRepaintBoundary {
2122    /// Creates a repaint boundary around `child`.
2123    pub fn new(app: &mut App, child: Option<AnyRenderBox>) -> RenderHandle<Self> {
2124        let this = RenderHandle::new_box(
2125            app,
2126            RenderRepaintBoundary {
2127                render_object: RenderObjectData::new(),
2128                render_box: RenderBoxData::new(),
2129                child: RenderObjectWithChildData::new(),
2130            },
2131        );
2132        this.set_child(app, child);
2133        this
2134    }
2135}
2136
2137impl RenderObjectWithChildMixin for RenderRepaintBoundary {
2138    type ChildType = AnyRenderBox;
2139
2140    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2141        &self.get(app).child
2142    }
2143
2144    fn child_data_mut(
2145        self: RenderHandle<Self>,
2146        app: &mut App,
2147    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2148        &mut self.get_mut(app).child
2149    }
2150}
2151
2152impl RenderProxyBoxMixin for RenderRepaintBoundary {}
2153
2154impl RenderObject for RenderRepaintBoundary {
2155    crate::render_object_accessors!();
2156
2157    fn is_repaint_boundary(self: RenderHandle<Self>, _app: &App) -> bool {
2158        true
2159    }
2160
2161    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2162        RenderProxyBoxMixin::perform_layout(self, app);
2163    }
2164
2165    fn paint(
2166        self: RenderHandle<Self>,
2167        app: &mut App,
2168        context: &mut PaintingContext,
2169        offset: Offset,
2170    ) {
2171        RenderProxyBoxMixin::paint(self, app, context, offset);
2172    }
2173
2174    fn visit_children(
2175        self: RenderHandle<Self>,
2176        app: &App,
2177        visitor: &mut dyn FnMut(AnyRenderObject),
2178    ) {
2179        if let Some(child) = self.child(app) {
2180            visitor(child.as_object());
2181        }
2182    }
2183}
2184
2185impl RenderBox for RenderRepaintBoundary {
2186    crate::render_box_accessors!();
2187
2188    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2189        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2190    }
2191
2192    fn apply_paint_transform(
2193        self: RenderHandle<Self>,
2194        app: &App,
2195        child: AnyRenderObject,
2196        transform: &mut Matrix4,
2197    ) {
2198        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2199    }
2200
2201    fn hit_test_children(
2202        self: RenderHandle<Self>,
2203        app: &mut App,
2204        result: &mut BoxHitTestResult<'_>,
2205        position: Offset,
2206    ) -> bool {
2207        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2208    }
2209
2210    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2211        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2212    }
2213
2214    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2215        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2216    }
2217
2218    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2219        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2220    }
2221
2222    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2223        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2224    }
2225
2226    fn compute_distance_to_actual_baseline(
2227        self: RenderHandle<Self>,
2228        app: &mut App,
2229        baseline: TextBaseline,
2230    ) -> Option<f64> {
2231        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2232    }
2233
2234    fn compute_dry_baseline(
2235        self: RenderHandle<Self>,
2236        app: &mut App,
2237        constraints: BoxConstraints,
2238        baseline: TextBaseline,
2239    ) -> Option<f64> {
2240        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2241    }
2242
2243    fn compute_dry_layout(
2244        self: RenderHandle<Self>,
2245        app: &mut App,
2246        constraints: BoxConstraints,
2247    ) -> Size {
2248        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
2249    }
2250}
2251
2252/// Calls callbacks in response to pointer events that are exclusive to mice.
2253///
2254/// It responds to events that are related to hovering, i.e. when the mouse
2255/// enters, exits (with or without pressing buttons), or moves over a region
2256/// without pressing buttons.
2257///
2258/// It does not respond to common events that construct gestures, such as when
2259/// the pointer is pressed, moved, then released or canceled. For these events,
2260/// use [`RenderPointerListener`].
2261///
2262/// If it has a child, it defers to the child for sizing behavior.
2263///
2264/// If it does not have a child, it grows to fit the parent-provided constraints.
2265///
2266/// Flutter's `RenderMouseRegion implements MouseTrackerAnnotation`: here it answers
2267/// [`RenderObject::mouse_tracker_annotation`] with its current callbacks, cursor, and validity.
2268///
2269/// See also:
2270///
2271///  * `MouseRegion`, a widget that listens to hover events using
2272///    [`RenderMouseRegion`].
2273pub struct RenderMouseRegion {
2274    render_object: RenderObjectData,
2275    render_box: RenderBoxData,
2276    child: RenderObjectWithChildData<AnyRenderBox>,
2277    on_enter: Option<PointerEnterEventListener>,
2278    on_hover: Option<PointerHoverEventListener>,
2279    on_exit: Option<PointerExitEventListener>,
2280    cursor: MouseCursorRef,
2281    valid_for_mouse_tracker: bool,
2282    opaque: bool,
2283    behavior: HitTestBehavior,
2284}
2285
2286impl RenderMouseRegion {
2287    /// Creates a render object that forwards pointer events to callbacks.
2288    ///
2289    /// Dart's remaining constructor arguments have setters: the callbacks, `cursor`
2290    /// (`MouseCursor.defer`), `opaque` (true), and `hit_test_behavior` (opaque).
2291    /// `valid_for_mouse_tracker` has none, so it is a parameter (Dart's default is true).
2292    pub fn new(
2293        app: &mut App,
2294        valid_for_mouse_tracker: bool,
2295        child: Option<AnyRenderBox>,
2296    ) -> RenderHandle<Self> {
2297        let this = RenderHandle::new_box(
2298            app,
2299            RenderMouseRegion {
2300                render_object: RenderObjectData::new(),
2301                render_box: RenderBoxData::new(),
2302                child: RenderObjectWithChildData::new(),
2303                on_enter: None,
2304                on_hover: None,
2305                on_exit: None,
2306                cursor: <dyn MouseCursor>::defer(),
2307                valid_for_mouse_tracker,
2308                opaque: true,
2309                behavior: HitTestBehavior::Opaque,
2310            },
2311        );
2312        this.set_child(app, child);
2313        this
2314    }
2315
2316    /// Whether this object should prevent [`RenderMouseRegion`]s visually behind it
2317    /// from detecting the pointer, thus affecting how their `on_hover`, `on_enter`,
2318    /// and `on_exit` behave.
2319    ///
2320    /// If `opaque` is true, this object will absorb the mouse pointer and
2321    /// prevent this object's siblings (or any other objects that are not
2322    /// ancestors or descendants of this object) from detecting the mouse
2323    /// pointer even when the pointer is within their areas.
2324    ///
2325    /// If `opaque` is false, this object will not affect how [`RenderMouseRegion`]s
2326    /// behind it behave, which will detect the mouse pointer as long as the
2327    /// pointer is within their areas.
2328    ///
2329    /// This defaults to true.
2330    pub fn opaque(self: RenderHandle<Self>, app: &App) -> bool {
2331        self.get(app).opaque
2332    }
2333
2334    /// Sets [`opaque`](Self::opaque).
2335    pub fn set_opaque(self: RenderHandle<Self>, app: &mut App, value: bool) {
2336        if self.get(app).opaque != value {
2337            self.get_mut(app).opaque = value;
2338            // Trigger [MouseTracker]'s device update to recalculate mouse states.
2339            self.mark_needs_paint(app);
2340        }
2341    }
2342
2343    /// How to behave during hit testing.
2344    ///
2345    /// This defaults to [`HitTestBehavior::Opaque`] if `None`.
2346    pub fn hit_test_behavior(self: RenderHandle<Self>, app: &App) -> Option<HitTestBehavior> {
2347        Some(self.get(app).behavior)
2348    }
2349
2350    /// Sets [`hit_test_behavior`](Self::hit_test_behavior).
2351    pub fn set_hit_test_behavior(
2352        self: RenderHandle<Self>,
2353        app: &mut App,
2354        value: Option<HitTestBehavior>,
2355    ) {
2356        let new_value = value.unwrap_or(HitTestBehavior::Opaque);
2357        if self.get(app).behavior != new_value {
2358            self.get_mut(app).behavior = new_value;
2359            // Trigger [MouseTracker]'s device update to recalculate mouse states.
2360            self.mark_needs_paint(app);
2361        }
2362    }
2363
2364    pointer_listener_field!(
2365        on_enter,
2366        set_on_enter,
2367        PointerEnterEventListener,
2368        "Triggered when a mouse pointer, with or without buttons pressed, has entered the region and `valid_for_mouse_tracker` is true."
2369    );
2370    pointer_listener_field!(
2371        on_hover,
2372        set_on_hover,
2373        PointerHoverEventListener,
2374        "Triggered when a pointer has moved onto or within the region without buttons pressed."
2375    );
2376    pointer_listener_field!(
2377        on_exit,
2378        set_on_exit,
2379        PointerExitEventListener,
2380        "Triggered when a mouse pointer, with or without buttons pressed, has exited the region and `valid_for_mouse_tracker` is true."
2381    );
2382
2383    /// The mouse cursor for mouse pointers that are hovering over the region.
2384    ///
2385    /// When a mouse enters the region, its cursor will be changed to the `cursor`.
2386    /// When the mouse leaves the region, the cursor will be set by the region
2387    /// found at the new location.
2388    ///
2389    /// Defaults to `MouseCursor.defer`, deferring the choice of cursor to the next
2390    /// region behind it in hit-test order.
2391    pub fn cursor(self: RenderHandle<Self>, app: &App) -> MouseCursorRef {
2392        Rc::clone(&self.get(app).cursor)
2393    }
2394
2395    /// Sets [`cursor`](Self::cursor).
2396    pub fn set_cursor(self: RenderHandle<Self>, app: &mut App, value: MouseCursorRef) {
2397        if *self.get(app).cursor != *value {
2398            self.get_mut(app).cursor = value;
2399            // A repaint is needed in order to trigger a device update of
2400            // [MouseTracker] so that this new value can be found.
2401            self.mark_needs_paint(app);
2402        }
2403    }
2404
2405    /// Whether this is included when a `MouseTracker` collects the list of
2406    /// annotations: true while attached to a pipeline owner.
2407    pub fn valid_for_mouse_tracker(self: RenderHandle<Self>, app: &App) -> bool {
2408        self.get(app).valid_for_mouse_tracker
2409    }
2410}
2411
2412impl RenderObjectWithChildMixin for RenderMouseRegion {
2413    type ChildType = AnyRenderBox;
2414
2415    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2416        &self.get(app).child
2417    }
2418
2419    fn child_data_mut(
2420        self: RenderHandle<Self>,
2421        app: &mut App,
2422    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2423        &mut self.get_mut(app).child
2424    }
2425}
2426
2427impl RenderProxyBoxMixin for RenderMouseRegion {
2428    fn compute_size_for_no_child(
2429        self: RenderHandle<Self>,
2430        _app: &App,
2431        constraints: BoxConstraints,
2432    ) -> Size {
2433        constraints.biggest()
2434    }
2435}
2436
2437impl RenderProxyBoxWithHitTestBehavior for RenderMouseRegion {
2438    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
2439        self.get(app).behavior
2440    }
2441}
2442
2443impl RenderObject for RenderMouseRegion {
2444    crate::render_object_accessors!();
2445
2446    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
2447        for child in [self.child(app)].into_iter().flatten() {
2448            child.as_object().attach(app, owner);
2449        }
2450        self.get_mut(app).valid_for_mouse_tracker = true;
2451    }
2452
2453    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
2454        // Dart clears the flag before `super.detach()`; nothing in the base body reads it.
2455        self.get_mut(app).valid_for_mouse_tracker = false;
2456        for child in [self.child(app)].into_iter().flatten() {
2457            child.as_object().detach(app);
2458        }
2459    }
2460
2461    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2462        RenderProxyBoxMixin::perform_layout(self, app);
2463    }
2464
2465    fn mouse_tracker_annotation(
2466        self: RenderHandle<Self>,
2467        app: &App,
2468    ) -> Option<MouseTrackerAnnotation> {
2469        let this = self.get(app);
2470        Some(MouseTrackerAnnotation {
2471            on_enter: this.on_enter.clone(),
2472            on_exit: this.on_exit.clone(),
2473            cursor: Rc::clone(&this.cursor),
2474            valid_for_mouse_tracker: this.valid_for_mouse_tracker,
2475        })
2476    }
2477
2478    fn paint(
2479        self: RenderHandle<Self>,
2480        app: &mut App,
2481        context: &mut PaintingContext,
2482        offset: Offset,
2483    ) {
2484        RenderProxyBoxMixin::paint(self, app, context, offset);
2485    }
2486
2487    fn visit_children(
2488        self: RenderHandle<Self>,
2489        app: &App,
2490        visitor: &mut dyn FnMut(AnyRenderObject),
2491    ) {
2492        if let Some(child) = self.child(app) {
2493            visitor(child.as_object());
2494        }
2495    }
2496}
2497
2498impl RenderBox for RenderMouseRegion {
2499    crate::render_box_accessors!();
2500
2501    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2502        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2503    }
2504
2505    fn apply_paint_transform(
2506        self: RenderHandle<Self>,
2507        app: &App,
2508        child: AnyRenderObject,
2509        transform: &mut Matrix4,
2510    ) {
2511        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2512    }
2513
2514    fn hit_test(
2515        self: RenderHandle<Self>,
2516        app: &mut App,
2517        result: &mut BoxHitTestResult<'_>,
2518        position: Offset,
2519    ) -> bool {
2520        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
2521            && self.get(app).opaque
2522    }
2523
2524    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
2525        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
2526    }
2527
2528    fn hit_test_children(
2529        self: RenderHandle<Self>,
2530        app: &mut App,
2531        result: &mut BoxHitTestResult<'_>,
2532        position: Offset,
2533    ) -> bool {
2534        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2535    }
2536
2537    fn handle_event(
2538        self: RenderHandle<Self>,
2539        app: &mut App,
2540        event: &PointerEvent,
2541        _entry: &BoxHitTestEntry,
2542    ) {
2543        if let PointerEvent::Hover(event) = event
2544            && let Some(on_hover) = self.get(app).on_hover.clone()
2545        {
2546            on_hover(app, event.clone());
2547        }
2548    }
2549
2550    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2551        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2552    }
2553
2554    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2555        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2556    }
2557
2558    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2559        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2560    }
2561
2562    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2563        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2564    }
2565
2566    fn compute_distance_to_actual_baseline(
2567        self: RenderHandle<Self>,
2568        app: &mut App,
2569        baseline: TextBaseline,
2570    ) -> Option<f64> {
2571        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2572    }
2573
2574    fn compute_dry_baseline(
2575        self: RenderHandle<Self>,
2576        app: &mut App,
2577        constraints: BoxConstraints,
2578        baseline: TextBaseline,
2579    ) -> Option<f64> {
2580        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2581    }
2582
2583    fn compute_dry_layout(
2584        self: RenderHandle<Self>,
2585        app: &mut App,
2586        constraints: BoxConstraints,
2587    ) -> Size {
2588        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
2589    }
2590}
2591
2592/// Dart's `a == b` for two objects that do not override `==`: the same instance.
2593pub(crate) fn same_instance<T: ?Sized>(a: Option<&Rc<T>>, b: Option<&Rc<T>>) -> bool {
2594    match (a, b) {
2595        (None, None) => true,
2596        (Some(a), Some(b)) => Rc::ptr_eq(a, b),
2597        _ => false,
2598    }
2599}
2600
2601/// Constrains the child's [`BoxConstraints::max_width`] and [`BoxConstraints::max_height`] if
2602/// they're otherwise unconstrained.
2603///
2604/// This has the effect of giving the child a natural dimension in unbounded
2605/// environments. For example, by providing a [`max_height`](Self::max_height) to a widget that
2606/// normally tries to be as big as possible, the widget will normally size
2607/// itself to fit its parent, but when placed in a vertical list, it will take
2608/// on the given height.
2609///
2610/// This is useful when composing widgets that normally try to match their
2611/// parents' size, so that they behave reasonably in lists (which are
2612/// unbounded).
2613pub struct RenderLimitedBox {
2614    render_object: RenderObjectData,
2615    render_box: RenderBoxData,
2616    child: RenderObjectWithChildData<AnyRenderBox>,
2617    max_width: f64,
2618    max_height: f64,
2619}
2620
2621impl RenderLimitedBox {
2622    /// Creates a render box that imposes a maximum width or maximum height on its
2623    /// child if the child is otherwise unconstrained.
2624    ///
2625    /// The `max_width` and `max_height` arguments must be non-negative.
2626    pub fn new(
2627        app: &mut App,
2628        max_width: f64,
2629        max_height: f64,
2630        child: Option<AnyRenderBox>,
2631    ) -> RenderHandle<RenderLimitedBox> {
2632        debug_assert!(max_width >= 0.0);
2633        debug_assert!(max_height >= 0.0);
2634        let this = RenderHandle::new_box(
2635            app,
2636            RenderLimitedBox {
2637                render_object: RenderObjectData::new(),
2638                render_box: RenderBoxData::new(),
2639                child: RenderObjectWithChildData::new(),
2640                max_width,
2641                max_height,
2642            },
2643        );
2644        this.set_child(app, child);
2645        this
2646    }
2647
2648    /// The value to use for `max_width` if the incoming `max_width` constraint is infinite.
2649    pub fn max_width(self: RenderHandle<Self>, app: &App) -> f64 {
2650        self.get(app).max_width
2651    }
2652
2653    /// Sets [`max_width`](Self::max_width).
2654    pub fn set_max_width(self: RenderHandle<Self>, app: &mut App, value: f64) {
2655        debug_assert!(value >= 0.0);
2656        if self.get(app).max_width == value {
2657            return;
2658        }
2659        self.get_mut(app).max_width = value;
2660        self.mark_needs_layout(app);
2661    }
2662
2663    /// The value to use for `max_height` if the incoming `max_height` constraint is infinite.
2664    pub fn max_height(self: RenderHandle<Self>, app: &App) -> f64 {
2665        self.get(app).max_height
2666    }
2667
2668    /// Sets [`max_height`](Self::max_height).
2669    pub fn set_max_height(self: RenderHandle<Self>, app: &mut App, value: f64) {
2670        debug_assert!(value >= 0.0);
2671        if self.get(app).max_height == value {
2672            return;
2673        }
2674        self.get_mut(app).max_height = value;
2675        self.mark_needs_layout(app);
2676    }
2677
2678    /// Flutter's `_computeSize`.
2679    fn compute_size(
2680        self: RenderHandle<Self>,
2681        app: &mut App,
2682        constraints: BoxConstraints,
2683        layout_child: ChildLayouter,
2684    ) -> Size {
2685        let limited = self.limit_constraints(app, constraints);
2686        match self.child(app) {
2687            Some(child) => constraints.constrain(layout_child(app, child, limited)),
2688            None => limited.constrain(Size::ZERO),
2689        }
2690    }
2691
2692    fn limit_constraints(
2693        self: RenderHandle<Self>,
2694        app: &App,
2695        constraints: BoxConstraints,
2696    ) -> BoxConstraints {
2697        let this = self.get(app);
2698        BoxConstraints::new()
2699            .min_width(constraints.min_width)
2700            .max_width(if constraints.has_bounded_width() {
2701                constraints.max_width
2702            } else {
2703                constraints.constrain_width(this.max_width)
2704            })
2705            .min_height(constraints.min_height)
2706            .max_height(if constraints.has_bounded_height() {
2707                constraints.max_height
2708            } else {
2709                constraints.constrain_height(this.max_height)
2710            })
2711    }
2712}
2713
2714impl RenderObjectWithChildMixin for RenderLimitedBox {
2715    type ChildType = AnyRenderBox;
2716
2717    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2718        &self.get(app).child
2719    }
2720
2721    fn child_data_mut(
2722        self: RenderHandle<Self>,
2723        app: &mut App,
2724    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2725        &mut self.get_mut(app).child
2726    }
2727}
2728
2729impl RenderProxyBoxMixin for RenderLimitedBox {}
2730
2731impl RenderObject for RenderLimitedBox {
2732    crate::render_object_accessors!();
2733
2734    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2735        let constraints = self.constraints(app);
2736        let size = self.compute_size(app, constraints, ChildLayoutHelper::layout_child);
2737        self.set_size(app, size);
2738    }
2739
2740    fn paint(
2741        self: RenderHandle<Self>,
2742        app: &mut App,
2743        context: &mut PaintingContext,
2744        offset: Offset,
2745    ) {
2746        RenderProxyBoxMixin::paint(self, app, context, offset);
2747    }
2748
2749    fn visit_children(
2750        self: RenderHandle<Self>,
2751        app: &App,
2752        visitor: &mut dyn FnMut(AnyRenderObject),
2753    ) {
2754        if let Some(child) = self.child(app) {
2755            visitor(child.as_object());
2756        }
2757    }
2758}
2759
2760impl RenderBox for RenderLimitedBox {
2761    crate::render_box_accessors!();
2762
2763    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2764        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2765    }
2766
2767    fn apply_paint_transform(
2768        self: RenderHandle<Self>,
2769        app: &App,
2770        child: AnyRenderObject,
2771        transform: &mut Matrix4,
2772    ) {
2773        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2774    }
2775
2776    fn hit_test_children(
2777        self: RenderHandle<Self>,
2778        app: &mut App,
2779        result: &mut BoxHitTestResult<'_>,
2780        position: Offset,
2781    ) -> bool {
2782        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2783    }
2784
2785    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2786        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2787    }
2788
2789    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2790        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2791    }
2792
2793    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2794        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2795    }
2796
2797    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2798        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2799    }
2800
2801    fn compute_distance_to_actual_baseline(
2802        self: RenderHandle<Self>,
2803        app: &mut App,
2804        baseline: TextBaseline,
2805    ) -> Option<f64> {
2806        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2807    }
2808
2809    fn compute_dry_baseline(
2810        self: RenderHandle<Self>,
2811        app: &mut App,
2812        constraints: BoxConstraints,
2813        baseline: TextBaseline,
2814    ) -> Option<f64> {
2815        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2816    }
2817
2818    fn compute_dry_layout(
2819        self: RenderHandle<Self>,
2820        app: &mut App,
2821        constraints: BoxConstraints,
2822    ) -> Size {
2823        self.compute_size(app, constraints, ChildLayoutHelper::dry_layout_child)
2824    }
2825}
2826
2827/// Attempts to size the child to a specific aspect ratio.
2828///
2829/// The render object first tries the largest width permitted by the layout constraints. The
2830/// height of the render object is determined by applying the given aspect ratio to the width,
2831/// expressed as a ratio of width to height.
2832///
2833/// For example, a 16:9 width:height aspect ratio would have a value of 16.0/9.0. If the maximum
2834/// width is infinite, the initial width is determined by applying the aspect ratio to the maximum
2835/// height.
2836///
2837/// Now consider a second example, this time with an aspect ratio of 2.0 and layout constraints
2838/// that require the width to be between 0.0 and 100.0 and the height to be between 0.0 and 100.0.
2839/// The largest width permitted is 100.0, and applying the ratio gives a height of 50.0.
2840pub struct RenderAspectRatio {
2841    render_object: RenderObjectData,
2842    render_box: RenderBoxData,
2843    child: RenderObjectWithChildData<AnyRenderBox>,
2844    aspect_ratio: f64,
2845}
2846
2847impl RenderAspectRatio {
2848    /// Creates a render object with a specific aspect ratio.
2849    ///
2850    /// The `aspect_ratio` argument must be a finite, positive value.
2851    pub fn new(
2852        app: &mut App,
2853        aspect_ratio: f64,
2854        child: Option<AnyRenderBox>,
2855    ) -> RenderHandle<RenderAspectRatio> {
2856        debug_assert!(aspect_ratio > 0.0);
2857        debug_assert!(aspect_ratio.is_finite());
2858        let this = RenderHandle::new_box(
2859            app,
2860            RenderAspectRatio {
2861                render_object: RenderObjectData::new(),
2862                render_box: RenderBoxData::new(),
2863                child: RenderObjectWithChildData::new(),
2864                aspect_ratio,
2865            },
2866        );
2867        this.set_child(app, child);
2868        this
2869    }
2870
2871    /// The aspect ratio to attempt to use.
2872    ///
2873    /// The aspect ratio is expressed as a ratio of width to height. For example, a 16:9
2874    /// width:height aspect ratio would have a value of 16.0/9.0.
2875    pub fn aspect_ratio(self: RenderHandle<Self>, app: &App) -> f64 {
2876        self.get(app).aspect_ratio
2877    }
2878
2879    /// Sets [`aspect_ratio`](Self::aspect_ratio).
2880    pub fn set_aspect_ratio(self: RenderHandle<Self>, app: &mut App, value: f64) {
2881        debug_assert!(value > 0.0);
2882        debug_assert!(value.is_finite());
2883        if self.get(app).aspect_ratio == value {
2884            return;
2885        }
2886        self.get_mut(app).aspect_ratio = value;
2887        self.mark_needs_layout(app);
2888    }
2889
2890    fn apply_aspect_ratio(
2891        self: RenderHandle<Self>,
2892        app: &App,
2893        constraints: BoxConstraints,
2894    ) -> Size {
2895        debug_assert!(constraints.debug_assert_is_valid(false));
2896        let aspect_ratio = self.get(app).aspect_ratio;
2897        debug_assert!(
2898            constraints.has_bounded_width() || constraints.has_bounded_height(),
2899            "{} has unbounded constraints.\n\
2900             This render object was given an aspect ratio of {aspect_ratio} but was given both \
2901             unbounded width and unbounded height constraints. Because both constraints were \
2902             unbounded, this render object doesn't know how much size to consume.",
2903            std::any::type_name::<Self>()
2904        );
2905
2906        if constraints.is_tight() {
2907            return constraints.smallest();
2908        }
2909
2910        let mut width = constraints.max_width;
2911        let mut height;
2912
2913        // We default to picking the height based on the width, but if the width would be
2914        // infinite, that's not sensible so we try to infer the height from the width.
2915        if width.is_finite() {
2916            height = width / aspect_ratio;
2917        } else {
2918            height = constraints.max_height;
2919            width = height * aspect_ratio;
2920        }
2921
2922        // We iteratively attempt to fit within the given constraints while maintaining the given
2923        // aspect ratio. The order of applying the constraints is also biased towards inferring
2924        // the height from the width.
2925
2926        if width > constraints.max_width {
2927            width = constraints.max_width;
2928            height = width / aspect_ratio;
2929        }
2930
2931        if height > constraints.max_height {
2932            height = constraints.max_height;
2933            width = height * aspect_ratio;
2934        }
2935
2936        if width < constraints.min_width {
2937            width = constraints.min_width;
2938            height = width / aspect_ratio;
2939        }
2940
2941        if height < constraints.min_height {
2942            height = constraints.min_height;
2943            width = height * aspect_ratio;
2944        }
2945
2946        constraints.constrain(Size::new(width, height))
2947    }
2948}
2949
2950impl RenderObjectWithChildMixin for RenderAspectRatio {
2951    type ChildType = AnyRenderBox;
2952
2953    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2954        &self.get(app).child
2955    }
2956
2957    fn child_data_mut(
2958        self: RenderHandle<Self>,
2959        app: &mut App,
2960    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2961        &mut self.get_mut(app).child
2962    }
2963}
2964
2965impl RenderProxyBoxMixin for RenderAspectRatio {}
2966
2967impl RenderObject for RenderAspectRatio {
2968    crate::render_object_accessors!();
2969
2970    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2971        let constraints = self.constraints(app);
2972        let size = self.get_dry_layout(app, constraints);
2973        self.set_size(app, size);
2974        if let Some(child) = self.child(app) {
2975            child.layout(app, BoxConstraints::tight(size), false);
2976        }
2977    }
2978
2979    fn paint(
2980        self: RenderHandle<Self>,
2981        app: &mut App,
2982        context: &mut PaintingContext,
2983        offset: Offset,
2984    ) {
2985        RenderProxyBoxMixin::paint(self, app, context, offset);
2986    }
2987
2988    fn visit_children(
2989        self: RenderHandle<Self>,
2990        app: &App,
2991        visitor: &mut dyn FnMut(AnyRenderObject),
2992    ) {
2993        if let Some(child) = self.child(app) {
2994            visitor(child.as_object());
2995        }
2996    }
2997}
2998
2999impl RenderBox for RenderAspectRatio {
3000    crate::render_box_accessors!();
3001
3002    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3003        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3004    }
3005
3006    fn apply_paint_transform(
3007        self: RenderHandle<Self>,
3008        app: &App,
3009        child: AnyRenderObject,
3010        transform: &mut Matrix4,
3011    ) {
3012        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3013    }
3014
3015    fn hit_test_children(
3016        self: RenderHandle<Self>,
3017        app: &mut App,
3018        result: &mut BoxHitTestResult<'_>,
3019        position: Offset,
3020    ) -> bool {
3021        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
3022    }
3023
3024    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3025        if height.is_finite() {
3026            return height * self.get(app).aspect_ratio;
3027        }
3028        match self.child(app) {
3029            Some(child) => child.get_min_intrinsic_width(app, height),
3030            None => 0.0,
3031        }
3032    }
3033
3034    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3035        if height.is_finite() {
3036            return height * self.get(app).aspect_ratio;
3037        }
3038        match self.child(app) {
3039            Some(child) => child.get_max_intrinsic_width(app, height),
3040            None => 0.0,
3041        }
3042    }
3043
3044    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3045        if width.is_finite() {
3046            return width / self.get(app).aspect_ratio;
3047        }
3048        match self.child(app) {
3049            Some(child) => child.get_min_intrinsic_height(app, width),
3050            None => 0.0,
3051        }
3052    }
3053
3054    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3055        if width.is_finite() {
3056            return width / self.get(app).aspect_ratio;
3057        }
3058        match self.child(app) {
3059            Some(child) => child.get_max_intrinsic_height(app, width),
3060            None => 0.0,
3061        }
3062    }
3063
3064    fn compute_distance_to_actual_baseline(
3065        self: RenderHandle<Self>,
3066        app: &mut App,
3067        baseline: TextBaseline,
3068    ) -> Option<f64> {
3069        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
3070    }
3071
3072    fn compute_dry_layout(
3073        self: RenderHandle<Self>,
3074        app: &mut App,
3075        constraints: BoxConstraints,
3076    ) -> Size {
3077        self.apply_aspect_ratio(app, constraints)
3078    }
3079
3080    fn compute_dry_baseline(
3081        self: RenderHandle<Self>,
3082        app: &mut App,
3083        constraints: BoxConstraints,
3084        baseline: TextBaseline,
3085    ) -> Option<f64> {
3086        let size = self.get_dry_layout(app, constraints);
3087        RenderProxyBoxMixin::compute_dry_baseline(self, app, BoxConstraints::tight(size), baseline)
3088    }
3089}
3090
3091/// Sizes its child to the child's maximum intrinsic width.
3092///
3093/// This class is useful, for example, when unlimited width is available and you would like a
3094/// child that would otherwise attempt to expand infinitely to instead size itself to a more
3095/// reasonable width.
3096///
3097/// The constraints that this object passes to its child will adhere to the parent's constraints,
3098/// so if the constraints are not large enough to satisfy the child's maximum intrinsic width,
3099/// then the child will get less width than it otherwise would. Likewise, if the minimum width
3100/// constraint is larger than the child's maximum intrinsic width, the child will be given more
3101/// width than it otherwise would.
3102///
3103/// If [`step_width`](Self::step_width) is non-null, the child's width will be snapped to a
3104/// multiple of it. Similarly, if [`step_height`](Self::step_height) is non-null, the child's
3105/// height will be snapped to a multiple of it.
3106///
3107/// This class is relatively expensive, because it adds a speculative layout pass before the final
3108/// layout phase. Avoid using it where possible. In the worst case, this render object can result
3109/// in a layout that is O(N²) in the depth of the tree.
3110pub struct RenderIntrinsicWidth {
3111    render_object: RenderObjectData,
3112    render_box: RenderBoxData,
3113    child: RenderObjectWithChildData<AnyRenderBox>,
3114    step_width: Option<f64>,
3115    step_height: Option<f64>,
3116}
3117
3118/// Flutter's `RenderIntrinsicWidth._applyStep`.
3119fn apply_step(input: f64, step: Option<f64>) -> f64 {
3120    debug_assert!(input.is_finite());
3121    match step {
3122        Some(step) => (input / step).ceil() * step,
3123        None => input,
3124    }
3125}
3126
3127impl RenderIntrinsicWidth {
3128    /// Creates a render object that sizes itself to its child's intrinsic width.
3129    ///
3130    /// If `step_width` is given it must be > 0.0. Similarly if `step_height` is given it must be
3131    /// > 0.0.
3132    pub fn new(
3133        app: &mut App,
3134        step_width: Option<f64>,
3135        step_height: Option<f64>,
3136        child: Option<AnyRenderBox>,
3137    ) -> RenderHandle<RenderIntrinsicWidth> {
3138        debug_assert!(step_width.is_none_or(|step| step > 0.0));
3139        debug_assert!(step_height.is_none_or(|step| step > 0.0));
3140        let this = RenderHandle::new_box(
3141            app,
3142            RenderIntrinsicWidth {
3143                render_object: RenderObjectData::new(),
3144                render_box: RenderBoxData::new(),
3145                child: RenderObjectWithChildData::new(),
3146                step_width,
3147                step_height,
3148            },
3149        );
3150        this.set_child(app, child);
3151        this
3152    }
3153
3154    /// If non-null, force the child's width to be a multiple of this value.
3155    pub fn step_width(self: RenderHandle<Self>, app: &App) -> Option<f64> {
3156        self.get(app).step_width
3157    }
3158
3159    /// Sets [`step_width`](Self::step_width).
3160    pub fn set_step_width(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
3161        debug_assert!(value.is_none_or(|step| step > 0.0));
3162        if self.get(app).step_width == value {
3163            return;
3164        }
3165        self.get_mut(app).step_width = value;
3166        self.mark_needs_layout(app);
3167    }
3168
3169    /// If non-null, force the child's height to be a multiple of this value.
3170    pub fn step_height(self: RenderHandle<Self>, app: &App) -> Option<f64> {
3171        self.get(app).step_height
3172    }
3173
3174    /// Sets [`step_height`](Self::step_height).
3175    pub fn set_step_height(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
3176        debug_assert!(value.is_none_or(|step| step > 0.0));
3177        if self.get(app).step_height == value {
3178            return;
3179        }
3180        self.get_mut(app).step_height = value;
3181        self.mark_needs_layout(app);
3182    }
3183
3184    fn child_constraints(
3185        self: RenderHandle<Self>,
3186        app: &mut App,
3187        child: AnyRenderBox,
3188        constraints: BoxConstraints,
3189    ) -> BoxConstraints {
3190        let (step_width, step_height) = {
3191            let this = self.get(app);
3192            (this.step_width, this.step_height)
3193        };
3194        let width = if constraints.has_tight_width() {
3195            None
3196        } else {
3197            Some(apply_step(
3198                child.get_max_intrinsic_width(app, constraints.max_height),
3199                step_width,
3200            ))
3201        };
3202        let height = step_height.map(|_| {
3203            apply_step(
3204                child.get_max_intrinsic_height(app, constraints.max_width),
3205                step_height,
3206            )
3207        });
3208        constraints.tighten(width, height)
3209    }
3210
3211    /// Flutter's `_computeSize`.
3212    fn compute_size(
3213        self: RenderHandle<Self>,
3214        app: &mut App,
3215        constraints: BoxConstraints,
3216        layout_child: ChildLayouter,
3217    ) -> Size {
3218        match self.child(app) {
3219            Some(child) => {
3220                let child_constraints = self.child_constraints(app, child, constraints);
3221                layout_child(app, child, child_constraints)
3222            }
3223            None => constraints.smallest(),
3224        }
3225    }
3226}
3227
3228impl RenderObjectWithChildMixin for RenderIntrinsicWidth {
3229    type ChildType = AnyRenderBox;
3230
3231    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
3232        &self.get(app).child
3233    }
3234
3235    fn child_data_mut(
3236        self: RenderHandle<Self>,
3237        app: &mut App,
3238    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
3239        &mut self.get_mut(app).child
3240    }
3241}
3242
3243impl RenderProxyBoxMixin for RenderIntrinsicWidth {}
3244
3245impl RenderObject for RenderIntrinsicWidth {
3246    crate::render_object_accessors!();
3247
3248    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3249        let constraints = self.constraints(app);
3250        let size = self.compute_size(app, constraints, ChildLayoutHelper::layout_child);
3251        self.set_size(app, size);
3252    }
3253
3254    fn paint(
3255        self: RenderHandle<Self>,
3256        app: &mut App,
3257        context: &mut PaintingContext,
3258        offset: Offset,
3259    ) {
3260        RenderProxyBoxMixin::paint(self, app, context, offset);
3261    }
3262
3263    fn visit_children(
3264        self: RenderHandle<Self>,
3265        app: &App,
3266        visitor: &mut dyn FnMut(AnyRenderObject),
3267    ) {
3268        if let Some(child) = self.child(app) {
3269            visitor(child.as_object());
3270        }
3271    }
3272}
3273
3274impl RenderBox for RenderIntrinsicWidth {
3275    crate::render_box_accessors!();
3276
3277    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3278        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3279    }
3280
3281    fn apply_paint_transform(
3282        self: RenderHandle<Self>,
3283        app: &App,
3284        child: AnyRenderObject,
3285        transform: &mut Matrix4,
3286    ) {
3287        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3288    }
3289
3290    fn hit_test_children(
3291        self: RenderHandle<Self>,
3292        app: &mut App,
3293        result: &mut BoxHitTestResult<'_>,
3294        position: Offset,
3295    ) -> bool {
3296        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
3297    }
3298
3299    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3300        self.as_box().get_max_intrinsic_width(app, height)
3301    }
3302
3303    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3304        let Some(child) = self.child(app) else {
3305            return 0.0;
3306        };
3307        let width = child.get_max_intrinsic_width(app, height);
3308        apply_step(width, self.get(app).step_width)
3309    }
3310
3311    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3312        let Some(child) = self.child(app) else {
3313            return 0.0;
3314        };
3315        let width = if width.is_finite() {
3316            width
3317        } else {
3318            self.as_box().get_max_intrinsic_width(app, f64::INFINITY)
3319        };
3320        debug_assert!(width.is_finite());
3321        let height = child.get_min_intrinsic_height(app, width);
3322        apply_step(height, self.get(app).step_height)
3323    }
3324
3325    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3326        let Some(child) = self.child(app) else {
3327            return 0.0;
3328        };
3329        let width = if width.is_finite() {
3330            width
3331        } else {
3332            self.as_box().get_max_intrinsic_width(app, f64::INFINITY)
3333        };
3334        debug_assert!(width.is_finite());
3335        let height = child.get_max_intrinsic_height(app, width);
3336        apply_step(height, self.get(app).step_height)
3337    }
3338
3339    fn compute_distance_to_actual_baseline(
3340        self: RenderHandle<Self>,
3341        app: &mut App,
3342        baseline: TextBaseline,
3343    ) -> Option<f64> {
3344        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
3345    }
3346
3347    fn compute_dry_layout(
3348        self: RenderHandle<Self>,
3349        app: &mut App,
3350        constraints: BoxConstraints,
3351    ) -> Size {
3352        self.compute_size(app, constraints, ChildLayoutHelper::dry_layout_child)
3353    }
3354
3355    fn compute_dry_baseline(
3356        self: RenderHandle<Self>,
3357        app: &mut App,
3358        constraints: BoxConstraints,
3359        baseline: TextBaseline,
3360    ) -> Option<f64> {
3361        let child = self.child(app)?;
3362        let child_constraints = self.child_constraints(app, child, constraints);
3363        child.get_dry_baseline(app, child_constraints, baseline)
3364    }
3365}
3366
3367/// Sizes its child to the child's intrinsic height.
3368///
3369/// This class is useful, for example, when unlimited height is available and you would like a
3370/// child that would otherwise attempt to expand infinitely to instead size itself to a more
3371/// reasonable height.
3372///
3373/// The constraints that this object passes to its child will adhere to the parent's constraints,
3374/// so if the constraints are not large enough to satisfy the child's maximum intrinsic height,
3375/// then the child will get less height than it otherwise would. Likewise, if the minimum height
3376/// constraint is larger than the child's maximum intrinsic height, the child will be given more
3377/// height than it otherwise would.
3378///
3379/// This class is relatively expensive, because it adds a speculative layout pass before the final
3380/// layout phase. Avoid using it where possible. In the worst case, this render object can result
3381/// in a layout that is O(N²) in the depth of the tree.
3382pub struct RenderIntrinsicHeight {
3383    render_object: RenderObjectData,
3384    render_box: RenderBoxData,
3385    child: RenderObjectWithChildData<AnyRenderBox>,
3386}
3387
3388impl RenderIntrinsicHeight {
3389    /// Creates a render object that sizes itself to its child's intrinsic height.
3390    pub fn new(app: &mut App, child: Option<AnyRenderBox>) -> RenderHandle<RenderIntrinsicHeight> {
3391        let this = RenderHandle::new_box(
3392            app,
3393            RenderIntrinsicHeight {
3394                render_object: RenderObjectData::new(),
3395                render_box: RenderBoxData::new(),
3396                child: RenderObjectWithChildData::new(),
3397            },
3398        );
3399        this.set_child(app, child);
3400        this
3401    }
3402
3403    fn child_constraints(
3404        self: RenderHandle<Self>,
3405        app: &mut App,
3406        child: AnyRenderBox,
3407        constraints: BoxConstraints,
3408    ) -> BoxConstraints {
3409        if constraints.has_tight_height() {
3410            return constraints;
3411        }
3412        let height = child.get_max_intrinsic_height(app, constraints.max_width);
3413        constraints.tighten(None, Some(height))
3414    }
3415
3416    /// Flutter's `_computeSize`.
3417    fn compute_size(
3418        self: RenderHandle<Self>,
3419        app: &mut App,
3420        constraints: BoxConstraints,
3421        layout_child: ChildLayouter,
3422    ) -> Size {
3423        match self.child(app) {
3424            Some(child) => {
3425                let child_constraints = self.child_constraints(app, child, constraints);
3426                layout_child(app, child, child_constraints)
3427            }
3428            None => constraints.smallest(),
3429        }
3430    }
3431}
3432
3433impl RenderObjectWithChildMixin for RenderIntrinsicHeight {
3434    type ChildType = AnyRenderBox;
3435
3436    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
3437        &self.get(app).child
3438    }
3439
3440    fn child_data_mut(
3441        self: RenderHandle<Self>,
3442        app: &mut App,
3443    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
3444        &mut self.get_mut(app).child
3445    }
3446}
3447
3448impl RenderProxyBoxMixin for RenderIntrinsicHeight {}
3449
3450impl RenderObject for RenderIntrinsicHeight {
3451    crate::render_object_accessors!();
3452
3453    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3454        let constraints = self.constraints(app);
3455        let size = self.compute_size(app, constraints, ChildLayoutHelper::layout_child);
3456        self.set_size(app, size);
3457    }
3458
3459    fn paint(
3460        self: RenderHandle<Self>,
3461        app: &mut App,
3462        context: &mut PaintingContext,
3463        offset: Offset,
3464    ) {
3465        RenderProxyBoxMixin::paint(self, app, context, offset);
3466    }
3467
3468    fn visit_children(
3469        self: RenderHandle<Self>,
3470        app: &App,
3471        visitor: &mut dyn FnMut(AnyRenderObject),
3472    ) {
3473        if let Some(child) = self.child(app) {
3474            visitor(child.as_object());
3475        }
3476    }
3477}
3478
3479impl RenderBox for RenderIntrinsicHeight {
3480    crate::render_box_accessors!();
3481
3482    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3483        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3484    }
3485
3486    fn apply_paint_transform(
3487        self: RenderHandle<Self>,
3488        app: &App,
3489        child: AnyRenderObject,
3490        transform: &mut Matrix4,
3491    ) {
3492        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3493    }
3494
3495    fn hit_test_children(
3496        self: RenderHandle<Self>,
3497        app: &mut App,
3498        result: &mut BoxHitTestResult<'_>,
3499        position: Offset,
3500    ) -> bool {
3501        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
3502    }
3503
3504    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3505        let Some(child) = self.child(app) else {
3506            return 0.0;
3507        };
3508        let height = if height.is_finite() {
3509            height
3510        } else {
3511            child.get_max_intrinsic_height(app, f64::INFINITY)
3512        };
3513        debug_assert!(height.is_finite());
3514        child.get_min_intrinsic_width(app, height)
3515    }
3516
3517    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3518        let Some(child) = self.child(app) else {
3519            return 0.0;
3520        };
3521        let height = if height.is_finite() {
3522            height
3523        } else {
3524            child.get_max_intrinsic_height(app, f64::INFINITY)
3525        };
3526        debug_assert!(height.is_finite());
3527        child.get_max_intrinsic_width(app, height)
3528    }
3529
3530    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3531        self.as_box().get_max_intrinsic_height(app, width)
3532    }
3533
3534    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3535        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
3536    }
3537
3538    fn compute_distance_to_actual_baseline(
3539        self: RenderHandle<Self>,
3540        app: &mut App,
3541        baseline: TextBaseline,
3542    ) -> Option<f64> {
3543        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
3544    }
3545
3546    fn compute_dry_layout(
3547        self: RenderHandle<Self>,
3548        app: &mut App,
3549        constraints: BoxConstraints,
3550    ) -> Size {
3551        self.compute_size(app, constraints, ChildLayoutHelper::dry_layout_child)
3552    }
3553
3554    fn compute_dry_baseline(
3555        self: RenderHandle<Self>,
3556        app: &mut App,
3557        constraints: BoxConstraints,
3558        baseline: TextBaseline,
3559    ) -> Option<f64> {
3560        let child = self.child(app)?;
3561        let child_constraints = self.child_constraints(app, child, constraints);
3562        child.get_dry_baseline(app, child_constraints, baseline)
3563    }
3564}
3565
3566/// An interface for providing custom clips.
3567///
3568/// This trait is used by a number of clip widgets (e.g., `ClipRect` and `ClipPath`).
3569///
3570/// The [`get_clip`](Self::get_clip) method is called whenever the custom clip needs to be
3571/// updated.
3572///
3573/// The [`should_reclip`](Self::should_reclip) method is called when a new instance of the class
3574/// is provided, to check if the new instance actually represents different information.
3575///
3576/// The most efficient way to update the clip provided by this class is to
3577/// supply a [`reclip`](Self::reclip) listenable, which notifies its listeners when it is time to
3578/// reclip, avoiding both the build and layout phases of the pipeline.
3579pub trait CustomClipper<T>: 'static {
3580    /// The [`Listenable`] that notifies when it is time to reclip.
3581    ///
3582    /// Dart's `CustomClipper` takes it as a constructor argument and forwards `addListener` /
3583    /// `removeListener` to it; here the clipper answers with it and the same forwarding is the
3584    /// [`Listenable`] implementation of `dyn CustomClipper<T>`.
3585    fn reclip(&self) -> Option<&Rc<dyn Listenable>> {
3586        None
3587    }
3588
3589    /// Returns a description of the clip given that the render object being
3590    /// clipped is of the given size.
3591    fn get_clip(&self, size: Size) -> T;
3592
3593    /// Called whenever a new instance of the custom clipper delegate class is
3594    /// provided to the clip object, or any time that a new clip object is created
3595    /// with a new instance of the custom clipper delegate class (which amounts to
3596    /// the same thing, because the latter is implemented in terms of the former).
3597    ///
3598    /// If the new instance represents different information than the old
3599    /// instance, then the method should return true, otherwise it should return
3600    /// false.
3601    ///
3602    /// If the method returns false, then the [`get_clip`](Self::get_clip) call might be
3603    /// optimized away.
3604    ///
3605    /// It's possible that the [`get_clip`](Self::get_clip) method will get called even if
3606    /// [`should_reclip`](Self::should_reclip) returns false or if the
3607    /// [`should_reclip`](Self::should_reclip) method is never called at all (e.g. if the box
3608    /// changes size). It is only called with a clipper of this clipper's own type, as Dart's
3609    /// `covariant` parameter is.
3610    fn should_reclip(&self, old_clipper: &dyn CustomClipper<T>) -> bool;
3611
3612    /// Downcast support for Dart's `runtimeType` comparison and `covariant` parameter.
3613    fn as_any(&self) -> &dyn Any;
3614}
3615
3616impl<T: 'static> Listenable for dyn CustomClipper<T> {
3617    /// Register a closure to be notified when it is time to reclip.
3618    ///
3619    /// Forwards to the [`reclip`](CustomClipper::reclip) listenable, if it is not `None`.
3620    fn add_listener(&self, app: &mut App, listener: Listener) {
3621        if let Some(reclip) = self.reclip() {
3622            reclip.add_listener(app, listener);
3623        }
3624    }
3625
3626    /// Remove a previously registered closure from the list of closures that the
3627    /// object notifies when it is time to reclip.
3628    fn remove_listener(&self, app: &mut App, listener: &Listener) {
3629        if let Some(reclip) = self.reclip() {
3630            reclip.remove_listener(app, listener);
3631        }
3632    }
3633}
3634
3635/// The fields of [`RenderCustomClip`].
3636pub struct RenderCustomClipData<T> {
3637    clipper: Option<Rc<dyn CustomClipper<T>>>,
3638    clip: Option<T>,
3639    clip_behavior: Clip,
3640}
3641
3642impl<T> RenderCustomClipData<T> {
3643    /// Creates the fields of a clip with no clip computed yet.
3644    pub fn new(
3645        clipper: Option<Rc<dyn CustomClipper<T>>>,
3646        clip_behavior: Clip,
3647    ) -> RenderCustomClipData<T> {
3648        RenderCustomClipData {
3649            clipper,
3650            clip: None,
3651            clip_behavior,
3652        }
3653    }
3654}
3655
3656/// A [`CustomClipper`] that clips to the outer path of a `ShapeBorder`.
3657pub struct ShapeBorderClipper {
3658    /// The shape border whose outer path defines the clip.
3659    pub shape: Box<dyn ShapeBorder>,
3660    /// The text direction to use for getting the outer path for `shape`.
3661    ///
3662    /// `ShapeBorder`s can depend on the text direction (e.g having a "dent" on the left hand
3663    /// side in LTR and on the right hand side in RTL).
3664    pub text_direction: Option<TextDirection>,
3665}
3666
3667impl ShapeBorderClipper {
3668    /// Creates a [`ShapeBorder`] clipper.
3669    ///
3670    /// The `text_direction` argument must be provided non-`None` if `shape` has a text
3671    /// direction dependency (for example if it is expressed in terms of "start" and "end"
3672    /// instead of "left" and "right"). It may be `None` if the border will not need the text
3673    /// direction to paint itself.
3674    pub fn new(shape: Box<dyn ShapeBorder>, text_direction: Option<TextDirection>) -> Self {
3675        ShapeBorderClipper {
3676            shape,
3677            text_direction,
3678        }
3679    }
3680}
3681
3682impl CustomClipper<Arc<Path>> for ShapeBorderClipper {
3683    fn get_clip(&self, size: Size) -> Arc<Path> {
3684        self.shape
3685            .get_outer_path(Offset::ZERO & size, self.text_direction)
3686    }
3687
3688    fn should_reclip(&self, old_clipper: &dyn CustomClipper<Arc<Path>>) -> bool {
3689        let Some(old_clipper) = old_clipper.as_any().downcast_ref::<ShapeBorderClipper>() else {
3690            return true;
3691        };
3692        !old_clipper.shape.eq_shape(&*self.shape)
3693            || old_clipper.text_direction != self.text_direction
3694    }
3695
3696    fn as_any(&self) -> &dyn Any {
3697        self
3698    }
3699}
3700
3701/// A base class for render boxes that clip their child.
3702///
3703/// Flutter's private `_RenderCustomClip<T>`: the shared bodies of a clip. A leaf implements
3704/// [`default_clip`](Self::default_clip), holds a [`RenderCustomClipData<T>`], and calls these
3705/// where Dart would run the inherited method: `RenderCustomClip::perform_layout(self, app)`.
3706pub trait RenderCustomClip<T: Clone + 'static>: RenderProxyBoxMixin {
3707    /// Mixin field access.
3708    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<T>;
3709
3710    /// See [`custom_clip_data`](Self::custom_clip_data).
3711    fn custom_clip_data_mut(
3712        self: RenderHandle<Self>,
3713        app: &mut App,
3714    ) -> &mut RenderCustomClipData<T>;
3715
3716    /// The clip to use when [`clipper`](Self::clipper) is `None`.
3717    fn default_clip(self: RenderHandle<Self>, app: &App) -> T;
3718
3719    /// If non-`None`, determines which clip to use on the child.
3720    fn clipper(self: RenderHandle<Self>, app: &App) -> Option<Rc<dyn CustomClipper<T>>> {
3721        self.custom_clip_data(app).clipper.clone()
3722    }
3723
3724    /// Sets [`clipper`](Self::clipper).
3725    fn set_clipper(
3726        self: RenderHandle<Self>,
3727        app: &mut App,
3728        new_clipper: Option<Rc<dyn CustomClipper<T>>>,
3729    ) {
3730        let old_clipper = self.clipper(app);
3731        if same_instance(old_clipper.as_ref(), new_clipper.as_ref()) {
3732            return;
3733        }
3734        self.custom_clip_data_mut(app).clipper = new_clipper.clone();
3735        debug_assert!(new_clipper.is_some() || old_clipper.is_some());
3736        let reclip = match (&new_clipper, &old_clipper) {
3737            (Some(new_clipper), Some(old_clipper)) => {
3738                new_clipper.as_any().type_id() != old_clipper.as_any().type_id()
3739                    || new_clipper.should_reclip(&**old_clipper)
3740            }
3741            _ => true,
3742        };
3743        if reclip {
3744            self.mark_needs_clip(app);
3745        }
3746        if self.attached(app) {
3747            if let Some(old_clipper) = &old_clipper {
3748                old_clipper.remove_listener(app, &self.clip_listener());
3749            }
3750            if let Some(new_clipper) = &new_clipper {
3751                new_clipper.add_listener(app, self.clip_listener());
3752            }
3753        }
3754    }
3755
3756    /// Flutter's `attach` after `super.attach(owner)`.
3757    fn did_attach(self: RenderHandle<Self>, app: &mut App) {
3758        if let Some(clipper) = self.clipper(app) {
3759            clipper.add_listener(app, self.clip_listener());
3760        }
3761    }
3762
3763    /// Flutter's `detach` before `super.detach()`.
3764    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
3765        if let Some(clipper) = self.clipper(app) {
3766            clipper.remove_listener(app, &self.clip_listener());
3767        }
3768    }
3769
3770    /// Flutter's `_markNeedsClip`.
3771    fn mark_needs_clip(self: RenderHandle<Self>, app: &mut App) {
3772        self.custom_clip_data_mut(app).clip = None;
3773        self.mark_needs_paint(app);
3774    }
3775
3776    /// The `_markNeedsClip` tear-off, equal to itself across registrations.
3777    fn clip_listener(self: RenderHandle<Self>) -> Listener {
3778        Listener::handle_method(self.handle(), mark_needs_clip::<Self, T>)
3779    }
3780
3781    /// Whether and how to clip the child.
3782    fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
3783        self.custom_clip_data(app).clip_behavior
3784    }
3785
3786    /// Sets [`clip_behavior`](Self::clip_behavior).
3787    fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
3788        if value != self.clip_behavior(app) {
3789            self.custom_clip_data_mut(app).clip_behavior = value;
3790            self.mark_needs_paint(app);
3791        }
3792    }
3793
3794    /// Flutter's `performLayout`: a resize drops the cached clip.
3795    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3796        let old_size = self.has_size(app).then(|| self.size(app));
3797        RenderProxyBoxMixin::perform_layout(self, app);
3798        if old_size != Some(self.size(app)) {
3799            self.custom_clip_data_mut(app).clip = None;
3800        }
3801    }
3802
3803    /// Flutter's `_updateClip`: computes the clip if it is not cached.
3804    fn update_clip(self: RenderHandle<Self>, app: &mut App) {
3805        if self.custom_clip_data(app).clip.is_some() {
3806            return;
3807        }
3808        let clip = match self.clipper(app) {
3809            Some(clipper) => clipper.get_clip(self.size(app)),
3810            None => self.default_clip(app),
3811        };
3812        self.custom_clip_data_mut(app).clip = Some(clip);
3813    }
3814
3815    /// The cached clip. Call [`update_clip`](Self::update_clip) first; Dart's `_clip!`.
3816    fn clip(self: RenderHandle<Self>, app: &App) -> T {
3817        self.custom_clip_data(app)
3818            .clip
3819            .clone()
3820            .expect("update_clip computes the clip")
3821    }
3822}
3823
3824fn mark_needs_clip<C: RenderCustomClip<T>, T: Clone + 'static>(this: Handle<C>, app: &mut App) {
3825    RenderCustomClip::mark_needs_clip(RenderHandle::from_handle(this), app);
3826}
3827
3828/// Clips its child using a rectangle.
3829///
3830/// By default, [`RenderClipRect`] prevents its child from painting outside its
3831/// bounds, but the size and location of the clip rect can be customized using a
3832/// custom [`clipper`](RenderCustomClip::clipper).
3833pub struct RenderClipRect {
3834    render_object: RenderObjectData,
3835    render_box: RenderBoxData,
3836    child: RenderObjectWithChildData<AnyRenderBox>,
3837    custom_clip: RenderCustomClipData<Rect>,
3838}
3839
3840impl RenderClipRect {
3841    /// Creates a rectangular clip.
3842    ///
3843    /// If `clipper` is `None`, the clip will match the layout size and position of
3844    /// the child.
3845    ///
3846    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
3847    pub fn new(
3848        app: &mut App,
3849        clipper: Option<Rc<dyn CustomClipper<Rect>>>,
3850        clip_behavior: Clip,
3851        child: Option<AnyRenderBox>,
3852    ) -> RenderHandle<RenderClipRect> {
3853        let this = RenderHandle::new_box(
3854            app,
3855            RenderClipRect {
3856                render_object: RenderObjectData::new(),
3857                render_box: RenderBoxData::new(),
3858                child: RenderObjectWithChildData::new(),
3859                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
3860            },
3861        );
3862        this.set_child(app, child);
3863        this
3864    }
3865}
3866
3867impl RenderObjectWithChildMixin for RenderClipRect {
3868    type ChildType = AnyRenderBox;
3869
3870    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
3871        &self.get(app).child
3872    }
3873
3874    fn child_data_mut(
3875        self: RenderHandle<Self>,
3876        app: &mut App,
3877    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
3878        &mut self.get_mut(app).child
3879    }
3880}
3881
3882impl RenderProxyBoxMixin for RenderClipRect {}
3883
3884impl RenderCustomClip<Rect> for RenderClipRect {
3885    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<Rect> {
3886        &self.get(app).custom_clip
3887    }
3888
3889    fn custom_clip_data_mut(
3890        self: RenderHandle<Self>,
3891        app: &mut App,
3892    ) -> &mut RenderCustomClipData<Rect> {
3893        &mut self.get_mut(app).custom_clip
3894    }
3895
3896    fn default_clip(self: RenderHandle<Self>, app: &App) -> Rect {
3897        Offset::ZERO & self.size(app)
3898    }
3899}
3900
3901impl RenderObject for RenderClipRect {
3902    crate::render_object_accessors!();
3903
3904    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
3905        if let Some(child) = self.child(app) {
3906            child.as_object().attach(app, owner);
3907        }
3908        RenderCustomClip::did_attach(self, app);
3909    }
3910
3911    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
3912        RenderCustomClip::did_detach(self, app);
3913        if let Some(child) = self.child(app) {
3914            child.as_object().detach(app);
3915        }
3916    }
3917
3918    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3919        RenderCustomClip::perform_layout(self, app);
3920    }
3921
3922    fn paint(
3923        self: RenderHandle<Self>,
3924        app: &mut App,
3925        context: &mut PaintingContext,
3926        offset: Offset,
3927    ) {
3928        if let Some(child) = self.child(app) {
3929            let clip_behavior = self.clip_behavior(app);
3930            if clip_behavior != Clip::None {
3931                self.update_clip(app);
3932                let clip = self.clip(app);
3933                let old = self.as_object().layer_as::<ClipRectLayer>(app);
3934                let layer = context.push_clip_rect(
3935                    app,
3936                    self.as_object().needs_compositing(app),
3937                    offset,
3938                    clip,
3939                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
3940                    clip_behavior,
3941                    old,
3942                );
3943                self.as_object()
3944                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
3945            } else {
3946                context.paint_child(app, child.as_object(), offset);
3947                self.as_object().set_layer(app, None);
3948            }
3949        } else {
3950            self.as_object().set_layer(app, None);
3951        }
3952    }
3953
3954    fn visit_children(
3955        self: RenderHandle<Self>,
3956        app: &App,
3957        visitor: &mut dyn FnMut(AnyRenderObject),
3958    ) {
3959        if let Some(child) = self.child(app) {
3960            visitor(child.as_object());
3961        }
3962    }
3963}
3964
3965impl RenderBox for RenderClipRect {
3966    crate::render_box_accessors!();
3967
3968    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3969        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3970    }
3971
3972    fn apply_paint_transform(
3973        self: RenderHandle<Self>,
3974        app: &App,
3975        child: AnyRenderObject,
3976        transform: &mut Matrix4,
3977    ) {
3978        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3979    }
3980
3981    fn hit_test(
3982        self: RenderHandle<Self>,
3983        app: &mut App,
3984        result: &mut BoxHitTestResult<'_>,
3985        position: Offset,
3986    ) -> bool {
3987        if self.clipper(app).is_some() {
3988            self.update_clip(app);
3989            if !self.clip(app).contains(position) {
3990                return false;
3991            }
3992        }
3993        RenderBoxBase::hit_test(self, app, result, position)
3994    }
3995
3996    fn hit_test_children(
3997        self: RenderHandle<Self>,
3998        app: &mut App,
3999        result: &mut BoxHitTestResult<'_>,
4000        position: Offset,
4001    ) -> bool {
4002        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4003    }
4004
4005    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4006        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4007    }
4008
4009    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4010        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4011    }
4012
4013    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4014        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4015    }
4016
4017    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4018        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4019    }
4020
4021    fn compute_distance_to_actual_baseline(
4022        self: RenderHandle<Self>,
4023        app: &mut App,
4024        baseline: TextBaseline,
4025    ) -> Option<f64> {
4026        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4027    }
4028
4029    fn compute_dry_baseline(
4030        self: RenderHandle<Self>,
4031        app: &mut App,
4032        constraints: BoxConstraints,
4033        baseline: TextBaseline,
4034    ) -> Option<f64> {
4035        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4036    }
4037
4038    fn compute_dry_layout(
4039        self: RenderHandle<Self>,
4040        app: &mut App,
4041        constraints: BoxConstraints,
4042    ) -> Size {
4043        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4044    }
4045}
4046
4047/// Clips its child using a rounded rectangle.
4048///
4049/// By default, [`RenderClipRRect`] uses its own bounds as the base rectangle for
4050/// the clip, but the size and location of the clip can be customized using a
4051/// custom [`clipper`](RenderCustomClip::clipper).
4052pub struct RenderClipRRect {
4053    render_object: RenderObjectData,
4054    render_box: RenderBoxData,
4055    child: RenderObjectWithChildData<AnyRenderBox>,
4056    custom_clip: RenderCustomClipData<RRect>,
4057    border_radius: BorderRadiusGeometry,
4058    text_direction: Option<TextDirection>,
4059}
4060
4061impl RenderClipRRect {
4062    /// Creates a rounded-rectangular clip.
4063    ///
4064    /// The `border_radius` defaults to [`BorderRadiusGeometry::ZERO`], i.e. a rectangle with
4065    /// right-angled corners.
4066    ///
4067    /// If `clipper` is non-`None`, then `border_radius` is ignored.
4068    ///
4069    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4070    pub fn new(
4071        app: &mut App,
4072        border_radius: BorderRadiusGeometry,
4073        clipper: Option<Rc<dyn CustomClipper<RRect>>>,
4074        clip_behavior: Clip,
4075        text_direction: Option<TextDirection>,
4076        child: Option<AnyRenderBox>,
4077    ) -> RenderHandle<RenderClipRRect> {
4078        let this = RenderHandle::new_box(
4079            app,
4080            RenderClipRRect {
4081                render_object: RenderObjectData::new(),
4082                render_box: RenderBoxData::new(),
4083                child: RenderObjectWithChildData::new(),
4084                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4085                border_radius,
4086                text_direction,
4087            },
4088        );
4089        this.set_child(app, child);
4090        this
4091    }
4092
4093    /// The border radius of the rounded corners.
4094    ///
4095    /// Values are clamped so that horizontal and vertical radii sums do not
4096    /// exceed width/height.
4097    ///
4098    /// This value is ignored if [`clipper`](RenderCustomClip::clipper) is non-`None`.
4099    pub fn border_radius(self: RenderHandle<Self>, app: &App) -> BorderRadiusGeometry {
4100        self.get(app).border_radius
4101    }
4102
4103    /// Sets [`border_radius`](Self::border_radius).
4104    pub fn set_border_radius(self: RenderHandle<Self>, app: &mut App, value: BorderRadiusGeometry) {
4105        if self.get(app).border_radius == value {
4106            return;
4107        }
4108        self.get_mut(app).border_radius = value;
4109        self.mark_needs_clip(app);
4110    }
4111
4112    /// The text direction with which to resolve [`border_radius`](Self::border_radius).
4113    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
4114        self.get(app).text_direction
4115    }
4116
4117    /// Sets [`text_direction`](Self::text_direction).
4118    pub fn set_text_direction(
4119        self: RenderHandle<Self>,
4120        app: &mut App,
4121        value: Option<TextDirection>,
4122    ) {
4123        if self.get(app).text_direction == value {
4124            return;
4125        }
4126        self.get_mut(app).text_direction = value;
4127        self.mark_needs_clip(app);
4128    }
4129}
4130
4131impl RenderObjectWithChildMixin for RenderClipRRect {
4132    type ChildType = AnyRenderBox;
4133
4134    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4135        &self.get(app).child
4136    }
4137
4138    fn child_data_mut(
4139        self: RenderHandle<Self>,
4140        app: &mut App,
4141    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4142        &mut self.get_mut(app).child
4143    }
4144}
4145
4146impl RenderProxyBoxMixin for RenderClipRRect {}
4147
4148impl RenderCustomClip<RRect> for RenderClipRRect {
4149    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<RRect> {
4150        &self.get(app).custom_clip
4151    }
4152
4153    fn custom_clip_data_mut(
4154        self: RenderHandle<Self>,
4155        app: &mut App,
4156    ) -> &mut RenderCustomClipData<RRect> {
4157        &mut self.get_mut(app).custom_clip
4158    }
4159
4160    fn default_clip(self: RenderHandle<Self>, app: &App) -> RRect {
4161        let this = self.get(app);
4162        this.border_radius
4163            .resolve(this.text_direction)
4164            .to_rrect(Offset::ZERO & self.size(app))
4165    }
4166}
4167
4168impl RenderObject for RenderClipRRect {
4169    crate::render_object_accessors!();
4170
4171    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4172        if let Some(child) = self.child(app) {
4173            child.as_object().attach(app, owner);
4174        }
4175        RenderCustomClip::did_attach(self, app);
4176    }
4177
4178    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4179        RenderCustomClip::did_detach(self, app);
4180        if let Some(child) = self.child(app) {
4181            child.as_object().detach(app);
4182        }
4183    }
4184
4185    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4186        RenderCustomClip::perform_layout(self, app);
4187    }
4188
4189    fn paint(
4190        self: RenderHandle<Self>,
4191        app: &mut App,
4192        context: &mut PaintingContext,
4193        offset: Offset,
4194    ) {
4195        if let Some(child) = self.child(app) {
4196            let clip_behavior = self.clip_behavior(app);
4197            if clip_behavior != Clip::None {
4198                self.update_clip(app);
4199                let clip = self.clip(app);
4200                let old = self.as_object().layer_as::<ClipRRectLayer>(app);
4201                let layer = context.push_clip_rrect(
4202                    app,
4203                    self.as_object().needs_compositing(app),
4204                    offset,
4205                    clip.outer_rect(),
4206                    clip,
4207                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4208                    clip_behavior,
4209                    old,
4210                );
4211                self.as_object()
4212                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4213            } else {
4214                context.paint_child(app, child.as_object(), offset);
4215                self.as_object().set_layer(app, None);
4216            }
4217        } else {
4218            self.as_object().set_layer(app, None);
4219        }
4220    }
4221
4222    fn visit_children(
4223        self: RenderHandle<Self>,
4224        app: &App,
4225        visitor: &mut dyn FnMut(AnyRenderObject),
4226    ) {
4227        if let Some(child) = self.child(app) {
4228            visitor(child.as_object());
4229        }
4230    }
4231}
4232
4233impl RenderBox for RenderClipRRect {
4234    crate::render_box_accessors!();
4235
4236    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4237        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4238    }
4239
4240    fn apply_paint_transform(
4241        self: RenderHandle<Self>,
4242        app: &App,
4243        child: AnyRenderObject,
4244        transform: &mut Matrix4,
4245    ) {
4246        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4247    }
4248
4249    fn hit_test(
4250        self: RenderHandle<Self>,
4251        app: &mut App,
4252        result: &mut BoxHitTestResult<'_>,
4253        position: Offset,
4254    ) -> bool {
4255        if self.clipper(app).is_some() {
4256            self.update_clip(app);
4257            if !self.clip(app).contains(position) {
4258                return false;
4259            }
4260        }
4261        RenderBoxBase::hit_test(self, app, result, position)
4262    }
4263
4264    fn hit_test_children(
4265        self: RenderHandle<Self>,
4266        app: &mut App,
4267        result: &mut BoxHitTestResult<'_>,
4268        position: Offset,
4269    ) -> bool {
4270        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4271    }
4272
4273    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4274        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4275    }
4276
4277    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4278        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4279    }
4280
4281    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4282        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4283    }
4284
4285    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4286        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4287    }
4288
4289    fn compute_distance_to_actual_baseline(
4290        self: RenderHandle<Self>,
4291        app: &mut App,
4292        baseline: TextBaseline,
4293    ) -> Option<f64> {
4294        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4295    }
4296
4297    fn compute_dry_baseline(
4298        self: RenderHandle<Self>,
4299        app: &mut App,
4300        constraints: BoxConstraints,
4301        baseline: TextBaseline,
4302    ) -> Option<f64> {
4303        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4304    }
4305
4306    fn compute_dry_layout(
4307        self: RenderHandle<Self>,
4308        app: &mut App,
4309        constraints: BoxConstraints,
4310    ) -> Size {
4311        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4312    }
4313}
4314
4315/// Clips its child using an oval.
4316///
4317/// Inscribes an oval into its layout dimensions and prevents its child from
4318/// painting outside that oval.
4319pub struct RenderClipOval {
4320    render_object: RenderObjectData,
4321    render_box: RenderBoxData,
4322    child: RenderObjectWithChildData<AnyRenderBox>,
4323    custom_clip: RenderCustomClipData<Rect>,
4324    cached_rect: Option<Rect>,
4325    cached_path: Option<Arc<Path>>,
4326}
4327
4328impl RenderClipOval {
4329    /// Creates an oval-shaped clip.
4330    ///
4331    /// If `clipper` is `None`, the oval will be inscribed into the layout size and
4332    /// position of the child.
4333    ///
4334    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4335    pub fn new(
4336        app: &mut App,
4337        clipper: Option<Rc<dyn CustomClipper<Rect>>>,
4338        clip_behavior: Clip,
4339        child: Option<AnyRenderBox>,
4340    ) -> RenderHandle<RenderClipOval> {
4341        let this = RenderHandle::new_box(
4342            app,
4343            RenderClipOval {
4344                render_object: RenderObjectData::new(),
4345                render_box: RenderBoxData::new(),
4346                child: RenderObjectWithChildData::new(),
4347                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4348                cached_rect: None,
4349                cached_path: None,
4350            },
4351        );
4352        this.set_child(app, child);
4353        this
4354    }
4355
4356    fn get_clip_path(self: RenderHandle<Self>, app: &mut App, rect: Rect) -> Arc<Path> {
4357        if self.get(app).cached_rect != Some(rect) {
4358            let radius = [(rect.width() / 2.0) as f32, (rect.height() / 2.0) as f32];
4359            let mut path = PathBuilder::new();
4360            path.rrect_radii_elliptical(rect, [radius; 4]);
4361            let this = self.get_mut(app);
4362            this.cached_rect = Some(rect);
4363            this.cached_path = Some(path.build());
4364        }
4365        self.get(app).cached_path.clone().expect("cached above")
4366    }
4367}
4368
4369impl RenderObjectWithChildMixin for RenderClipOval {
4370    type ChildType = AnyRenderBox;
4371
4372    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4373        &self.get(app).child
4374    }
4375
4376    fn child_data_mut(
4377        self: RenderHandle<Self>,
4378        app: &mut App,
4379    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4380        &mut self.get_mut(app).child
4381    }
4382}
4383
4384impl RenderProxyBoxMixin for RenderClipOval {}
4385
4386impl RenderCustomClip<Rect> for RenderClipOval {
4387    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<Rect> {
4388        &self.get(app).custom_clip
4389    }
4390
4391    fn custom_clip_data_mut(
4392        self: RenderHandle<Self>,
4393        app: &mut App,
4394    ) -> &mut RenderCustomClipData<Rect> {
4395        &mut self.get_mut(app).custom_clip
4396    }
4397
4398    fn default_clip(self: RenderHandle<Self>, app: &App) -> Rect {
4399        Offset::ZERO & self.size(app)
4400    }
4401}
4402
4403impl RenderObject for RenderClipOval {
4404    crate::render_object_accessors!();
4405
4406    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4407        if let Some(child) = self.child(app) {
4408            child.as_object().attach(app, owner);
4409        }
4410        RenderCustomClip::did_attach(self, app);
4411    }
4412
4413    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4414        RenderCustomClip::did_detach(self, app);
4415        if let Some(child) = self.child(app) {
4416            child.as_object().detach(app);
4417        }
4418    }
4419
4420    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4421        RenderCustomClip::perform_layout(self, app);
4422    }
4423
4424    fn paint(
4425        self: RenderHandle<Self>,
4426        app: &mut App,
4427        context: &mut PaintingContext,
4428        offset: Offset,
4429    ) {
4430        if let Some(child) = self.child(app) {
4431            let clip_behavior = self.clip_behavior(app);
4432            if clip_behavior != Clip::None {
4433                self.update_clip(app);
4434                let clip = self.clip(app);
4435                let clip_path = self.get_clip_path(app, clip);
4436                let old = self.as_object().layer_as::<ClipPathLayer>(app);
4437                let layer = context.push_clip_path(
4438                    app,
4439                    self.as_object().needs_compositing(app),
4440                    offset,
4441                    clip,
4442                    clip_path,
4443                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4444                    clip_behavior,
4445                    old,
4446                );
4447                self.as_object()
4448                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4449            } else {
4450                context.paint_child(app, child.as_object(), offset);
4451                self.as_object().set_layer(app, None);
4452            }
4453        } else {
4454            self.as_object().set_layer(app, None);
4455        }
4456    }
4457
4458    fn visit_children(
4459        self: RenderHandle<Self>,
4460        app: &App,
4461        visitor: &mut dyn FnMut(AnyRenderObject),
4462    ) {
4463        if let Some(child) = self.child(app) {
4464            visitor(child.as_object());
4465        }
4466    }
4467}
4468
4469impl RenderBox for RenderClipOval {
4470    crate::render_box_accessors!();
4471
4472    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4473        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4474    }
4475
4476    fn apply_paint_transform(
4477        self: RenderHandle<Self>,
4478        app: &App,
4479        child: AnyRenderObject,
4480        transform: &mut Matrix4,
4481    ) {
4482        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4483    }
4484
4485    fn hit_test(
4486        self: RenderHandle<Self>,
4487        app: &mut App,
4488        result: &mut BoxHitTestResult<'_>,
4489        position: Offset,
4490    ) -> bool {
4491        self.update_clip(app);
4492        let clip = self.clip(app);
4493        let center = clip.center();
4494        // convert the position to an offset from the center of the unit circle
4495        let offset = Offset::new(
4496            (position.dx() - center.dx()) / clip.width(),
4497            (position.dy() - center.dy()) / clip.height(),
4498        );
4499        // check if the point is outside the unit circle
4500        if offset.distance_squared() > 0.25 {
4501            // x^2 + y^2 > r^2
4502            return false;
4503        }
4504        RenderBoxBase::hit_test(self, app, result, position)
4505    }
4506
4507    fn hit_test_children(
4508        self: RenderHandle<Self>,
4509        app: &mut App,
4510        result: &mut BoxHitTestResult<'_>,
4511        position: Offset,
4512    ) -> bool {
4513        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4514    }
4515
4516    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4517        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4518    }
4519
4520    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4521        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4522    }
4523
4524    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4525        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4526    }
4527
4528    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4529        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4530    }
4531
4532    fn compute_distance_to_actual_baseline(
4533        self: RenderHandle<Self>,
4534        app: &mut App,
4535        baseline: TextBaseline,
4536    ) -> Option<f64> {
4537        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4538    }
4539
4540    fn compute_dry_baseline(
4541        self: RenderHandle<Self>,
4542        app: &mut App,
4543        constraints: BoxConstraints,
4544        baseline: TextBaseline,
4545    ) -> Option<f64> {
4546        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4547    }
4548
4549    fn compute_dry_layout(
4550        self: RenderHandle<Self>,
4551        app: &mut App,
4552        constraints: BoxConstraints,
4553    ) -> Size {
4554        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4555    }
4556}
4557
4558/// Clips its child using a path.
4559///
4560/// Takes a delegate whose primary method returns a path that should
4561/// be used to prevent the child from painting outside the path.
4562///
4563/// Clipping to a path is expensive. Certain shapes have more
4564/// optimized render objects:
4565///
4566///  * To clip to a rectangle, consider [`RenderClipRect`].
4567///  * To clip to an oval or circle, consider [`RenderClipOval`].
4568///  * To clip to a rounded rectangle, consider [`RenderClipRRect`].
4569pub struct RenderClipPath {
4570    render_object: RenderObjectData,
4571    render_box: RenderBoxData,
4572    child: RenderObjectWithChildData<AnyRenderBox>,
4573    custom_clip: RenderCustomClipData<Arc<Path>>,
4574}
4575
4576impl RenderClipPath {
4577    /// Creates a path clip.
4578    ///
4579    /// If `clipper` is `None`, the clip will be a rectangle that matches the layout
4580    /// size and location of the child. However, rather than use this default,
4581    /// consider using a [`RenderClipRect`], which can achieve the same effect more
4582    /// efficiently.
4583    ///
4584    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4585    pub fn new(
4586        app: &mut App,
4587        clipper: Option<Rc<dyn CustomClipper<Arc<Path>>>>,
4588        clip_behavior: Clip,
4589        child: Option<AnyRenderBox>,
4590    ) -> RenderHandle<RenderClipPath> {
4591        let this = RenderHandle::new_box(
4592            app,
4593            RenderClipPath {
4594                render_object: RenderObjectData::new(),
4595                render_box: RenderBoxData::new(),
4596                child: RenderObjectWithChildData::new(),
4597                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4598            },
4599        );
4600        this.set_child(app, child);
4601        this
4602    }
4603}
4604
4605impl RenderObjectWithChildMixin for RenderClipPath {
4606    type ChildType = AnyRenderBox;
4607
4608    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4609        &self.get(app).child
4610    }
4611
4612    fn child_data_mut(
4613        self: RenderHandle<Self>,
4614        app: &mut App,
4615    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4616        &mut self.get_mut(app).child
4617    }
4618}
4619
4620impl RenderProxyBoxMixin for RenderClipPath {}
4621
4622impl RenderCustomClip<Arc<Path>> for RenderClipPath {
4623    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<Arc<Path>> {
4624        &self.get(app).custom_clip
4625    }
4626
4627    fn custom_clip_data_mut(
4628        self: RenderHandle<Self>,
4629        app: &mut App,
4630    ) -> &mut RenderCustomClipData<Arc<Path>> {
4631        &mut self.get_mut(app).custom_clip
4632    }
4633
4634    fn default_clip(self: RenderHandle<Self>, app: &App) -> Arc<Path> {
4635        let mut path = PathBuilder::new();
4636        path.rect((Offset::ZERO & self.size(app)).into());
4637        path.build()
4638    }
4639}
4640
4641impl RenderObject for RenderClipPath {
4642    crate::render_object_accessors!();
4643
4644    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4645        if let Some(child) = self.child(app) {
4646            child.as_object().attach(app, owner);
4647        }
4648        RenderCustomClip::did_attach(self, app);
4649    }
4650
4651    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4652        RenderCustomClip::did_detach(self, app);
4653        if let Some(child) = self.child(app) {
4654            child.as_object().detach(app);
4655        }
4656    }
4657
4658    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4659        RenderCustomClip::perform_layout(self, app);
4660    }
4661
4662    fn paint(
4663        self: RenderHandle<Self>,
4664        app: &mut App,
4665        context: &mut PaintingContext,
4666        offset: Offset,
4667    ) {
4668        if let Some(child) = self.child(app) {
4669            let clip_behavior = self.clip_behavior(app);
4670            if clip_behavior != Clip::None {
4671                self.update_clip(app);
4672                let clip = self.clip(app);
4673                let bounds = Offset::ZERO & self.size(app);
4674                let old = self.as_object().layer_as::<ClipPathLayer>(app);
4675                let layer = context.push_clip_path(
4676                    app,
4677                    self.as_object().needs_compositing(app),
4678                    offset,
4679                    bounds,
4680                    clip,
4681                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4682                    clip_behavior,
4683                    old,
4684                );
4685                self.as_object()
4686                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4687            } else {
4688                context.paint_child(app, child.as_object(), offset);
4689                self.as_object().set_layer(app, None);
4690            }
4691        } else {
4692            self.as_object().set_layer(app, None);
4693        }
4694    }
4695
4696    fn visit_children(
4697        self: RenderHandle<Self>,
4698        app: &App,
4699        visitor: &mut dyn FnMut(AnyRenderObject),
4700    ) {
4701        if let Some(child) = self.child(app) {
4702            visitor(child.as_object());
4703        }
4704    }
4705}
4706
4707impl RenderBox for RenderClipPath {
4708    crate::render_box_accessors!();
4709
4710    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4711        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4712    }
4713
4714    fn apply_paint_transform(
4715        self: RenderHandle<Self>,
4716        app: &App,
4717        child: AnyRenderObject,
4718        transform: &mut Matrix4,
4719    ) {
4720        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4721    }
4722
4723    fn hit_test(
4724        self: RenderHandle<Self>,
4725        app: &mut App,
4726        result: &mut BoxHitTestResult<'_>,
4727        position: Offset,
4728    ) -> bool {
4729        if self.clipper(app).is_some() {
4730            self.update_clip(app);
4731            let point = Point::new(position.dx() as f32, position.dy() as f32);
4732            if !self.clip(app).contains(point, FillRule::NonZero) {
4733                return false;
4734            }
4735        }
4736        RenderBoxBase::hit_test(self, app, result, position)
4737    }
4738
4739    fn hit_test_children(
4740        self: RenderHandle<Self>,
4741        app: &mut App,
4742        result: &mut BoxHitTestResult<'_>,
4743        position: Offset,
4744    ) -> bool {
4745        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4746    }
4747
4748    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4749        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4750    }
4751
4752    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4753        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4754    }
4755
4756    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4757        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4758    }
4759
4760    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4761        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4762    }
4763
4764    fn compute_distance_to_actual_baseline(
4765        self: RenderHandle<Self>,
4766        app: &mut App,
4767        baseline: TextBaseline,
4768    ) -> Option<f64> {
4769        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4770    }
4771
4772    fn compute_dry_baseline(
4773        self: RenderHandle<Self>,
4774        app: &mut App,
4775        constraints: BoxConstraints,
4776        baseline: TextBaseline,
4777    ) -> Option<f64> {
4778        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4779    }
4780
4781    fn compute_dry_layout(
4782        self: RenderHandle<Self>,
4783        app: &mut App,
4784        constraints: BoxConstraints,
4785    ) -> Size {
4786        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4787    }
4788}
4789
4790/// Clips its child using a rounded superellipse.
4791///
4792/// By default, [`RenderClipRSuperellipse`] uses its own
4793/// [`border_radius`](Self::border_radius) to create the shape. A custom `clipper` can
4794/// define any rounded superellipse.
4795pub struct RenderClipRSuperellipse {
4796    render_object: RenderObjectData,
4797    render_box: RenderBoxData,
4798    child: RenderObjectWithChildData<AnyRenderBox>,
4799    custom_clip: RenderCustomClipData<RSuperellipse>,
4800    border_radius: BorderRadiusGeometry,
4801    text_direction: Option<TextDirection>,
4802}
4803
4804impl RenderClipRSuperellipse {
4805    /// Creates a rounded-superellipse clip.
4806    ///
4807    /// The `border_radius` defaults to [`BorderRadiusGeometry::ZERO`], i.e. a rectangle with
4808    /// right-angled corners.
4809    ///
4810    /// If `clipper` is non-`None`, then `border_radius` is ignored.
4811    ///
4812    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4813    pub fn new(
4814        app: &mut App,
4815        border_radius: BorderRadiusGeometry,
4816        clipper: Option<Rc<dyn CustomClipper<RSuperellipse>>>,
4817        clip_behavior: Clip,
4818        text_direction: Option<TextDirection>,
4819        child: Option<AnyRenderBox>,
4820    ) -> RenderHandle<RenderClipRSuperellipse> {
4821        let this = RenderHandle::new_box(
4822            app,
4823            RenderClipRSuperellipse {
4824                render_object: RenderObjectData::new(),
4825                render_box: RenderBoxData::new(),
4826                child: RenderObjectWithChildData::new(),
4827                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4828                border_radius,
4829                text_direction,
4830            },
4831        );
4832        this.set_child(app, child);
4833        this
4834    }
4835
4836    /// The border radius of the rounded corners.
4837    ///
4838    /// Values are clamped so that horizontal and vertical radii sums do not exceed
4839    /// width/height.
4840    ///
4841    /// This value is ignored if `clipper` is non-`None`.
4842    pub fn border_radius(self: RenderHandle<Self>, app: &App) -> BorderRadiusGeometry {
4843        self.get(app).border_radius
4844    }
4845
4846    /// Sets [`border_radius`](Self::border_radius).
4847    pub fn set_border_radius(self: RenderHandle<Self>, app: &mut App, value: BorderRadiusGeometry) {
4848        if self.get(app).border_radius == value {
4849            return;
4850        }
4851        self.get_mut(app).border_radius = value;
4852        self.mark_needs_clip(app);
4853    }
4854
4855    /// The text direction with which to resolve [`border_radius`](Self::border_radius).
4856    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
4857        self.get(app).text_direction
4858    }
4859
4860    /// Sets [`text_direction`](Self::text_direction).
4861    pub fn set_text_direction(
4862        self: RenderHandle<Self>,
4863        app: &mut App,
4864        value: Option<TextDirection>,
4865    ) {
4866        if self.get(app).text_direction == value {
4867            return;
4868        }
4869        self.get_mut(app).text_direction = value;
4870        self.mark_needs_clip(app);
4871    }
4872}
4873
4874impl RenderObjectWithChildMixin for RenderClipRSuperellipse {
4875    type ChildType = AnyRenderBox;
4876
4877    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4878        &self.get(app).child
4879    }
4880
4881    fn child_data_mut(
4882        self: RenderHandle<Self>,
4883        app: &mut App,
4884    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4885        &mut self.get_mut(app).child
4886    }
4887}
4888
4889impl RenderProxyBoxMixin for RenderClipRSuperellipse {}
4890
4891impl RenderCustomClip<RSuperellipse> for RenderClipRSuperellipse {
4892    fn custom_clip_data(
4893        self: RenderHandle<Self>,
4894        app: &App,
4895    ) -> &RenderCustomClipData<RSuperellipse> {
4896        &self.get(app).custom_clip
4897    }
4898
4899    fn custom_clip_data_mut(
4900        self: RenderHandle<Self>,
4901        app: &mut App,
4902    ) -> &mut RenderCustomClipData<RSuperellipse> {
4903        &mut self.get_mut(app).custom_clip
4904    }
4905
4906    fn default_clip(self: RenderHandle<Self>, app: &App) -> RSuperellipse {
4907        let this = self.get(app);
4908        this.border_radius
4909            .resolve(this.text_direction)
4910            .to_r_superellipse(Offset::ZERO & self.size(app))
4911    }
4912}
4913
4914impl RenderObject for RenderClipRSuperellipse {
4915    crate::render_object_accessors!();
4916
4917    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4918        if let Some(child) = self.child(app) {
4919            child.as_object().attach(app, owner);
4920        }
4921        RenderCustomClip::did_attach(self, app);
4922    }
4923
4924    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4925        RenderCustomClip::did_detach(self, app);
4926        if let Some(child) = self.child(app) {
4927            child.as_object().detach(app);
4928        }
4929    }
4930
4931    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4932        RenderCustomClip::perform_layout(self, app);
4933    }
4934
4935    fn paint(
4936        self: RenderHandle<Self>,
4937        app: &mut App,
4938        context: &mut PaintingContext,
4939        offset: Offset,
4940    ) {
4941        if let Some(child) = self.child(app) {
4942            let clip_behavior = self.clip_behavior(app);
4943            if clip_behavior != Clip::None {
4944                self.update_clip(app);
4945                let clip = self.clip(app);
4946                let mut clip_path = PathBuilder::new();
4947                clip_path.rsuperellipse_radii(
4948                    clip.outer_rect().into(),
4949                    rsuperellipse_radii_elliptical(clip),
4950                );
4951                let old = self.as_object().layer_as::<ClipPathLayer>(app);
4952                let layer = context.push_clip_path(
4953                    app,
4954                    self.as_object().needs_compositing(app),
4955                    offset,
4956                    clip.outer_rect(),
4957                    clip_path.build(),
4958                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4959                    clip_behavior,
4960                    old,
4961                );
4962                self.as_object()
4963                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4964            } else {
4965                context.paint_child(app, child.as_object(), offset);
4966                self.as_object().set_layer(app, None);
4967            }
4968        } else {
4969            self.as_object().set_layer(app, None);
4970        }
4971    }
4972
4973    fn visit_children(
4974        self: RenderHandle<Self>,
4975        app: &App,
4976        visitor: &mut dyn FnMut(AnyRenderObject),
4977    ) {
4978        if let Some(child) = self.child(app) {
4979            visitor(child.as_object());
4980        }
4981    }
4982}
4983
4984impl RenderBox for RenderClipRSuperellipse {
4985    crate::render_box_accessors!();
4986
4987    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4988        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4989    }
4990
4991    fn apply_paint_transform(
4992        self: RenderHandle<Self>,
4993        app: &App,
4994        child: AnyRenderObject,
4995        transform: &mut Matrix4,
4996    ) {
4997        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4998    }
4999
5000    fn hit_test(
5001        self: RenderHandle<Self>,
5002        app: &mut App,
5003        result: &mut BoxHitTestResult<'_>,
5004        position: Offset,
5005    ) -> bool {
5006        if self.clipper(app).is_some() {
5007            self.update_clip(app);
5008            if !self.clip(app).outer_rect().contains(position) {
5009                return false;
5010            }
5011        }
5012        RenderBoxBase::hit_test(self, app, result, position)
5013    }
5014
5015    fn hit_test_children(
5016        self: RenderHandle<Self>,
5017        app: &mut App,
5018        result: &mut BoxHitTestResult<'_>,
5019        position: Offset,
5020    ) -> bool {
5021        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
5022    }
5023
5024    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5025        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
5026    }
5027
5028    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5029        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
5030    }
5031
5032    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5033        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
5034    }
5035
5036    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5037        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
5038    }
5039
5040    fn compute_distance_to_actual_baseline(
5041        self: RenderHandle<Self>,
5042        app: &mut App,
5043        baseline: TextBaseline,
5044    ) -> Option<f64> {
5045        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
5046    }
5047
5048    fn compute_dry_baseline(
5049        self: RenderHandle<Self>,
5050        app: &mut App,
5051        constraints: BoxConstraints,
5052        baseline: TextBaseline,
5053    ) -> Option<f64> {
5054        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
5055    }
5056
5057    fn compute_dry_layout(
5058        self: RenderHandle<Self>,
5059        app: &mut App,
5060        constraints: BoxConstraints,
5061    ) -> Size {
5062        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
5063    }
5064}
5065
5066/// Applies a transformation before painting its child.
5067pub struct RenderTransform {
5068    render_object: RenderObjectData,
5069    render_box: RenderBoxData,
5070    child: RenderObjectWithChildData<AnyRenderBox>,
5071    origin: Option<Offset>,
5072    alignment: Option<AlignmentGeometry>,
5073    text_direction: Option<TextDirection>,
5074    transform_hit_tests: bool,
5075    transform: Matrix4,
5076}
5077
5078impl RenderTransform {
5079    /// Creates a render object that transforms its child.
5080    pub fn new(
5081        app: &mut App,
5082        transform: Matrix4,
5083        origin: Option<Offset>,
5084        alignment: Option<AlignmentGeometry>,
5085        text_direction: Option<TextDirection>,
5086        transform_hit_tests: bool,
5087        child: Option<AnyRenderBox>,
5088    ) -> RenderHandle<RenderTransform> {
5089        let this = RenderHandle::new_box(
5090            app,
5091            RenderTransform {
5092                render_object: RenderObjectData::new(),
5093                render_box: RenderBoxData::new(),
5094                child: RenderObjectWithChildData::new(),
5095                origin,
5096                alignment,
5097                text_direction,
5098                transform_hit_tests,
5099                transform,
5100            },
5101        );
5102        this.set_child(app, child);
5103        this
5104    }
5105
5106    /// The origin of the coordinate system (relative to the upper left corner of
5107    /// this render object) in which to apply the matrix.
5108    ///
5109    /// Setting an origin is equivalent to conjugating the transform matrix by a
5110    /// translation. This property is provided just for convenience.
5111    pub fn origin(self: RenderHandle<Self>, app: &App) -> Option<Offset> {
5112        self.get(app).origin
5113    }
5114
5115    /// Sets [`origin`](Self::origin).
5116    pub fn set_origin(self: RenderHandle<Self>, app: &mut App, value: Option<Offset>) {
5117        if self.get(app).origin == value {
5118            return;
5119        }
5120        self.get_mut(app).origin = value;
5121        self.mark_needs_paint(app);
5122    }
5123
5124    /// The alignment of the origin, relative to the size of the box.
5125    ///
5126    /// This is equivalent to setting an origin based on the size of the box.
5127    /// If it is specified at the same time as an offset, both are applied.
5128    ///
5129    /// An `AlignmentDirectional::CENTER_START` value is the same as an [`Alignment`]
5130    /// whose `x` value is `-1.0` if [`text_direction`](Self::text_direction) is
5131    /// [`TextDirection::Ltr`], and `1.0` if it is [`TextDirection::Rtl`].
5132    /// Similarly `AlignmentDirectional::CENTER_END` is the same as an [`Alignment`]
5133    /// whose `x` value is `1.0` if [`text_direction`](Self::text_direction) is
5134    /// [`TextDirection::Ltr`], and `-1.0` if it is [`TextDirection::Rtl`].
5135    ///
5136    /// [`Alignment`]: inset_painting::Alignment
5137    pub fn alignment(self: RenderHandle<Self>, app: &App) -> Option<AlignmentGeometry> {
5138        self.get(app).alignment
5139    }
5140
5141    /// Sets [`alignment`](Self::alignment).
5142    pub fn set_alignment(
5143        self: RenderHandle<Self>,
5144        app: &mut App,
5145        value: Option<AlignmentGeometry>,
5146    ) {
5147        if self.get(app).alignment == value {
5148            return;
5149        }
5150        self.get_mut(app).alignment = value;
5151        self.mark_needs_paint(app);
5152    }
5153
5154    /// The text direction with which to resolve [`alignment`](Self::alignment).
5155    ///
5156    /// This may be changed to `None`, but only after [`alignment`](Self::alignment) has been
5157    /// changed to a value that does not depend on the direction.
5158    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
5159        self.get(app).text_direction
5160    }
5161
5162    /// Sets [`text_direction`](Self::text_direction).
5163    pub fn set_text_direction(
5164        self: RenderHandle<Self>,
5165        app: &mut App,
5166        value: Option<TextDirection>,
5167    ) {
5168        if self.get(app).text_direction == value {
5169            return;
5170        }
5171        self.get_mut(app).text_direction = value;
5172        self.mark_needs_paint(app);
5173    }
5174
5175    /// When true, hit tests are performed based on the position of the
5176    /// child as it is painted. When false, hit tests are performed
5177    /// ignoring the transformation.
5178    ///
5179    /// [`RenderBox::apply_paint_transform`], and therefore
5180    /// [`AnyRenderBox::local_to_global`] and [`AnyRenderBox::global_to_local`], always honor
5181    /// the transformation, regardless of the value of this property.
5182    pub fn transform_hit_tests(self: RenderHandle<Self>, app: &App) -> bool {
5183        self.get(app).transform_hit_tests
5184    }
5185
5186    /// Sets [`transform_hit_tests`](Self::transform_hit_tests). Dart's plain field.
5187    pub fn set_transform_hit_tests(self: RenderHandle<Self>, app: &mut App, value: bool) {
5188        self.get_mut(app).transform_hit_tests = value;
5189    }
5190
5191    /// Sets the matrix to transform the child by during painting.
5192    ///
5193    /// There is no getter for the transform, as in Dart, where the matrix is mutable and
5194    /// mutations outside of the control of the render object could not reliably be reflected
5195    /// in the rendering.
5196    pub fn set_transform(self: RenderHandle<Self>, app: &mut App, value: Matrix4) {
5197        if self.get(app).transform == value {
5198            return;
5199        }
5200        self.get_mut(app).transform = value;
5201        self.mark_needs_paint(app);
5202    }
5203
5204    /// Sets the transform to the identity matrix.
5205    pub fn set_identity(self: RenderHandle<Self>, app: &mut App) {
5206        self.get_mut(app).transform = Matrix4::IDENTITY;
5207        self.mark_needs_paint(app);
5208    }
5209
5210    /// Concatenates a rotation about the x axis into the transform.
5211    pub fn rotate_x(self: RenderHandle<Self>, app: &mut App, radians: f64) {
5212        let (sin, cos) = (radians.sin() as f32, radians.cos() as f32);
5213        #[rustfmt::skip]
5214        let rotation = Matrix4::from_flutter_array(&[
5215            1.0, 0.0, 0.0, 0.0,
5216            0.0, cos, sin, 0.0,
5217            0.0, -sin, cos, 0.0,
5218            0.0, 0.0, 0.0, 1.0,
5219        ]);
5220        self.concat(app, &rotation);
5221    }
5222
5223    /// Concatenates a rotation about the y axis into the transform.
5224    pub fn rotate_y(self: RenderHandle<Self>, app: &mut App, radians: f64) {
5225        let (sin, cos) = (radians.sin() as f32, radians.cos() as f32);
5226        #[rustfmt::skip]
5227        let rotation = Matrix4::from_flutter_array(&[
5228            cos, 0.0, -sin, 0.0,
5229            0.0, 1.0, 0.0, 0.0,
5230            sin, 0.0, cos, 0.0,
5231            0.0, 0.0, 0.0, 1.0,
5232        ]);
5233        self.concat(app, &rotation);
5234    }
5235
5236    /// Concatenates a rotation about the z axis into the transform.
5237    pub fn rotate_z(self: RenderHandle<Self>, app: &mut App, radians: f64) {
5238        let (sin, cos) = (radians.sin() as f32, radians.cos() as f32);
5239        #[rustfmt::skip]
5240        let rotation = Matrix4::from_flutter_array(&[
5241            cos, sin, 0.0, 0.0,
5242            -sin, cos, 0.0, 0.0,
5243            0.0, 0.0, 1.0, 0.0,
5244            0.0, 0.0, 0.0, 1.0,
5245        ]);
5246        self.concat(app, &rotation);
5247    }
5248
5249    /// Concatenates a translation by (x, y, z) into the transform.
5250    pub fn translate(self: RenderHandle<Self>, app: &mut App, x: f64, y: f64, z: f64) {
5251        #[rustfmt::skip]
5252        let translation = Matrix4::from_flutter_array(&[
5253            1.0, 0.0, 0.0, 0.0,
5254            0.0, 1.0, 0.0, 0.0,
5255            0.0, 0.0, 1.0, 0.0,
5256            x as f32, y as f32, z as f32, 1.0,
5257        ]);
5258        self.concat(app, &translation);
5259    }
5260
5261    /// Concatenates a scale into the transform. Dart's optional `y` and `z` default to `x`.
5262    pub fn scale(self: RenderHandle<Self>, app: &mut App, x: f64, y: Option<f64>, z: Option<f64>) {
5263        let (y, z) = (y.unwrap_or(x) as f32, z.unwrap_or(x) as f32);
5264        #[rustfmt::skip]
5265        let scale = Matrix4::from_flutter_array(&[
5266            x as f32, 0.0, 0.0, 0.0,
5267            0.0, y, 0.0, 0.0,
5268            0.0, 0.0, z, 0.0,
5269            0.0, 0.0, 0.0, 1.0,
5270        ]);
5271        self.concat(app, &scale);
5272    }
5273
5274    /// vector_math's in-place `rotateX` / `translate` / `scale`: a right multiplication of the
5275    /// transform, then a repaint.
5276    fn concat(self: RenderHandle<Self>, app: &mut App, other: &Matrix4) {
5277        crate::object::multiply(&mut self.get_mut(app).transform, other);
5278        self.mark_needs_paint(app);
5279    }
5280
5281    /// Flutter's `_effectiveTransform`: the transform around [`origin`](Self::origin) and the
5282    /// resolved [`alignment`](Self::alignment).
5283    fn effective_transform(self: RenderHandle<Self>, app: &App) -> Matrix4 {
5284        let this = self.get(app);
5285        let resolved_alignment = this
5286            .alignment
5287            .map(|alignment| alignment.resolve(this.text_direction));
5288        let origin = this.origin;
5289        if origin.is_none() && resolved_alignment.is_none() {
5290            return this.transform;
5291        }
5292        let mut result = Matrix4::IDENTITY;
5293        if let Some(origin) = origin {
5294            crate::object::translate(&mut result, origin.dx(), origin.dy());
5295        }
5296        let translation = resolved_alignment.map(|alignment| alignment.along_size(self.size(app)));
5297        if let Some(translation) = translation {
5298            crate::object::translate(&mut result, translation.dx(), translation.dy());
5299        }
5300        crate::object::multiply(&mut result, &self.get(app).transform);
5301        if let Some(translation) = translation {
5302            crate::object::translate(&mut result, -translation.dx(), -translation.dy());
5303        }
5304        if let Some(origin) = origin {
5305            crate::object::translate(&mut result, -origin.dx(), -origin.dy());
5306        }
5307        result
5308    }
5309}
5310
5311impl RenderObjectWithChildMixin for RenderTransform {
5312    type ChildType = AnyRenderBox;
5313
5314    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
5315        &self.get(app).child
5316    }
5317
5318    fn child_data_mut(
5319        self: RenderHandle<Self>,
5320        app: &mut App,
5321    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
5322        &mut self.get_mut(app).child
5323    }
5324}
5325
5326impl RenderProxyBoxMixin for RenderTransform {}
5327
5328impl RenderObject for RenderTransform {
5329    crate::render_object_accessors!();
5330
5331    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
5332        RenderProxyBoxMixin::perform_layout(self, app);
5333    }
5334
5335    fn paint(
5336        self: RenderHandle<Self>,
5337        app: &mut App,
5338        context: &mut PaintingContext,
5339        offset: Offset,
5340    ) {
5341        if self.child(app).is_none() {
5342            return;
5343        }
5344        let transform = self.effective_transform(app);
5345        let Some(child_offset) = get_as_translation(transform) else {
5346            // If the matrix is singular the children would be compressed to a line or
5347            // single point, instead short-circuit and paint nothing.
5348            let determinant = transform.determinant();
5349            if determinant == 0.0 || !determinant.is_finite() {
5350                self.as_object().set_layer(app, None);
5351                return;
5352            }
5353            let old = self.as_object().layer_as::<TransformLayer>(app);
5354            let layer = context.push_transform(
5355                app,
5356                self.as_object().needs_compositing(app),
5357                offset,
5358                transform,
5359                |app, context, offset| {
5360                    RenderProxyBoxMixin::paint(self, app, context, offset);
5361                },
5362                old,
5363            );
5364            self.as_object()
5365                .set_layer(app, layer.map(|layer| layer.as_container_layer()));
5366            return;
5367        };
5368        RenderProxyBoxMixin::paint(self, app, context, offset + child_offset);
5369        self.as_object().set_layer(app, None);
5370    }
5371
5372    fn visit_children(
5373        self: RenderHandle<Self>,
5374        app: &App,
5375        visitor: &mut dyn FnMut(AnyRenderObject),
5376    ) {
5377        if let Some(child) = self.child(app) {
5378            visitor(child.as_object());
5379        }
5380    }
5381}
5382
5383impl RenderBox for RenderTransform {
5384    crate::render_box_accessors!();
5385
5386    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
5387        RenderProxyBoxMixin::setup_parent_data(self, app, child);
5388    }
5389
5390    fn apply_paint_transform(
5391        self: RenderHandle<Self>,
5392        app: &App,
5393        _child: AnyRenderObject,
5394        transform: &mut Matrix4,
5395    ) {
5396        crate::object::multiply(transform, &self.effective_transform(app));
5397    }
5398
5399    fn hit_test(
5400        self: RenderHandle<Self>,
5401        app: &mut App,
5402        result: &mut BoxHitTestResult<'_>,
5403        position: Offset,
5404    ) -> bool {
5405        // RenderTransform objects don't check if they are
5406        // themselves hit, because it's confusing to think about
5407        // how the untransformed size and the child's transformed
5408        // position interact.
5409        RenderBox::hit_test_children(self, app, result, position)
5410    }
5411
5412    fn hit_test_children(
5413        self: RenderHandle<Self>,
5414        app: &mut App,
5415        result: &mut BoxHitTestResult<'_>,
5416        position: Offset,
5417    ) -> bool {
5418        let transform = self
5419            .transform_hit_tests(app)
5420            .then(|| self.effective_transform(app));
5421        result.add_with_paint_transform(transform, position, |result, position| {
5422            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
5423        })
5424    }
5425
5426    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5427        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
5428    }
5429
5430    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5431        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
5432    }
5433
5434    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5435        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
5436    }
5437
5438    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5439        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
5440    }
5441
5442    fn compute_distance_to_actual_baseline(
5443        self: RenderHandle<Self>,
5444        app: &mut App,
5445        baseline: TextBaseline,
5446    ) -> Option<f64> {
5447        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
5448    }
5449
5450    fn compute_dry_baseline(
5451        self: RenderHandle<Self>,
5452        app: &mut App,
5453        constraints: BoxConstraints,
5454        baseline: TextBaseline,
5455    ) -> Option<f64> {
5456        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
5457    }
5458
5459    fn compute_dry_layout(
5460        self: RenderHandle<Self>,
5461        app: &mut App,
5462        constraints: BoxConstraints,
5463    ) -> Size {
5464        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
5465    }
5466}
5467
5468/// Scales and positions its child within itself according to [`fit`](Self::fit).
5469pub struct RenderFittedBox {
5470    render_object: RenderObjectData,
5471    render_box: RenderBoxData,
5472    child: RenderObjectWithChildData<AnyRenderBox>,
5473    fit: BoxFit,
5474    alignment: AlignmentGeometry,
5475    text_direction: Option<TextDirection>,
5476    resolved_alignment: Option<Alignment>,
5477    clip_behavior: Clip,
5478    has_visual_overflow: Option<bool>,
5479    transform: Option<Matrix4>,
5480}
5481
5482/// Whether a change of [`BoxFit`] changes the size this box takes.
5483fn fit_affects_layout(fit: BoxFit) -> bool {
5484    match fit {
5485        BoxFit::ScaleDown => true,
5486        BoxFit::Contain
5487        | BoxFit::Cover
5488        | BoxFit::Fill
5489        | BoxFit::FitHeight
5490        | BoxFit::FitWidth
5491        | BoxFit::None => false,
5492    }
5493}
5494
5495impl RenderFittedBox {
5496    /// Creates a render object that scales and positions its child within itself.
5497    pub fn new(
5498        app: &mut App,
5499        fit: BoxFit,
5500        alignment: AlignmentGeometry,
5501        text_direction: Option<TextDirection>,
5502        child: Option<AnyRenderBox>,
5503    ) -> RenderHandle<RenderFittedBox> {
5504        let this = RenderHandle::new_box(
5505            app,
5506            RenderFittedBox {
5507                render_object: RenderObjectData::new(),
5508                render_box: RenderBoxData::new(),
5509                child: RenderObjectWithChildData::new(),
5510                fit,
5511                alignment,
5512                text_direction,
5513                resolved_alignment: None,
5514                clip_behavior: Clip::None,
5515                has_visual_overflow: None,
5516                transform: None,
5517            },
5518        );
5519        this.set_child(app, child);
5520        this
5521    }
5522
5523    fn resolve(self: RenderHandle<Self>, app: &mut App) -> Alignment {
5524        let this = self.get(app);
5525        if let Some(resolved) = this.resolved_alignment {
5526            return resolved;
5527        }
5528        let resolved = this.alignment.resolve(this.text_direction);
5529        self.get_mut(app).resolved_alignment = Some(resolved);
5530        resolved
5531    }
5532
5533    fn mark_need_resolution(self: RenderHandle<Self>, app: &mut App) {
5534        self.get_mut(app).resolved_alignment = None;
5535        self.mark_needs_paint(app);
5536    }
5537
5538    /// How to inscribe the child into the space allocated during layout.
5539    pub fn fit(self: RenderHandle<Self>, app: &App) -> BoxFit {
5540        self.get(app).fit
5541    }
5542
5543    /// Sets [`fit`](Self::fit).
5544    pub fn set_fit(self: RenderHandle<Self>, app: &mut App, value: BoxFit) {
5545        let last_fit = self.get(app).fit;
5546        if last_fit == value {
5547            return;
5548        }
5549        self.get_mut(app).fit = value;
5550        if fit_affects_layout(last_fit) || fit_affects_layout(value) {
5551            self.mark_needs_layout(app);
5552        } else {
5553            self.clear_paint_data(app);
5554            self.mark_needs_paint(app);
5555        }
5556    }
5557
5558    /// How to align the child within its parent's bounds.
5559    ///
5560    /// An alignment of (0.0, 0.0) aligns the child to the top-left corner of its parent's bounds.
5561    /// An alignment of (1.0, 0.5) aligns the child to the middle of the right edge of its
5562    /// parent's bounds.
5563    pub fn alignment(self: RenderHandle<Self>, app: &App) -> AlignmentGeometry {
5564        self.get(app).alignment
5565    }
5566
5567    /// Sets [`alignment`](Self::alignment).
5568    pub fn set_alignment(self: RenderHandle<Self>, app: &mut App, value: AlignmentGeometry) {
5569        if self.get(app).alignment == value {
5570            return;
5571        }
5572        self.get_mut(app).alignment = value;
5573        self.clear_paint_data(app);
5574        self.mark_need_resolution(app);
5575    }
5576
5577    /// The text direction with which to resolve [`alignment`](Self::alignment).
5578    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
5579        self.get(app).text_direction
5580    }
5581
5582    /// Sets [`text_direction`](Self::text_direction).
5583    pub fn set_text_direction(
5584        self: RenderHandle<Self>,
5585        app: &mut App,
5586        value: Option<TextDirection>,
5587    ) {
5588        if self.get(app).text_direction == value {
5589            return;
5590        }
5591        self.get_mut(app).text_direction = value;
5592        self.clear_paint_data(app);
5593        self.mark_need_resolution(app);
5594    }
5595
5596    /// How to clip a child that overflows this box. Defaults to [`Clip::None`].
5597    pub fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
5598        self.get(app).clip_behavior
5599    }
5600
5601    /// Sets [`clip_behavior`](Self::clip_behavior).
5602    pub fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
5603        if self.get(app).clip_behavior == value {
5604            return;
5605        }
5606        self.get_mut(app).clip_behavior = value;
5607        self.mark_needs_paint(app);
5608    }
5609
5610    /// Whether the given child would be painted if [`RenderObject::paint`] were called.
5611    ///
5612    /// Flutter's `RenderObject.paintsChild` is a virtual whose default is true; here it is an
5613    /// inherent method (`PORTING.md`).
5614    pub fn paints_child(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> bool {
5615        debug_assert_eq!(child.as_object().parent(app), Some(self.as_object()));
5616        !self.size(app).is_empty() && !child.size(app).is_empty()
5617    }
5618
5619    fn clear_paint_data(self: RenderHandle<Self>, app: &mut App) {
5620        let this = self.get_mut(app);
5621        this.has_visual_overflow = None;
5622        this.transform = None;
5623    }
5624
5625    /// Flutter's `_updatePaintData`, without the cache: the transform that fits the child into
5626    /// this box, and whether the child overflows it.
5627    fn paint_data(self: RenderHandle<Self>, app: &App) -> (bool, Matrix4) {
5628        let Some(child) = self.child(app) else {
5629            return (false, Matrix4::IDENTITY);
5630        };
5631        let this = self.get(app);
5632        let resolved_alignment = this
5633            .resolved_alignment
5634            .unwrap_or_else(|| this.alignment.resolve(this.text_direction));
5635        let child_size = child.size(app);
5636        let sizes = apply_box_fit(this.fit, child_size, self.size(app));
5637        let scale_x = sizes.destination.width() / sizes.source.width();
5638        let scale_y = sizes.destination.height() / sizes.source.height();
5639        let source_rect = resolved_alignment.inscribe(sizes.source, Offset::ZERO & child_size);
5640        let destination_rect =
5641            resolved_alignment.inscribe(sizes.destination, Offset::ZERO & self.size(app));
5642        debug_assert!(scale_x.is_finite() && scale_y.is_finite());
5643        let mut transform =
5644            Matrix4::translation(destination_rect.left as f32, destination_rect.top as f32);
5645        crate::object::multiply(
5646            &mut transform,
5647            &Matrix4::scale(scale_x as f32, scale_y as f32),
5648        );
5649        crate::object::translate(&mut transform, -source_rect.left, -source_rect.top);
5650        let has_visual_overflow =
5651            source_rect.width() < child_size.width() || source_rect.height() < child_size.height();
5652        (has_visual_overflow, transform)
5653    }
5654
5655    fn update_paint_data(self: RenderHandle<Self>, app: &mut App) {
5656        if self.get(app).transform.is_some() {
5657            return;
5658        }
5659        // Dart's `_resolve()` memoizes the resolved alignment here.
5660        self.resolve(app);
5661        let (has_visual_overflow, transform) = self.paint_data(app);
5662        let this = self.get_mut(app);
5663        this.has_visual_overflow = Some(has_visual_overflow);
5664        this.transform = Some(transform);
5665    }
5666
5667    fn paint_child_with_transform(
5668        self: RenderHandle<Self>,
5669        app: &mut App,
5670        context: &mut PaintingContext,
5671        offset: Offset,
5672    ) -> Option<Handle<TransformLayer>> {
5673        let transform = self.get(app).transform.expect("update_paint_data ran");
5674        match get_as_translation(transform) {
5675            Some(child_offset) => {
5676                RenderProxyBoxMixin::paint(self, app, context, offset + child_offset);
5677                None
5678            }
5679            None => context.push_transform(
5680                app,
5681                self.as_object().needs_compositing(app),
5682                offset,
5683                transform,
5684                |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
5685                self.as_object().layer_as::<TransformLayer>(app),
5686            ),
5687        }
5688    }
5689}
5690
5691impl RenderObjectWithChildMixin for RenderFittedBox {
5692    type ChildType = AnyRenderBox;
5693
5694    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
5695        &self.get(app).child
5696    }
5697
5698    fn child_data_mut(
5699        self: RenderHandle<Self>,
5700        app: &mut App,
5701    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
5702        &mut self.get_mut(app).child
5703    }
5704}
5705
5706impl RenderProxyBoxMixin for RenderFittedBox {}
5707
5708impl RenderObject for RenderFittedBox {
5709    crate::render_object_accessors!();
5710
5711    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
5712        let constraints = self.constraints(app);
5713        let Some(child) = self.child(app) else {
5714            self.set_size(app, constraints.smallest());
5715            return;
5716        };
5717        child.layout(app, BoxConstraints::new(), true);
5718        let child_size = child.size(app);
5719        let size = match self.fit(app) {
5720            BoxFit::ScaleDown => {
5721                let size_constraints = constraints.loosen();
5722                let unconstrained_size = size_constraints
5723                    .constrain_size_and_attempt_to_preserve_aspect_ratio(child_size);
5724                constraints.constrain(unconstrained_size)
5725            }
5726            BoxFit::Contain
5727            | BoxFit::Cover
5728            | BoxFit::Fill
5729            | BoxFit::FitHeight
5730            | BoxFit::FitWidth
5731            | BoxFit::None => {
5732                constraints.constrain_size_and_attempt_to_preserve_aspect_ratio(child_size)
5733            }
5734        };
5735        self.set_size(app, size);
5736        self.clear_paint_data(app);
5737    }
5738
5739    fn paint(
5740        self: RenderHandle<Self>,
5741        app: &mut App,
5742        context: &mut PaintingContext,
5743        offset: Offset,
5744    ) {
5745        let Some(child) = self.child(app) else {
5746            return;
5747        };
5748        if self.size(app).is_empty() || child.size(app).is_empty() {
5749            return;
5750        }
5751        self.update_paint_data(app);
5752        let clip_behavior = self.clip_behavior(app);
5753        if self.get(app).has_visual_overflow == Some(true) && clip_behavior != Clip::None {
5754            let clip_rect = Offset::ZERO & self.size(app);
5755            let old = self.as_object().layer_as::<ClipRectLayer>(app);
5756            let layer = context.push_clip_rect(
5757                app,
5758                self.as_object().needs_compositing(app),
5759                offset,
5760                clip_rect,
5761                |app, context, offset| {
5762                    let _ = self.paint_child_with_transform(app, context, offset);
5763                },
5764                clip_behavior,
5765                old,
5766            );
5767            self.as_object()
5768                .set_layer(app, layer.map(|layer| layer.as_container_layer()));
5769        } else {
5770            let layer = self.paint_child_with_transform(app, context, offset);
5771            self.as_object()
5772                .set_layer(app, layer.map(|layer| layer.as_container_layer()));
5773        }
5774    }
5775
5776    fn visit_children(
5777        self: RenderHandle<Self>,
5778        app: &App,
5779        visitor: &mut dyn FnMut(AnyRenderObject),
5780    ) {
5781        if let Some(child) = self.child(app) {
5782            visitor(child.as_object());
5783        }
5784    }
5785}
5786
5787impl RenderBox for RenderFittedBox {
5788    crate::render_box_accessors!();
5789
5790    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
5791        RenderProxyBoxMixin::setup_parent_data(self, app, child);
5792    }
5793
5794    fn apply_paint_transform(
5795        self: RenderHandle<Self>,
5796        app: &App,
5797        child: AnyRenderObject,
5798        transform: &mut Matrix4,
5799    ) {
5800        let child = child.as_box().expect("a fitted box has a box child");
5801        if !self.paints_child(app, child) {
5802            *transform = crate::object::zero_matrix();
5803            return;
5804        }
5805        let (_, fitted) = self.paint_data(app);
5806        crate::object::multiply(transform, &fitted);
5807    }
5808
5809    fn hit_test_children(
5810        self: RenderHandle<Self>,
5811        app: &mut App,
5812        result: &mut BoxHitTestResult<'_>,
5813        position: Offset,
5814    ) -> bool {
5815        let child_is_empty = self
5816            .child(app)
5817            .is_none_or(|child| child.size(app).is_empty());
5818        if self.size(app).is_empty() || child_is_empty {
5819            return false;
5820        }
5821        self.update_paint_data(app);
5822        let transform = self.get(app).transform;
5823        result.add_with_paint_transform(transform, position, |result, position| {
5824            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
5825        })
5826    }
5827
5828    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5829        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
5830    }
5831
5832    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5833        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
5834    }
5835
5836    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5837        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
5838    }
5839
5840    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5841        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
5842    }
5843
5844    fn compute_distance_to_actual_baseline(
5845        self: RenderHandle<Self>,
5846        app: &mut App,
5847        baseline: TextBaseline,
5848    ) -> Option<f64> {
5849        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
5850    }
5851
5852    fn compute_dry_layout(
5853        self: RenderHandle<Self>,
5854        app: &mut App,
5855        constraints: BoxConstraints,
5856    ) -> Size {
5857        let Some(child) = self.child(app) else {
5858            return constraints.smallest();
5859        };
5860        let child_size = child.get_dry_layout(app, BoxConstraints::new());
5861        match self.fit(app) {
5862            BoxFit::ScaleDown => {
5863                let size_constraints = constraints.loosen();
5864                let unconstrained_size = size_constraints
5865                    .constrain_size_and_attempt_to_preserve_aspect_ratio(child_size);
5866                constraints.constrain(unconstrained_size)
5867            }
5868            BoxFit::Contain
5869            | BoxFit::Cover
5870            | BoxFit::Fill
5871            | BoxFit::FitHeight
5872            | BoxFit::FitWidth
5873            | BoxFit::None => {
5874                constraints.constrain_size_and_attempt_to_preserve_aspect_ratio(child_size)
5875            }
5876        }
5877    }
5878
5879    fn compute_dry_baseline(
5880        self: RenderHandle<Self>,
5881        app: &mut App,
5882        _constraints: BoxConstraints,
5883        baseline: TextBaseline,
5884    ) -> Option<f64> {
5885        // The baseline of the child with unconstrained layout, without applying any transforms
5886        // or scaling that would be applied during paint.
5887        self.child(app)?
5888            .get_dry_baseline(app, BoxConstraints::new(), baseline)
5889    }
5890}
5891
5892/// Applies a translation transformation before painting its child.
5893///
5894/// The translation is expressed as an [`Offset`] scaled to the child's size. For
5895/// example, an [`Offset`] with a `dx` of 0.25 will result in a horizontal
5896/// translation of one quarter the width of the child.
5897///
5898/// Hit tests will only be detected inside the bounds of the
5899/// [`RenderFractionalTranslation`], even if the contents are offset such that
5900/// they overflow.
5901pub struct RenderFractionalTranslation {
5902    render_object: RenderObjectData,
5903    render_box: RenderBoxData,
5904    child: RenderObjectWithChildData<AnyRenderBox>,
5905    translation: Offset,
5906    transform_hit_tests: bool,
5907}
5908
5909impl RenderFractionalTranslation {
5910    /// Creates a render object that translates its child's painting.
5911    pub fn new(
5912        app: &mut App,
5913        translation: Offset,
5914        transform_hit_tests: bool,
5915        child: Option<AnyRenderBox>,
5916    ) -> RenderHandle<RenderFractionalTranslation> {
5917        let this = RenderHandle::new_box(
5918            app,
5919            RenderFractionalTranslation {
5920                render_object: RenderObjectData::new(),
5921                render_box: RenderBoxData::new(),
5922                child: RenderObjectWithChildData::new(),
5923                translation,
5924                transform_hit_tests,
5925            },
5926        );
5927        this.set_child(app, child);
5928        this
5929    }
5930
5931    /// The translation to apply to the child, scaled to the child's size.
5932    ///
5933    /// For example, an [`Offset`] with a `dx` of 0.25 will result in a horizontal
5934    /// translation of one quarter the width of the child.
5935    pub fn translation(self: RenderHandle<Self>, app: &App) -> Offset {
5936        self.get(app).translation
5937    }
5938
5939    /// Sets [`translation`](Self::translation).
5940    pub fn set_translation(self: RenderHandle<Self>, app: &mut App, value: Offset) {
5941        if self.get(app).translation == value {
5942            return;
5943        }
5944        self.get_mut(app).translation = value;
5945        self.mark_needs_paint(app);
5946    }
5947
5948    /// When true, hit tests are performed based on the position of the
5949    /// child as it is painted. When false, hit tests are performed
5950    /// ignoring the transformation.
5951    ///
5952    /// [`RenderBox::apply_paint_transform`], and therefore
5953    /// [`AnyRenderBox::local_to_global`] and [`AnyRenderBox::global_to_local`], always honor
5954    /// the transformation, regardless of the value of this property.
5955    pub fn transform_hit_tests(self: RenderHandle<Self>, app: &App) -> bool {
5956        self.get(app).transform_hit_tests
5957    }
5958
5959    /// Sets [`transform_hit_tests`](Self::transform_hit_tests). Dart's plain field.
5960    pub fn set_transform_hit_tests(self: RenderHandle<Self>, app: &mut App, value: bool) {
5961        self.get_mut(app).transform_hit_tests = value;
5962    }
5963
5964    /// The translation in layout pixels: [`translation`](Self::translation) along the size.
5965    fn absolute_translation(self: RenderHandle<Self>, app: &App) -> Offset {
5966        let translation = self.get(app).translation;
5967        let size = self.size(app);
5968        Offset::new(
5969            translation.dx() * size.width(),
5970            translation.dy() * size.height(),
5971        )
5972    }
5973}
5974
5975impl RenderObjectWithChildMixin for RenderFractionalTranslation {
5976    type ChildType = AnyRenderBox;
5977
5978    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
5979        &self.get(app).child
5980    }
5981
5982    fn child_data_mut(
5983        self: RenderHandle<Self>,
5984        app: &mut App,
5985    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
5986        &mut self.get_mut(app).child
5987    }
5988}
5989
5990impl RenderProxyBoxMixin for RenderFractionalTranslation {}
5991
5992impl RenderObject for RenderFractionalTranslation {
5993    crate::render_object_accessors!();
5994
5995    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
5996        RenderProxyBoxMixin::perform_layout(self, app);
5997    }
5998
5999    fn paint(
6000        self: RenderHandle<Self>,
6001        app: &mut App,
6002        context: &mut PaintingContext,
6003        offset: Offset,
6004    ) {
6005        debug_assert!(!self.debug_needs_layout(app));
6006        if self.child(app).is_none() {
6007            return;
6008        }
6009        let translation = self.absolute_translation(app);
6010        RenderProxyBoxMixin::paint(self, app, context, offset + translation);
6011    }
6012
6013    fn visit_children(
6014        self: RenderHandle<Self>,
6015        app: &App,
6016        visitor: &mut dyn FnMut(AnyRenderObject),
6017    ) {
6018        if let Some(child) = self.child(app) {
6019            visitor(child.as_object());
6020        }
6021    }
6022}
6023
6024impl RenderBox for RenderFractionalTranslation {
6025    crate::render_box_accessors!();
6026
6027    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6028        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6029    }
6030
6031    fn apply_paint_transform(
6032        self: RenderHandle<Self>,
6033        app: &App,
6034        _child: AnyRenderObject,
6035        transform: &mut Matrix4,
6036    ) {
6037        let translation = self.absolute_translation(app);
6038        crate::object::translate(transform, translation.dx(), translation.dy());
6039    }
6040
6041    fn hit_test(
6042        self: RenderHandle<Self>,
6043        app: &mut App,
6044        result: &mut BoxHitTestResult<'_>,
6045        position: Offset,
6046    ) -> bool {
6047        // RenderFractionalTranslation objects don't check if they are
6048        // themselves hit, because it's confusing to think about
6049        // how the untransformed size and the child's transformed
6050        // position interact.
6051        RenderBox::hit_test_children(self, app, result, position)
6052    }
6053
6054    fn hit_test_children(
6055        self: RenderHandle<Self>,
6056        app: &mut App,
6057        result: &mut BoxHitTestResult<'_>,
6058        position: Offset,
6059    ) -> bool {
6060        debug_assert!(!self.debug_needs_layout(app));
6061        let offset = self
6062            .transform_hit_tests(app)
6063            .then(|| self.absolute_translation(app));
6064        result.add_with_paint_offset(offset, position, |result, position| {
6065            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6066        })
6067    }
6068
6069    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6070        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6071    }
6072
6073    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6074        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6075    }
6076
6077    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6078        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6079    }
6080
6081    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6082        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6083    }
6084
6085    fn compute_distance_to_actual_baseline(
6086        self: RenderHandle<Self>,
6087        app: &mut App,
6088        baseline: TextBaseline,
6089    ) -> Option<f64> {
6090        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6091    }
6092
6093    fn compute_dry_baseline(
6094        self: RenderHandle<Self>,
6095        app: &mut App,
6096        constraints: BoxConstraints,
6097        baseline: TextBaseline,
6098    ) -> Option<f64> {
6099        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6100    }
6101
6102    fn compute_dry_layout(
6103        self: RenderHandle<Self>,
6104        app: &mut App,
6105        constraints: BoxConstraints,
6106    ) -> Size {
6107        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6108    }
6109}
6110
6111/// A render object that is invisible during hit testing.
6112///
6113/// When [`ignoring`](Self::ignoring) is true, this render object (and its subtree) is invisible
6114/// to hit testing. It still consumes space during layout and paints its child
6115/// as usual. It just cannot be the target of located events, because its render
6116/// object returns false from [`RenderBox::hit_test`].
6117///
6118/// See also:
6119///
6120///  * [`RenderAbsorbPointer`], which takes the pointer events but prevents any
6121///    nodes in the subtree from seeing them.
6122pub struct RenderIgnorePointer {
6123    render_object: RenderObjectData,
6124    render_box: RenderBoxData,
6125    child: RenderObjectWithChildData<AnyRenderBox>,
6126    ignoring: bool,
6127}
6128
6129impl RenderIgnorePointer {
6130    /// Creates a render object that is invisible to hit testing.
6131    pub fn new(
6132        app: &mut App,
6133        ignoring: bool,
6134        child: Option<AnyRenderBox>,
6135    ) -> RenderHandle<RenderIgnorePointer> {
6136        let this = RenderHandle::new_box(
6137            app,
6138            RenderIgnorePointer {
6139                render_object: RenderObjectData::new(),
6140                render_box: RenderBoxData::new(),
6141                child: RenderObjectWithChildData::new(),
6142                ignoring,
6143            },
6144        );
6145        this.set_child(app, child);
6146        this
6147    }
6148
6149    /// Whether this render object is ignored during hit testing.
6150    ///
6151    /// Regardless of whether this render object is ignored during hit testing, it
6152    /// will still consume space during layout and be visible during painting.
6153    pub fn ignoring(self: RenderHandle<Self>, app: &App) -> bool {
6154        self.get(app).ignoring
6155    }
6156
6157    /// Sets [`ignoring`](Self::ignoring).
6158    pub fn set_ignoring(self: RenderHandle<Self>, app: &mut App, value: bool) {
6159        if value == self.get(app).ignoring {
6160            return;
6161        }
6162        self.get_mut(app).ignoring = value;
6163    }
6164}
6165
6166impl RenderObjectWithChildMixin for RenderIgnorePointer {
6167    type ChildType = AnyRenderBox;
6168
6169    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6170        &self.get(app).child
6171    }
6172
6173    fn child_data_mut(
6174        self: RenderHandle<Self>,
6175        app: &mut App,
6176    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6177        &mut self.get_mut(app).child
6178    }
6179}
6180
6181impl RenderProxyBoxMixin for RenderIgnorePointer {}
6182
6183impl RenderObject for RenderIgnorePointer {
6184    crate::render_object_accessors!();
6185
6186    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6187        RenderProxyBoxMixin::perform_layout(self, app);
6188    }
6189
6190    fn paint(
6191        self: RenderHandle<Self>,
6192        app: &mut App,
6193        context: &mut PaintingContext,
6194        offset: Offset,
6195    ) {
6196        RenderProxyBoxMixin::paint(self, app, context, offset);
6197    }
6198
6199    fn visit_children(
6200        self: RenderHandle<Self>,
6201        app: &App,
6202        visitor: &mut dyn FnMut(AnyRenderObject),
6203    ) {
6204        if let Some(child) = self.child(app) {
6205            visitor(child.as_object());
6206        }
6207    }
6208}
6209
6210impl RenderBox for RenderIgnorePointer {
6211    crate::render_box_accessors!();
6212
6213    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6214        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6215    }
6216
6217    fn apply_paint_transform(
6218        self: RenderHandle<Self>,
6219        app: &App,
6220        child: AnyRenderObject,
6221        transform: &mut Matrix4,
6222    ) {
6223        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6224    }
6225
6226    fn hit_test(
6227        self: RenderHandle<Self>,
6228        app: &mut App,
6229        result: &mut BoxHitTestResult<'_>,
6230        position: Offset,
6231    ) -> bool {
6232        !self.ignoring(app) && RenderBoxBase::hit_test(self, app, result, position)
6233    }
6234
6235    fn hit_test_children(
6236        self: RenderHandle<Self>,
6237        app: &mut App,
6238        result: &mut BoxHitTestResult<'_>,
6239        position: Offset,
6240    ) -> bool {
6241        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6242    }
6243
6244    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6245        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6246    }
6247
6248    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6249        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6250    }
6251
6252    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6253        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6254    }
6255
6256    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6257        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6258    }
6259
6260    fn compute_distance_to_actual_baseline(
6261        self: RenderHandle<Self>,
6262        app: &mut App,
6263        baseline: TextBaseline,
6264    ) -> Option<f64> {
6265        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6266    }
6267
6268    fn compute_dry_baseline(
6269        self: RenderHandle<Self>,
6270        app: &mut App,
6271        constraints: BoxConstraints,
6272        baseline: TextBaseline,
6273    ) -> Option<f64> {
6274        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6275    }
6276
6277    fn compute_dry_layout(
6278        self: RenderHandle<Self>,
6279        app: &mut App,
6280        constraints: BoxConstraints,
6281    ) -> Size {
6282        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6283    }
6284}
6285
6286/// Lays the child out as if it was in the tree, but without painting anything,
6287/// without making the child available for hit testing, and without taking any
6288/// room in the parent.
6289pub struct RenderOffstage {
6290    render_object: RenderObjectData,
6291    render_box: RenderBoxData,
6292    child: RenderObjectWithChildData<AnyRenderBox>,
6293    offstage: bool,
6294}
6295
6296impl RenderOffstage {
6297    /// Creates an offstage render object.
6298    pub fn new(
6299        app: &mut App,
6300        offstage: bool,
6301        child: Option<AnyRenderBox>,
6302    ) -> RenderHandle<RenderOffstage> {
6303        let this = RenderHandle::new_box(
6304            app,
6305            RenderOffstage {
6306                render_object: RenderObjectData::new(),
6307                render_box: RenderBoxData::new(),
6308                child: RenderObjectWithChildData::new(),
6309                offstage,
6310            },
6311        );
6312        this.set_child(app, child);
6313        this
6314    }
6315
6316    /// Whether the child is hidden from the rest of the tree.
6317    ///
6318    /// If true, the child is laid out as if it was in the tree, but without
6319    /// painting anything, without making the child available for hit testing, and
6320    /// without taking any room in the parent.
6321    ///
6322    /// If false, the child is included in the tree as normal.
6323    pub fn offstage(self: RenderHandle<Self>, app: &App) -> bool {
6324        self.get(app).offstage
6325    }
6326
6327    /// Sets [`offstage`](Self::offstage).
6328    pub fn set_offstage(self: RenderHandle<Self>, app: &mut App, value: bool) {
6329        if value == self.get(app).offstage {
6330            return;
6331        }
6332        self.get_mut(app).offstage = value;
6333        self.as_object()
6334            .mark_needs_layout_for_sized_by_parent_change(app);
6335    }
6336
6337    /// Whether the given child would be painted if [`RenderObject::paint`] were called.
6338    ///
6339    /// Flutter's `RenderObject.paintsChild` is a virtual whose default is true; here only this
6340    /// override exists, as an inherent method (`PORTING.md`).
6341    pub fn paints_child(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> bool {
6342        debug_assert_eq!(child.as_object().parent(app), Some(self.as_object()));
6343        !self.get(app).offstage
6344    }
6345}
6346
6347impl RenderObjectWithChildMixin for RenderOffstage {
6348    type ChildType = AnyRenderBox;
6349
6350    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6351        &self.get(app).child
6352    }
6353
6354    fn child_data_mut(
6355        self: RenderHandle<Self>,
6356        app: &mut App,
6357    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6358        &mut self.get_mut(app).child
6359    }
6360}
6361
6362impl RenderProxyBoxMixin for RenderOffstage {}
6363
6364impl RenderObject for RenderOffstage {
6365    crate::render_object_accessors!();
6366
6367    fn sized_by_parent(self: RenderHandle<Self>, app: &App) -> bool {
6368        self.get(app).offstage
6369    }
6370
6371    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6372        if !self.get(app).offstage {
6373            RenderProxyBoxMixin::perform_layout(self, app);
6374            return;
6375        }
6376        if let Some(child) = self.child(app) {
6377            let constraints = self.constraints(app);
6378            child.layout(app, constraints, false);
6379        }
6380    }
6381
6382    fn paint(
6383        self: RenderHandle<Self>,
6384        app: &mut App,
6385        context: &mut PaintingContext,
6386        offset: Offset,
6387    ) {
6388        if self.get(app).offstage {
6389            return;
6390        }
6391        RenderProxyBoxMixin::paint(self, app, context, offset);
6392    }
6393
6394    fn visit_children(
6395        self: RenderHandle<Self>,
6396        app: &App,
6397        visitor: &mut dyn FnMut(AnyRenderObject),
6398    ) {
6399        if let Some(child) = self.child(app) {
6400            visitor(child.as_object());
6401        }
6402    }
6403}
6404
6405impl RenderBox for RenderOffstage {
6406    crate::render_box_accessors!();
6407
6408    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6409        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6410    }
6411
6412    fn apply_paint_transform(
6413        self: RenderHandle<Self>,
6414        app: &App,
6415        child: AnyRenderObject,
6416        transform: &mut Matrix4,
6417    ) {
6418        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6419    }
6420
6421    fn hit_test(
6422        self: RenderHandle<Self>,
6423        app: &mut App,
6424        result: &mut BoxHitTestResult<'_>,
6425        position: Offset,
6426    ) -> bool {
6427        !self.get(app).offstage && RenderBoxBase::hit_test(self, app, result, position)
6428    }
6429
6430    fn hit_test_children(
6431        self: RenderHandle<Self>,
6432        app: &mut App,
6433        result: &mut BoxHitTestResult<'_>,
6434        position: Offset,
6435    ) -> bool {
6436        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6437    }
6438
6439    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6440        if self.get(app).offstage {
6441            return 0.0;
6442        }
6443        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6444    }
6445
6446    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6447        if self.get(app).offstage {
6448            return 0.0;
6449        }
6450        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6451    }
6452
6453    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6454        if self.get(app).offstage {
6455            return 0.0;
6456        }
6457        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6458    }
6459
6460    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6461        if self.get(app).offstage {
6462            return 0.0;
6463        }
6464        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6465    }
6466
6467    fn compute_distance_to_actual_baseline(
6468        self: RenderHandle<Self>,
6469        app: &mut App,
6470        baseline: TextBaseline,
6471    ) -> Option<f64> {
6472        if self.get(app).offstage {
6473            return None;
6474        }
6475        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6476    }
6477
6478    fn compute_dry_baseline(
6479        self: RenderHandle<Self>,
6480        app: &mut App,
6481        constraints: BoxConstraints,
6482        baseline: TextBaseline,
6483    ) -> Option<f64> {
6484        if self.get(app).offstage {
6485            return None;
6486        }
6487        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6488    }
6489
6490    fn compute_dry_layout(
6491        self: RenderHandle<Self>,
6492        app: &mut App,
6493        constraints: BoxConstraints,
6494    ) -> Size {
6495        if self.get(app).offstage {
6496            return constraints.smallest();
6497        }
6498        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6499    }
6500
6501    /// Flutter's `performResize` asserts and calls `super.performResize`.
6502    fn perform_resize(self: RenderHandle<Self>, app: &mut App) {
6503        debug_assert!(self.get(app).offstage);
6504        RenderBoxBase::perform_resize(self, app);
6505    }
6506}
6507
6508/// A render object that absorbs pointers during hit testing.
6509///
6510/// When [`absorbing`](Self::absorbing) is true, this render object prevents its subtree from
6511/// receiving pointer events by terminating hit testing at itself. It still
6512/// consumes space during layout and paints its child as usual. It just prevents
6513/// its children from being the target of located events, because its render
6514/// object returns true from [`RenderBox::hit_test`].
6515///
6516/// See also:
6517///
6518///  * [`RenderIgnorePointer`], which has the opposite effect: removing the
6519///    subtree from considering entirely for the purposes of hit testing.
6520pub struct RenderAbsorbPointer {
6521    render_object: RenderObjectData,
6522    render_box: RenderBoxData,
6523    child: RenderObjectWithChildData<AnyRenderBox>,
6524    absorbing: bool,
6525}
6526
6527impl RenderAbsorbPointer {
6528    /// Creates a render object that absorbs pointers during hit testing.
6529    pub fn new(
6530        app: &mut App,
6531        absorbing: bool,
6532        child: Option<AnyRenderBox>,
6533    ) -> RenderHandle<RenderAbsorbPointer> {
6534        let this = RenderHandle::new_box(
6535            app,
6536            RenderAbsorbPointer {
6537                render_object: RenderObjectData::new(),
6538                render_box: RenderBoxData::new(),
6539                child: RenderObjectWithChildData::new(),
6540                absorbing,
6541            },
6542        );
6543        this.set_child(app, child);
6544        this
6545    }
6546
6547    /// Whether this render object absorbs pointers during hit testing.
6548    ///
6549    /// Regardless of whether this render object absorbs pointers during hit
6550    /// testing, it will still consume space during layout and be visible during
6551    /// painting.
6552    pub fn absorbing(self: RenderHandle<Self>, app: &App) -> bool {
6553        self.get(app).absorbing
6554    }
6555
6556    /// Sets [`absorbing`](Self::absorbing).
6557    pub fn set_absorbing(self: RenderHandle<Self>, app: &mut App, value: bool) {
6558        if self.get(app).absorbing == value {
6559            return;
6560        }
6561        self.get_mut(app).absorbing = value;
6562    }
6563}
6564
6565impl RenderObjectWithChildMixin for RenderAbsorbPointer {
6566    type ChildType = AnyRenderBox;
6567
6568    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6569        &self.get(app).child
6570    }
6571
6572    fn child_data_mut(
6573        self: RenderHandle<Self>,
6574        app: &mut App,
6575    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6576        &mut self.get_mut(app).child
6577    }
6578}
6579
6580impl RenderProxyBoxMixin for RenderAbsorbPointer {}
6581
6582impl RenderObject for RenderAbsorbPointer {
6583    crate::render_object_accessors!();
6584
6585    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6586        RenderProxyBoxMixin::perform_layout(self, app);
6587    }
6588
6589    fn paint(
6590        self: RenderHandle<Self>,
6591        app: &mut App,
6592        context: &mut PaintingContext,
6593        offset: Offset,
6594    ) {
6595        RenderProxyBoxMixin::paint(self, app, context, offset);
6596    }
6597
6598    fn visit_children(
6599        self: RenderHandle<Self>,
6600        app: &App,
6601        visitor: &mut dyn FnMut(AnyRenderObject),
6602    ) {
6603        if let Some(child) = self.child(app) {
6604            visitor(child.as_object());
6605        }
6606    }
6607}
6608
6609impl RenderBox for RenderAbsorbPointer {
6610    crate::render_box_accessors!();
6611
6612    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6613        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6614    }
6615
6616    fn apply_paint_transform(
6617        self: RenderHandle<Self>,
6618        app: &App,
6619        child: AnyRenderObject,
6620        transform: &mut Matrix4,
6621    ) {
6622        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6623    }
6624
6625    fn hit_test(
6626        self: RenderHandle<Self>,
6627        app: &mut App,
6628        result: &mut BoxHitTestResult<'_>,
6629        position: Offset,
6630    ) -> bool {
6631        if self.absorbing(app) {
6632            return self.size(app).contains(position);
6633        }
6634        RenderBoxBase::hit_test(self, app, result, position)
6635    }
6636
6637    fn hit_test_children(
6638        self: RenderHandle<Self>,
6639        app: &mut App,
6640        result: &mut BoxHitTestResult<'_>,
6641        position: Offset,
6642    ) -> bool {
6643        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6644    }
6645
6646    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6647        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6648    }
6649
6650    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6651        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6652    }
6653
6654    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6655        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6656    }
6657
6658    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6659        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6660    }
6661
6662    fn compute_distance_to_actual_baseline(
6663        self: RenderHandle<Self>,
6664        app: &mut App,
6665        baseline: TextBaseline,
6666    ) -> Option<f64> {
6667        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6668    }
6669
6670    fn compute_dry_baseline(
6671        self: RenderHandle<Self>,
6672        app: &mut App,
6673        constraints: BoxConstraints,
6674        baseline: TextBaseline,
6675    ) -> Option<f64> {
6676        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6677    }
6678
6679    fn compute_dry_layout(
6680        self: RenderHandle<Self>,
6681        app: &mut App,
6682        constraints: BoxConstraints,
6683    ) -> Size {
6684        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6685    }
6686}
6687
6688/// Paints its area with a specified [`Color`] and then draws its child on top of that color.
6689///
6690/// Flutter's `_RenderColoredBox`, the render object of the `ColoredBox` widget, in
6691/// `widgets/basic.dart`.
6692pub struct RenderColoredBox {
6693    render_object: RenderObjectData,
6694    render_box: RenderBoxData,
6695    child: RenderObjectWithChildData<AnyRenderBox>,
6696    color: Color,
6697    is_anti_alias: bool,
6698    behavior: HitTestBehavior,
6699}
6700
6701impl RenderColoredBox {
6702    /// Creates a render object that paints its area with `color`.
6703    pub fn new(
6704        app: &mut App,
6705        color: Color,
6706        is_anti_alias: bool,
6707        child: Option<AnyRenderBox>,
6708    ) -> RenderHandle<RenderColoredBox> {
6709        let this = RenderHandle::new_box(
6710            app,
6711            RenderColoredBox {
6712                render_object: RenderObjectData::new(),
6713                render_box: RenderBoxData::new(),
6714                child: RenderObjectWithChildData::new(),
6715                color,
6716                is_anti_alias,
6717                behavior: HitTestBehavior::Opaque,
6718            },
6719        );
6720        this.set_child(app, child);
6721        this
6722    }
6723
6724    /// The fill color for this render object.
6725    pub fn color(self: RenderHandle<Self>, app: &App) -> Color {
6726        self.get(app).color
6727    }
6728
6729    /// Sets [`color`](Self::color).
6730    pub fn set_color(self: RenderHandle<Self>, app: &mut App, value: Color) {
6731        if value == self.get(app).color {
6732            return;
6733        }
6734        self.get_mut(app).color = value;
6735        self.mark_needs_paint(app);
6736    }
6737
6738    /// Whether to apply anti-aliasing when painting the box.
6739    pub fn is_anti_alias(self: RenderHandle<Self>, app: &App) -> bool {
6740        self.get(app).is_anti_alias
6741    }
6742
6743    /// Sets [`is_anti_alias`](Self::is_anti_alias).
6744    pub fn set_is_anti_alias(self: RenderHandle<Self>, app: &mut App, value: bool) {
6745        if value == self.get(app).is_anti_alias {
6746            return;
6747        }
6748        self.get_mut(app).is_anti_alias = value;
6749        self.mark_needs_paint(app);
6750    }
6751}
6752
6753impl RenderObjectWithChildMixin for RenderColoredBox {
6754    type ChildType = AnyRenderBox;
6755
6756    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6757        &self.get(app).child
6758    }
6759
6760    fn child_data_mut(
6761        self: RenderHandle<Self>,
6762        app: &mut App,
6763    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6764        &mut self.get_mut(app).child
6765    }
6766}
6767
6768impl RenderProxyBoxMixin for RenderColoredBox {}
6769
6770impl RenderProxyBoxWithHitTestBehavior for RenderColoredBox {
6771    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
6772        self.get(app).behavior
6773    }
6774}
6775
6776impl RenderObject for RenderColoredBox {
6777    crate::render_object_accessors!();
6778
6779    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6780        RenderProxyBoxMixin::perform_layout(self, app);
6781    }
6782
6783    fn paint(
6784        self: RenderHandle<Self>,
6785        app: &mut App,
6786        context: &mut PaintingContext,
6787        offset: Offset,
6788    ) {
6789        // It's tempting to want to optimize out this `draw_rect()` call if the
6790        // color is transparent (alpha==0), but doing so would be incorrect. See
6791        // https://github.com/flutter/flutter/pull/72526#issuecomment-749185938 for
6792        // a good description of why.
6793        let size = self.size(app);
6794        if size.gt(&Size::ZERO) {
6795            let paint = Paint {
6796                color: self.get(app).color.into(),
6797                ..Paint::default()
6798            };
6799            context.canvas().draw_rect(offset & size, &paint);
6800        }
6801        if let Some(child) = self.child(app) {
6802            context.paint_child(app, child.as_object(), offset);
6803        }
6804    }
6805
6806    fn visit_children(
6807        self: RenderHandle<Self>,
6808        app: &App,
6809        visitor: &mut dyn FnMut(AnyRenderObject),
6810    ) {
6811        if let Some(child) = self.child(app) {
6812            visitor(child.as_object());
6813        }
6814    }
6815}
6816
6817impl RenderBox for RenderColoredBox {
6818    crate::render_box_accessors!();
6819
6820    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6821        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6822    }
6823
6824    fn apply_paint_transform(
6825        self: RenderHandle<Self>,
6826        app: &App,
6827        child: AnyRenderObject,
6828        transform: &mut Matrix4,
6829    ) {
6830        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6831    }
6832
6833    fn hit_test(
6834        self: RenderHandle<Self>,
6835        app: &mut App,
6836        result: &mut BoxHitTestResult<'_>,
6837        position: Offset,
6838    ) -> bool {
6839        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
6840    }
6841
6842    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
6843        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
6844    }
6845
6846    fn hit_test_children(
6847        self: RenderHandle<Self>,
6848        app: &mut App,
6849        result: &mut BoxHitTestResult<'_>,
6850        position: Offset,
6851    ) -> bool {
6852        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6853    }
6854
6855    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6856        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6857    }
6858
6859    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6860        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6861    }
6862
6863    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6864        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6865    }
6866
6867    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6868        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6869    }
6870
6871    fn compute_distance_to_actual_baseline(
6872        self: RenderHandle<Self>,
6873        app: &mut App,
6874        baseline: TextBaseline,
6875    ) -> Option<f64> {
6876        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6877    }
6878
6879    fn compute_dry_baseline(
6880        self: RenderHandle<Self>,
6881        app: &mut App,
6882        constraints: BoxConstraints,
6883        baseline: TextBaseline,
6884    ) -> Option<f64> {
6885        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6886    }
6887
6888    fn compute_dry_layout(
6889        self: RenderHandle<Self>,
6890        app: &mut App,
6891        constraints: BoxConstraints,
6892    ) -> Size {
6893        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6894    }
6895}
6896
6897/// Holds opaque meta data in the render tree.
6898///
6899/// Useful for decorating the render tree with information that will be consumed
6900/// later. For example, you could store information in the render tree that will
6901/// be used when the user interacts with the render tree but has no visual impact
6902/// prior to the interaction.
6903pub struct RenderMetaData {
6904    render_object: RenderObjectData,
6905    render_box: RenderBoxData,
6906    child: RenderObjectWithChildData<AnyRenderBox>,
6907    meta_data: Option<Rc<dyn Any>>,
6908    behavior: HitTestBehavior,
6909}
6910
6911impl RenderMetaData {
6912    /// Creates a render object that hold opaque meta data.
6913    ///
6914    /// The `behavior` argument defaults to [`HitTestBehavior::DeferToChild`].
6915    pub fn new(
6916        app: &mut App,
6917        meta_data: Option<Rc<dyn Any>>,
6918        behavior: HitTestBehavior,
6919        child: Option<AnyRenderBox>,
6920    ) -> RenderHandle<Self> {
6921        let this = RenderHandle::new_box(
6922            app,
6923            RenderMetaData {
6924                render_object: RenderObjectData::new(),
6925                render_box: RenderBoxData::new(),
6926                child: RenderObjectWithChildData::new(),
6927                meta_data,
6928                behavior,
6929            },
6930        );
6931        this.set_child(app, child);
6932        this
6933    }
6934
6935    /// Opaque meta data ignored by the render tree.
6936    pub fn meta_data(self: RenderHandle<Self>, app: &App) -> Option<Rc<dyn Any>> {
6937        self.get(app).meta_data.clone()
6938    }
6939
6940    /// Sets [`meta_data`](Self::meta_data).
6941    pub fn set_meta_data(self: RenderHandle<Self>, app: &mut App, value: Option<Rc<dyn Any>>) {
6942        self.get_mut(app).meta_data = value;
6943    }
6944
6945    /// Sets [`behavior`](RenderProxyBoxWithHitTestBehavior::behavior).
6946    pub fn set_behavior(self: RenderHandle<Self>, app: &mut App, value: HitTestBehavior) {
6947        self.get_mut(app).behavior = value;
6948    }
6949}
6950
6951impl RenderObjectWithChildMixin for RenderMetaData {
6952    type ChildType = AnyRenderBox;
6953
6954    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6955        &self.get(app).child
6956    }
6957
6958    fn child_data_mut(
6959        self: RenderHandle<Self>,
6960        app: &mut App,
6961    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6962        &mut self.get_mut(app).child
6963    }
6964}
6965
6966impl RenderProxyBoxMixin for RenderMetaData {}
6967
6968impl RenderProxyBoxWithHitTestBehavior for RenderMetaData {
6969    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
6970        self.get(app).behavior
6971    }
6972}
6973
6974impl RenderObject for RenderMetaData {
6975    crate::render_object_accessors!();
6976
6977    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6978        RenderProxyBoxMixin::perform_layout(self, app);
6979    }
6980
6981    fn paint(
6982        self: RenderHandle<Self>,
6983        app: &mut App,
6984        context: &mut PaintingContext,
6985        offset: Offset,
6986    ) {
6987        RenderProxyBoxMixin::paint(self, app, context, offset);
6988    }
6989
6990    fn visit_children(
6991        self: RenderHandle<Self>,
6992        app: &App,
6993        visitor: &mut dyn FnMut(AnyRenderObject),
6994    ) {
6995        if let Some(child) = self.child(app) {
6996            visitor(child.as_object());
6997        }
6998    }
6999}
7000
7001impl RenderBox for RenderMetaData {
7002    crate::render_box_accessors!();
7003
7004    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
7005        RenderProxyBoxMixin::setup_parent_data(self, app, child);
7006    }
7007
7008    fn apply_paint_transform(
7009        self: RenderHandle<Self>,
7010        app: &App,
7011        child: AnyRenderObject,
7012        transform: &mut Matrix4,
7013    ) {
7014        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
7015    }
7016
7017    fn hit_test(
7018        self: RenderHandle<Self>,
7019        app: &mut App,
7020        result: &mut BoxHitTestResult<'_>,
7021        position: Offset,
7022    ) -> bool {
7023        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
7024    }
7025
7026    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
7027        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
7028    }
7029
7030    fn hit_test_children(
7031        self: RenderHandle<Self>,
7032        app: &mut App,
7033        result: &mut BoxHitTestResult<'_>,
7034        position: Offset,
7035    ) -> bool {
7036        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
7037    }
7038
7039    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7040        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
7041    }
7042
7043    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7044        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
7045    }
7046
7047    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7048        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
7049    }
7050
7051    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7052        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
7053    }
7054
7055    fn compute_distance_to_actual_baseline(
7056        self: RenderHandle<Self>,
7057        app: &mut App,
7058        baseline: TextBaseline,
7059    ) -> Option<f64> {
7060        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
7061    }
7062
7063    fn compute_dry_baseline(
7064        self: RenderHandle<Self>,
7065        app: &mut App,
7066        constraints: BoxConstraints,
7067        baseline: TextBaseline,
7068    ) -> Option<f64> {
7069        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
7070    }
7071
7072    fn compute_dry_layout(
7073        self: RenderHandle<Self>,
7074        app: &mut App,
7075        constraints: BoxConstraints,
7076    ) -> Size {
7077        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
7078    }
7079}
7080
7081/// Applies a filter to the existing painted content and then paints `child`.
7082///
7083/// This effect is relatively expensive, especially if the filter is non-local,
7084/// such as a blur.
7085pub struct RenderBackdropFilter {
7086    render_object: RenderObjectData,
7087    render_box: RenderBoxData,
7088    child: RenderObjectWithChildData<AnyRenderBox>,
7089    filter_config: ImageFilterConfig,
7090    blend_mode: BlendMode,
7091    enabled: bool,
7092    backdrop_key: Option<BackdropKey>,
7093}
7094
7095impl RenderBackdropFilter {
7096    /// Creates a backdrop filter.
7097    ///
7098    /// The `blend_mode` argument defaults to [`BlendMode::SrcOver`].
7099    pub fn new(
7100        app: &mut App,
7101        filter_config: ImageFilterConfig,
7102        blend_mode: BlendMode,
7103        enabled: bool,
7104        backdrop_key: Option<BackdropKey>,
7105        child: Option<AnyRenderBox>,
7106    ) -> RenderHandle<Self> {
7107        let this = RenderHandle::new_box(
7108            app,
7109            RenderBackdropFilter {
7110                render_object: RenderObjectData::new(),
7111                render_box: RenderBoxData::new(),
7112                child: RenderObjectWithChildData::new(),
7113                filter_config,
7114                blend_mode,
7115                enabled,
7116                backdrop_key,
7117            },
7118        );
7119        this.set_child(app, child);
7120        this
7121    }
7122
7123    /// Whether or not the backdrop filter operation will be applied to the child.
7124    pub fn enabled(self: RenderHandle<Self>, app: &App) -> bool {
7125        self.get(app).enabled
7126    }
7127
7128    /// Sets [`enabled`](Self::enabled).
7129    pub fn set_enabled(self: RenderHandle<Self>, app: &mut App, value: bool) {
7130        if self.get(app).enabled == value {
7131            return;
7132        }
7133        self.get_mut(app).enabled = value;
7134        self.mark_needs_paint(app);
7135    }
7136
7137    /// The image filter to apply to the existing painted content before painting the child.
7138    ///
7139    /// Dart's deprecated `filter` getter: only valid when the configuration was set through
7140    /// [`set_filter`](Self::set_filter).
7141    pub fn filter(self: RenderHandle<Self>, app: &App) -> ImageFilter {
7142        self.get(app)
7143            .filter_config
7144            .filter()
7145            .expect(
7146                "This getter should only be called when the filter is assigned via the \
7147                 `filter` setter.",
7148            )
7149            .clone()
7150    }
7151
7152    /// Sets the filter as a direct configuration (Dart's `filter` setter).
7153    pub fn set_filter(self: RenderHandle<Self>, app: &mut App, value: ImageFilter) {
7154        self.set_filter_config(app, ImageFilterConfig::new(value));
7155    }
7156
7157    /// The configuration that resolves the filter against the paint bounds.
7158    pub fn filter_config(self: RenderHandle<Self>, app: &App) -> &ImageFilterConfig {
7159        &self.get(app).filter_config
7160    }
7161
7162    /// Sets [`filter_config`](Self::filter_config).
7163    pub fn set_filter_config(self: RenderHandle<Self>, app: &mut App, value: ImageFilterConfig) {
7164        if self.get(app).filter_config == value {
7165            return;
7166        }
7167        self.get_mut(app).filter_config = value;
7168        self.mark_needs_paint(app);
7169    }
7170
7171    /// The blend mode to use to apply the filtered background content onto the background
7172    /// surface.
7173    pub fn blend_mode(self: RenderHandle<Self>, app: &App) -> BlendMode {
7174        self.get(app).blend_mode
7175    }
7176
7177    /// Sets [`blend_mode`](Self::blend_mode).
7178    pub fn set_blend_mode(self: RenderHandle<Self>, app: &mut App, value: BlendMode) {
7179        if self.get(app).blend_mode == value {
7180            return;
7181        }
7182        self.get_mut(app).blend_mode = value;
7183        self.mark_needs_paint(app);
7184    }
7185
7186    /// The backdrop key that identifies the shared backdrop this filter belongs to.
7187    pub fn backdrop_key(self: RenderHandle<Self>, app: &App) -> Option<BackdropKey> {
7188        self.get(app).backdrop_key
7189    }
7190
7191    /// Sets [`backdrop_key`](Self::backdrop_key).
7192    pub fn set_backdrop_key(self: RenderHandle<Self>, app: &mut App, value: Option<BackdropKey>) {
7193        if self.get(app).backdrop_key == value {
7194            return;
7195        }
7196        self.get_mut(app).backdrop_key = value;
7197        self.mark_needs_paint(app);
7198    }
7199}
7200
7201impl RenderObjectWithChildMixin for RenderBackdropFilter {
7202    type ChildType = AnyRenderBox;
7203
7204    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
7205        &self.get(app).child
7206    }
7207
7208    fn child_data_mut(
7209        self: RenderHandle<Self>,
7210        app: &mut App,
7211    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
7212        &mut self.get_mut(app).child
7213    }
7214}
7215
7216impl RenderProxyBoxMixin for RenderBackdropFilter {}
7217
7218impl RenderObject for RenderBackdropFilter {
7219    crate::render_object_accessors!();
7220
7221    fn always_needs_compositing(self: RenderHandle<Self>, app: &App) -> bool {
7222        self.child(app).is_some()
7223    }
7224
7225    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
7226        RenderProxyBoxMixin::perform_layout(self, app);
7227    }
7228
7229    fn paint(
7230        self: RenderHandle<Self>,
7231        app: &mut App,
7232        context: &mut PaintingContext,
7233        offset: Offset,
7234    ) {
7235        if !self.get(app).enabled {
7236            RenderProxyBoxMixin::paint(self, app, context, offset);
7237            return;
7238        }
7239        let bounds = offset & self.size(app);
7240        let effective_filter = self
7241            .get(app)
7242            .filter_config
7243            .resolve(ImageFilterContext { bounds });
7244        if self.child(app).is_some() {
7245            debug_assert!(self.as_object().needs_compositing(app));
7246            let (blend_mode, backdrop_key) = {
7247                let this = self.get(app);
7248                (this.blend_mode, this.backdrop_key)
7249            };
7250            let layer = match self.as_object().layer_as::<BackdropFilterLayer>(app) {
7251                Some(layer) => layer,
7252                None => {
7253                    let layer = BackdropFilterLayer::new(app);
7254                    self.as_object()
7255                        .set_layer(app, Some(layer.as_container_layer()));
7256                    layer
7257                }
7258            };
7259            layer.set_filter(app, Some(effective_filter));
7260            layer.set_blend_mode(app, blend_mode);
7261            layer.set_backdrop_key(app, backdrop_key);
7262            context.push_layer(
7263                app,
7264                layer.as_container_layer(),
7265                |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
7266                offset,
7267                None,
7268            );
7269        } else {
7270            self.as_object().set_layer(app, None);
7271        }
7272    }
7273
7274    fn visit_children(
7275        self: RenderHandle<Self>,
7276        app: &App,
7277        visitor: &mut dyn FnMut(AnyRenderObject),
7278    ) {
7279        if let Some(child) = self.child(app) {
7280            visitor(child.as_object());
7281        }
7282    }
7283}
7284
7285impl RenderBox for RenderBackdropFilter {
7286    crate::render_box_accessors!();
7287
7288    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
7289        RenderProxyBoxMixin::setup_parent_data(self, app, child);
7290    }
7291
7292    fn apply_paint_transform(
7293        self: RenderHandle<Self>,
7294        app: &App,
7295        child: AnyRenderObject,
7296        transform: &mut Matrix4,
7297    ) {
7298        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
7299    }
7300
7301    fn hit_test_children(
7302        self: RenderHandle<Self>,
7303        app: &mut App,
7304        result: &mut BoxHitTestResult<'_>,
7305        position: Offset,
7306    ) -> bool {
7307        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
7308    }
7309
7310    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7311        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
7312    }
7313
7314    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7315        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
7316    }
7317
7318    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7319        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
7320    }
7321
7322    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7323        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
7324    }
7325
7326    fn compute_distance_to_actual_baseline(
7327        self: RenderHandle<Self>,
7328        app: &mut App,
7329        baseline: TextBaseline,
7330    ) -> Option<f64> {
7331        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
7332    }
7333
7334    fn compute_dry_baseline(
7335        self: RenderHandle<Self>,
7336        app: &mut App,
7337        constraints: BoxConstraints,
7338        baseline: TextBaseline,
7339    ) -> Option<f64> {
7340        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
7341    }
7342
7343    fn compute_dry_layout(
7344        self: RenderHandle<Self>,
7345        app: &mut App,
7346        constraints: BoxConstraints,
7347    ) -> Size {
7348        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
7349    }
7350}
7351
7352/// Annotates a region of the layer tree with a value.
7353///
7354/// The value can be retrieved with [`AnyLayer::find`](crate::AnyLayer::find) at a
7355/// position; `AnnotatedRegion` is the widget that inserts one.
7356pub struct RenderAnnotatedRegion<T> {
7357    render_object: RenderObjectData,
7358    render_box: RenderBoxData,
7359    child: RenderObjectWithChildData<AnyRenderBox>,
7360    value: Rc<T>,
7361    sized: bool,
7362    layer_handle: LayerHandle<Handle<AnnotatedRegionLayer>>,
7363}
7364
7365impl<T: PartialEq + 'static> RenderAnnotatedRegion<T> {
7366    /// Creates a new [`RenderAnnotatedRegion`] to insert `value` into the layer tree.
7367    ///
7368    /// If `sized` is true, the layer is provided with the size of this render object to clip
7369    /// the results of [`AnyLayer::find`](crate::AnyLayer::find).
7370    pub fn new(
7371        app: &mut App,
7372        value: Rc<T>,
7373        sized: bool,
7374        child: Option<AnyRenderBox>,
7375    ) -> RenderHandle<RenderAnnotatedRegion<T>> {
7376        let this = RenderHandle::new_box(
7377            app,
7378            RenderAnnotatedRegion {
7379                render_object: RenderObjectData::new(),
7380                render_box: RenderBoxData::new(),
7381                child: RenderObjectWithChildData::new(),
7382                value,
7383                sized,
7384                layer_handle: LayerHandle::new(),
7385            },
7386        );
7387        this.set_child(app, child);
7388        this
7389    }
7390
7391    /// A value which can be retrieved using
7392    /// [`AnyLayer::find`](crate::AnyLayer::find).
7393    pub fn value(self: RenderHandle<Self>, app: &App) -> Rc<T> {
7394        Rc::clone(&self.get(app).value)
7395    }
7396
7397    /// Sets [`value`](Self::value).
7398    pub fn set_value(self: RenderHandle<Self>, app: &mut App, new_value: Rc<T>) {
7399        if *self.get(app).value == *new_value {
7400            return;
7401        }
7402        self.get_mut(app).value = new_value;
7403        self.mark_needs_paint(app);
7404    }
7405
7406    /// Whether the render object will pass its size to the annotated region.
7407    pub fn sized(self: RenderHandle<Self>, app: &App) -> bool {
7408        self.get(app).sized
7409    }
7410
7411    /// Sets [`sized`](Self::sized).
7412    pub fn set_sized(self: RenderHandle<Self>, app: &mut App, value: bool) {
7413        if self.get(app).sized == value {
7414            return;
7415        }
7416        self.get_mut(app).sized = value;
7417        self.mark_needs_paint(app);
7418    }
7419}
7420
7421impl<T: PartialEq + 'static> RenderObjectWithChildMixin for RenderAnnotatedRegion<T> {
7422    type ChildType = AnyRenderBox;
7423
7424    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
7425        &self.get(app).child
7426    }
7427
7428    fn child_data_mut(
7429        self: RenderHandle<Self>,
7430        app: &mut App,
7431    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
7432        &mut self.get_mut(app).child
7433    }
7434}
7435
7436impl<T: PartialEq + 'static> RenderProxyBoxMixin for RenderAnnotatedRegion<T> {}
7437
7438impl<T: PartialEq + 'static> RenderObject for RenderAnnotatedRegion<T> {
7439    crate::render_object_accessors!();
7440
7441    fn always_needs_compositing(self: RenderHandle<Self>, _app: &App) -> bool {
7442        true
7443    }
7444
7445    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
7446        RenderProxyBoxMixin::perform_layout(self, app);
7447    }
7448
7449    fn paint(
7450        self: RenderHandle<Self>,
7451        app: &mut App,
7452        context: &mut PaintingContext,
7453        offset: Offset,
7454    ) {
7455        let sized = self.sized(app);
7456        let value: Rc<dyn Any> = self.value(app);
7457        let layer = AnnotatedRegionLayer::new(app, value);
7458        if sized {
7459            layer.set_size(app, Some(self.size(app)));
7460            layer.set_offset(app, offset);
7461        }
7462        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).layer_handle, Some(layer));
7463        context.push_layer(
7464            app,
7465            layer.as_container_layer(),
7466            |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
7467            offset,
7468            None,
7469        );
7470    }
7471
7472    fn dispose(self: RenderHandle<Self>, app: &mut App) {
7473        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).layer_handle, None);
7474        crate::object::RenderObjectBase::dispose(self, app);
7475    }
7476
7477    fn visit_children(
7478        self: RenderHandle<Self>,
7479        app: &App,
7480        visitor: &mut dyn FnMut(AnyRenderObject),
7481    ) {
7482        if let Some(child) = self.child(app) {
7483            visitor(child.as_object());
7484        }
7485    }
7486}
7487
7488impl<T: PartialEq + 'static> RenderBox for RenderAnnotatedRegion<T> {
7489    crate::render_box_accessors!();
7490
7491    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
7492        RenderProxyBoxMixin::setup_parent_data(self, app, child);
7493    }
7494
7495    fn apply_paint_transform(
7496        self: RenderHandle<Self>,
7497        app: &App,
7498        child: AnyRenderObject,
7499        transform: &mut Matrix4,
7500    ) {
7501        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
7502    }
7503
7504    fn hit_test_children(
7505        self: RenderHandle<Self>,
7506        app: &mut App,
7507        result: &mut BoxHitTestResult<'_>,
7508        position: Offset,
7509    ) -> bool {
7510        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
7511    }
7512
7513    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7514        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
7515    }
7516
7517    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7518        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
7519    }
7520
7521    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7522        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
7523    }
7524
7525    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7526        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
7527    }
7528
7529    fn compute_distance_to_actual_baseline(
7530        self: RenderHandle<Self>,
7531        app: &mut App,
7532        baseline: TextBaseline,
7533    ) -> Option<f64> {
7534        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
7535    }
7536
7537    fn compute_dry_baseline(
7538        self: RenderHandle<Self>,
7539        app: &mut App,
7540        constraints: BoxConstraints,
7541        baseline: TextBaseline,
7542    ) -> Option<f64> {
7543        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
7544    }
7545
7546    fn compute_dry_layout(
7547        self: RenderHandle<Self>,
7548        app: &mut App,
7549        constraints: BoxConstraints,
7550    ) -> Size {
7551        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
7552    }
7553}
7554
7555#[cfg(test)]
7556mod tests {
7557    use inset_animation::{k_always_complete_animation, k_always_dismissed_animation};
7558    use inset_embedder::ColorFilter;
7559    use inset_embedder::valo::{self, Op};
7560    use inset_foundation::AppCell;
7561    use inset_foundation::ValueNotifier;
7562    use inset_gestures::HitTestResult;
7563    use inset_painting::BoxDecoration;
7564
7565    use super::*;
7566    use crate::layer::{ErasedLayer, OffsetLayer, PictureLayer};
7567    use crate::pipeline_owner::PipelineOwner;
7568    use inset_embedder::SceneBuilder;
7569
7570    fn sized_box(app: &mut App, size: Size) -> RenderHandle<RenderConstrainedBox> {
7571        RenderConstrainedBox::new(app, BoxConstraints::tight(size), None)
7572    }
7573
7574    /// A leaf that reports fixed intrinsic dimensions and takes the size its constraints allow
7575    /// around them.
7576    struct IntrinsicTestBox {
7577        render_object: RenderObjectData,
7578        render_box: RenderBoxData,
7579        intrinsic: Size,
7580    }
7581
7582    impl RenderObject for IntrinsicTestBox {
7583        crate::render_object_accessors!();
7584
7585        fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
7586            let intrinsic = self.get(app).intrinsic;
7587            let size = self.constraints(app).constrain(intrinsic);
7588            self.set_size(app, size);
7589        }
7590    }
7591
7592    impl RenderBox for IntrinsicTestBox {
7593        crate::render_box_accessors!();
7594
7595        fn compute_min_intrinsic_width(
7596            self: RenderHandle<Self>,
7597            app: &mut App,
7598            _height: f64,
7599        ) -> f64 {
7600            self.get(app).intrinsic.width()
7601        }
7602
7603        fn compute_max_intrinsic_width(
7604            self: RenderHandle<Self>,
7605            app: &mut App,
7606            _height: f64,
7607        ) -> f64 {
7608            self.get(app).intrinsic.width()
7609        }
7610
7611        fn compute_min_intrinsic_height(
7612            self: RenderHandle<Self>,
7613            app: &mut App,
7614            _width: f64,
7615        ) -> f64 {
7616            self.get(app).intrinsic.height()
7617        }
7618
7619        fn compute_max_intrinsic_height(
7620            self: RenderHandle<Self>,
7621            app: &mut App,
7622            _width: f64,
7623        ) -> f64 {
7624            self.get(app).intrinsic.height()
7625        }
7626
7627        fn compute_dry_layout(
7628            self: RenderHandle<Self>,
7629            app: &mut App,
7630            constraints: BoxConstraints,
7631        ) -> Size {
7632            constraints.constrain(self.get(app).intrinsic)
7633        }
7634    }
7635
7636    fn intrinsic_box(app: &mut App, intrinsic: Size) -> RenderHandle<IntrinsicTestBox> {
7637        RenderHandle::new_box(
7638            app,
7639            IntrinsicTestBox {
7640                render_object: RenderObjectData::new(),
7641                render_box: RenderBoxData::new(),
7642                intrinsic,
7643            },
7644        )
7645    }
7646
7647    fn schedule_root_paint(app: &mut App, node: AnyRenderObject) {
7648        let root = OffsetLayer::new(app, Offset::ZERO);
7649        root.as_layer().attach(app, node.id());
7650        node.schedule_initial_paint(app, root.as_container_layer());
7651    }
7652
7653    /// The test binding's first frame: attach, lay the root out, schedule and flush paint.
7654    fn first_frame(app: &mut App, root: AnyRenderBox) -> Handle<PipelineOwner> {
7655        let owner = PipelineOwner::new(app, None, None);
7656        owner.set_root_node(app, Some(root.as_object()));
7657        root.layout(app, BoxConstraints::tight(Size::new(100.0, 100.0)), false);
7658        schedule_root_paint(app, root.as_object());
7659        owner.flush_compositing_bits(app);
7660        owner.flush_paint(app);
7661        owner
7662    }
7663
7664    fn pump_frame(app: &mut App, owner: Handle<PipelineOwner>) {
7665        owner.flush_layout(app);
7666        owner.flush_compositing_bits(app);
7667        owner.flush_paint(app);
7668    }
7669
7670    /// `box_test.dart`: a `RenderConstrainedBox` reports its child's intrinsics enforced by its
7671    /// additional constraints, and a tight axis reports that tight extent.
7672    #[test]
7673    fn constrained_box_intrinsics_enforce_the_additional_constraints() {
7674        let cell = AppCell::new();
7675        let mut app = cell.borrow_mut();
7676        let child = intrinsic_box(&mut app, Size::new(20.0, 30.0));
7677        let loose = RenderConstrainedBox::new(
7678            &mut app,
7679            BoxConstraints::new().min_width(50.0).max_width(60.0),
7680            Some(child.as_box()),
7681        );
7682        assert_eq!(loose.as_box().get_min_intrinsic_width(&mut app, 0.0), 50.0);
7683        assert_eq!(loose.as_box().get_max_intrinsic_width(&mut app, 0.0), 50.0);
7684        assert_eq!(loose.as_box().get_min_intrinsic_height(&mut app, 0.0), 30.0);
7685
7686        let child = intrinsic_box(&mut app, Size::new(20.0, 30.0));
7687        let tight = RenderConstrainedBox::new(
7688            &mut app,
7689            BoxConstraints::tight(Size::new(80.0, 90.0)),
7690            Some(child.as_box()),
7691        );
7692        assert_eq!(tight.as_box().get_max_intrinsic_width(&mut app, 0.0), 80.0);
7693        assert_eq!(tight.as_box().get_max_intrinsic_height(&mut app, 0.0), 90.0);
7694    }
7695
7696    /// `intrinsic_width_test.dart`: the child is sized to its maximum intrinsic width, snapped to
7697    /// `step_width` when there is one.
7698    #[test]
7699    fn intrinsic_width_sizes_the_child_to_its_max_intrinsic_width() {
7700        let cell = AppCell::new();
7701        let mut app = cell.borrow_mut();
7702        let child = intrinsic_box(&mut app, Size::new(100.0, 40.0));
7703        let intrinsic = RenderIntrinsicWidth::new(&mut app, None, None, Some(child.as_box()));
7704        intrinsic.layout(&mut app, BoxConstraints::new().max_width(500.0), false);
7705        assert_eq!(intrinsic.size(&app), Size::new(100.0, 40.0));
7706        assert_eq!(child.size(&app), Size::new(100.0, 40.0));
7707
7708        intrinsic.set_step_width(&mut app, Some(30.0));
7709        intrinsic.layout(&mut app, BoxConstraints::new().max_width(500.0), false);
7710        assert_eq!(intrinsic.size(&app), Size::new(120.0, 40.0));
7711    }
7712
7713    /// The dry layout of a `RenderIntrinsicWidth` is the size it lays out to.
7714    #[test]
7715    fn intrinsic_width_dry_layout_matches_its_layout() {
7716        let cell = AppCell::new();
7717        let mut app = cell.borrow_mut();
7718        let child = intrinsic_box(&mut app, Size::new(100.0, 40.0));
7719        let intrinsic = RenderIntrinsicWidth::new(&mut app, None, None, Some(child.as_box()));
7720        let constraints = BoxConstraints::new().max_width(500.0);
7721        let dry = intrinsic.as_box().get_dry_layout(&mut app, constraints);
7722        intrinsic.layout(&mut app, constraints, false);
7723        assert_eq!(dry, intrinsic.size(&app));
7724    }
7725
7726    /// `intrinsic_height_test.dart`: the child is sized to its maximum intrinsic height.
7727    #[test]
7728    fn intrinsic_height_sizes_the_child_to_its_max_intrinsic_height() {
7729        let cell = AppCell::new();
7730        let mut app = cell.borrow_mut();
7731        let child = intrinsic_box(&mut app, Size::new(100.0, 40.0));
7732        let intrinsic = RenderIntrinsicHeight::new(&mut app, Some(child.as_box()));
7733        intrinsic.layout(&mut app, BoxConstraints::new().max_height(500.0), false);
7734        assert_eq!(intrinsic.size(&app), Size::new(100.0, 40.0));
7735        assert_eq!(
7736            intrinsic
7737                .as_box()
7738                .get_max_intrinsic_width(&mut app, f64::INFINITY),
7739            100.0
7740        );
7741    }
7742
7743    /// `fitted_box_test.dart`: a `BoxFit::Contain` child is scaled into the box, and the scale
7744    /// shows up in the paint transform.
7745    #[test]
7746    fn fitted_box_scales_its_child_into_itself() {
7747        let cell = AppCell::new();
7748        let mut app = cell.borrow_mut();
7749        let child = sized_box(&mut app, Size::new(100.0, 100.0));
7750        let fitted = RenderFittedBox::new(
7751            &mut app,
7752            BoxFit::Contain,
7753            AlignmentGeometry::CENTER,
7754            None,
7755            Some(child.as_box()),
7756        );
7757        fitted.layout(
7758            &mut app,
7759            BoxConstraints::tight(Size::new(50.0, 50.0)),
7760            false,
7761        );
7762        assert_eq!(fitted.size(&app), Size::new(50.0, 50.0));
7763        assert_eq!(child.size(&app), Size::new(100.0, 100.0));
7764
7765        let mut transform = Matrix4::IDENTITY;
7766        RenderBox::apply_paint_transform(fitted, &app, child.as_object(), &mut transform);
7767        assert_eq!(
7768            inset_painting::transform_point(&transform, Offset::new(100.0, 100.0)),
7769            Offset::new(50.0, 50.0)
7770        );
7771    }
7772
7773    /// `aspect_ratio_test.dart`: the widest width the constraints allow, with the height from the
7774    /// ratio.
7775    #[test]
7776    fn aspect_ratio_sizes_itself_from_the_width() {
7777        let cell = AppCell::new();
7778        let mut app = cell.borrow_mut();
7779        let child = sized_box(&mut app, Size::new(10.0, 10.0));
7780        let aspect = RenderAspectRatio::new(&mut app, 2.0, Some(child.as_box()));
7781        aspect.layout(
7782            &mut app,
7783            BoxConstraints::new().max_width(200.0).max_height(200.0),
7784            false,
7785        );
7786        assert_eq!(aspect.size(&app), Size::new(200.0, 100.0));
7787        assert_eq!(child.size(&app), Size::new(200.0, 100.0));
7788        assert_eq!(
7789            aspect.as_box().get_min_intrinsic_width(&mut app, 50.0),
7790            100.0
7791        );
7792        assert_eq!(
7793            aspect.as_box().get_min_intrinsic_height(&mut app, 50.0),
7794            25.0
7795        );
7796    }
7797
7798    /// An aspect ratio box infers its width from the height when the width is unbounded.
7799    #[test]
7800    fn aspect_ratio_infers_the_width_from_an_unbounded_axis() {
7801        let cell = AppCell::new();
7802        let mut app = cell.borrow_mut();
7803        let aspect = RenderAspectRatio::new(&mut app, 0.5, None);
7804        aspect.layout(&mut app, BoxConstraints::new().max_height(100.0), false);
7805        assert_eq!(aspect.size(&app), Size::new(50.0, 100.0));
7806    }
7807
7808    #[test]
7809    fn constrained_box_without_child() {
7810        let cell = AppCell::new();
7811        let mut app = cell.borrow_mut();
7812        let box_ =
7813            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
7814        box_.layout(&mut app, BoxConstraints::new(), false);
7815        assert_eq!(box_.size(&app), Size::new(80.0, 40.0));
7816    }
7817
7818    #[test]
7819    fn additional_constraints_change_marks_layout() {
7820        let cell = AppCell::new();
7821        let mut app = cell.borrow_mut();
7822        let box_ =
7823            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
7824        box_.layout(&mut app, BoxConstraints::new(), false);
7825        assert!(!box_.debug_needs_layout(&app));
7826        box_.set_additional_constraints(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)));
7827        assert!(box_.debug_needs_layout(&app));
7828        box_.layout(&mut app, BoxConstraints::new(), false);
7829        assert_eq!(box_.size(&app), Size::new(20.0, 20.0));
7830    }
7831
7832    /// Flutter's `RenderProxyBoxMixin.setupParentData` gives the child plain `ParentData`.
7833    #[test]
7834    fn proxy_box_child_gets_empty_parent_data() {
7835        let cell = AppCell::new();
7836        let mut app = cell.borrow_mut();
7837        let child = sized_box(&mut app, Size::new(10.0, 10.0));
7838        let parent = RenderConstrainedBox::new(
7839            &mut app,
7840            BoxConstraints::tight(Size::new(10.0, 10.0)),
7841            Some(child.as_box()),
7842        );
7843        parent.layout(&mut app, BoxConstraints::new(), false);
7844        assert!(child.as_box().parent_data_is::<EmptyParentData>(&app));
7845    }
7846
7847    /// `proxy_box_test.dart`: `RenderOpacity does not composite if it is transparent` and the
7848    /// opaque / partially opaque cases. Ours: whether it is a repaint boundary.
7849    #[test]
7850    fn render_opacity_composites_only_when_visible() {
7851        let cell = AppCell::new();
7852        let mut app = cell.borrow_mut();
7853        for (opacity, composites) in [(0.0, false), (1.0, true), (0.1, true)] {
7854            let child = sized_box(&mut app, Size::new(1.0, 1.0));
7855            let opacity = RenderOpacity::new(&mut app, opacity, Some(child.as_box()));
7856            assert_eq!(opacity.as_object().is_repaint_boundary(&app), composites);
7857        }
7858    }
7859
7860    /// `layers_test.dart`: `non-painted layers are detached`.
7861    #[test]
7862    fn non_painted_layers_are_detached() {
7863        let cell = AppCell::new();
7864        let mut app = cell.borrow_mut();
7865        let inner = RenderDecoratedBox::new(
7866            &mut app,
7867            Box::new(BoxDecoration::new()),
7868            DecorationPosition::Background,
7869            ImageConfiguration::EMPTY,
7870            None,
7871        );
7872        let boundary = RenderRepaintBoundary::new(&mut app, Some(inner.as_box()));
7873        let opacity = RenderOpacity::new(&mut app, 1.0, Some(boundary.as_box()));
7874        // Flutter's test binding puts a `RenderView` above; a root must stay a repaint boundary.
7875        let root = RenderRepaintBoundary::new(&mut app, Some(opacity.as_box()));
7876        let owner = first_frame(&mut app, root.as_box());
7877        assert!(!inner.as_object().is_repaint_boundary(&app));
7878        assert!(inner.as_object().debug_layer(&app).is_none());
7879        assert!(boundary.as_object().is_repaint_boundary(&app));
7880        let layer = boundary.as_object().debug_layer(&app).expect("painted");
7881        assert!(layer.as_layer().attached(&app), "this time it painted");
7882
7883        opacity.set_opacity(&mut app, 0.0);
7884        pump_frame(&mut app, owner);
7885        assert!(inner.as_object().debug_layer(&app).is_none());
7886        let layer = boundary.as_object().debug_layer(&app).expect("kept");
7887        assert!(!layer.as_layer().attached(&app), "this time it did not");
7888
7889        opacity.set_opacity(&mut app, 0.5);
7890        pump_frame(&mut app, owner);
7891        let layer = boundary.as_object().debug_layer(&app).expect("kept");
7892        assert!(layer.as_layer().attached(&app), "this time it did again");
7893    }
7894
7895    #[test]
7896    fn animated_opacity_follows_its_animation() {
7897        let cell = AppCell::new();
7898        let mut app = cell.borrow_mut();
7899        let child = sized_box(&mut app, Size::new(1.0, 1.0));
7900        let dismissed = k_always_dismissed_animation(&mut app);
7901        let complete = k_always_complete_animation(&mut app);
7902        let fade = RenderAnimatedOpacity::new(&mut app, dismissed, Some(child.as_box()));
7903        assert!(!fade.as_object().is_repaint_boundary(&app));
7904        let root = RenderRepaintBoundary::new(&mut app, Some(fade.as_box()));
7905        let owner = first_frame(&mut app, root.as_box());
7906
7907        fade.set_opacity(&mut app, complete);
7908        assert!(fade.as_object().is_repaint_boundary(&app));
7909        assert!(fade.as_object().debug_needs_paint(&app));
7910        pump_frame(&mut app, owner);
7911        let layer = fade.as_object().debug_layer(&app).expect("a boundary now");
7912        let opacity = app
7913            .handle::<OpacityLayer>(layer.id())
7914            .expect("an OpacityLayer");
7915        assert_eq!(opacity.alpha(&app), Some(255));
7916    }
7917
7918    #[test]
7919    fn decorated_box_paints_its_decoration() {
7920        let cell = AppCell::new();
7921        let mut app = cell.borrow_mut();
7922        let decorated = RenderDecoratedBox::new(
7923            &mut app,
7924            Box::new(BoxDecoration::new().color(Color::from_argb(255, 255, 0, 0))),
7925            DecorationPosition::Background,
7926            ImageConfiguration::EMPTY,
7927            None,
7928        );
7929        let root = RenderRepaintBoundary::new(&mut app, Some(decorated.as_box()));
7930        first_frame(&mut app, root.as_box());
7931        let ops = scene_ops(&mut app, root.as_object());
7932        assert!(
7933            ops.iter()
7934                .any(|op| matches!(op, inset_embedder::valo::Op::DrawDisplayList { .. })),
7935            "{ops:?}"
7936        );
7937    }
7938
7939    /// A leaf that fills the constraints it is given and is hit anywhere within them.
7940    fn opaque_leaf(app: &mut App) -> RenderHandle<RenderPointerListener> {
7941        RenderPointerListener::new(app, HitTestBehavior::Opaque, None)
7942    }
7943
7944    const RED: Color = Color::from_argb(255, 255, 0, 0);
7945    const BLUE: Color = Color::from_argb(255, 0, 0, 255);
7946
7947    fn red_box(app: &mut App) -> RenderHandle<RenderColoredBox> {
7948        RenderColoredBox::new(app, RED, true, None)
7949    }
7950
7951    /// Hit tests `target` at `position`: whether the hit was absorbed, and the path's length.
7952    fn hit_test(app: &mut App, target: AnyRenderBox, position: Offset) -> (bool, usize) {
7953        let mut result = HitTestResult::new();
7954        let is_hit = target.hit_test(app, &mut BoxHitTestResult::wrap(&mut result), position);
7955        (is_hit, result.path().len())
7956    }
7957
7958    /// Every canvas operation of the pictures in a repaint boundary's layer tree.
7959    fn picture_ops(app: &App, boundary: AnyRenderObject) -> Vec<Op> {
7960        let layer = boundary.debug_layer(app).expect("painted");
7961        layer
7962            .depth_first_iterate_children(app)
7963            .into_iter()
7964            .filter_map(|child| {
7965                app.handle::<PictureLayer>(child.id())
7966                    .and_then(|picture| picture.picture(app).map(|p| p.ops().to_vec()))
7967            })
7968            .flatten()
7969            .collect()
7970    }
7971
7972    fn picture_has_clip(app: &App, boundary: AnyRenderObject) -> bool {
7973        picture_ops(app, boundary)
7974            .iter()
7975            .any(|op| matches!(op, Op::ClipPath { .. }))
7976    }
7977
7978    /// The rect and color of every fill in a repaint boundary's recording.
7979    fn drawn_rects(app: &App, boundary: AnyRenderObject) -> Vec<(valo::Rect, valo::Color)> {
7980        picture_ops(app, boundary)
7981            .iter()
7982            .filter_map(|op| match op {
7983                Op::DrawRect { rect, paint, .. } => Some((*rect, paint.color)),
7984                _ => None,
7985            })
7986            .collect()
7987    }
7988
7989    fn fill(rect: Rect, color: Color) -> (valo::Rect, valo::Color) {
7990        (rect.into(), color.into())
7991    }
7992
7993    #[test]
7994    fn limited_box_limits_only_unbounded_constraints() {
7995        let cell = AppCell::new();
7996        let mut app = cell.borrow_mut();
7997        let child = opaque_leaf(&mut app);
7998        let limited = RenderLimitedBox::new(&mut app, 100.0, 50.0, Some(child.as_box()));
7999
8000        limited.layout(&mut app, BoxConstraints::new(), false);
8001        assert_eq!(limited.size(&app), Size::new(100.0, 50.0));
8002
8003        limited.layout(
8004            &mut app,
8005            BoxConstraints::loose(Size::new(30.0, 30.0)),
8006            false,
8007        );
8008        assert_eq!(
8009            limited.size(&app),
8010            Size::new(30.0, 30.0),
8011            "a bounded constraint is left alone"
8012        );
8013    }
8014
8015    #[test]
8016    fn limited_box_without_child_is_empty() {
8017        let cell = AppCell::new();
8018        let mut app = cell.borrow_mut();
8019        let limited = RenderLimitedBox::new(&mut app, 100.0, 50.0, None);
8020        limited.layout(&mut app, BoxConstraints::new(), false);
8021        assert_eq!(limited.size(&app), Size::ZERO);
8022    }
8023
8024    /// Clips to the left half of the box, so a test can tell the clip from the bounds.
8025    struct LeftHalfClipper;
8026
8027    impl CustomClipper<Rect> for LeftHalfClipper {
8028        fn get_clip(&self, size: Size) -> Rect {
8029            Rect::from_ltwh(0.0, 0.0, size.width() / 2.0, size.height())
8030        }
8031
8032        fn should_reclip(&self, _old_clipper: &dyn CustomClipper<Rect>) -> bool {
8033            false
8034        }
8035
8036        fn as_any(&self) -> &dyn Any {
8037            self
8038        }
8039    }
8040
8041    impl CustomClipper<RRect> for LeftHalfClipper {
8042        fn get_clip(&self, size: Size) -> RRect {
8043            RRect::from_rect_xy(
8044                Rect::from_ltwh(0.0, 0.0, size.width() / 2.0, size.height()),
8045                0.0,
8046                0.0,
8047            )
8048        }
8049
8050        fn should_reclip(&self, _old_clipper: &dyn CustomClipper<RRect>) -> bool {
8051            false
8052        }
8053
8054        fn as_any(&self) -> &dyn Any {
8055            self
8056        }
8057    }
8058
8059    /// A clipper of the whole box whose `reclip` listenable a test can notify.
8060    struct NotifyingClipper {
8061        reclip: Rc<dyn Listenable>,
8062    }
8063
8064    impl CustomClipper<Rect> for NotifyingClipper {
8065        fn reclip(&self) -> Option<&Rc<dyn Listenable>> {
8066            Some(&self.reclip)
8067        }
8068
8069        fn get_clip(&self, size: Size) -> Rect {
8070            Offset::ZERO & size
8071        }
8072
8073        fn should_reclip(&self, _old_clipper: &dyn CustomClipper<Rect>) -> bool {
8074            false
8075        }
8076
8077        fn as_any(&self) -> &dyn Any {
8078            self
8079        }
8080    }
8081
8082    #[test]
8083    fn clip_rect_pushes_its_clipper_and_clips_hit_tests() {
8084        let cell = AppCell::new();
8085        let mut app = cell.borrow_mut();
8086        let child = opaque_leaf(&mut app);
8087        let clipper: Rc<dyn CustomClipper<Rect>> = Rc::new(LeftHalfClipper);
8088        let clip = RenderClipRect::new(
8089            &mut app,
8090            Some(clipper),
8091            Clip::HardEdge,
8092            Some(child.as_box()),
8093        );
8094        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8095        first_frame(&mut app, root.as_box());
8096
8097        let ops = picture_ops(&app, root.as_object());
8098        let clip_path = ops
8099            .iter()
8100            .find_map(|op| match op {
8101                Op::ClipPath { path, .. } => Some(path),
8102                _ => None,
8103            })
8104            .expect("the recording clips");
8105        assert_eq!(
8106            clip_path.bounds(),
8107            Rect::from_ltwh(0.0, 0.0, 50.0, 100.0).into()
8108        );
8109
8110        assert!(hit_test(&mut app, clip.as_box(), Offset::new(25.0, 50.0)).0);
8111        assert!(
8112            !hit_test(&mut app, clip.as_box(), Offset::new(75.0, 50.0)).0,
8113            "outside the clipper's clip"
8114        );
8115    }
8116
8117    #[test]
8118    fn clip_rect_without_clipping_paints_its_child_directly() {
8119        let cell = AppCell::new();
8120        let mut app = cell.borrow_mut();
8121        let child = red_box(&mut app);
8122        let clip = RenderClipRect::new(&mut app, None, Clip::None, Some(child.as_box()));
8123        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8124        first_frame(&mut app, root.as_box());
8125
8126        assert!(
8127            !picture_has_clip(&app, root.as_object()),
8128            "Clip::None paints the child directly"
8129        );
8130        assert_eq!(
8131            drawn_rects(&app, root.as_object()),
8132            [fill(Rect::from_ltwh(0.0, 0.0, 100.0, 100.0), RED)]
8133        );
8134    }
8135
8136    #[test]
8137    fn clip_rrect_pushes_its_border_radius() {
8138        let cell = AppCell::new();
8139        let mut app = cell.borrow_mut();
8140        let child = opaque_leaf(&mut app);
8141        let clip = RenderClipRRect::new(
8142            &mut app,
8143            BorderRadiusGeometry::circular(20.0),
8144            None,
8145            Clip::AntiAlias,
8146            None,
8147            Some(child.as_box()),
8148        );
8149        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8150        first_frame(&mut app, root.as_box());
8151
8152        let bounds = Rect::from_ltwh(0.0, 0.0, 100.0, 100.0);
8153        let ops = picture_ops(&app, root.as_object());
8154        let clip_path = ops
8155            .iter()
8156            .find_map(|op| match op {
8157                Op::ClipPath { path, .. } => Some(path),
8158                _ => None,
8159            })
8160            .expect("the recording starts with the clip");
8161        assert_eq!(clip_path.bounds(), bounds.into());
8162
8163        assert!(
8164            hit_test(&mut app, clip.as_box(), Offset::new(99.0, 99.0)).0,
8165            "without a clipper the hit test is not clipped, as in Dart"
8166        );
8167    }
8168
8169    #[test]
8170    fn clip_rrect_clips_hit_tests_to_its_clipper() {
8171        let cell = AppCell::new();
8172        let mut app = cell.borrow_mut();
8173        let child = opaque_leaf(&mut app);
8174        let clipper: Rc<dyn CustomClipper<RRect>> = Rc::new(LeftHalfClipper);
8175        let clip = RenderClipRRect::new(
8176            &mut app,
8177            BorderRadiusGeometry::ZERO,
8178            Some(clipper),
8179            Clip::AntiAlias,
8180            None,
8181            Some(child.as_box()),
8182        );
8183        clip.layout(
8184            &mut app,
8185            BoxConstraints::tight(Size::new(100.0, 100.0)),
8186            false,
8187        );
8188
8189        assert!(hit_test(&mut app, clip.as_box(), Offset::new(25.0, 50.0)).0);
8190        assert!(!hit_test(&mut app, clip.as_box(), Offset::new(75.0, 50.0)).0);
8191    }
8192
8193    /// The cached clip is dropped when the clipper notifies and when the box is resized.
8194    #[test]
8195    fn clip_rect_reclips_on_notification_and_on_resize() {
8196        let cell = AppCell::new();
8197        let mut app = cell.borrow_mut();
8198        let reclip = app.create(ValueNotifier::new(0));
8199        let clipper: Rc<dyn CustomClipper<Rect>> = Rc::new(NotifyingClipper {
8200            reclip: Rc::new(reclip),
8201        });
8202        let child = red_box(&mut app);
8203        let clip = RenderClipRect::new(
8204            &mut app,
8205            Some(clipper),
8206            Clip::HardEdge,
8207            Some(child.as_box()),
8208        );
8209        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8210        let owner = first_frame(&mut app, root.as_box());
8211        assert!(clip.custom_clip_data(&app).clip.is_some());
8212
8213        reclip.set_value(&mut app, 1);
8214        assert!(
8215            clip.custom_clip_data(&app).clip.is_none(),
8216            "the clipper's notification dropped the cached clip"
8217        );
8218        assert!(clip.as_object().debug_needs_paint(&app));
8219        pump_frame(&mut app, owner);
8220        assert!(clip.custom_clip_data(&app).clip.is_some());
8221
8222        clip.layout(
8223            &mut app,
8224            BoxConstraints::tight(Size::new(50.0, 50.0)),
8225            false,
8226        );
8227        assert!(
8228            clip.custom_clip_data(&app).clip.is_none(),
8229            "a new size dropped the cached clip"
8230        );
8231    }
8232
8233    #[test]
8234    fn transform_paints_under_its_matrix() {
8235        let cell = AppCell::new();
8236        let mut app = cell.borrow_mut();
8237        let child = red_box(&mut app);
8238        let transform = RenderTransform::new(
8239            &mut app,
8240            Matrix4::scale(2.0, 2.0),
8241            None,
8242            None,
8243            None,
8244            true,
8245            Some(child.as_box()),
8246        );
8247        let root = RenderRepaintBoundary::new(&mut app, Some(transform.as_box()));
8248        first_frame(&mut app, root.as_box());
8249
8250        let ops = picture_ops(&app, root.as_object());
8251        let pushed = ops.iter().find_map(|op| match op {
8252            Op::Transform(transform) => Some(*transform),
8253            _ => None,
8254        });
8255        assert_eq!(pushed, Some(Matrix4::scale(2.0, 2.0)));
8256    }
8257
8258    /// A translation is folded into the child's paint offset instead of a pushed transform.
8259    #[test]
8260    fn transform_by_a_translation_paints_at_an_offset() {
8261        let cell = AppCell::new();
8262        let mut app = cell.borrow_mut();
8263        let child = red_box(&mut app);
8264        let transform = RenderTransform::new(
8265            &mut app,
8266            Matrix4::translation(10.0, 20.0),
8267            None,
8268            None,
8269            None,
8270            true,
8271            Some(child.as_box()),
8272        );
8273        let root = RenderRepaintBoundary::new(&mut app, Some(transform.as_box()));
8274        first_frame(&mut app, root.as_box());
8275
8276        assert!(
8277            !picture_ops(&app, root.as_object())
8278                .iter()
8279                .any(|op| matches!(op, Op::Transform(_))),
8280            "a translation is folded into the child's paint offset"
8281        );
8282        assert_eq!(
8283            drawn_rects(&app, root.as_object()),
8284            [fill(Rect::from_ltwh(10.0, 20.0, 100.0, 100.0), RED)]
8285        );
8286    }
8287
8288    #[test]
8289    fn transform_hit_tests_through_its_matrix() {
8290        let cell = AppCell::new();
8291        let mut app = cell.borrow_mut();
8292        let child = opaque_leaf(&mut app);
8293        let transform = RenderTransform::new(
8294            &mut app,
8295            Matrix4::scale(2.0, 2.0),
8296            None,
8297            None,
8298            None,
8299            true,
8300            Some(child.as_box()),
8301        );
8302        transform.layout(
8303            &mut app,
8304            BoxConstraints::tight(Size::new(100.0, 100.0)),
8305            false,
8306        );
8307
8308        assert_eq!(
8309            hit_test(&mut app, transform.as_box(), Offset::new(150.0, 50.0)),
8310            (true, 1),
8311            "the child covers twice the box, and the transform does not add itself"
8312        );
8313
8314        transform.set_transform_hit_tests(&mut app, false);
8315        assert!(!hit_test(&mut app, transform.as_box(), Offset::new(150.0, 50.0)).0);
8316        assert!(hit_test(&mut app, transform.as_box(), Offset::new(50.0, 50.0)).0);
8317    }
8318
8319    /// `Transform.scale(alignment: Alignment.center)`: the child grows around the box's centre.
8320    #[test]
8321    fn transform_scales_around_its_alignment_and_origin() {
8322        let cell = AppCell::new();
8323        let mut app = cell.borrow_mut();
8324        let child = opaque_leaf(&mut app);
8325        let transform = RenderTransform::new(
8326            &mut app,
8327            Matrix4::scale(2.0, 2.0),
8328            None,
8329            Some(AlignmentGeometry::CENTER),
8330            None,
8331            true,
8332            Some(child.as_box()),
8333        );
8334        transform.layout(
8335            &mut app,
8336            BoxConstraints::tight(Size::new(100.0, 100.0)),
8337            false,
8338        );
8339        assert!(hit_test(&mut app, transform.as_box(), Offset::new(140.0, 140.0)).0);
8340        assert!(!hit_test(&mut app, transform.as_box(), Offset::new(160.0, 160.0)).0);
8341
8342        transform.set_alignment(&mut app, None);
8343        transform.set_origin(&mut app, Some(Offset::new(50.0, 50.0)));
8344        assert!(
8345            hit_test(&mut app, transform.as_box(), Offset::new(140.0, 140.0)).0,
8346            "an origin at the centre is the same conjugation"
8347        );
8348        assert!(!hit_test(&mut app, transform.as_box(), Offset::new(160.0, 160.0)).0);
8349    }
8350
8351    #[test]
8352    fn transform_applies_its_paint_transform_to_the_child() {
8353        let cell = AppCell::new();
8354        let mut app = cell.borrow_mut();
8355        let child = opaque_leaf(&mut app);
8356        let transform = RenderTransform::new(
8357            &mut app,
8358            Matrix4::translation(10.0, 20.0),
8359            None,
8360            None,
8361            None,
8362            true,
8363            Some(child.as_box()),
8364        );
8365        let mut matrix = Matrix4::IDENTITY;
8366        RenderBox::apply_paint_transform(transform, &app, child.as_object(), &mut matrix);
8367        assert_eq!(matrix, Matrix4::translation(10.0, 20.0));
8368    }
8369
8370    #[test]
8371    fn fractional_translation_offsets_paint_and_hits() {
8372        let cell = AppCell::new();
8373        let mut app = cell.borrow_mut();
8374        let child = red_box(&mut app);
8375        let translated = RenderFractionalTranslation::new(
8376            &mut app,
8377            Offset::new(0.5, 0.0),
8378            true,
8379            Some(child.as_box()),
8380        );
8381        let root = RenderRepaintBoundary::new(&mut app, Some(translated.as_box()));
8382        first_frame(&mut app, root.as_box());
8383
8384        assert_eq!(
8385            drawn_rects(&app, root.as_object()),
8386            [fill(Rect::from_ltwh(50.0, 0.0, 100.0, 100.0), RED)],
8387            "half the width to the right"
8388        );
8389
8390        assert!(hit_test(&mut app, translated.as_box(), Offset::new(75.0, 50.0)).0);
8391        assert!(!hit_test(&mut app, translated.as_box(), Offset::new(25.0, 50.0)).0);
8392
8393        translated.set_transform_hit_tests(&mut app, false);
8394        assert!(
8395            hit_test(&mut app, translated.as_box(), Offset::new(25.0, 50.0)).0,
8396            "an untransformed hit test reaches the child where it was laid out"
8397        );
8398    }
8399
8400    #[test]
8401    fn ignore_pointer_is_invisible_to_hit_testing() {
8402        let cell = AppCell::new();
8403        let mut app = cell.borrow_mut();
8404        let child = opaque_leaf(&mut app);
8405        let ignoring = RenderIgnorePointer::new(&mut app, true, Some(child.as_box()));
8406        ignoring.layout(
8407            &mut app,
8408            BoxConstraints::tight(Size::new(100.0, 100.0)),
8409            false,
8410        );
8411
8412        assert_eq!(
8413            hit_test(&mut app, ignoring.as_box(), Offset::new(50.0, 50.0)),
8414            (false, 0)
8415        );
8416
8417        ignoring.set_ignoring(&mut app, false);
8418        assert_eq!(
8419            hit_test(&mut app, ignoring.as_box(), Offset::new(50.0, 50.0)),
8420            (true, 2),
8421            "the child and the ignore pointer itself"
8422        );
8423    }
8424
8425    #[test]
8426    fn absorb_pointer_takes_the_hit_from_its_subtree() {
8427        let cell = AppCell::new();
8428        let mut app = cell.borrow_mut();
8429        let child = opaque_leaf(&mut app);
8430        let absorbing = RenderAbsorbPointer::new(&mut app, true, Some(child.as_box()));
8431        absorbing.layout(
8432            &mut app,
8433            BoxConstraints::tight(Size::new(100.0, 100.0)),
8434            false,
8435        );
8436
8437        assert_eq!(
8438            hit_test(&mut app, absorbing.as_box(), Offset::new(50.0, 50.0)),
8439            (true, 0),
8440            "hit testing stops here, and nothing is added to the path"
8441        );
8442        assert_eq!(
8443            hit_test(&mut app, absorbing.as_box(), Offset::new(150.0, 50.0)),
8444            (false, 0)
8445        );
8446
8447        absorbing.set_absorbing(&mut app, false);
8448        assert_eq!(
8449            hit_test(&mut app, absorbing.as_box(), Offset::new(50.0, 50.0)),
8450            (true, 2)
8451        );
8452    }
8453
8454    #[test]
8455    fn offstage_lays_out_without_painting_or_hit_testing() {
8456        let cell = AppCell::new();
8457        let mut app = cell.borrow_mut();
8458        let child = red_box(&mut app);
8459        let offstage = RenderOffstage::new(&mut app, true, Some(child.as_box()));
8460        let root = RenderRepaintBoundary::new(&mut app, Some(offstage.as_box()));
8461        let owner = first_frame(&mut app, root.as_box());
8462
8463        assert!(RenderObject::sized_by_parent(offstage, &app));
8464        assert_eq!(child.size(&app), Size::new(100.0, 100.0), "still laid out");
8465        assert!(
8466            !picture_has_clip(&app, root.as_object()),
8467            "offstage paints nothing"
8468        );
8469        assert_eq!(
8470            hit_test(&mut app, offstage.as_box(), Offset::new(50.0, 50.0)),
8471            (false, 0)
8472        );
8473        assert!(!offstage.paints_child(&app, child.as_box()));
8474
8475        offstage.set_offstage(&mut app, false);
8476        pump_frame(&mut app, owner);
8477        assert_eq!(
8478            drawn_rects(&app, root.as_object()),
8479            [fill(Rect::from_ltwh(0.0, 0.0, 100.0, 100.0), RED)]
8480        );
8481        assert!(hit_test(&mut app, offstage.as_box(), Offset::new(50.0, 50.0)).0);
8482        assert!(offstage.paints_child(&app, child.as_box()));
8483    }
8484
8485    #[test]
8486    fn colored_box_fills_its_bounds() {
8487        let cell = AppCell::new();
8488        let mut app = cell.borrow_mut();
8489        let colored = red_box(&mut app);
8490        let root = RenderRepaintBoundary::new(&mut app, Some(colored.as_box()));
8491        first_frame(&mut app, root.as_box());
8492
8493        assert_eq!(
8494            drawn_rects(&app, root.as_object()),
8495            [fill(Rect::from_ltwh(0.0, 0.0, 100.0, 100.0), RED)]
8496        );
8497        assert_eq!(
8498            hit_test(&mut app, colored.as_box(), Offset::new(50.0, 50.0)),
8499            (true, 1),
8500            "an opaque box is hit by itself"
8501        );
8502    }
8503
8504    #[test]
8505    fn colored_box_paints_its_child_over_the_color() {
8506        let cell = AppCell::new();
8507        let mut app = cell.borrow_mut();
8508        let child = red_box(&mut app);
8509        let colored = RenderColoredBox::new(&mut app, BLUE, true, Some(child.as_box()));
8510        let root = RenderRepaintBoundary::new(&mut app, Some(colored.as_box()));
8511        first_frame(&mut app, root.as_box());
8512
8513        let bounds = Rect::from_ltwh(0.0, 0.0, 100.0, 100.0);
8514        assert_eq!(
8515            drawn_rects(&app, root.as_object()),
8516            [fill(bounds, BLUE), fill(bounds, RED)]
8517        );
8518    }
8519
8520    #[test]
8521    fn meta_data_carries_its_payload_and_hit_tests_by_behavior() {
8522        let cell = AppCell::new();
8523        let mut app = cell.borrow_mut();
8524        let payload: Rc<dyn Any> = Rc::new(42u32);
8525        let opaque = RenderMetaData::new(
8526            &mut app,
8527            Some(Rc::clone(&payload)),
8528            HitTestBehavior::Opaque,
8529            None,
8530        );
8531        opaque.layout(
8532            &mut app,
8533            BoxConstraints::tight(Size::new(10.0, 10.0)),
8534            false,
8535        );
8536        assert_eq!(
8537            opaque
8538                .meta_data(&app)
8539                .and_then(|data| data.downcast::<u32>().ok())
8540                .as_deref(),
8541            Some(&42)
8542        );
8543        let mut result = HitTestResult::new();
8544        assert!(opaque.as_box().hit_test(
8545            &mut app,
8546            &mut BoxHitTestResult::wrap(&mut result),
8547            Offset::new(5.0, 5.0)
8548        ));
8549        assert_eq!(result.path().len(), 1);
8550
8551        let deferring = RenderMetaData::new(&mut app, None, HitTestBehavior::DeferToChild, None);
8552        deferring.layout(
8553            &mut app,
8554            BoxConstraints::tight(Size::new(10.0, 10.0)),
8555            false,
8556        );
8557        let mut result = HitTestResult::new();
8558        assert!(!deferring.as_box().hit_test(
8559            &mut app,
8560            &mut BoxHitTestResult::wrap(&mut result),
8561            Offset::new(5.0, 5.0)
8562        ));
8563        assert!(result.path().is_empty());
8564
8565        // Deferring to a child that is hit puts the meta data on the path above it.
8566        let child = opaque_leaf(&mut app);
8567        deferring.set_child(&mut app, Some(child.as_box()));
8568        deferring.layout(
8569            &mut app,
8570            BoxConstraints::tight(Size::new(10.0, 10.0)),
8571            false,
8572        );
8573        let mut result = HitTestResult::new();
8574        assert!(deferring.as_box().hit_test(
8575            &mut app,
8576            &mut BoxHitTestResult::wrap(&mut result),
8577            Offset::new(5.0, 5.0)
8578        ));
8579        assert_eq!(result.path().len(), 2, "the child, then the meta data");
8580    }
8581
8582    /// The scene of a repaint-boundary root after a frame, as display-list ops.
8583    fn scene_ops(app: &mut App, root: AnyRenderObject) -> Vec<Op> {
8584        let scene = root
8585            .debug_layer(app)
8586            .expect("painted")
8587            .build_scene(app, SceneBuilder::new());
8588        inset_embedder::flattened_ops(&inset_embedder::slices(&scene, |_| None).picture_with_room())
8589    }
8590
8591    #[test]
8592    fn a_backdrop_filter_blurs_under_its_bounds_before_its_child_paints() {
8593        let cell = AppCell::new();
8594        let mut app = cell.borrow_mut();
8595        let child = RenderColoredBox::new(&mut app, Color::new(0xFF00FF00), true, None);
8596        let filter = RenderBackdropFilter::new(
8597            &mut app,
8598            ImageFilterConfig::new(ImageFilter::blur(6.0, 6.0)),
8599            BlendMode::SrcOver,
8600            true,
8601            None,
8602            Some(child.as_box()),
8603        );
8604        let root = RenderRepaintBoundary::new(&mut app, Some(filter.as_box()));
8605        let owner = first_frame(&mut app, root.as_box());
8606        let ops = scene_ops(&mut app, root.as_object());
8607        let blur = ops
8608            .iter()
8609            .position(|op| {
8610                matches!(
8611                    op,
8612                    Op::SaveLayer {
8613                        backdrop: Some(_),
8614                        ..
8615                    }
8616                )
8617            })
8618            .expect("a backdrop layer");
8619        let draw = ops
8620            .iter()
8621            .position(|op| matches!(op, Op::DrawRect { .. }))
8622            .expect("the child's paint");
8623        assert!(blur < draw, "the blur precedes the child: {ops:?}");
8624        if let Op::SaveLayer {
8625            backdrop: Some(backdrop),
8626            ..
8627        } = &ops[blur]
8628        {
8629            assert_eq!(
8630                backdrop.filter,
8631                inset_embedder::valo::ImageFilter::blur(6.0, 6.0)
8632            );
8633            assert_eq!(backdrop.shared_key, None);
8634        }
8635
8636        let key = BackdropKey::new();
8637        filter.set_backdrop_key(&mut app, Some(key));
8638        pump_frame(&mut app, owner);
8639        let ops = scene_ops(&mut app, root.as_object());
8640        assert!(
8641            ops.iter().any(|op| matches!(
8642                op,
8643                Op::SaveLayer {
8644                    backdrop: Some(valo::Backdrop {
8645                        shared_key: Some(_),
8646                        ..
8647                    }),
8648                    ..
8649                }
8650            )),
8651            "a keyed filter shares its blur: {ops:?}"
8652        );
8653
8654        filter.set_enabled(&mut app, false);
8655        pump_frame(&mut app, owner);
8656        let ops = scene_ops(&mut app, root.as_object());
8657        assert!(
8658            !ops.iter().any(|op| matches!(
8659                op,
8660                Op::SaveLayer {
8661                    backdrop: Some(_),
8662                    ..
8663                }
8664            )),
8665            "disabled paints the child only: {ops:?}"
8666        );
8667    }
8668
8669    #[test]
8670    fn a_composed_backdrop_filter_reaches_the_backdrop_whole() {
8671        let cell = AppCell::new();
8672        let mut app = cell.borrow_mut();
8673        let child = RenderColoredBox::new(&mut app, Color::new(0xFF00FF00), true, None);
8674        let saturation = ColorFilter::saturation(1.8);
8675        let filter = RenderBackdropFilter::new(
8676            &mut app,
8677            ImageFilterConfig::compose(
8678                ImageFilterConfig::new(ImageFilter::Color(saturation)),
8679                ImageFilterConfig::blur().sigma_x(4.0),
8680            ),
8681            BlendMode::SrcOver,
8682            true,
8683            None,
8684            Some(child.as_box()),
8685        );
8686        let root = RenderRepaintBoundary::new(&mut app, Some(filter.as_box()));
8687        first_frame(&mut app, root.as_box());
8688        let ops = scene_ops(&mut app, root.as_object());
8689        let composed = valo::ImageFilter::compose(
8690            valo::ImageFilter::Color(saturation.to_valo()),
8691            valo::ImageFilter::blur(4.0, 0.0),
8692        );
8693        assert!(
8694            ops.iter().any(|op| matches!(
8695                op,
8696                Op::SaveLayer {
8697                    backdrop: Some(backdrop),
8698                    ..
8699                } if backdrop.filter == composed
8700            )),
8701            "the saturation and the blur reach the backdrop in their order: {ops:?}"
8702        );
8703    }
8704
8705    #[test]
8706    fn clip_oval_hit_tests_inside_the_inscribed_oval_and_clips_with_its_path() {
8707        let cell = AppCell::new();
8708        let mut app = cell.borrow_mut();
8709        let child = opaque_leaf(&mut app);
8710        let oval = RenderClipOval::new(&mut app, None, Clip::AntiAlias, Some(child.as_box()));
8711        let root = RenderRepaintBoundary::new(&mut app, Some(oval.as_box()));
8712        first_frame(&mut app, root.as_box());
8713        let hit = |app: &mut App, x: f64, y: f64| {
8714            let mut result = HitTestResult::new();
8715            oval.as_box().hit_test(
8716                app,
8717                &mut BoxHitTestResult::wrap(&mut result),
8718                Offset::new(x, y),
8719            )
8720        };
8721        assert!(hit(&mut app, 50.0, 50.0), "the center is inside");
8722        assert!(!hit(&mut app, 2.0, 2.0), "a corner is outside the oval");
8723        assert!(
8724            picture_has_clip(&app, root.as_object()),
8725            "an oval clips with a path"
8726        );
8727    }
8728
8729    #[test]
8730    fn clip_path_uses_its_clipper_for_hit_tests_and_the_rect_by_default() {
8731        struct Triangle;
8732        impl CustomClipper<Arc<Path>> for Triangle {
8733            fn get_clip(&self, size: Size) -> Arc<Path> {
8734                let mut path = PathBuilder::new();
8735                path.move_to(Point::new(0.0, 0.0));
8736                path.line_to(Point::new(size.width() as f32, 0.0));
8737                path.line_to(Point::new(0.0, size.height() as f32));
8738                path.close();
8739                path.build()
8740            }
8741
8742            fn should_reclip(&self, _old: &dyn CustomClipper<Arc<Path>>) -> bool {
8743                false
8744            }
8745
8746            fn as_any(&self) -> &dyn Any {
8747                self
8748            }
8749        }
8750        let cell = AppCell::new();
8751        let mut app = cell.borrow_mut();
8752        let child = opaque_leaf(&mut app);
8753        let clip = RenderClipPath::new(
8754            &mut app,
8755            Some(Rc::new(Triangle)),
8756            Clip::AntiAlias,
8757            Some(child.as_box()),
8758        );
8759        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8760        first_frame(&mut app, root.as_box());
8761        let hit = |app: &mut App, x: f64, y: f64| {
8762            let mut result = HitTestResult::new();
8763            clip.as_box().hit_test(
8764                app,
8765                &mut BoxHitTestResult::wrap(&mut result),
8766                Offset::new(x, y),
8767            )
8768        };
8769        assert!(hit(&mut app, 10.0, 10.0), "inside the triangle");
8770        assert!(!hit(&mut app, 90.0, 90.0), "outside the triangle");
8771
8772        let plain = RenderClipPath::new(&mut app, None, Clip::HardEdge, None);
8773        plain.layout(
8774            &mut app,
8775            BoxConstraints::tight(Size::new(30.0, 20.0)),
8776            false,
8777        );
8778        assert!(
8779            plain
8780                .default_clip(&app)
8781                .contains(Point::new(29.0, 19.0), FillRule::NonZero),
8782            "the default clip is the box's rect"
8783        );
8784    }
8785
8786    #[test]
8787    fn clip_rsuperellipse_resolves_its_border_radius_and_clips_with_a_path() {
8788        let cell = AppCell::new();
8789        let mut app = cell.borrow_mut();
8790        let child = RenderConstrainedBox::new(&mut app, BoxConstraints::expand(None, None), None);
8791        let clip = RenderClipRSuperellipse::new(
8792            &mut app,
8793            BorderRadiusGeometry::circular(12.0),
8794            None,
8795            Clip::AntiAlias,
8796            Some(TextDirection::Ltr),
8797            Some(child.as_box()),
8798        );
8799        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8800        first_frame(&mut app, root.as_box());
8801        clip.update_clip(&mut app);
8802        assert_eq!(clip.clip(&app).tl_radius_x, 12.0);
8803        assert_eq!(
8804            clip.clip(&app).outer_rect(),
8805            Rect::from_ltwh(0.0, 0.0, 100.0, 100.0)
8806        );
8807        assert!(
8808            picture_has_clip(&app, root.as_object()),
8809            "a superellipse clips with its path"
8810        );
8811        clip.set_border_radius(&mut app, BorderRadiusGeometry::circular(4.0));
8812        assert!(
8813            clip.custom_clip_data(&app).clip.is_none(),
8814            "a new radius marks the clip"
8815        );
8816    }
8817
8818    #[test]
8819    fn a_shape_border_clipper_clips_to_the_shape_and_reclips_when_it_changes() {
8820        let square: Box<dyn ShapeBorder> = Box::new(inset_painting::RoundedRectangleBorder::new(
8821            inset_painting::BorderSide::NONE,
8822            inset_painting::BorderRadiusGeometry::circular(10.0),
8823        ));
8824        let clipper = ShapeBorderClipper::new(square.clone_box(), Some(TextDirection::Ltr));
8825        let clip = clipper.get_clip(Size::new(40.0, 40.0));
8826        assert!(clip.contains(Point::new(20.0, 20.0), FillRule::NonZero));
8827        assert!(
8828            !clip.contains(Point::new(0.5, 0.5), FillRule::NonZero),
8829            "a rounded corner"
8830        );
8831        let same = ShapeBorderClipper::new(square.clone_box(), Some(TextDirection::Ltr));
8832        assert!(!clipper.should_reclip(&same));
8833        let other = ShapeBorderClipper::new(square, Some(TextDirection::Rtl));
8834        assert!(clipper.should_reclip(&other));
8835    }
8836}