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
1955                .painter
1956                .get_or_insert_with(|| this.decoration.create_box_painter(None));
1957            painter.paint(context.canvas(), offset, configuration);
1958            this.decoration.is_complex()
1959        };
1960        debug_assert_eq!(
1961            debug_save_count,
1962            context.canvas().save_count(),
1963            "the decoration's painter had mismatching save and restore calls"
1964        );
1965        if is_complex {
1966            context.set_is_complex_hint();
1967        }
1968    }
1969}
1970
1971impl RenderObjectWithChildMixin for RenderDecoratedBox {
1972    type ChildType = AnyRenderBox;
1973
1974    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
1975        &self.get(app).child
1976    }
1977
1978    fn child_data_mut(
1979        self: RenderHandle<Self>,
1980        app: &mut App,
1981    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
1982        &mut self.get_mut(app).child
1983    }
1984}
1985
1986impl RenderProxyBoxMixin for RenderDecoratedBox {}
1987
1988impl RenderObject for RenderDecoratedBox {
1989    crate::render_object_accessors!();
1990
1991    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
1992        if let Some(mut painter) = self.get_mut(app).painter.take() {
1993            painter.dispose();
1994        }
1995        if let Some(child) = self.child(app) {
1996            child.as_object().detach(app);
1997        }
1998        self.mark_needs_paint(app);
1999    }
2000
2001    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2002        RenderProxyBoxMixin::perform_layout(self, app);
2003    }
2004
2005    fn paint(
2006        self: RenderHandle<Self>,
2007        app: &mut App,
2008        context: &mut PaintingContext,
2009        offset: Offset,
2010    ) {
2011        let size = self.size(app);
2012        let filled_configuration =
2013            self.get(app)
2014                .configuration
2015                .copy_with(None, None, None, None, Some(size), None);
2016        if self.get(app).position == DecorationPosition::Background {
2017            self.paint_decoration(app, context, offset, &filled_configuration);
2018        }
2019        RenderProxyBoxMixin::paint(self, app, context, offset);
2020        if self.get(app).position == DecorationPosition::Foreground {
2021            self.paint_decoration(app, context, offset, &filled_configuration);
2022        }
2023    }
2024
2025    fn visit_children(
2026        self: RenderHandle<Self>,
2027        app: &App,
2028        visitor: &mut dyn FnMut(AnyRenderObject),
2029    ) {
2030        if let Some(child) = self.child(app) {
2031            visitor(child.as_object());
2032        }
2033    }
2034}
2035
2036impl RenderBox for RenderDecoratedBox {
2037    crate::render_box_accessors!();
2038
2039    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
2040        let this = self.get(app);
2041        this.decoration
2042            .hit_test(self.size(app), position, this.configuration.text_direction)
2043    }
2044
2045    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2046        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2047    }
2048
2049    fn apply_paint_transform(
2050        self: RenderHandle<Self>,
2051        app: &App,
2052        child: AnyRenderObject,
2053        transform: &mut Matrix4,
2054    ) {
2055        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2056    }
2057
2058    fn hit_test_children(
2059        self: RenderHandle<Self>,
2060        app: &mut App,
2061        result: &mut BoxHitTestResult<'_>,
2062        position: Offset,
2063    ) -> bool {
2064        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2065    }
2066
2067    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2068        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2069    }
2070
2071    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2072        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2073    }
2074
2075    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2076        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2077    }
2078
2079    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2080        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2081    }
2082
2083    fn compute_distance_to_actual_baseline(
2084        self: RenderHandle<Self>,
2085        app: &mut App,
2086        baseline: TextBaseline,
2087    ) -> Option<f64> {
2088        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2089    }
2090
2091    fn compute_dry_baseline(
2092        self: RenderHandle<Self>,
2093        app: &mut App,
2094        constraints: BoxConstraints,
2095        baseline: TextBaseline,
2096    ) -> Option<f64> {
2097        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2098    }
2099
2100    fn compute_dry_layout(
2101        self: RenderHandle<Self>,
2102        app: &mut App,
2103        constraints: BoxConstraints,
2104    ) -> Size {
2105        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
2106    }
2107}
2108
2109/// Creates a separate display list for its child.
2110///
2111/// This render object creates a separate display list for its child, which
2112/// can improve performance if the subtree repaints at different times than
2113/// the surrounding parts of the tree.
2114pub struct RenderRepaintBoundary {
2115    render_object: RenderObjectData,
2116    render_box: RenderBoxData,
2117    child: RenderObjectWithChildData<AnyRenderBox>,
2118}
2119
2120impl RenderRepaintBoundary {
2121    /// Creates a repaint boundary around `child`.
2122    pub fn new(app: &mut App, child: Option<AnyRenderBox>) -> RenderHandle<Self> {
2123        let this = RenderHandle::new_box(
2124            app,
2125            RenderRepaintBoundary {
2126                render_object: RenderObjectData::new(),
2127                render_box: RenderBoxData::new(),
2128                child: RenderObjectWithChildData::new(),
2129            },
2130        );
2131        this.set_child(app, child);
2132        this
2133    }
2134}
2135
2136impl RenderObjectWithChildMixin for RenderRepaintBoundary {
2137    type ChildType = AnyRenderBox;
2138
2139    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2140        &self.get(app).child
2141    }
2142
2143    fn child_data_mut(
2144        self: RenderHandle<Self>,
2145        app: &mut App,
2146    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2147        &mut self.get_mut(app).child
2148    }
2149}
2150
2151impl RenderProxyBoxMixin for RenderRepaintBoundary {}
2152
2153impl RenderObject for RenderRepaintBoundary {
2154    crate::render_object_accessors!();
2155
2156    fn is_repaint_boundary(self: RenderHandle<Self>, _app: &App) -> bool {
2157        true
2158    }
2159
2160    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2161        RenderProxyBoxMixin::perform_layout(self, app);
2162    }
2163
2164    fn paint(
2165        self: RenderHandle<Self>,
2166        app: &mut App,
2167        context: &mut PaintingContext,
2168        offset: Offset,
2169    ) {
2170        RenderProxyBoxMixin::paint(self, app, context, offset);
2171    }
2172
2173    fn visit_children(
2174        self: RenderHandle<Self>,
2175        app: &App,
2176        visitor: &mut dyn FnMut(AnyRenderObject),
2177    ) {
2178        if let Some(child) = self.child(app) {
2179            visitor(child.as_object());
2180        }
2181    }
2182}
2183
2184impl RenderBox for RenderRepaintBoundary {
2185    crate::render_box_accessors!();
2186
2187    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2188        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2189    }
2190
2191    fn apply_paint_transform(
2192        self: RenderHandle<Self>,
2193        app: &App,
2194        child: AnyRenderObject,
2195        transform: &mut Matrix4,
2196    ) {
2197        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2198    }
2199
2200    fn hit_test_children(
2201        self: RenderHandle<Self>,
2202        app: &mut App,
2203        result: &mut BoxHitTestResult<'_>,
2204        position: Offset,
2205    ) -> bool {
2206        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2207    }
2208
2209    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2210        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2211    }
2212
2213    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2214        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2215    }
2216
2217    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2218        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2219    }
2220
2221    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2222        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2223    }
2224
2225    fn compute_distance_to_actual_baseline(
2226        self: RenderHandle<Self>,
2227        app: &mut App,
2228        baseline: TextBaseline,
2229    ) -> Option<f64> {
2230        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2231    }
2232
2233    fn compute_dry_baseline(
2234        self: RenderHandle<Self>,
2235        app: &mut App,
2236        constraints: BoxConstraints,
2237        baseline: TextBaseline,
2238    ) -> Option<f64> {
2239        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2240    }
2241
2242    fn compute_dry_layout(
2243        self: RenderHandle<Self>,
2244        app: &mut App,
2245        constraints: BoxConstraints,
2246    ) -> Size {
2247        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
2248    }
2249}
2250
2251/// Calls callbacks in response to pointer events that are exclusive to mice.
2252///
2253/// It responds to events that are related to hovering, i.e. when the mouse
2254/// enters, exits (with or without pressing buttons), or moves over a region
2255/// without pressing buttons.
2256///
2257/// It does not respond to common events that construct gestures, such as when
2258/// the pointer is pressed, moved, then released or canceled. For these events,
2259/// use [`RenderPointerListener`].
2260///
2261/// If it has a child, it defers to the child for sizing behavior.
2262///
2263/// If it does not have a child, it grows to fit the parent-provided constraints.
2264///
2265/// Flutter's `RenderMouseRegion implements MouseTrackerAnnotation`: here it answers
2266/// [`RenderObject::mouse_tracker_annotation`] with its current callbacks, cursor, and validity.
2267///
2268/// See also:
2269///
2270///  * `MouseRegion`, a widget that listens to hover events using
2271///    [`RenderMouseRegion`].
2272pub struct RenderMouseRegion {
2273    render_object: RenderObjectData,
2274    render_box: RenderBoxData,
2275    child: RenderObjectWithChildData<AnyRenderBox>,
2276    on_enter: Option<PointerEnterEventListener>,
2277    on_hover: Option<PointerHoverEventListener>,
2278    on_exit: Option<PointerExitEventListener>,
2279    cursor: MouseCursorRef,
2280    valid_for_mouse_tracker: bool,
2281    opaque: bool,
2282    behavior: HitTestBehavior,
2283}
2284
2285impl RenderMouseRegion {
2286    /// Creates a render object that forwards pointer events to callbacks.
2287    ///
2288    /// Dart's remaining constructor arguments have setters: the callbacks, `cursor`
2289    /// (`MouseCursor.defer`), `opaque` (true), and `hit_test_behavior` (opaque).
2290    /// `valid_for_mouse_tracker` has none, so it is a parameter (Dart's default is true).
2291    pub fn new(
2292        app: &mut App,
2293        valid_for_mouse_tracker: bool,
2294        child: Option<AnyRenderBox>,
2295    ) -> RenderHandle<Self> {
2296        let this = RenderHandle::new_box(
2297            app,
2298            RenderMouseRegion {
2299                render_object: RenderObjectData::new(),
2300                render_box: RenderBoxData::new(),
2301                child: RenderObjectWithChildData::new(),
2302                on_enter: None,
2303                on_hover: None,
2304                on_exit: None,
2305                cursor: <dyn MouseCursor>::defer(),
2306                valid_for_mouse_tracker,
2307                opaque: true,
2308                behavior: HitTestBehavior::Opaque,
2309            },
2310        );
2311        this.set_child(app, child);
2312        this
2313    }
2314
2315    /// Whether this object should prevent [`RenderMouseRegion`]s visually behind it
2316    /// from detecting the pointer, thus affecting how their `on_hover`, `on_enter`,
2317    /// and `on_exit` behave.
2318    ///
2319    /// If `opaque` is true, this object will absorb the mouse pointer and
2320    /// prevent this object's siblings (or any other objects that are not
2321    /// ancestors or descendants of this object) from detecting the mouse
2322    /// pointer even when the pointer is within their areas.
2323    ///
2324    /// If `opaque` is false, this object will not affect how [`RenderMouseRegion`]s
2325    /// behind it behave, which will detect the mouse pointer as long as the
2326    /// pointer is within their areas.
2327    ///
2328    /// This defaults to true.
2329    pub fn opaque(self: RenderHandle<Self>, app: &App) -> bool {
2330        self.get(app).opaque
2331    }
2332
2333    /// Sets [`opaque`](Self::opaque).
2334    pub fn set_opaque(self: RenderHandle<Self>, app: &mut App, value: bool) {
2335        if self.get(app).opaque != value {
2336            self.get_mut(app).opaque = value;
2337            // Trigger [MouseTracker]'s device update to recalculate mouse states.
2338            self.mark_needs_paint(app);
2339        }
2340    }
2341
2342    /// How to behave during hit testing.
2343    ///
2344    /// This defaults to [`HitTestBehavior::Opaque`] if `None`.
2345    pub fn hit_test_behavior(self: RenderHandle<Self>, app: &App) -> Option<HitTestBehavior> {
2346        Some(self.get(app).behavior)
2347    }
2348
2349    /// Sets [`hit_test_behavior`](Self::hit_test_behavior).
2350    pub fn set_hit_test_behavior(
2351        self: RenderHandle<Self>,
2352        app: &mut App,
2353        value: Option<HitTestBehavior>,
2354    ) {
2355        let new_value = value.unwrap_or(HitTestBehavior::Opaque);
2356        if self.get(app).behavior != new_value {
2357            self.get_mut(app).behavior = new_value;
2358            // Trigger [MouseTracker]'s device update to recalculate mouse states.
2359            self.mark_needs_paint(app);
2360        }
2361    }
2362
2363    pointer_listener_field!(
2364        on_enter,
2365        set_on_enter,
2366        PointerEnterEventListener,
2367        "Triggered when a mouse pointer, with or without buttons pressed, has entered the region and `valid_for_mouse_tracker` is true."
2368    );
2369    pointer_listener_field!(
2370        on_hover,
2371        set_on_hover,
2372        PointerHoverEventListener,
2373        "Triggered when a pointer has moved onto or within the region without buttons pressed."
2374    );
2375    pointer_listener_field!(
2376        on_exit,
2377        set_on_exit,
2378        PointerExitEventListener,
2379        "Triggered when a mouse pointer, with or without buttons pressed, has exited the region and `valid_for_mouse_tracker` is true."
2380    );
2381
2382    /// The mouse cursor for mouse pointers that are hovering over the region.
2383    ///
2384    /// When a mouse enters the region, its cursor will be changed to the `cursor`.
2385    /// When the mouse leaves the region, the cursor will be set by the region
2386    /// found at the new location.
2387    ///
2388    /// Defaults to `MouseCursor.defer`, deferring the choice of cursor to the next
2389    /// region behind it in hit-test order.
2390    pub fn cursor(self: RenderHandle<Self>, app: &App) -> MouseCursorRef {
2391        Rc::clone(&self.get(app).cursor)
2392    }
2393
2394    /// Sets [`cursor`](Self::cursor).
2395    pub fn set_cursor(self: RenderHandle<Self>, app: &mut App, value: MouseCursorRef) {
2396        if *self.get(app).cursor != *value {
2397            self.get_mut(app).cursor = value;
2398            // A repaint is needed in order to trigger a device update of
2399            // [MouseTracker] so that this new value can be found.
2400            self.mark_needs_paint(app);
2401        }
2402    }
2403
2404    /// Whether this is included when a `MouseTracker` collects the list of
2405    /// annotations: true while attached to a pipeline owner.
2406    pub fn valid_for_mouse_tracker(self: RenderHandle<Self>, app: &App) -> bool {
2407        self.get(app).valid_for_mouse_tracker
2408    }
2409}
2410
2411impl RenderObjectWithChildMixin for RenderMouseRegion {
2412    type ChildType = AnyRenderBox;
2413
2414    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2415        &self.get(app).child
2416    }
2417
2418    fn child_data_mut(
2419        self: RenderHandle<Self>,
2420        app: &mut App,
2421    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2422        &mut self.get_mut(app).child
2423    }
2424}
2425
2426impl RenderProxyBoxMixin for RenderMouseRegion {
2427    fn compute_size_for_no_child(
2428        self: RenderHandle<Self>,
2429        _app: &App,
2430        constraints: BoxConstraints,
2431    ) -> Size {
2432        constraints.biggest()
2433    }
2434}
2435
2436impl RenderProxyBoxWithHitTestBehavior for RenderMouseRegion {
2437    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
2438        self.get(app).behavior
2439    }
2440}
2441
2442impl RenderObject for RenderMouseRegion {
2443    crate::render_object_accessors!();
2444
2445    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
2446        for child in [self.child(app)].into_iter().flatten() {
2447            child.as_object().attach(app, owner);
2448        }
2449        self.get_mut(app).valid_for_mouse_tracker = true;
2450    }
2451
2452    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
2453        // Dart clears the flag before `super.detach()`; nothing in the base body reads it.
2454        self.get_mut(app).valid_for_mouse_tracker = false;
2455        for child in [self.child(app)].into_iter().flatten() {
2456            child.as_object().detach(app);
2457        }
2458    }
2459
2460    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2461        RenderProxyBoxMixin::perform_layout(self, app);
2462    }
2463
2464    fn mouse_tracker_annotation(
2465        self: RenderHandle<Self>,
2466        app: &App,
2467    ) -> Option<MouseTrackerAnnotation> {
2468        let this = self.get(app);
2469        Some(MouseTrackerAnnotation {
2470            on_enter: this.on_enter.clone(),
2471            on_exit: this.on_exit.clone(),
2472            cursor: Rc::clone(&this.cursor),
2473            valid_for_mouse_tracker: this.valid_for_mouse_tracker,
2474        })
2475    }
2476
2477    fn paint(
2478        self: RenderHandle<Self>,
2479        app: &mut App,
2480        context: &mut PaintingContext,
2481        offset: Offset,
2482    ) {
2483        RenderProxyBoxMixin::paint(self, app, context, offset);
2484    }
2485
2486    fn visit_children(
2487        self: RenderHandle<Self>,
2488        app: &App,
2489        visitor: &mut dyn FnMut(AnyRenderObject),
2490    ) {
2491        if let Some(child) = self.child(app) {
2492            visitor(child.as_object());
2493        }
2494    }
2495}
2496
2497impl RenderBox for RenderMouseRegion {
2498    crate::render_box_accessors!();
2499
2500    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2501        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2502    }
2503
2504    fn apply_paint_transform(
2505        self: RenderHandle<Self>,
2506        app: &App,
2507        child: AnyRenderObject,
2508        transform: &mut Matrix4,
2509    ) {
2510        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2511    }
2512
2513    fn hit_test(
2514        self: RenderHandle<Self>,
2515        app: &mut App,
2516        result: &mut BoxHitTestResult<'_>,
2517        position: Offset,
2518    ) -> bool {
2519        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
2520            && self.get(app).opaque
2521    }
2522
2523    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
2524        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
2525    }
2526
2527    fn hit_test_children(
2528        self: RenderHandle<Self>,
2529        app: &mut App,
2530        result: &mut BoxHitTestResult<'_>,
2531        position: Offset,
2532    ) -> bool {
2533        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2534    }
2535
2536    fn handle_event(
2537        self: RenderHandle<Self>,
2538        app: &mut App,
2539        event: &PointerEvent,
2540        _entry: &BoxHitTestEntry,
2541    ) {
2542        if let PointerEvent::Hover(event) = event
2543            && let Some(on_hover) = self.get(app).on_hover.clone()
2544        {
2545            on_hover(app, event.clone());
2546        }
2547    }
2548
2549    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2550        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2551    }
2552
2553    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2554        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2555    }
2556
2557    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2558        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2559    }
2560
2561    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2562        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2563    }
2564
2565    fn compute_distance_to_actual_baseline(
2566        self: RenderHandle<Self>,
2567        app: &mut App,
2568        baseline: TextBaseline,
2569    ) -> Option<f64> {
2570        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2571    }
2572
2573    fn compute_dry_baseline(
2574        self: RenderHandle<Self>,
2575        app: &mut App,
2576        constraints: BoxConstraints,
2577        baseline: TextBaseline,
2578    ) -> Option<f64> {
2579        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2580    }
2581
2582    fn compute_dry_layout(
2583        self: RenderHandle<Self>,
2584        app: &mut App,
2585        constraints: BoxConstraints,
2586    ) -> Size {
2587        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
2588    }
2589}
2590
2591/// Dart's `a == b` for two objects that do not override `==`: the same instance.
2592pub(crate) fn same_instance<T: ?Sized>(a: Option<&Rc<T>>, b: Option<&Rc<T>>) -> bool {
2593    match (a, b) {
2594        (None, None) => true,
2595        (Some(a), Some(b)) => Rc::ptr_eq(a, b),
2596        _ => false,
2597    }
2598}
2599
2600/// Constrains the child's [`BoxConstraints::max_width`] and [`BoxConstraints::max_height`] if
2601/// they're otherwise unconstrained.
2602///
2603/// This has the effect of giving the child a natural dimension in unbounded
2604/// environments. For example, by providing a [`max_height`](Self::max_height) to a widget that
2605/// normally tries to be as big as possible, the widget will normally size
2606/// itself to fit its parent, but when placed in a vertical list, it will take
2607/// on the given height.
2608///
2609/// This is useful when composing widgets that normally try to match their
2610/// parents' size, so that they behave reasonably in lists (which are
2611/// unbounded).
2612pub struct RenderLimitedBox {
2613    render_object: RenderObjectData,
2614    render_box: RenderBoxData,
2615    child: RenderObjectWithChildData<AnyRenderBox>,
2616    max_width: f64,
2617    max_height: f64,
2618}
2619
2620impl RenderLimitedBox {
2621    /// Creates a render box that imposes a maximum width or maximum height on its
2622    /// child if the child is otherwise unconstrained.
2623    ///
2624    /// The `max_width` and `max_height` arguments must be non-negative.
2625    pub fn new(
2626        app: &mut App,
2627        max_width: f64,
2628        max_height: f64,
2629        child: Option<AnyRenderBox>,
2630    ) -> RenderHandle<RenderLimitedBox> {
2631        debug_assert!(max_width >= 0.0);
2632        debug_assert!(max_height >= 0.0);
2633        let this = RenderHandle::new_box(
2634            app,
2635            RenderLimitedBox {
2636                render_object: RenderObjectData::new(),
2637                render_box: RenderBoxData::new(),
2638                child: RenderObjectWithChildData::new(),
2639                max_width,
2640                max_height,
2641            },
2642        );
2643        this.set_child(app, child);
2644        this
2645    }
2646
2647    /// The value to use for `max_width` if the incoming `max_width` constraint is infinite.
2648    pub fn max_width(self: RenderHandle<Self>, app: &App) -> f64 {
2649        self.get(app).max_width
2650    }
2651
2652    /// Sets [`max_width`](Self::max_width).
2653    pub fn set_max_width(self: RenderHandle<Self>, app: &mut App, value: f64) {
2654        debug_assert!(value >= 0.0);
2655        if self.get(app).max_width == value {
2656            return;
2657        }
2658        self.get_mut(app).max_width = value;
2659        self.mark_needs_layout(app);
2660    }
2661
2662    /// The value to use for `max_height` if the incoming `max_height` constraint is infinite.
2663    pub fn max_height(self: RenderHandle<Self>, app: &App) -> f64 {
2664        self.get(app).max_height
2665    }
2666
2667    /// Sets [`max_height`](Self::max_height).
2668    pub fn set_max_height(self: RenderHandle<Self>, app: &mut App, value: f64) {
2669        debug_assert!(value >= 0.0);
2670        if self.get(app).max_height == value {
2671            return;
2672        }
2673        self.get_mut(app).max_height = value;
2674        self.mark_needs_layout(app);
2675    }
2676
2677    /// Flutter's `_computeSize`.
2678    fn compute_size(
2679        self: RenderHandle<Self>,
2680        app: &mut App,
2681        constraints: BoxConstraints,
2682        layout_child: ChildLayouter,
2683    ) -> Size {
2684        let limited = self.limit_constraints(app, constraints);
2685        match self.child(app) {
2686            Some(child) => constraints.constrain(layout_child(app, child, limited)),
2687            None => limited.constrain(Size::ZERO),
2688        }
2689    }
2690
2691    fn limit_constraints(
2692        self: RenderHandle<Self>,
2693        app: &App,
2694        constraints: BoxConstraints,
2695    ) -> BoxConstraints {
2696        let this = self.get(app);
2697        BoxConstraints::new()
2698            .min_width(constraints.min_width)
2699            .max_width(if constraints.has_bounded_width() {
2700                constraints.max_width
2701            } else {
2702                constraints.constrain_width(this.max_width)
2703            })
2704            .min_height(constraints.min_height)
2705            .max_height(if constraints.has_bounded_height() {
2706                constraints.max_height
2707            } else {
2708                constraints.constrain_height(this.max_height)
2709            })
2710    }
2711}
2712
2713impl RenderObjectWithChildMixin for RenderLimitedBox {
2714    type ChildType = AnyRenderBox;
2715
2716    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2717        &self.get(app).child
2718    }
2719
2720    fn child_data_mut(
2721        self: RenderHandle<Self>,
2722        app: &mut App,
2723    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2724        &mut self.get_mut(app).child
2725    }
2726}
2727
2728impl RenderProxyBoxMixin for RenderLimitedBox {}
2729
2730impl RenderObject for RenderLimitedBox {
2731    crate::render_object_accessors!();
2732
2733    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2734        let constraints = self.constraints(app);
2735        let size = self.compute_size(app, constraints, ChildLayoutHelper::layout_child);
2736        self.set_size(app, size);
2737    }
2738
2739    fn paint(
2740        self: RenderHandle<Self>,
2741        app: &mut App,
2742        context: &mut PaintingContext,
2743        offset: Offset,
2744    ) {
2745        RenderProxyBoxMixin::paint(self, app, context, offset);
2746    }
2747
2748    fn visit_children(
2749        self: RenderHandle<Self>,
2750        app: &App,
2751        visitor: &mut dyn FnMut(AnyRenderObject),
2752    ) {
2753        if let Some(child) = self.child(app) {
2754            visitor(child.as_object());
2755        }
2756    }
2757}
2758
2759impl RenderBox for RenderLimitedBox {
2760    crate::render_box_accessors!();
2761
2762    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2763        RenderProxyBoxMixin::setup_parent_data(self, app, child);
2764    }
2765
2766    fn apply_paint_transform(
2767        self: RenderHandle<Self>,
2768        app: &App,
2769        child: AnyRenderObject,
2770        transform: &mut Matrix4,
2771    ) {
2772        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
2773    }
2774
2775    fn hit_test_children(
2776        self: RenderHandle<Self>,
2777        app: &mut App,
2778        result: &mut BoxHitTestResult<'_>,
2779        position: Offset,
2780    ) -> bool {
2781        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
2782    }
2783
2784    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2785        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
2786    }
2787
2788    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
2789        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
2790    }
2791
2792    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2793        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
2794    }
2795
2796    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
2797        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
2798    }
2799
2800    fn compute_distance_to_actual_baseline(
2801        self: RenderHandle<Self>,
2802        app: &mut App,
2803        baseline: TextBaseline,
2804    ) -> Option<f64> {
2805        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
2806    }
2807
2808    fn compute_dry_baseline(
2809        self: RenderHandle<Self>,
2810        app: &mut App,
2811        constraints: BoxConstraints,
2812        baseline: TextBaseline,
2813    ) -> Option<f64> {
2814        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
2815    }
2816
2817    fn compute_dry_layout(
2818        self: RenderHandle<Self>,
2819        app: &mut App,
2820        constraints: BoxConstraints,
2821    ) -> Size {
2822        self.compute_size(app, constraints, ChildLayoutHelper::dry_layout_child)
2823    }
2824}
2825
2826/// Attempts to size the child to a specific aspect ratio.
2827///
2828/// The render object first tries the largest width permitted by the layout constraints. The
2829/// height of the render object is determined by applying the given aspect ratio to the width,
2830/// expressed as a ratio of width to height.
2831///
2832/// For example, a 16:9 width:height aspect ratio would have a value of 16.0/9.0. If the maximum
2833/// width is infinite, the initial width is determined by applying the aspect ratio to the maximum
2834/// height.
2835///
2836/// Now consider a second example, this time with an aspect ratio of 2.0 and layout constraints
2837/// that require the width to be between 0.0 and 100.0 and the height to be between 0.0 and 100.0.
2838/// The largest width permitted is 100.0, and applying the ratio gives a height of 50.0.
2839pub struct RenderAspectRatio {
2840    render_object: RenderObjectData,
2841    render_box: RenderBoxData,
2842    child: RenderObjectWithChildData<AnyRenderBox>,
2843    aspect_ratio: f64,
2844}
2845
2846impl RenderAspectRatio {
2847    /// Creates a render object with a specific aspect ratio.
2848    ///
2849    /// The `aspect_ratio` argument must be a finite, positive value.
2850    pub fn new(
2851        app: &mut App,
2852        aspect_ratio: f64,
2853        child: Option<AnyRenderBox>,
2854    ) -> RenderHandle<RenderAspectRatio> {
2855        debug_assert!(aspect_ratio > 0.0);
2856        debug_assert!(aspect_ratio.is_finite());
2857        let this = RenderHandle::new_box(
2858            app,
2859            RenderAspectRatio {
2860                render_object: RenderObjectData::new(),
2861                render_box: RenderBoxData::new(),
2862                child: RenderObjectWithChildData::new(),
2863                aspect_ratio,
2864            },
2865        );
2866        this.set_child(app, child);
2867        this
2868    }
2869
2870    /// The aspect ratio to attempt to use.
2871    ///
2872    /// The aspect ratio is expressed as a ratio of width to height. For example, a 16:9
2873    /// width:height aspect ratio would have a value of 16.0/9.0.
2874    pub fn aspect_ratio(self: RenderHandle<Self>, app: &App) -> f64 {
2875        self.get(app).aspect_ratio
2876    }
2877
2878    /// Sets [`aspect_ratio`](Self::aspect_ratio).
2879    pub fn set_aspect_ratio(self: RenderHandle<Self>, app: &mut App, value: f64) {
2880        debug_assert!(value > 0.0);
2881        debug_assert!(value.is_finite());
2882        if self.get(app).aspect_ratio == value {
2883            return;
2884        }
2885        self.get_mut(app).aspect_ratio = value;
2886        self.mark_needs_layout(app);
2887    }
2888
2889    fn apply_aspect_ratio(
2890        self: RenderHandle<Self>,
2891        app: &App,
2892        constraints: BoxConstraints,
2893    ) -> Size {
2894        debug_assert!(constraints.debug_assert_is_valid(false));
2895        let aspect_ratio = self.get(app).aspect_ratio;
2896        debug_assert!(
2897            constraints.has_bounded_width() || constraints.has_bounded_height(),
2898            "{} has unbounded constraints.\n\
2899             This render object was given an aspect ratio of {aspect_ratio} but was given both \
2900             unbounded width and unbounded height constraints. Because both constraints were \
2901             unbounded, this render object doesn't know how much size to consume.",
2902            std::any::type_name::<Self>()
2903        );
2904
2905        if constraints.is_tight() {
2906            return constraints.smallest();
2907        }
2908
2909        let mut width = constraints.max_width;
2910        let mut height;
2911
2912        // We default to picking the height based on the width, but if the width would be
2913        // infinite, that's not sensible so we try to infer the height from the width.
2914        if width.is_finite() {
2915            height = width / aspect_ratio;
2916        } else {
2917            height = constraints.max_height;
2918            width = height * aspect_ratio;
2919        }
2920
2921        // We iteratively attempt to fit within the given constraints while maintaining the given
2922        // aspect ratio. The order of applying the constraints is also biased towards inferring
2923        // the height from the width.
2924
2925        if width > constraints.max_width {
2926            width = constraints.max_width;
2927            height = width / aspect_ratio;
2928        }
2929
2930        if height > constraints.max_height {
2931            height = constraints.max_height;
2932            width = height * aspect_ratio;
2933        }
2934
2935        if width < constraints.min_width {
2936            width = constraints.min_width;
2937            height = width / aspect_ratio;
2938        }
2939
2940        if height < constraints.min_height {
2941            height = constraints.min_height;
2942            width = height * aspect_ratio;
2943        }
2944
2945        constraints.constrain(Size::new(width, height))
2946    }
2947}
2948
2949impl RenderObjectWithChildMixin for RenderAspectRatio {
2950    type ChildType = AnyRenderBox;
2951
2952    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2953        &self.get(app).child
2954    }
2955
2956    fn child_data_mut(
2957        self: RenderHandle<Self>,
2958        app: &mut App,
2959    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2960        &mut self.get_mut(app).child
2961    }
2962}
2963
2964impl RenderProxyBoxMixin for RenderAspectRatio {}
2965
2966impl RenderObject for RenderAspectRatio {
2967    crate::render_object_accessors!();
2968
2969    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2970        let constraints = self.constraints(app);
2971        let size = self.get_dry_layout(app, constraints);
2972        self.set_size(app, size);
2973        if let Some(child) = self.child(app) {
2974            child.layout(app, BoxConstraints::tight(size), false);
2975        }
2976    }
2977
2978    fn paint(
2979        self: RenderHandle<Self>,
2980        app: &mut App,
2981        context: &mut PaintingContext,
2982        offset: Offset,
2983    ) {
2984        RenderProxyBoxMixin::paint(self, app, context, offset);
2985    }
2986
2987    fn visit_children(
2988        self: RenderHandle<Self>,
2989        app: &App,
2990        visitor: &mut dyn FnMut(AnyRenderObject),
2991    ) {
2992        if let Some(child) = self.child(app) {
2993            visitor(child.as_object());
2994        }
2995    }
2996}
2997
2998impl RenderBox for RenderAspectRatio {
2999    crate::render_box_accessors!();
3000
3001    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3002        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3003    }
3004
3005    fn apply_paint_transform(
3006        self: RenderHandle<Self>,
3007        app: &App,
3008        child: AnyRenderObject,
3009        transform: &mut Matrix4,
3010    ) {
3011        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3012    }
3013
3014    fn hit_test_children(
3015        self: RenderHandle<Self>,
3016        app: &mut App,
3017        result: &mut BoxHitTestResult<'_>,
3018        position: Offset,
3019    ) -> bool {
3020        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
3021    }
3022
3023    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3024        if height.is_finite() {
3025            return height * self.get(app).aspect_ratio;
3026        }
3027        match self.child(app) {
3028            Some(child) => child.get_min_intrinsic_width(app, height),
3029            None => 0.0,
3030        }
3031    }
3032
3033    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3034        if height.is_finite() {
3035            return height * self.get(app).aspect_ratio;
3036        }
3037        match self.child(app) {
3038            Some(child) => child.get_max_intrinsic_width(app, height),
3039            None => 0.0,
3040        }
3041    }
3042
3043    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3044        if width.is_finite() {
3045            return width / self.get(app).aspect_ratio;
3046        }
3047        match self.child(app) {
3048            Some(child) => child.get_min_intrinsic_height(app, width),
3049            None => 0.0,
3050        }
3051    }
3052
3053    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3054        if width.is_finite() {
3055            return width / self.get(app).aspect_ratio;
3056        }
3057        match self.child(app) {
3058            Some(child) => child.get_max_intrinsic_height(app, width),
3059            None => 0.0,
3060        }
3061    }
3062
3063    fn compute_distance_to_actual_baseline(
3064        self: RenderHandle<Self>,
3065        app: &mut App,
3066        baseline: TextBaseline,
3067    ) -> Option<f64> {
3068        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
3069    }
3070
3071    fn compute_dry_layout(
3072        self: RenderHandle<Self>,
3073        app: &mut App,
3074        constraints: BoxConstraints,
3075    ) -> Size {
3076        self.apply_aspect_ratio(app, constraints)
3077    }
3078
3079    fn compute_dry_baseline(
3080        self: RenderHandle<Self>,
3081        app: &mut App,
3082        constraints: BoxConstraints,
3083        baseline: TextBaseline,
3084    ) -> Option<f64> {
3085        let size = self.get_dry_layout(app, constraints);
3086        RenderProxyBoxMixin::compute_dry_baseline(self, app, BoxConstraints::tight(size), baseline)
3087    }
3088}
3089
3090/// Sizes its child to the child's maximum intrinsic width.
3091///
3092/// This class is useful, for example, when unlimited width is available and you would like a
3093/// child that would otherwise attempt to expand infinitely to instead size itself to a more
3094/// reasonable width.
3095///
3096/// The constraints that this object passes to its child will adhere to the parent's constraints,
3097/// so if the constraints are not large enough to satisfy the child's maximum intrinsic width,
3098/// then the child will get less width than it otherwise would. Likewise, if the minimum width
3099/// constraint is larger than the child's maximum intrinsic width, the child will be given more
3100/// width than it otherwise would.
3101///
3102/// If [`step_width`](Self::step_width) is non-null, the child's width will be snapped to a
3103/// multiple of it. Similarly, if [`step_height`](Self::step_height) is non-null, the child's
3104/// height will be snapped to a multiple of it.
3105///
3106/// This class is relatively expensive, because it adds a speculative layout pass before the final
3107/// layout phase. Avoid using it where possible. In the worst case, this render object can result
3108/// in a layout that is O(N²) in the depth of the tree.
3109pub struct RenderIntrinsicWidth {
3110    render_object: RenderObjectData,
3111    render_box: RenderBoxData,
3112    child: RenderObjectWithChildData<AnyRenderBox>,
3113    step_width: Option<f64>,
3114    step_height: Option<f64>,
3115}
3116
3117/// Flutter's `RenderIntrinsicWidth._applyStep`.
3118fn apply_step(input: f64, step: Option<f64>) -> f64 {
3119    debug_assert!(input.is_finite());
3120    match step {
3121        Some(step) => (input / step).ceil() * step,
3122        None => input,
3123    }
3124}
3125
3126impl RenderIntrinsicWidth {
3127    /// Creates a render object that sizes itself to its child's intrinsic width.
3128    ///
3129    /// If `step_width` is given it must be > 0.0. Similarly if `step_height` is given it must be
3130    /// > 0.0.
3131    pub fn new(
3132        app: &mut App,
3133        step_width: Option<f64>,
3134        step_height: Option<f64>,
3135        child: Option<AnyRenderBox>,
3136    ) -> RenderHandle<RenderIntrinsicWidth> {
3137        debug_assert!(step_width.is_none_or(|step| step > 0.0));
3138        debug_assert!(step_height.is_none_or(|step| step > 0.0));
3139        let this = RenderHandle::new_box(
3140            app,
3141            RenderIntrinsicWidth {
3142                render_object: RenderObjectData::new(),
3143                render_box: RenderBoxData::new(),
3144                child: RenderObjectWithChildData::new(),
3145                step_width,
3146                step_height,
3147            },
3148        );
3149        this.set_child(app, child);
3150        this
3151    }
3152
3153    /// If non-null, force the child's width to be a multiple of this value.
3154    pub fn step_width(self: RenderHandle<Self>, app: &App) -> Option<f64> {
3155        self.get(app).step_width
3156    }
3157
3158    /// Sets [`step_width`](Self::step_width).
3159    pub fn set_step_width(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
3160        debug_assert!(value.is_none_or(|step| step > 0.0));
3161        if self.get(app).step_width == value {
3162            return;
3163        }
3164        self.get_mut(app).step_width = value;
3165        self.mark_needs_layout(app);
3166    }
3167
3168    /// If non-null, force the child's height to be a multiple of this value.
3169    pub fn step_height(self: RenderHandle<Self>, app: &App) -> Option<f64> {
3170        self.get(app).step_height
3171    }
3172
3173    /// Sets [`step_height`](Self::step_height).
3174    pub fn set_step_height(self: RenderHandle<Self>, app: &mut App, value: Option<f64>) {
3175        debug_assert!(value.is_none_or(|step| step > 0.0));
3176        if self.get(app).step_height == value {
3177            return;
3178        }
3179        self.get_mut(app).step_height = value;
3180        self.mark_needs_layout(app);
3181    }
3182
3183    fn child_constraints(
3184        self: RenderHandle<Self>,
3185        app: &mut App,
3186        child: AnyRenderBox,
3187        constraints: BoxConstraints,
3188    ) -> BoxConstraints {
3189        let (step_width, step_height) = {
3190            let this = self.get(app);
3191            (this.step_width, this.step_height)
3192        };
3193        let width = if constraints.has_tight_width() {
3194            None
3195        } else {
3196            Some(apply_step(
3197                child.get_max_intrinsic_width(app, constraints.max_height),
3198                step_width,
3199            ))
3200        };
3201        let height = step_height.map(|_| {
3202            apply_step(
3203                child.get_max_intrinsic_height(app, constraints.max_width),
3204                step_height,
3205            )
3206        });
3207        constraints.tighten(width, height)
3208    }
3209
3210    /// Flutter's `_computeSize`.
3211    fn compute_size(
3212        self: RenderHandle<Self>,
3213        app: &mut App,
3214        constraints: BoxConstraints,
3215        layout_child: ChildLayouter,
3216    ) -> Size {
3217        match self.child(app) {
3218            Some(child) => {
3219                let child_constraints = self.child_constraints(app, child, constraints);
3220                layout_child(app, child, child_constraints)
3221            }
3222            None => constraints.smallest(),
3223        }
3224    }
3225}
3226
3227impl RenderObjectWithChildMixin for RenderIntrinsicWidth {
3228    type ChildType = AnyRenderBox;
3229
3230    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
3231        &self.get(app).child
3232    }
3233
3234    fn child_data_mut(
3235        self: RenderHandle<Self>,
3236        app: &mut App,
3237    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
3238        &mut self.get_mut(app).child
3239    }
3240}
3241
3242impl RenderProxyBoxMixin for RenderIntrinsicWidth {}
3243
3244impl RenderObject for RenderIntrinsicWidth {
3245    crate::render_object_accessors!();
3246
3247    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3248        let constraints = self.constraints(app);
3249        let size = self.compute_size(app, constraints, ChildLayoutHelper::layout_child);
3250        self.set_size(app, size);
3251    }
3252
3253    fn paint(
3254        self: RenderHandle<Self>,
3255        app: &mut App,
3256        context: &mut PaintingContext,
3257        offset: Offset,
3258    ) {
3259        RenderProxyBoxMixin::paint(self, app, context, offset);
3260    }
3261
3262    fn visit_children(
3263        self: RenderHandle<Self>,
3264        app: &App,
3265        visitor: &mut dyn FnMut(AnyRenderObject),
3266    ) {
3267        if let Some(child) = self.child(app) {
3268            visitor(child.as_object());
3269        }
3270    }
3271}
3272
3273impl RenderBox for RenderIntrinsicWidth {
3274    crate::render_box_accessors!();
3275
3276    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3277        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3278    }
3279
3280    fn apply_paint_transform(
3281        self: RenderHandle<Self>,
3282        app: &App,
3283        child: AnyRenderObject,
3284        transform: &mut Matrix4,
3285    ) {
3286        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3287    }
3288
3289    fn hit_test_children(
3290        self: RenderHandle<Self>,
3291        app: &mut App,
3292        result: &mut BoxHitTestResult<'_>,
3293        position: Offset,
3294    ) -> bool {
3295        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
3296    }
3297
3298    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3299        self.as_box().get_max_intrinsic_width(app, height)
3300    }
3301
3302    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3303        let Some(child) = self.child(app) else {
3304            return 0.0;
3305        };
3306        let width = child.get_max_intrinsic_width(app, height);
3307        apply_step(width, self.get(app).step_width)
3308    }
3309
3310    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3311        let Some(child) = self.child(app) else {
3312            return 0.0;
3313        };
3314        let width = if width.is_finite() {
3315            width
3316        } else {
3317            self.as_box().get_max_intrinsic_width(app, f64::INFINITY)
3318        };
3319        debug_assert!(width.is_finite());
3320        let height = child.get_min_intrinsic_height(app, width);
3321        apply_step(height, self.get(app).step_height)
3322    }
3323
3324    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3325        let Some(child) = self.child(app) else {
3326            return 0.0;
3327        };
3328        let width = if width.is_finite() {
3329            width
3330        } else {
3331            self.as_box().get_max_intrinsic_width(app, f64::INFINITY)
3332        };
3333        debug_assert!(width.is_finite());
3334        let height = child.get_max_intrinsic_height(app, width);
3335        apply_step(height, self.get(app).step_height)
3336    }
3337
3338    fn compute_distance_to_actual_baseline(
3339        self: RenderHandle<Self>,
3340        app: &mut App,
3341        baseline: TextBaseline,
3342    ) -> Option<f64> {
3343        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
3344    }
3345
3346    fn compute_dry_layout(
3347        self: RenderHandle<Self>,
3348        app: &mut App,
3349        constraints: BoxConstraints,
3350    ) -> Size {
3351        self.compute_size(app, constraints, ChildLayoutHelper::dry_layout_child)
3352    }
3353
3354    fn compute_dry_baseline(
3355        self: RenderHandle<Self>,
3356        app: &mut App,
3357        constraints: BoxConstraints,
3358        baseline: TextBaseline,
3359    ) -> Option<f64> {
3360        let child = self.child(app)?;
3361        let child_constraints = self.child_constraints(app, child, constraints);
3362        child.get_dry_baseline(app, child_constraints, baseline)
3363    }
3364}
3365
3366/// Sizes its child to the child's intrinsic height.
3367///
3368/// This class is useful, for example, when unlimited height is available and you would like a
3369/// child that would otherwise attempt to expand infinitely to instead size itself to a more
3370/// reasonable height.
3371///
3372/// The constraints that this object passes to its child will adhere to the parent's constraints,
3373/// so if the constraints are not large enough to satisfy the child's maximum intrinsic height,
3374/// then the child will get less height than it otherwise would. Likewise, if the minimum height
3375/// constraint is larger than the child's maximum intrinsic height, the child will be given more
3376/// height than it otherwise would.
3377///
3378/// This class is relatively expensive, because it adds a speculative layout pass before the final
3379/// layout phase. Avoid using it where possible. In the worst case, this render object can result
3380/// in a layout that is O(N²) in the depth of the tree.
3381pub struct RenderIntrinsicHeight {
3382    render_object: RenderObjectData,
3383    render_box: RenderBoxData,
3384    child: RenderObjectWithChildData<AnyRenderBox>,
3385}
3386
3387impl RenderIntrinsicHeight {
3388    /// Creates a render object that sizes itself to its child's intrinsic height.
3389    pub fn new(app: &mut App, child: Option<AnyRenderBox>) -> RenderHandle<RenderIntrinsicHeight> {
3390        let this = RenderHandle::new_box(
3391            app,
3392            RenderIntrinsicHeight {
3393                render_object: RenderObjectData::new(),
3394                render_box: RenderBoxData::new(),
3395                child: RenderObjectWithChildData::new(),
3396            },
3397        );
3398        this.set_child(app, child);
3399        this
3400    }
3401
3402    fn child_constraints(
3403        self: RenderHandle<Self>,
3404        app: &mut App,
3405        child: AnyRenderBox,
3406        constraints: BoxConstraints,
3407    ) -> BoxConstraints {
3408        if constraints.has_tight_height() {
3409            return constraints;
3410        }
3411        let height = child.get_max_intrinsic_height(app, constraints.max_width);
3412        constraints.tighten(None, Some(height))
3413    }
3414
3415    /// Flutter's `_computeSize`.
3416    fn compute_size(
3417        self: RenderHandle<Self>,
3418        app: &mut App,
3419        constraints: BoxConstraints,
3420        layout_child: ChildLayouter,
3421    ) -> Size {
3422        match self.child(app) {
3423            Some(child) => {
3424                let child_constraints = self.child_constraints(app, child, constraints);
3425                layout_child(app, child, child_constraints)
3426            }
3427            None => constraints.smallest(),
3428        }
3429    }
3430}
3431
3432impl RenderObjectWithChildMixin for RenderIntrinsicHeight {
3433    type ChildType = AnyRenderBox;
3434
3435    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
3436        &self.get(app).child
3437    }
3438
3439    fn child_data_mut(
3440        self: RenderHandle<Self>,
3441        app: &mut App,
3442    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
3443        &mut self.get_mut(app).child
3444    }
3445}
3446
3447impl RenderProxyBoxMixin for RenderIntrinsicHeight {}
3448
3449impl RenderObject for RenderIntrinsicHeight {
3450    crate::render_object_accessors!();
3451
3452    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3453        let constraints = self.constraints(app);
3454        let size = self.compute_size(app, constraints, ChildLayoutHelper::layout_child);
3455        self.set_size(app, size);
3456    }
3457
3458    fn paint(
3459        self: RenderHandle<Self>,
3460        app: &mut App,
3461        context: &mut PaintingContext,
3462        offset: Offset,
3463    ) {
3464        RenderProxyBoxMixin::paint(self, app, context, offset);
3465    }
3466
3467    fn visit_children(
3468        self: RenderHandle<Self>,
3469        app: &App,
3470        visitor: &mut dyn FnMut(AnyRenderObject),
3471    ) {
3472        if let Some(child) = self.child(app) {
3473            visitor(child.as_object());
3474        }
3475    }
3476}
3477
3478impl RenderBox for RenderIntrinsicHeight {
3479    crate::render_box_accessors!();
3480
3481    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3482        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3483    }
3484
3485    fn apply_paint_transform(
3486        self: RenderHandle<Self>,
3487        app: &App,
3488        child: AnyRenderObject,
3489        transform: &mut Matrix4,
3490    ) {
3491        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3492    }
3493
3494    fn hit_test_children(
3495        self: RenderHandle<Self>,
3496        app: &mut App,
3497        result: &mut BoxHitTestResult<'_>,
3498        position: Offset,
3499    ) -> bool {
3500        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
3501    }
3502
3503    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3504        let Some(child) = self.child(app) else {
3505            return 0.0;
3506        };
3507        let height = if height.is_finite() {
3508            height
3509        } else {
3510            child.get_max_intrinsic_height(app, f64::INFINITY)
3511        };
3512        debug_assert!(height.is_finite());
3513        child.get_min_intrinsic_width(app, height)
3514    }
3515
3516    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
3517        let Some(child) = self.child(app) else {
3518            return 0.0;
3519        };
3520        let height = if height.is_finite() {
3521            height
3522        } else {
3523            child.get_max_intrinsic_height(app, f64::INFINITY)
3524        };
3525        debug_assert!(height.is_finite());
3526        child.get_max_intrinsic_width(app, height)
3527    }
3528
3529    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3530        self.as_box().get_max_intrinsic_height(app, width)
3531    }
3532
3533    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
3534        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
3535    }
3536
3537    fn compute_distance_to_actual_baseline(
3538        self: RenderHandle<Self>,
3539        app: &mut App,
3540        baseline: TextBaseline,
3541    ) -> Option<f64> {
3542        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
3543    }
3544
3545    fn compute_dry_layout(
3546        self: RenderHandle<Self>,
3547        app: &mut App,
3548        constraints: BoxConstraints,
3549    ) -> Size {
3550        self.compute_size(app, constraints, ChildLayoutHelper::dry_layout_child)
3551    }
3552
3553    fn compute_dry_baseline(
3554        self: RenderHandle<Self>,
3555        app: &mut App,
3556        constraints: BoxConstraints,
3557        baseline: TextBaseline,
3558    ) -> Option<f64> {
3559        let child = self.child(app)?;
3560        let child_constraints = self.child_constraints(app, child, constraints);
3561        child.get_dry_baseline(app, child_constraints, baseline)
3562    }
3563}
3564
3565/// An interface for providing custom clips.
3566///
3567/// This trait is used by a number of clip widgets (e.g., `ClipRect` and `ClipPath`).
3568///
3569/// The [`get_clip`](Self::get_clip) method is called whenever the custom clip needs to be
3570/// updated.
3571///
3572/// The [`should_reclip`](Self::should_reclip) method is called when a new instance of the class
3573/// is provided, to check if the new instance actually represents different information.
3574///
3575/// The most efficient way to update the clip provided by this class is to
3576/// supply a [`reclip`](Self::reclip) listenable, which notifies its listeners when it is time to
3577/// reclip, avoiding both the build and layout phases of the pipeline.
3578pub trait CustomClipper<T>: 'static {
3579    /// The [`Listenable`] that notifies when it is time to reclip.
3580    ///
3581    /// Dart's `CustomClipper` takes it as a constructor argument and forwards `addListener` /
3582    /// `removeListener` to it; here the clipper answers with it and the same forwarding is the
3583    /// [`Listenable`] implementation of `dyn CustomClipper<T>`.
3584    fn reclip(&self) -> Option<&Rc<dyn Listenable>> {
3585        None
3586    }
3587
3588    /// Returns a description of the clip given that the render object being
3589    /// clipped is of the given size.
3590    fn get_clip(&self, size: Size) -> T;
3591
3592    /// Called whenever a new instance of the custom clipper delegate class is
3593    /// provided to the clip object, or any time that a new clip object is created
3594    /// with a new instance of the custom clipper delegate class (which amounts to
3595    /// the same thing, because the latter is implemented in terms of the former).
3596    ///
3597    /// If the new instance represents different information than the old
3598    /// instance, then the method should return true, otherwise it should return
3599    /// false.
3600    ///
3601    /// If the method returns false, then the [`get_clip`](Self::get_clip) call might be
3602    /// optimized away.
3603    ///
3604    /// It's possible that the [`get_clip`](Self::get_clip) method will get called even if
3605    /// [`should_reclip`](Self::should_reclip) returns false or if the
3606    /// [`should_reclip`](Self::should_reclip) method is never called at all (e.g. if the box
3607    /// changes size). It is only called with a clipper of this clipper's own type, as Dart's
3608    /// `covariant` parameter is.
3609    fn should_reclip(&self, old_clipper: &dyn CustomClipper<T>) -> bool;
3610
3611    /// Downcast support for Dart's `runtimeType` comparison and `covariant` parameter.
3612    fn as_any(&self) -> &dyn Any;
3613}
3614
3615impl<T: 'static> Listenable for dyn CustomClipper<T> {
3616    /// Register a closure to be notified when it is time to reclip.
3617    ///
3618    /// Forwards to the [`reclip`](CustomClipper::reclip) listenable, if it is not `None`.
3619    fn add_listener(&self, app: &mut App, listener: Listener) {
3620        if let Some(reclip) = self.reclip() {
3621            reclip.add_listener(app, listener);
3622        }
3623    }
3624
3625    /// Remove a previously registered closure from the list of closures that the
3626    /// object notifies when it is time to reclip.
3627    fn remove_listener(&self, app: &mut App, listener: &Listener) {
3628        if let Some(reclip) = self.reclip() {
3629            reclip.remove_listener(app, listener);
3630        }
3631    }
3632}
3633
3634/// The fields of [`RenderCustomClip`].
3635pub struct RenderCustomClipData<T> {
3636    clipper: Option<Rc<dyn CustomClipper<T>>>,
3637    clip: Option<T>,
3638    clip_behavior: Clip,
3639}
3640
3641impl<T> RenderCustomClipData<T> {
3642    /// Creates the fields of a clip with no clip computed yet.
3643    pub fn new(
3644        clipper: Option<Rc<dyn CustomClipper<T>>>,
3645        clip_behavior: Clip,
3646    ) -> RenderCustomClipData<T> {
3647        RenderCustomClipData {
3648            clipper,
3649            clip: None,
3650            clip_behavior,
3651        }
3652    }
3653}
3654
3655/// A [`CustomClipper`] that clips to the outer path of a `ShapeBorder`.
3656pub struct ShapeBorderClipper {
3657    /// The shape border whose outer path defines the clip.
3658    pub shape: Box<dyn ShapeBorder>,
3659    /// The text direction to use for getting the outer path for `shape`.
3660    ///
3661    /// `ShapeBorder`s can depend on the text direction (e.g having a "dent" on the left hand
3662    /// side in LTR and on the right hand side in RTL).
3663    pub text_direction: Option<TextDirection>,
3664}
3665
3666impl ShapeBorderClipper {
3667    /// Creates a [`ShapeBorder`] clipper.
3668    ///
3669    /// The `text_direction` argument must be provided non-`None` if `shape` has a text
3670    /// direction dependency (for example if it is expressed in terms of "start" and "end"
3671    /// instead of "left" and "right"). It may be `None` if the border will not need the text
3672    /// direction to paint itself.
3673    pub fn new(shape: Box<dyn ShapeBorder>, text_direction: Option<TextDirection>) -> Self {
3674        ShapeBorderClipper {
3675            shape,
3676            text_direction,
3677        }
3678    }
3679}
3680
3681impl CustomClipper<Arc<Path>> for ShapeBorderClipper {
3682    fn get_clip(&self, size: Size) -> Arc<Path> {
3683        self.shape
3684            .get_outer_path(Offset::ZERO & size, self.text_direction)
3685    }
3686
3687    fn should_reclip(&self, old_clipper: &dyn CustomClipper<Arc<Path>>) -> bool {
3688        let Some(old_clipper) = old_clipper.as_any().downcast_ref::<ShapeBorderClipper>() else {
3689            return true;
3690        };
3691        !old_clipper.shape.eq_shape(&*self.shape)
3692            || old_clipper.text_direction != self.text_direction
3693    }
3694
3695    fn as_any(&self) -> &dyn Any {
3696        self
3697    }
3698}
3699
3700/// A base class for render boxes that clip their child.
3701///
3702/// Flutter's private `_RenderCustomClip<T>`: the shared bodies of a clip. A leaf implements
3703/// [`default_clip`](Self::default_clip), holds a [`RenderCustomClipData<T>`], and calls these
3704/// where Dart would run the inherited method: `RenderCustomClip::perform_layout(self, app)`.
3705pub trait RenderCustomClip<T: Clone + 'static>: RenderProxyBoxMixin {
3706    /// Mixin field access.
3707    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<T>;
3708
3709    /// See [`custom_clip_data`](Self::custom_clip_data).
3710    fn custom_clip_data_mut(
3711        self: RenderHandle<Self>,
3712        app: &mut App,
3713    ) -> &mut RenderCustomClipData<T>;
3714
3715    /// The clip to use when [`clipper`](Self::clipper) is `None`.
3716    fn default_clip(self: RenderHandle<Self>, app: &App) -> T;
3717
3718    /// If non-`None`, determines which clip to use on the child.
3719    fn clipper(self: RenderHandle<Self>, app: &App) -> Option<Rc<dyn CustomClipper<T>>> {
3720        self.custom_clip_data(app).clipper.clone()
3721    }
3722
3723    /// Sets [`clipper`](Self::clipper).
3724    fn set_clipper(
3725        self: RenderHandle<Self>,
3726        app: &mut App,
3727        new_clipper: Option<Rc<dyn CustomClipper<T>>>,
3728    ) {
3729        let old_clipper = self.clipper(app);
3730        if same_instance(old_clipper.as_ref(), new_clipper.as_ref()) {
3731            return;
3732        }
3733        self.custom_clip_data_mut(app).clipper = new_clipper.clone();
3734        debug_assert!(new_clipper.is_some() || old_clipper.is_some());
3735        let reclip = match (&new_clipper, &old_clipper) {
3736            (Some(new_clipper), Some(old_clipper)) => {
3737                new_clipper.as_any().type_id() != old_clipper.as_any().type_id()
3738                    || new_clipper.should_reclip(&**old_clipper)
3739            }
3740            _ => true,
3741        };
3742        if reclip {
3743            self.mark_needs_clip(app);
3744        }
3745        if self.attached(app) {
3746            if let Some(old_clipper) = &old_clipper {
3747                old_clipper.remove_listener(app, &self.clip_listener());
3748            }
3749            if let Some(new_clipper) = &new_clipper {
3750                new_clipper.add_listener(app, self.clip_listener());
3751            }
3752        }
3753    }
3754
3755    /// Flutter's `attach` after `super.attach(owner)`.
3756    fn did_attach(self: RenderHandle<Self>, app: &mut App) {
3757        if let Some(clipper) = self.clipper(app) {
3758            clipper.add_listener(app, self.clip_listener());
3759        }
3760    }
3761
3762    /// Flutter's `detach` before `super.detach()`.
3763    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
3764        if let Some(clipper) = self.clipper(app) {
3765            clipper.remove_listener(app, &self.clip_listener());
3766        }
3767    }
3768
3769    /// Flutter's `_markNeedsClip`.
3770    fn mark_needs_clip(self: RenderHandle<Self>, app: &mut App) {
3771        self.custom_clip_data_mut(app).clip = None;
3772        self.mark_needs_paint(app);
3773    }
3774
3775    /// The `_markNeedsClip` tear-off, equal to itself across registrations.
3776    fn clip_listener(self: RenderHandle<Self>) -> Listener {
3777        Listener::handle_method(self.handle(), mark_needs_clip::<Self, T>)
3778    }
3779
3780    /// Whether and how to clip the child.
3781    fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
3782        self.custom_clip_data(app).clip_behavior
3783    }
3784
3785    /// Sets [`clip_behavior`](Self::clip_behavior).
3786    fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
3787        if value != self.clip_behavior(app) {
3788            self.custom_clip_data_mut(app).clip_behavior = value;
3789            self.mark_needs_paint(app);
3790        }
3791    }
3792
3793    /// Flutter's `performLayout`: a resize drops the cached clip.
3794    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3795        let old_size = self.has_size(app).then(|| self.size(app));
3796        RenderProxyBoxMixin::perform_layout(self, app);
3797        if old_size != Some(self.size(app)) {
3798            self.custom_clip_data_mut(app).clip = None;
3799        }
3800    }
3801
3802    /// Flutter's `_updateClip`: computes the clip if it is not cached.
3803    fn update_clip(self: RenderHandle<Self>, app: &mut App) {
3804        if self.custom_clip_data(app).clip.is_some() {
3805            return;
3806        }
3807        let clip = match self.clipper(app) {
3808            Some(clipper) => clipper.get_clip(self.size(app)),
3809            None => self.default_clip(app),
3810        };
3811        self.custom_clip_data_mut(app).clip = Some(clip);
3812    }
3813
3814    /// The cached clip. Call [`update_clip`](Self::update_clip) first; Dart's `_clip!`.
3815    fn clip(self: RenderHandle<Self>, app: &App) -> T {
3816        self.custom_clip_data(app)
3817            .clip
3818            .clone()
3819            .expect("update_clip computes the clip")
3820    }
3821}
3822
3823fn mark_needs_clip<C: RenderCustomClip<T>, T: Clone + 'static>(this: Handle<C>, app: &mut App) {
3824    RenderCustomClip::mark_needs_clip(RenderHandle::from_handle(this), app);
3825}
3826
3827/// Clips its child using a rectangle.
3828///
3829/// By default, [`RenderClipRect`] prevents its child from painting outside its
3830/// bounds, but the size and location of the clip rect can be customized using a
3831/// custom [`clipper`](RenderCustomClip::clipper).
3832pub struct RenderClipRect {
3833    render_object: RenderObjectData,
3834    render_box: RenderBoxData,
3835    child: RenderObjectWithChildData<AnyRenderBox>,
3836    custom_clip: RenderCustomClipData<Rect>,
3837}
3838
3839impl RenderClipRect {
3840    /// Creates a rectangular clip.
3841    ///
3842    /// If `clipper` is `None`, the clip will match the layout size and position of
3843    /// the child.
3844    ///
3845    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
3846    pub fn new(
3847        app: &mut App,
3848        clipper: Option<Rc<dyn CustomClipper<Rect>>>,
3849        clip_behavior: Clip,
3850        child: Option<AnyRenderBox>,
3851    ) -> RenderHandle<RenderClipRect> {
3852        let this = RenderHandle::new_box(
3853            app,
3854            RenderClipRect {
3855                render_object: RenderObjectData::new(),
3856                render_box: RenderBoxData::new(),
3857                child: RenderObjectWithChildData::new(),
3858                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
3859            },
3860        );
3861        this.set_child(app, child);
3862        this
3863    }
3864}
3865
3866impl RenderObjectWithChildMixin for RenderClipRect {
3867    type ChildType = AnyRenderBox;
3868
3869    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
3870        &self.get(app).child
3871    }
3872
3873    fn child_data_mut(
3874        self: RenderHandle<Self>,
3875        app: &mut App,
3876    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
3877        &mut self.get_mut(app).child
3878    }
3879}
3880
3881impl RenderProxyBoxMixin for RenderClipRect {}
3882
3883impl RenderCustomClip<Rect> for RenderClipRect {
3884    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<Rect> {
3885        &self.get(app).custom_clip
3886    }
3887
3888    fn custom_clip_data_mut(
3889        self: RenderHandle<Self>,
3890        app: &mut App,
3891    ) -> &mut RenderCustomClipData<Rect> {
3892        &mut self.get_mut(app).custom_clip
3893    }
3894
3895    fn default_clip(self: RenderHandle<Self>, app: &App) -> Rect {
3896        Offset::ZERO & self.size(app)
3897    }
3898}
3899
3900impl RenderObject for RenderClipRect {
3901    crate::render_object_accessors!();
3902
3903    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
3904        if let Some(child) = self.child(app) {
3905            child.as_object().attach(app, owner);
3906        }
3907        RenderCustomClip::did_attach(self, app);
3908    }
3909
3910    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
3911        RenderCustomClip::did_detach(self, app);
3912        if let Some(child) = self.child(app) {
3913            child.as_object().detach(app);
3914        }
3915    }
3916
3917    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
3918        RenderCustomClip::perform_layout(self, app);
3919    }
3920
3921    fn paint(
3922        self: RenderHandle<Self>,
3923        app: &mut App,
3924        context: &mut PaintingContext,
3925        offset: Offset,
3926    ) {
3927        if let Some(child) = self.child(app) {
3928            let clip_behavior = self.clip_behavior(app);
3929            if clip_behavior != Clip::None {
3930                self.update_clip(app);
3931                let clip = self.clip(app);
3932                let old = self.as_object().layer_as::<ClipRectLayer>(app);
3933                let layer = context.push_clip_rect(
3934                    app,
3935                    self.as_object().needs_compositing(app),
3936                    offset,
3937                    clip,
3938                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
3939                    clip_behavior,
3940                    old,
3941                );
3942                self.as_object()
3943                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
3944            } else {
3945                context.paint_child(app, child.as_object(), offset);
3946                self.as_object().set_layer(app, None);
3947            }
3948        } else {
3949            self.as_object().set_layer(app, None);
3950        }
3951    }
3952
3953    fn visit_children(
3954        self: RenderHandle<Self>,
3955        app: &App,
3956        visitor: &mut dyn FnMut(AnyRenderObject),
3957    ) {
3958        if let Some(child) = self.child(app) {
3959            visitor(child.as_object());
3960        }
3961    }
3962}
3963
3964impl RenderBox for RenderClipRect {
3965    crate::render_box_accessors!();
3966
3967    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
3968        RenderProxyBoxMixin::setup_parent_data(self, app, child);
3969    }
3970
3971    fn apply_paint_transform(
3972        self: RenderHandle<Self>,
3973        app: &App,
3974        child: AnyRenderObject,
3975        transform: &mut Matrix4,
3976    ) {
3977        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
3978    }
3979
3980    fn hit_test(
3981        self: RenderHandle<Self>,
3982        app: &mut App,
3983        result: &mut BoxHitTestResult<'_>,
3984        position: Offset,
3985    ) -> bool {
3986        if self.clipper(app).is_some() {
3987            self.update_clip(app);
3988            if !self.clip(app).contains(position) {
3989                return false;
3990            }
3991        }
3992        RenderBoxBase::hit_test(self, app, result, position)
3993    }
3994
3995    fn hit_test_children(
3996        self: RenderHandle<Self>,
3997        app: &mut App,
3998        result: &mut BoxHitTestResult<'_>,
3999        position: Offset,
4000    ) -> bool {
4001        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4002    }
4003
4004    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4005        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4006    }
4007
4008    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4009        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4010    }
4011
4012    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4013        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4014    }
4015
4016    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4017        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4018    }
4019
4020    fn compute_distance_to_actual_baseline(
4021        self: RenderHandle<Self>,
4022        app: &mut App,
4023        baseline: TextBaseline,
4024    ) -> Option<f64> {
4025        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4026    }
4027
4028    fn compute_dry_baseline(
4029        self: RenderHandle<Self>,
4030        app: &mut App,
4031        constraints: BoxConstraints,
4032        baseline: TextBaseline,
4033    ) -> Option<f64> {
4034        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4035    }
4036
4037    fn compute_dry_layout(
4038        self: RenderHandle<Self>,
4039        app: &mut App,
4040        constraints: BoxConstraints,
4041    ) -> Size {
4042        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4043    }
4044}
4045
4046/// Clips its child using a rounded rectangle.
4047///
4048/// By default, [`RenderClipRRect`] uses its own bounds as the base rectangle for
4049/// the clip, but the size and location of the clip can be customized using a
4050/// custom [`clipper`](RenderCustomClip::clipper).
4051pub struct RenderClipRRect {
4052    render_object: RenderObjectData,
4053    render_box: RenderBoxData,
4054    child: RenderObjectWithChildData<AnyRenderBox>,
4055    custom_clip: RenderCustomClipData<RRect>,
4056    border_radius: BorderRadiusGeometry,
4057    text_direction: Option<TextDirection>,
4058}
4059
4060impl RenderClipRRect {
4061    /// Creates a rounded-rectangular clip.
4062    ///
4063    /// The `border_radius` defaults to [`BorderRadiusGeometry::ZERO`], i.e. a rectangle with
4064    /// right-angled corners.
4065    ///
4066    /// If `clipper` is non-`None`, then `border_radius` is ignored.
4067    ///
4068    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4069    pub fn new(
4070        app: &mut App,
4071        border_radius: BorderRadiusGeometry,
4072        clipper: Option<Rc<dyn CustomClipper<RRect>>>,
4073        clip_behavior: Clip,
4074        text_direction: Option<TextDirection>,
4075        child: Option<AnyRenderBox>,
4076    ) -> RenderHandle<RenderClipRRect> {
4077        let this = RenderHandle::new_box(
4078            app,
4079            RenderClipRRect {
4080                render_object: RenderObjectData::new(),
4081                render_box: RenderBoxData::new(),
4082                child: RenderObjectWithChildData::new(),
4083                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4084                border_radius,
4085                text_direction,
4086            },
4087        );
4088        this.set_child(app, child);
4089        this
4090    }
4091
4092    /// The border radius of the rounded corners.
4093    ///
4094    /// Values are clamped so that horizontal and vertical radii sums do not
4095    /// exceed width/height.
4096    ///
4097    /// This value is ignored if [`clipper`](RenderCustomClip::clipper) is non-`None`.
4098    pub fn border_radius(self: RenderHandle<Self>, app: &App) -> BorderRadiusGeometry {
4099        self.get(app).border_radius
4100    }
4101
4102    /// Sets [`border_radius`](Self::border_radius).
4103    pub fn set_border_radius(self: RenderHandle<Self>, app: &mut App, value: BorderRadiusGeometry) {
4104        if self.get(app).border_radius == value {
4105            return;
4106        }
4107        self.get_mut(app).border_radius = value;
4108        self.mark_needs_clip(app);
4109    }
4110
4111    /// The text direction with which to resolve [`border_radius`](Self::border_radius).
4112    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
4113        self.get(app).text_direction
4114    }
4115
4116    /// Sets [`text_direction`](Self::text_direction).
4117    pub fn set_text_direction(
4118        self: RenderHandle<Self>,
4119        app: &mut App,
4120        value: Option<TextDirection>,
4121    ) {
4122        if self.get(app).text_direction == value {
4123            return;
4124        }
4125        self.get_mut(app).text_direction = value;
4126        self.mark_needs_clip(app);
4127    }
4128}
4129
4130impl RenderObjectWithChildMixin for RenderClipRRect {
4131    type ChildType = AnyRenderBox;
4132
4133    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4134        &self.get(app).child
4135    }
4136
4137    fn child_data_mut(
4138        self: RenderHandle<Self>,
4139        app: &mut App,
4140    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4141        &mut self.get_mut(app).child
4142    }
4143}
4144
4145impl RenderProxyBoxMixin for RenderClipRRect {}
4146
4147impl RenderCustomClip<RRect> for RenderClipRRect {
4148    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<RRect> {
4149        &self.get(app).custom_clip
4150    }
4151
4152    fn custom_clip_data_mut(
4153        self: RenderHandle<Self>,
4154        app: &mut App,
4155    ) -> &mut RenderCustomClipData<RRect> {
4156        &mut self.get_mut(app).custom_clip
4157    }
4158
4159    fn default_clip(self: RenderHandle<Self>, app: &App) -> RRect {
4160        let this = self.get(app);
4161        this.border_radius
4162            .resolve(this.text_direction)
4163            .to_rrect(Offset::ZERO & self.size(app))
4164    }
4165}
4166
4167impl RenderObject for RenderClipRRect {
4168    crate::render_object_accessors!();
4169
4170    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4171        if let Some(child) = self.child(app) {
4172            child.as_object().attach(app, owner);
4173        }
4174        RenderCustomClip::did_attach(self, app);
4175    }
4176
4177    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4178        RenderCustomClip::did_detach(self, app);
4179        if let Some(child) = self.child(app) {
4180            child.as_object().detach(app);
4181        }
4182    }
4183
4184    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4185        RenderCustomClip::perform_layout(self, app);
4186    }
4187
4188    fn paint(
4189        self: RenderHandle<Self>,
4190        app: &mut App,
4191        context: &mut PaintingContext,
4192        offset: Offset,
4193    ) {
4194        if let Some(child) = self.child(app) {
4195            let clip_behavior = self.clip_behavior(app);
4196            if clip_behavior != Clip::None {
4197                self.update_clip(app);
4198                let clip = self.clip(app);
4199                let old = self.as_object().layer_as::<ClipRRectLayer>(app);
4200                let layer = context.push_clip_rrect(
4201                    app,
4202                    self.as_object().needs_compositing(app),
4203                    offset,
4204                    clip.outer_rect(),
4205                    clip,
4206                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4207                    clip_behavior,
4208                    old,
4209                );
4210                self.as_object()
4211                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4212            } else {
4213                context.paint_child(app, child.as_object(), offset);
4214                self.as_object().set_layer(app, None);
4215            }
4216        } else {
4217            self.as_object().set_layer(app, None);
4218        }
4219    }
4220
4221    fn visit_children(
4222        self: RenderHandle<Self>,
4223        app: &App,
4224        visitor: &mut dyn FnMut(AnyRenderObject),
4225    ) {
4226        if let Some(child) = self.child(app) {
4227            visitor(child.as_object());
4228        }
4229    }
4230}
4231
4232impl RenderBox for RenderClipRRect {
4233    crate::render_box_accessors!();
4234
4235    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4236        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4237    }
4238
4239    fn apply_paint_transform(
4240        self: RenderHandle<Self>,
4241        app: &App,
4242        child: AnyRenderObject,
4243        transform: &mut Matrix4,
4244    ) {
4245        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4246    }
4247
4248    fn hit_test(
4249        self: RenderHandle<Self>,
4250        app: &mut App,
4251        result: &mut BoxHitTestResult<'_>,
4252        position: Offset,
4253    ) -> bool {
4254        if self.clipper(app).is_some() {
4255            self.update_clip(app);
4256            if !self.clip(app).contains(position) {
4257                return false;
4258            }
4259        }
4260        RenderBoxBase::hit_test(self, app, result, position)
4261    }
4262
4263    fn hit_test_children(
4264        self: RenderHandle<Self>,
4265        app: &mut App,
4266        result: &mut BoxHitTestResult<'_>,
4267        position: Offset,
4268    ) -> bool {
4269        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4270    }
4271
4272    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4273        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4274    }
4275
4276    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4277        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4278    }
4279
4280    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4281        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4282    }
4283
4284    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4285        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4286    }
4287
4288    fn compute_distance_to_actual_baseline(
4289        self: RenderHandle<Self>,
4290        app: &mut App,
4291        baseline: TextBaseline,
4292    ) -> Option<f64> {
4293        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4294    }
4295
4296    fn compute_dry_baseline(
4297        self: RenderHandle<Self>,
4298        app: &mut App,
4299        constraints: BoxConstraints,
4300        baseline: TextBaseline,
4301    ) -> Option<f64> {
4302        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4303    }
4304
4305    fn compute_dry_layout(
4306        self: RenderHandle<Self>,
4307        app: &mut App,
4308        constraints: BoxConstraints,
4309    ) -> Size {
4310        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4311    }
4312}
4313
4314/// Clips its child using an oval.
4315///
4316/// Inscribes an oval into its layout dimensions and prevents its child from
4317/// painting outside that oval.
4318pub struct RenderClipOval {
4319    render_object: RenderObjectData,
4320    render_box: RenderBoxData,
4321    child: RenderObjectWithChildData<AnyRenderBox>,
4322    custom_clip: RenderCustomClipData<Rect>,
4323    cached_rect: Option<Rect>,
4324    cached_path: Option<Arc<Path>>,
4325}
4326
4327impl RenderClipOval {
4328    /// Creates an oval-shaped clip.
4329    ///
4330    /// If `clipper` is `None`, the oval will be inscribed into the layout size and
4331    /// position of the child.
4332    ///
4333    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4334    pub fn new(
4335        app: &mut App,
4336        clipper: Option<Rc<dyn CustomClipper<Rect>>>,
4337        clip_behavior: Clip,
4338        child: Option<AnyRenderBox>,
4339    ) -> RenderHandle<RenderClipOval> {
4340        let this = RenderHandle::new_box(
4341            app,
4342            RenderClipOval {
4343                render_object: RenderObjectData::new(),
4344                render_box: RenderBoxData::new(),
4345                child: RenderObjectWithChildData::new(),
4346                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4347                cached_rect: None,
4348                cached_path: None,
4349            },
4350        );
4351        this.set_child(app, child);
4352        this
4353    }
4354
4355    fn get_clip_path(self: RenderHandle<Self>, app: &mut App, rect: Rect) -> Arc<Path> {
4356        if self.get(app).cached_rect != Some(rect) {
4357            let radius = [(rect.width() / 2.0) as f32, (rect.height() / 2.0) as f32];
4358            let mut path = PathBuilder::new();
4359            path.rrect_radii_elliptical(rect, [radius; 4]);
4360            let this = self.get_mut(app);
4361            this.cached_rect = Some(rect);
4362            this.cached_path = Some(path.build());
4363        }
4364        self.get(app).cached_path.clone().expect("cached above")
4365    }
4366}
4367
4368impl RenderObjectWithChildMixin for RenderClipOval {
4369    type ChildType = AnyRenderBox;
4370
4371    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4372        &self.get(app).child
4373    }
4374
4375    fn child_data_mut(
4376        self: RenderHandle<Self>,
4377        app: &mut App,
4378    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4379        &mut self.get_mut(app).child
4380    }
4381}
4382
4383impl RenderProxyBoxMixin for RenderClipOval {}
4384
4385impl RenderCustomClip<Rect> for RenderClipOval {
4386    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<Rect> {
4387        &self.get(app).custom_clip
4388    }
4389
4390    fn custom_clip_data_mut(
4391        self: RenderHandle<Self>,
4392        app: &mut App,
4393    ) -> &mut RenderCustomClipData<Rect> {
4394        &mut self.get_mut(app).custom_clip
4395    }
4396
4397    fn default_clip(self: RenderHandle<Self>, app: &App) -> Rect {
4398        Offset::ZERO & self.size(app)
4399    }
4400}
4401
4402impl RenderObject for RenderClipOval {
4403    crate::render_object_accessors!();
4404
4405    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4406        if let Some(child) = self.child(app) {
4407            child.as_object().attach(app, owner);
4408        }
4409        RenderCustomClip::did_attach(self, app);
4410    }
4411
4412    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4413        RenderCustomClip::did_detach(self, app);
4414        if let Some(child) = self.child(app) {
4415            child.as_object().detach(app);
4416        }
4417    }
4418
4419    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4420        RenderCustomClip::perform_layout(self, app);
4421    }
4422
4423    fn paint(
4424        self: RenderHandle<Self>,
4425        app: &mut App,
4426        context: &mut PaintingContext,
4427        offset: Offset,
4428    ) {
4429        if let Some(child) = self.child(app) {
4430            let clip_behavior = self.clip_behavior(app);
4431            if clip_behavior != Clip::None {
4432                self.update_clip(app);
4433                let clip = self.clip(app);
4434                let clip_path = self.get_clip_path(app, clip);
4435                let old = self.as_object().layer_as::<ClipPathLayer>(app);
4436                let layer = context.push_clip_path(
4437                    app,
4438                    self.as_object().needs_compositing(app),
4439                    offset,
4440                    clip,
4441                    clip_path,
4442                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4443                    clip_behavior,
4444                    old,
4445                );
4446                self.as_object()
4447                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4448            } else {
4449                context.paint_child(app, child.as_object(), offset);
4450                self.as_object().set_layer(app, None);
4451            }
4452        } else {
4453            self.as_object().set_layer(app, None);
4454        }
4455    }
4456
4457    fn visit_children(
4458        self: RenderHandle<Self>,
4459        app: &App,
4460        visitor: &mut dyn FnMut(AnyRenderObject),
4461    ) {
4462        if let Some(child) = self.child(app) {
4463            visitor(child.as_object());
4464        }
4465    }
4466}
4467
4468impl RenderBox for RenderClipOval {
4469    crate::render_box_accessors!();
4470
4471    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4472        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4473    }
4474
4475    fn apply_paint_transform(
4476        self: RenderHandle<Self>,
4477        app: &App,
4478        child: AnyRenderObject,
4479        transform: &mut Matrix4,
4480    ) {
4481        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4482    }
4483
4484    fn hit_test(
4485        self: RenderHandle<Self>,
4486        app: &mut App,
4487        result: &mut BoxHitTestResult<'_>,
4488        position: Offset,
4489    ) -> bool {
4490        self.update_clip(app);
4491        let clip = self.clip(app);
4492        let center = clip.center();
4493        // convert the position to an offset from the center of the unit circle
4494        let offset = Offset::new(
4495            (position.dx() - center.dx()) / clip.width(),
4496            (position.dy() - center.dy()) / clip.height(),
4497        );
4498        // check if the point is outside the unit circle
4499        if offset.distance_squared() > 0.25 {
4500            // x^2 + y^2 > r^2
4501            return false;
4502        }
4503        RenderBoxBase::hit_test(self, app, result, position)
4504    }
4505
4506    fn hit_test_children(
4507        self: RenderHandle<Self>,
4508        app: &mut App,
4509        result: &mut BoxHitTestResult<'_>,
4510        position: Offset,
4511    ) -> bool {
4512        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4513    }
4514
4515    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4516        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4517    }
4518
4519    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4520        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4521    }
4522
4523    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4524        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4525    }
4526
4527    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4528        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4529    }
4530
4531    fn compute_distance_to_actual_baseline(
4532        self: RenderHandle<Self>,
4533        app: &mut App,
4534        baseline: TextBaseline,
4535    ) -> Option<f64> {
4536        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4537    }
4538
4539    fn compute_dry_baseline(
4540        self: RenderHandle<Self>,
4541        app: &mut App,
4542        constraints: BoxConstraints,
4543        baseline: TextBaseline,
4544    ) -> Option<f64> {
4545        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4546    }
4547
4548    fn compute_dry_layout(
4549        self: RenderHandle<Self>,
4550        app: &mut App,
4551        constraints: BoxConstraints,
4552    ) -> Size {
4553        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4554    }
4555}
4556
4557/// Clips its child using a path.
4558///
4559/// Takes a delegate whose primary method returns a path that should
4560/// be used to prevent the child from painting outside the path.
4561///
4562/// Clipping to a path is expensive. Certain shapes have more
4563/// optimized render objects:
4564///
4565///  * To clip to a rectangle, consider [`RenderClipRect`].
4566///  * To clip to an oval or circle, consider [`RenderClipOval`].
4567///  * To clip to a rounded rectangle, consider [`RenderClipRRect`].
4568pub struct RenderClipPath {
4569    render_object: RenderObjectData,
4570    render_box: RenderBoxData,
4571    child: RenderObjectWithChildData<AnyRenderBox>,
4572    custom_clip: RenderCustomClipData<Arc<Path>>,
4573}
4574
4575impl RenderClipPath {
4576    /// Creates a path clip.
4577    ///
4578    /// If `clipper` is `None`, the clip will be a rectangle that matches the layout
4579    /// size and location of the child. However, rather than use this default,
4580    /// consider using a [`RenderClipRect`], which can achieve the same effect more
4581    /// efficiently.
4582    ///
4583    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4584    pub fn new(
4585        app: &mut App,
4586        clipper: Option<Rc<dyn CustomClipper<Arc<Path>>>>,
4587        clip_behavior: Clip,
4588        child: Option<AnyRenderBox>,
4589    ) -> RenderHandle<RenderClipPath> {
4590        let this = RenderHandle::new_box(
4591            app,
4592            RenderClipPath {
4593                render_object: RenderObjectData::new(),
4594                render_box: RenderBoxData::new(),
4595                child: RenderObjectWithChildData::new(),
4596                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4597            },
4598        );
4599        this.set_child(app, child);
4600        this
4601    }
4602}
4603
4604impl RenderObjectWithChildMixin for RenderClipPath {
4605    type ChildType = AnyRenderBox;
4606
4607    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4608        &self.get(app).child
4609    }
4610
4611    fn child_data_mut(
4612        self: RenderHandle<Self>,
4613        app: &mut App,
4614    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4615        &mut self.get_mut(app).child
4616    }
4617}
4618
4619impl RenderProxyBoxMixin for RenderClipPath {}
4620
4621impl RenderCustomClip<Arc<Path>> for RenderClipPath {
4622    fn custom_clip_data(self: RenderHandle<Self>, app: &App) -> &RenderCustomClipData<Arc<Path>> {
4623        &self.get(app).custom_clip
4624    }
4625
4626    fn custom_clip_data_mut(
4627        self: RenderHandle<Self>,
4628        app: &mut App,
4629    ) -> &mut RenderCustomClipData<Arc<Path>> {
4630        &mut self.get_mut(app).custom_clip
4631    }
4632
4633    fn default_clip(self: RenderHandle<Self>, app: &App) -> Arc<Path> {
4634        let mut path = PathBuilder::new();
4635        path.rect((Offset::ZERO & self.size(app)).into());
4636        path.build()
4637    }
4638}
4639
4640impl RenderObject for RenderClipPath {
4641    crate::render_object_accessors!();
4642
4643    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4644        if let Some(child) = self.child(app) {
4645            child.as_object().attach(app, owner);
4646        }
4647        RenderCustomClip::did_attach(self, app);
4648    }
4649
4650    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4651        RenderCustomClip::did_detach(self, app);
4652        if let Some(child) = self.child(app) {
4653            child.as_object().detach(app);
4654        }
4655    }
4656
4657    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4658        RenderCustomClip::perform_layout(self, app);
4659    }
4660
4661    fn paint(
4662        self: RenderHandle<Self>,
4663        app: &mut App,
4664        context: &mut PaintingContext,
4665        offset: Offset,
4666    ) {
4667        if let Some(child) = self.child(app) {
4668            let clip_behavior = self.clip_behavior(app);
4669            if clip_behavior != Clip::None {
4670                self.update_clip(app);
4671                let clip = self.clip(app);
4672                let bounds = Offset::ZERO & self.size(app);
4673                let old = self.as_object().layer_as::<ClipPathLayer>(app);
4674                let layer = context.push_clip_path(
4675                    app,
4676                    self.as_object().needs_compositing(app),
4677                    offset,
4678                    bounds,
4679                    clip,
4680                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4681                    clip_behavior,
4682                    old,
4683                );
4684                self.as_object()
4685                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4686            } else {
4687                context.paint_child(app, child.as_object(), offset);
4688                self.as_object().set_layer(app, None);
4689            }
4690        } else {
4691            self.as_object().set_layer(app, None);
4692        }
4693    }
4694
4695    fn visit_children(
4696        self: RenderHandle<Self>,
4697        app: &App,
4698        visitor: &mut dyn FnMut(AnyRenderObject),
4699    ) {
4700        if let Some(child) = self.child(app) {
4701            visitor(child.as_object());
4702        }
4703    }
4704}
4705
4706impl RenderBox for RenderClipPath {
4707    crate::render_box_accessors!();
4708
4709    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4710        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4711    }
4712
4713    fn apply_paint_transform(
4714        self: RenderHandle<Self>,
4715        app: &App,
4716        child: AnyRenderObject,
4717        transform: &mut Matrix4,
4718    ) {
4719        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4720    }
4721
4722    fn hit_test(
4723        self: RenderHandle<Self>,
4724        app: &mut App,
4725        result: &mut BoxHitTestResult<'_>,
4726        position: Offset,
4727    ) -> bool {
4728        if self.clipper(app).is_some() {
4729            self.update_clip(app);
4730            let point = Point::new(position.dx() as f32, position.dy() as f32);
4731            if !self.clip(app).contains(point, FillRule::NonZero) {
4732                return false;
4733            }
4734        }
4735        RenderBoxBase::hit_test(self, app, result, position)
4736    }
4737
4738    fn hit_test_children(
4739        self: RenderHandle<Self>,
4740        app: &mut App,
4741        result: &mut BoxHitTestResult<'_>,
4742        position: Offset,
4743    ) -> bool {
4744        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
4745    }
4746
4747    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4748        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
4749    }
4750
4751    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
4752        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
4753    }
4754
4755    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4756        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
4757    }
4758
4759    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
4760        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
4761    }
4762
4763    fn compute_distance_to_actual_baseline(
4764        self: RenderHandle<Self>,
4765        app: &mut App,
4766        baseline: TextBaseline,
4767    ) -> Option<f64> {
4768        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
4769    }
4770
4771    fn compute_dry_baseline(
4772        self: RenderHandle<Self>,
4773        app: &mut App,
4774        constraints: BoxConstraints,
4775        baseline: TextBaseline,
4776    ) -> Option<f64> {
4777        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
4778    }
4779
4780    fn compute_dry_layout(
4781        self: RenderHandle<Self>,
4782        app: &mut App,
4783        constraints: BoxConstraints,
4784    ) -> Size {
4785        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
4786    }
4787}
4788
4789/// Clips its child using a rounded superellipse.
4790///
4791/// By default, [`RenderClipRSuperellipse`] uses its own
4792/// [`border_radius`](Self::border_radius) to create the shape. A custom `clipper` can
4793/// define any rounded superellipse.
4794pub struct RenderClipRSuperellipse {
4795    render_object: RenderObjectData,
4796    render_box: RenderBoxData,
4797    child: RenderObjectWithChildData<AnyRenderBox>,
4798    custom_clip: RenderCustomClipData<RSuperellipse>,
4799    border_radius: BorderRadiusGeometry,
4800    text_direction: Option<TextDirection>,
4801}
4802
4803impl RenderClipRSuperellipse {
4804    /// Creates a rounded-superellipse clip.
4805    ///
4806    /// The `border_radius` defaults to [`BorderRadiusGeometry::ZERO`], i.e. a rectangle with
4807    /// right-angled corners.
4808    ///
4809    /// If `clipper` is non-`None`, then `border_radius` is ignored.
4810    ///
4811    /// If `clip_behavior` is [`Clip::None`], no clipping will be applied.
4812    pub fn new(
4813        app: &mut App,
4814        border_radius: BorderRadiusGeometry,
4815        clipper: Option<Rc<dyn CustomClipper<RSuperellipse>>>,
4816        clip_behavior: Clip,
4817        text_direction: Option<TextDirection>,
4818        child: Option<AnyRenderBox>,
4819    ) -> RenderHandle<RenderClipRSuperellipse> {
4820        let this = RenderHandle::new_box(
4821            app,
4822            RenderClipRSuperellipse {
4823                render_object: RenderObjectData::new(),
4824                render_box: RenderBoxData::new(),
4825                child: RenderObjectWithChildData::new(),
4826                custom_clip: RenderCustomClipData::new(clipper, clip_behavior),
4827                border_radius,
4828                text_direction,
4829            },
4830        );
4831        this.set_child(app, child);
4832        this
4833    }
4834
4835    /// The border radius of the rounded corners.
4836    ///
4837    /// Values are clamped so that horizontal and vertical radii sums do not exceed
4838    /// width/height.
4839    ///
4840    /// This value is ignored if `clipper` is non-`None`.
4841    pub fn border_radius(self: RenderHandle<Self>, app: &App) -> BorderRadiusGeometry {
4842        self.get(app).border_radius
4843    }
4844
4845    /// Sets [`border_radius`](Self::border_radius).
4846    pub fn set_border_radius(self: RenderHandle<Self>, app: &mut App, value: BorderRadiusGeometry) {
4847        if self.get(app).border_radius == value {
4848            return;
4849        }
4850        self.get_mut(app).border_radius = value;
4851        self.mark_needs_clip(app);
4852    }
4853
4854    /// The text direction with which to resolve [`border_radius`](Self::border_radius).
4855    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
4856        self.get(app).text_direction
4857    }
4858
4859    /// Sets [`text_direction`](Self::text_direction).
4860    pub fn set_text_direction(
4861        self: RenderHandle<Self>,
4862        app: &mut App,
4863        value: Option<TextDirection>,
4864    ) {
4865        if self.get(app).text_direction == value {
4866            return;
4867        }
4868        self.get_mut(app).text_direction = value;
4869        self.mark_needs_clip(app);
4870    }
4871}
4872
4873impl RenderObjectWithChildMixin for RenderClipRSuperellipse {
4874    type ChildType = AnyRenderBox;
4875
4876    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
4877        &self.get(app).child
4878    }
4879
4880    fn child_data_mut(
4881        self: RenderHandle<Self>,
4882        app: &mut App,
4883    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
4884        &mut self.get_mut(app).child
4885    }
4886}
4887
4888impl RenderProxyBoxMixin for RenderClipRSuperellipse {}
4889
4890impl RenderCustomClip<RSuperellipse> for RenderClipRSuperellipse {
4891    fn custom_clip_data(
4892        self: RenderHandle<Self>,
4893        app: &App,
4894    ) -> &RenderCustomClipData<RSuperellipse> {
4895        &self.get(app).custom_clip
4896    }
4897
4898    fn custom_clip_data_mut(
4899        self: RenderHandle<Self>,
4900        app: &mut App,
4901    ) -> &mut RenderCustomClipData<RSuperellipse> {
4902        &mut self.get_mut(app).custom_clip
4903    }
4904
4905    fn default_clip(self: RenderHandle<Self>, app: &App) -> RSuperellipse {
4906        let this = self.get(app);
4907        this.border_radius
4908            .resolve(this.text_direction)
4909            .to_r_superellipse(Offset::ZERO & self.size(app))
4910    }
4911}
4912
4913impl RenderObject for RenderClipRSuperellipse {
4914    crate::render_object_accessors!();
4915
4916    fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
4917        if let Some(child) = self.child(app) {
4918            child.as_object().attach(app, owner);
4919        }
4920        RenderCustomClip::did_attach(self, app);
4921    }
4922
4923    fn did_detach(self: RenderHandle<Self>, app: &mut App) {
4924        RenderCustomClip::did_detach(self, app);
4925        if let Some(child) = self.child(app) {
4926            child.as_object().detach(app);
4927        }
4928    }
4929
4930    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
4931        RenderCustomClip::perform_layout(self, app);
4932    }
4933
4934    fn paint(
4935        self: RenderHandle<Self>,
4936        app: &mut App,
4937        context: &mut PaintingContext,
4938        offset: Offset,
4939    ) {
4940        if let Some(child) = self.child(app) {
4941            let clip_behavior = self.clip_behavior(app);
4942            if clip_behavior != Clip::None {
4943                self.update_clip(app);
4944                let clip = self.clip(app);
4945                let mut clip_path = PathBuilder::new();
4946                clip_path.rsuperellipse_radii(
4947                    clip.outer_rect().into(),
4948                    rsuperellipse_radii_elliptical(clip),
4949                );
4950                let old = self.as_object().layer_as::<ClipPathLayer>(app);
4951                let layer = context.push_clip_path(
4952                    app,
4953                    self.as_object().needs_compositing(app),
4954                    offset,
4955                    clip.outer_rect(),
4956                    clip_path.build(),
4957                    |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
4958                    clip_behavior,
4959                    old,
4960                );
4961                self.as_object()
4962                    .set_layer(app, layer.map(|layer| layer.as_container_layer()));
4963            } else {
4964                context.paint_child(app, child.as_object(), offset);
4965                self.as_object().set_layer(app, None);
4966            }
4967        } else {
4968            self.as_object().set_layer(app, None);
4969        }
4970    }
4971
4972    fn visit_children(
4973        self: RenderHandle<Self>,
4974        app: &App,
4975        visitor: &mut dyn FnMut(AnyRenderObject),
4976    ) {
4977        if let Some(child) = self.child(app) {
4978            visitor(child.as_object());
4979        }
4980    }
4981}
4982
4983impl RenderBox for RenderClipRSuperellipse {
4984    crate::render_box_accessors!();
4985
4986    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
4987        RenderProxyBoxMixin::setup_parent_data(self, app, child);
4988    }
4989
4990    fn apply_paint_transform(
4991        self: RenderHandle<Self>,
4992        app: &App,
4993        child: AnyRenderObject,
4994        transform: &mut Matrix4,
4995    ) {
4996        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
4997    }
4998
4999    fn hit_test(
5000        self: RenderHandle<Self>,
5001        app: &mut App,
5002        result: &mut BoxHitTestResult<'_>,
5003        position: Offset,
5004    ) -> bool {
5005        if self.clipper(app).is_some() {
5006            self.update_clip(app);
5007            if !self.clip(app).outer_rect().contains(position) {
5008                return false;
5009            }
5010        }
5011        RenderBoxBase::hit_test(self, app, result, position)
5012    }
5013
5014    fn hit_test_children(
5015        self: RenderHandle<Self>,
5016        app: &mut App,
5017        result: &mut BoxHitTestResult<'_>,
5018        position: Offset,
5019    ) -> bool {
5020        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
5021    }
5022
5023    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5024        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
5025    }
5026
5027    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5028        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
5029    }
5030
5031    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5032        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
5033    }
5034
5035    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5036        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
5037    }
5038
5039    fn compute_distance_to_actual_baseline(
5040        self: RenderHandle<Self>,
5041        app: &mut App,
5042        baseline: TextBaseline,
5043    ) -> Option<f64> {
5044        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
5045    }
5046
5047    fn compute_dry_baseline(
5048        self: RenderHandle<Self>,
5049        app: &mut App,
5050        constraints: BoxConstraints,
5051        baseline: TextBaseline,
5052    ) -> Option<f64> {
5053        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
5054    }
5055
5056    fn compute_dry_layout(
5057        self: RenderHandle<Self>,
5058        app: &mut App,
5059        constraints: BoxConstraints,
5060    ) -> Size {
5061        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
5062    }
5063}
5064
5065/// Applies a transformation before painting its child.
5066pub struct RenderTransform {
5067    render_object: RenderObjectData,
5068    render_box: RenderBoxData,
5069    child: RenderObjectWithChildData<AnyRenderBox>,
5070    origin: Option<Offset>,
5071    alignment: Option<AlignmentGeometry>,
5072    text_direction: Option<TextDirection>,
5073    transform_hit_tests: bool,
5074    transform: Matrix4,
5075}
5076
5077impl RenderTransform {
5078    /// Creates a render object that transforms its child.
5079    pub fn new(
5080        app: &mut App,
5081        transform: Matrix4,
5082        origin: Option<Offset>,
5083        alignment: Option<AlignmentGeometry>,
5084        text_direction: Option<TextDirection>,
5085        transform_hit_tests: bool,
5086        child: Option<AnyRenderBox>,
5087    ) -> RenderHandle<RenderTransform> {
5088        let this = RenderHandle::new_box(
5089            app,
5090            RenderTransform {
5091                render_object: RenderObjectData::new(),
5092                render_box: RenderBoxData::new(),
5093                child: RenderObjectWithChildData::new(),
5094                origin,
5095                alignment,
5096                text_direction,
5097                transform_hit_tests,
5098                transform,
5099            },
5100        );
5101        this.set_child(app, child);
5102        this
5103    }
5104
5105    /// The origin of the coordinate system (relative to the upper left corner of
5106    /// this render object) in which to apply the matrix.
5107    ///
5108    /// Setting an origin is equivalent to conjugating the transform matrix by a
5109    /// translation. This property is provided just for convenience.
5110    pub fn origin(self: RenderHandle<Self>, app: &App) -> Option<Offset> {
5111        self.get(app).origin
5112    }
5113
5114    /// Sets [`origin`](Self::origin).
5115    pub fn set_origin(self: RenderHandle<Self>, app: &mut App, value: Option<Offset>) {
5116        if self.get(app).origin == value {
5117            return;
5118        }
5119        self.get_mut(app).origin = value;
5120        self.mark_needs_paint(app);
5121    }
5122
5123    /// The alignment of the origin, relative to the size of the box.
5124    ///
5125    /// This is equivalent to setting an origin based on the size of the box.
5126    /// If it is specified at the same time as an offset, both are applied.
5127    ///
5128    /// An `AlignmentDirectional::CENTER_START` value is the same as an [`Alignment`]
5129    /// whose `x` value is `-1.0` if [`text_direction`](Self::text_direction) is
5130    /// [`TextDirection::Ltr`], and `1.0` if it is [`TextDirection::Rtl`].
5131    /// Similarly `AlignmentDirectional::CENTER_END` is the same as an [`Alignment`]
5132    /// whose `x` value is `1.0` if [`text_direction`](Self::text_direction) is
5133    /// [`TextDirection::Ltr`], and `-1.0` if it is [`TextDirection::Rtl`].
5134    ///
5135    /// [`Alignment`]: inset_painting::Alignment
5136    pub fn alignment(self: RenderHandle<Self>, app: &App) -> Option<AlignmentGeometry> {
5137        self.get(app).alignment
5138    }
5139
5140    /// Sets [`alignment`](Self::alignment).
5141    pub fn set_alignment(
5142        self: RenderHandle<Self>,
5143        app: &mut App,
5144        value: Option<AlignmentGeometry>,
5145    ) {
5146        if self.get(app).alignment == value {
5147            return;
5148        }
5149        self.get_mut(app).alignment = value;
5150        self.mark_needs_paint(app);
5151    }
5152
5153    /// The text direction with which to resolve [`alignment`](Self::alignment).
5154    ///
5155    /// This may be changed to `None`, but only after [`alignment`](Self::alignment) has been
5156    /// changed to a value that does not depend on the direction.
5157    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
5158        self.get(app).text_direction
5159    }
5160
5161    /// Sets [`text_direction`](Self::text_direction).
5162    pub fn set_text_direction(
5163        self: RenderHandle<Self>,
5164        app: &mut App,
5165        value: Option<TextDirection>,
5166    ) {
5167        if self.get(app).text_direction == value {
5168            return;
5169        }
5170        self.get_mut(app).text_direction = value;
5171        self.mark_needs_paint(app);
5172    }
5173
5174    /// When true, hit tests are performed based on the position of the
5175    /// child as it is painted. When false, hit tests are performed
5176    /// ignoring the transformation.
5177    ///
5178    /// [`RenderBox::apply_paint_transform`], and therefore
5179    /// [`AnyRenderBox::local_to_global`] and [`AnyRenderBox::global_to_local`], always honor
5180    /// the transformation, regardless of the value of this property.
5181    pub fn transform_hit_tests(self: RenderHandle<Self>, app: &App) -> bool {
5182        self.get(app).transform_hit_tests
5183    }
5184
5185    /// Sets [`transform_hit_tests`](Self::transform_hit_tests). Dart's plain field.
5186    pub fn set_transform_hit_tests(self: RenderHandle<Self>, app: &mut App, value: bool) {
5187        self.get_mut(app).transform_hit_tests = value;
5188    }
5189
5190    /// Sets the matrix to transform the child by during painting.
5191    ///
5192    /// There is no getter for the transform, as in Dart, where the matrix is mutable and
5193    /// mutations outside of the control of the render object could not reliably be reflected
5194    /// in the rendering.
5195    pub fn set_transform(self: RenderHandle<Self>, app: &mut App, value: Matrix4) {
5196        if self.get(app).transform == value {
5197            return;
5198        }
5199        self.get_mut(app).transform = value;
5200        self.mark_needs_paint(app);
5201    }
5202
5203    /// Sets the transform to the identity matrix.
5204    pub fn set_identity(self: RenderHandle<Self>, app: &mut App) {
5205        self.get_mut(app).transform = Matrix4::IDENTITY;
5206        self.mark_needs_paint(app);
5207    }
5208
5209    /// Concatenates a rotation about the x axis into the transform.
5210    pub fn rotate_x(self: RenderHandle<Self>, app: &mut App, radians: f64) {
5211        let (sin, cos) = (radians.sin() as f32, radians.cos() as f32);
5212        #[rustfmt::skip]
5213        let rotation = Matrix4::from_flutter_array(&[
5214            1.0, 0.0, 0.0, 0.0,
5215            0.0, cos, sin, 0.0,
5216            0.0, -sin, cos, 0.0,
5217            0.0, 0.0, 0.0, 1.0,
5218        ]);
5219        self.concat(app, &rotation);
5220    }
5221
5222    /// Concatenates a rotation about the y axis into the transform.
5223    pub fn rotate_y(self: RenderHandle<Self>, app: &mut App, radians: f64) {
5224        let (sin, cos) = (radians.sin() as f32, radians.cos() as f32);
5225        #[rustfmt::skip]
5226        let rotation = Matrix4::from_flutter_array(&[
5227            cos, 0.0, -sin, 0.0,
5228            0.0, 1.0, 0.0, 0.0,
5229            sin, 0.0, cos, 0.0,
5230            0.0, 0.0, 0.0, 1.0,
5231        ]);
5232        self.concat(app, &rotation);
5233    }
5234
5235    /// Concatenates a rotation about the z axis into the transform.
5236    pub fn rotate_z(self: RenderHandle<Self>, app: &mut App, radians: f64) {
5237        let (sin, cos) = (radians.sin() as f32, radians.cos() as f32);
5238        #[rustfmt::skip]
5239        let rotation = Matrix4::from_flutter_array(&[
5240            cos, sin, 0.0, 0.0,
5241            -sin, cos, 0.0, 0.0,
5242            0.0, 0.0, 1.0, 0.0,
5243            0.0, 0.0, 0.0, 1.0,
5244        ]);
5245        self.concat(app, &rotation);
5246    }
5247
5248    /// Concatenates a translation by (x, y, z) into the transform.
5249    pub fn translate(self: RenderHandle<Self>, app: &mut App, x: f64, y: f64, z: f64) {
5250        #[rustfmt::skip]
5251        let translation = Matrix4::from_flutter_array(&[
5252            1.0, 0.0, 0.0, 0.0,
5253            0.0, 1.0, 0.0, 0.0,
5254            0.0, 0.0, 1.0, 0.0,
5255            x as f32, y as f32, z as f32, 1.0,
5256        ]);
5257        self.concat(app, &translation);
5258    }
5259
5260    /// Concatenates a scale into the transform. Dart's optional `y` and `z` default to `x`.
5261    pub fn scale(self: RenderHandle<Self>, app: &mut App, x: f64, y: Option<f64>, z: Option<f64>) {
5262        let (y, z) = (y.unwrap_or(x) as f32, z.unwrap_or(x) as f32);
5263        #[rustfmt::skip]
5264        let scale = Matrix4::from_flutter_array(&[
5265            x as f32, 0.0, 0.0, 0.0,
5266            0.0, y, 0.0, 0.0,
5267            0.0, 0.0, z, 0.0,
5268            0.0, 0.0, 0.0, 1.0,
5269        ]);
5270        self.concat(app, &scale);
5271    }
5272
5273    /// vector_math's in-place `rotateX` / `translate` / `scale`: a right multiplication of the
5274    /// transform, then a repaint.
5275    fn concat(self: RenderHandle<Self>, app: &mut App, other: &Matrix4) {
5276        crate::object::multiply(&mut self.get_mut(app).transform, other);
5277        self.mark_needs_paint(app);
5278    }
5279
5280    /// Flutter's `_effectiveTransform`: the transform around [`origin`](Self::origin) and the
5281    /// resolved [`alignment`](Self::alignment).
5282    fn effective_transform(self: RenderHandle<Self>, app: &App) -> Matrix4 {
5283        let this = self.get(app);
5284        let resolved_alignment = this
5285            .alignment
5286            .map(|alignment| alignment.resolve(this.text_direction));
5287        let origin = this.origin;
5288        if origin.is_none() && resolved_alignment.is_none() {
5289            return this.transform;
5290        }
5291        let mut result = Matrix4::IDENTITY;
5292        if let Some(origin) = origin {
5293            crate::object::translate(&mut result, origin.dx(), origin.dy());
5294        }
5295        let translation = resolved_alignment.map(|alignment| alignment.along_size(self.size(app)));
5296        if let Some(translation) = translation {
5297            crate::object::translate(&mut result, translation.dx(), translation.dy());
5298        }
5299        crate::object::multiply(&mut result, &self.get(app).transform);
5300        if let Some(translation) = translation {
5301            crate::object::translate(&mut result, -translation.dx(), -translation.dy());
5302        }
5303        if let Some(origin) = origin {
5304            crate::object::translate(&mut result, -origin.dx(), -origin.dy());
5305        }
5306        result
5307    }
5308}
5309
5310impl RenderObjectWithChildMixin for RenderTransform {
5311    type ChildType = AnyRenderBox;
5312
5313    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
5314        &self.get(app).child
5315    }
5316
5317    fn child_data_mut(
5318        self: RenderHandle<Self>,
5319        app: &mut App,
5320    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
5321        &mut self.get_mut(app).child
5322    }
5323}
5324
5325impl RenderProxyBoxMixin for RenderTransform {}
5326
5327impl RenderObject for RenderTransform {
5328    crate::render_object_accessors!();
5329
5330    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
5331        RenderProxyBoxMixin::perform_layout(self, app);
5332    }
5333
5334    fn paint(
5335        self: RenderHandle<Self>,
5336        app: &mut App,
5337        context: &mut PaintingContext,
5338        offset: Offset,
5339    ) {
5340        if self.child(app).is_none() {
5341            return;
5342        }
5343        let transform = self.effective_transform(app);
5344        let Some(child_offset) = get_as_translation(transform) else {
5345            // If the matrix is singular the children would be compressed to a line or
5346            // single point, instead short-circuit and paint nothing.
5347            let determinant = transform.determinant();
5348            if determinant == 0.0 || !determinant.is_finite() {
5349                self.as_object().set_layer(app, None);
5350                return;
5351            }
5352            let old = self.as_object().layer_as::<TransformLayer>(app);
5353            let layer = context.push_transform(
5354                app,
5355                self.as_object().needs_compositing(app),
5356                offset,
5357                transform,
5358                |app, context, offset| {
5359                    RenderProxyBoxMixin::paint(self, app, context, offset);
5360                },
5361                old,
5362            );
5363            self.as_object()
5364                .set_layer(app, layer.map(|layer| layer.as_container_layer()));
5365            return;
5366        };
5367        RenderProxyBoxMixin::paint(self, app, context, offset + child_offset);
5368        self.as_object().set_layer(app, None);
5369    }
5370
5371    fn visit_children(
5372        self: RenderHandle<Self>,
5373        app: &App,
5374        visitor: &mut dyn FnMut(AnyRenderObject),
5375    ) {
5376        if let Some(child) = self.child(app) {
5377            visitor(child.as_object());
5378        }
5379    }
5380}
5381
5382impl RenderBox for RenderTransform {
5383    crate::render_box_accessors!();
5384
5385    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
5386        RenderProxyBoxMixin::setup_parent_data(self, app, child);
5387    }
5388
5389    fn apply_paint_transform(
5390        self: RenderHandle<Self>,
5391        app: &App,
5392        _child: AnyRenderObject,
5393        transform: &mut Matrix4,
5394    ) {
5395        crate::object::multiply(transform, &self.effective_transform(app));
5396    }
5397
5398    fn hit_test(
5399        self: RenderHandle<Self>,
5400        app: &mut App,
5401        result: &mut BoxHitTestResult<'_>,
5402        position: Offset,
5403    ) -> bool {
5404        // RenderTransform objects don't check if they are
5405        // themselves hit, because it's confusing to think about
5406        // how the untransformed size and the child's transformed
5407        // position interact.
5408        RenderBox::hit_test_children(self, app, result, position)
5409    }
5410
5411    fn hit_test_children(
5412        self: RenderHandle<Self>,
5413        app: &mut App,
5414        result: &mut BoxHitTestResult<'_>,
5415        position: Offset,
5416    ) -> bool {
5417        let transform = self
5418            .transform_hit_tests(app)
5419            .then(|| self.effective_transform(app));
5420        result.add_with_paint_transform(transform, position, |result, position| {
5421            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
5422        })
5423    }
5424
5425    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5426        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
5427    }
5428
5429    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5430        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
5431    }
5432
5433    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5434        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
5435    }
5436
5437    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5438        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
5439    }
5440
5441    fn compute_distance_to_actual_baseline(
5442        self: RenderHandle<Self>,
5443        app: &mut App,
5444        baseline: TextBaseline,
5445    ) -> Option<f64> {
5446        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
5447    }
5448
5449    fn compute_dry_baseline(
5450        self: RenderHandle<Self>,
5451        app: &mut App,
5452        constraints: BoxConstraints,
5453        baseline: TextBaseline,
5454    ) -> Option<f64> {
5455        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
5456    }
5457
5458    fn compute_dry_layout(
5459        self: RenderHandle<Self>,
5460        app: &mut App,
5461        constraints: BoxConstraints,
5462    ) -> Size {
5463        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
5464    }
5465}
5466
5467/// Scales and positions its child within itself according to [`fit`](Self::fit).
5468pub struct RenderFittedBox {
5469    render_object: RenderObjectData,
5470    render_box: RenderBoxData,
5471    child: RenderObjectWithChildData<AnyRenderBox>,
5472    fit: BoxFit,
5473    alignment: AlignmentGeometry,
5474    text_direction: Option<TextDirection>,
5475    resolved_alignment: Option<Alignment>,
5476    clip_behavior: Clip,
5477    has_visual_overflow: Option<bool>,
5478    transform: Option<Matrix4>,
5479}
5480
5481/// Whether a change of [`BoxFit`] changes the size this box takes.
5482fn fit_affects_layout(fit: BoxFit) -> bool {
5483    match fit {
5484        BoxFit::ScaleDown => true,
5485        BoxFit::Contain
5486        | BoxFit::Cover
5487        | BoxFit::Fill
5488        | BoxFit::FitHeight
5489        | BoxFit::FitWidth
5490        | BoxFit::None => false,
5491    }
5492}
5493
5494impl RenderFittedBox {
5495    /// Creates a render object that scales and positions its child within itself.
5496    pub fn new(
5497        app: &mut App,
5498        fit: BoxFit,
5499        alignment: AlignmentGeometry,
5500        text_direction: Option<TextDirection>,
5501        child: Option<AnyRenderBox>,
5502    ) -> RenderHandle<RenderFittedBox> {
5503        let this = RenderHandle::new_box(
5504            app,
5505            RenderFittedBox {
5506                render_object: RenderObjectData::new(),
5507                render_box: RenderBoxData::new(),
5508                child: RenderObjectWithChildData::new(),
5509                fit,
5510                alignment,
5511                text_direction,
5512                resolved_alignment: None,
5513                clip_behavior: Clip::None,
5514                has_visual_overflow: None,
5515                transform: None,
5516            },
5517        );
5518        this.set_child(app, child);
5519        this
5520    }
5521
5522    fn resolve(self: RenderHandle<Self>, app: &mut App) -> Alignment {
5523        let this = self.get(app);
5524        if let Some(resolved) = this.resolved_alignment {
5525            return resolved;
5526        }
5527        let resolved = this.alignment.resolve(this.text_direction);
5528        self.get_mut(app).resolved_alignment = Some(resolved);
5529        resolved
5530    }
5531
5532    fn mark_need_resolution(self: RenderHandle<Self>, app: &mut App) {
5533        self.get_mut(app).resolved_alignment = None;
5534        self.mark_needs_paint(app);
5535    }
5536
5537    /// How to inscribe the child into the space allocated during layout.
5538    pub fn fit(self: RenderHandle<Self>, app: &App) -> BoxFit {
5539        self.get(app).fit
5540    }
5541
5542    /// Sets [`fit`](Self::fit).
5543    pub fn set_fit(self: RenderHandle<Self>, app: &mut App, value: BoxFit) {
5544        let last_fit = self.get(app).fit;
5545        if last_fit == value {
5546            return;
5547        }
5548        self.get_mut(app).fit = value;
5549        if fit_affects_layout(last_fit) || fit_affects_layout(value) {
5550            self.mark_needs_layout(app);
5551        } else {
5552            self.clear_paint_data(app);
5553            self.mark_needs_paint(app);
5554        }
5555    }
5556
5557    /// How to align the child within its parent's bounds.
5558    ///
5559    /// An alignment of (0.0, 0.0) aligns the child to the top-left corner of its parent's bounds.
5560    /// An alignment of (1.0, 0.5) aligns the child to the middle of the right edge of its
5561    /// parent's bounds.
5562    pub fn alignment(self: RenderHandle<Self>, app: &App) -> AlignmentGeometry {
5563        self.get(app).alignment
5564    }
5565
5566    /// Sets [`alignment`](Self::alignment).
5567    pub fn set_alignment(self: RenderHandle<Self>, app: &mut App, value: AlignmentGeometry) {
5568        if self.get(app).alignment == value {
5569            return;
5570        }
5571        self.get_mut(app).alignment = value;
5572        self.clear_paint_data(app);
5573        self.mark_need_resolution(app);
5574    }
5575
5576    /// The text direction with which to resolve [`alignment`](Self::alignment).
5577    pub fn text_direction(self: RenderHandle<Self>, app: &App) -> Option<TextDirection> {
5578        self.get(app).text_direction
5579    }
5580
5581    /// Sets [`text_direction`](Self::text_direction).
5582    pub fn set_text_direction(
5583        self: RenderHandle<Self>,
5584        app: &mut App,
5585        value: Option<TextDirection>,
5586    ) {
5587        if self.get(app).text_direction == value {
5588            return;
5589        }
5590        self.get_mut(app).text_direction = value;
5591        self.clear_paint_data(app);
5592        self.mark_need_resolution(app);
5593    }
5594
5595    /// How to clip a child that overflows this box. Defaults to [`Clip::None`].
5596    pub fn clip_behavior(self: RenderHandle<Self>, app: &App) -> Clip {
5597        self.get(app).clip_behavior
5598    }
5599
5600    /// Sets [`clip_behavior`](Self::clip_behavior).
5601    pub fn set_clip_behavior(self: RenderHandle<Self>, app: &mut App, value: Clip) {
5602        if self.get(app).clip_behavior == value {
5603            return;
5604        }
5605        self.get_mut(app).clip_behavior = value;
5606        self.mark_needs_paint(app);
5607    }
5608
5609    /// Whether the given child would be painted if [`RenderObject::paint`] were called.
5610    ///
5611    /// Flutter's `RenderObject.paintsChild` is a virtual whose default is true; here it is an
5612    /// inherent method (`PORTING.md`).
5613    pub fn paints_child(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> bool {
5614        debug_assert_eq!(child.as_object().parent(app), Some(self.as_object()));
5615        !self.size(app).is_empty() && !child.size(app).is_empty()
5616    }
5617
5618    fn clear_paint_data(self: RenderHandle<Self>, app: &mut App) {
5619        let this = self.get_mut(app);
5620        this.has_visual_overflow = None;
5621        this.transform = None;
5622    }
5623
5624    /// Flutter's `_updatePaintData`, without the cache: the transform that fits the child into
5625    /// this box, and whether the child overflows it.
5626    fn paint_data(self: RenderHandle<Self>, app: &App) -> (bool, Matrix4) {
5627        let Some(child) = self.child(app) else {
5628            return (false, Matrix4::IDENTITY);
5629        };
5630        let this = self.get(app);
5631        let resolved_alignment = this
5632            .resolved_alignment
5633            .unwrap_or_else(|| this.alignment.resolve(this.text_direction));
5634        let child_size = child.size(app);
5635        let sizes = apply_box_fit(this.fit, child_size, self.size(app));
5636        let scale_x = sizes.destination.width() / sizes.source.width();
5637        let scale_y = sizes.destination.height() / sizes.source.height();
5638        let source_rect = resolved_alignment.inscribe(sizes.source, Offset::ZERO & child_size);
5639        let destination_rect =
5640            resolved_alignment.inscribe(sizes.destination, Offset::ZERO & self.size(app));
5641        debug_assert!(scale_x.is_finite() && scale_y.is_finite());
5642        let mut transform =
5643            Matrix4::translation(destination_rect.left as f32, destination_rect.top as f32);
5644        crate::object::multiply(
5645            &mut transform,
5646            &Matrix4::scale(scale_x as f32, scale_y as f32),
5647        );
5648        crate::object::translate(&mut transform, -source_rect.left, -source_rect.top);
5649        let has_visual_overflow =
5650            source_rect.width() < child_size.width() || source_rect.height() < child_size.height();
5651        (has_visual_overflow, transform)
5652    }
5653
5654    fn update_paint_data(self: RenderHandle<Self>, app: &mut App) {
5655        if self.get(app).transform.is_some() {
5656            return;
5657        }
5658        // Dart's `_resolve()` memoizes the resolved alignment here.
5659        self.resolve(app);
5660        let (has_visual_overflow, transform) = self.paint_data(app);
5661        let this = self.get_mut(app);
5662        this.has_visual_overflow = Some(has_visual_overflow);
5663        this.transform = Some(transform);
5664    }
5665
5666    fn paint_child_with_transform(
5667        self: RenderHandle<Self>,
5668        app: &mut App,
5669        context: &mut PaintingContext,
5670        offset: Offset,
5671    ) -> Option<Handle<TransformLayer>> {
5672        let transform = self.get(app).transform.expect("update_paint_data ran");
5673        match get_as_translation(transform) {
5674            Some(child_offset) => {
5675                RenderProxyBoxMixin::paint(self, app, context, offset + child_offset);
5676                None
5677            }
5678            None => context.push_transform(
5679                app,
5680                self.as_object().needs_compositing(app),
5681                offset,
5682                transform,
5683                |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
5684                self.as_object().layer_as::<TransformLayer>(app),
5685            ),
5686        }
5687    }
5688}
5689
5690impl RenderObjectWithChildMixin for RenderFittedBox {
5691    type ChildType = AnyRenderBox;
5692
5693    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
5694        &self.get(app).child
5695    }
5696
5697    fn child_data_mut(
5698        self: RenderHandle<Self>,
5699        app: &mut App,
5700    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
5701        &mut self.get_mut(app).child
5702    }
5703}
5704
5705impl RenderProxyBoxMixin for RenderFittedBox {}
5706
5707impl RenderObject for RenderFittedBox {
5708    crate::render_object_accessors!();
5709
5710    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
5711        let constraints = self.constraints(app);
5712        let Some(child) = self.child(app) else {
5713            self.set_size(app, constraints.smallest());
5714            return;
5715        };
5716        child.layout(app, BoxConstraints::new(), true);
5717        let child_size = child.size(app);
5718        let size = match self.fit(app) {
5719            BoxFit::ScaleDown => {
5720                let size_constraints = constraints.loosen();
5721                let unconstrained_size = size_constraints
5722                    .constrain_size_and_attempt_to_preserve_aspect_ratio(child_size);
5723                constraints.constrain(unconstrained_size)
5724            }
5725            BoxFit::Contain
5726            | BoxFit::Cover
5727            | BoxFit::Fill
5728            | BoxFit::FitHeight
5729            | BoxFit::FitWidth
5730            | BoxFit::None => {
5731                constraints.constrain_size_and_attempt_to_preserve_aspect_ratio(child_size)
5732            }
5733        };
5734        self.set_size(app, size);
5735        self.clear_paint_data(app);
5736    }
5737
5738    fn paint(
5739        self: RenderHandle<Self>,
5740        app: &mut App,
5741        context: &mut PaintingContext,
5742        offset: Offset,
5743    ) {
5744        let Some(child) = self.child(app) else {
5745            return;
5746        };
5747        if self.size(app).is_empty() || child.size(app).is_empty() {
5748            return;
5749        }
5750        self.update_paint_data(app);
5751        let clip_behavior = self.clip_behavior(app);
5752        if self.get(app).has_visual_overflow == Some(true) && clip_behavior != Clip::None {
5753            let clip_rect = Offset::ZERO & self.size(app);
5754            let old = self.as_object().layer_as::<ClipRectLayer>(app);
5755            let layer = context.push_clip_rect(
5756                app,
5757                self.as_object().needs_compositing(app),
5758                offset,
5759                clip_rect,
5760                |app, context, offset| {
5761                    let _ = self.paint_child_with_transform(app, context, offset);
5762                },
5763                clip_behavior,
5764                old,
5765            );
5766            self.as_object()
5767                .set_layer(app, layer.map(|layer| layer.as_container_layer()));
5768        } else {
5769            let layer = self.paint_child_with_transform(app, context, offset);
5770            self.as_object()
5771                .set_layer(app, layer.map(|layer| layer.as_container_layer()));
5772        }
5773    }
5774
5775    fn visit_children(
5776        self: RenderHandle<Self>,
5777        app: &App,
5778        visitor: &mut dyn FnMut(AnyRenderObject),
5779    ) {
5780        if let Some(child) = self.child(app) {
5781            visitor(child.as_object());
5782        }
5783    }
5784}
5785
5786impl RenderBox for RenderFittedBox {
5787    crate::render_box_accessors!();
5788
5789    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
5790        RenderProxyBoxMixin::setup_parent_data(self, app, child);
5791    }
5792
5793    fn apply_paint_transform(
5794        self: RenderHandle<Self>,
5795        app: &App,
5796        child: AnyRenderObject,
5797        transform: &mut Matrix4,
5798    ) {
5799        let child = child.as_box().expect("a fitted box has a box child");
5800        if !self.paints_child(app, child) {
5801            *transform = crate::object::zero_matrix();
5802            return;
5803        }
5804        let (_, fitted) = self.paint_data(app);
5805        crate::object::multiply(transform, &fitted);
5806    }
5807
5808    fn hit_test_children(
5809        self: RenderHandle<Self>,
5810        app: &mut App,
5811        result: &mut BoxHitTestResult<'_>,
5812        position: Offset,
5813    ) -> bool {
5814        let child_is_empty = self
5815            .child(app)
5816            .is_none_or(|child| child.size(app).is_empty());
5817        if self.size(app).is_empty() || child_is_empty {
5818            return false;
5819        }
5820        self.update_paint_data(app);
5821        let transform = self.get(app).transform;
5822        result.add_with_paint_transform(transform, position, |result, position| {
5823            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
5824        })
5825    }
5826
5827    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5828        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
5829    }
5830
5831    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
5832        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
5833    }
5834
5835    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5836        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
5837    }
5838
5839    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
5840        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
5841    }
5842
5843    fn compute_distance_to_actual_baseline(
5844        self: RenderHandle<Self>,
5845        app: &mut App,
5846        baseline: TextBaseline,
5847    ) -> Option<f64> {
5848        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
5849    }
5850
5851    fn compute_dry_layout(
5852        self: RenderHandle<Self>,
5853        app: &mut App,
5854        constraints: BoxConstraints,
5855    ) -> Size {
5856        let Some(child) = self.child(app) else {
5857            return constraints.smallest();
5858        };
5859        let child_size = child.get_dry_layout(app, BoxConstraints::new());
5860        match self.fit(app) {
5861            BoxFit::ScaleDown => {
5862                let size_constraints = constraints.loosen();
5863                let unconstrained_size = size_constraints
5864                    .constrain_size_and_attempt_to_preserve_aspect_ratio(child_size);
5865                constraints.constrain(unconstrained_size)
5866            }
5867            BoxFit::Contain
5868            | BoxFit::Cover
5869            | BoxFit::Fill
5870            | BoxFit::FitHeight
5871            | BoxFit::FitWidth
5872            | BoxFit::None => {
5873                constraints.constrain_size_and_attempt_to_preserve_aspect_ratio(child_size)
5874            }
5875        }
5876    }
5877
5878    fn compute_dry_baseline(
5879        self: RenderHandle<Self>,
5880        app: &mut App,
5881        _constraints: BoxConstraints,
5882        baseline: TextBaseline,
5883    ) -> Option<f64> {
5884        // The baseline of the child with unconstrained layout, without applying any transforms
5885        // or scaling that would be applied during paint.
5886        self.child(app)?
5887            .get_dry_baseline(app, BoxConstraints::new(), baseline)
5888    }
5889}
5890
5891/// Applies a translation transformation before painting its child.
5892///
5893/// The translation is expressed as an [`Offset`] scaled to the child's size. For
5894/// example, an [`Offset`] with a `dx` of 0.25 will result in a horizontal
5895/// translation of one quarter the width of the child.
5896///
5897/// Hit tests will only be detected inside the bounds of the
5898/// [`RenderFractionalTranslation`], even if the contents are offset such that
5899/// they overflow.
5900pub struct RenderFractionalTranslation {
5901    render_object: RenderObjectData,
5902    render_box: RenderBoxData,
5903    child: RenderObjectWithChildData<AnyRenderBox>,
5904    translation: Offset,
5905    transform_hit_tests: bool,
5906}
5907
5908impl RenderFractionalTranslation {
5909    /// Creates a render object that translates its child's painting.
5910    pub fn new(
5911        app: &mut App,
5912        translation: Offset,
5913        transform_hit_tests: bool,
5914        child: Option<AnyRenderBox>,
5915    ) -> RenderHandle<RenderFractionalTranslation> {
5916        let this = RenderHandle::new_box(
5917            app,
5918            RenderFractionalTranslation {
5919                render_object: RenderObjectData::new(),
5920                render_box: RenderBoxData::new(),
5921                child: RenderObjectWithChildData::new(),
5922                translation,
5923                transform_hit_tests,
5924            },
5925        );
5926        this.set_child(app, child);
5927        this
5928    }
5929
5930    /// The translation to apply to the child, scaled to the child's size.
5931    ///
5932    /// For example, an [`Offset`] with a `dx` of 0.25 will result in a horizontal
5933    /// translation of one quarter the width of the child.
5934    pub fn translation(self: RenderHandle<Self>, app: &App) -> Offset {
5935        self.get(app).translation
5936    }
5937
5938    /// Sets [`translation`](Self::translation).
5939    pub fn set_translation(self: RenderHandle<Self>, app: &mut App, value: Offset) {
5940        if self.get(app).translation == value {
5941            return;
5942        }
5943        self.get_mut(app).translation = value;
5944        self.mark_needs_paint(app);
5945    }
5946
5947    /// When true, hit tests are performed based on the position of the
5948    /// child as it is painted. When false, hit tests are performed
5949    /// ignoring the transformation.
5950    ///
5951    /// [`RenderBox::apply_paint_transform`], and therefore
5952    /// [`AnyRenderBox::local_to_global`] and [`AnyRenderBox::global_to_local`], always honor
5953    /// the transformation, regardless of the value of this property.
5954    pub fn transform_hit_tests(self: RenderHandle<Self>, app: &App) -> bool {
5955        self.get(app).transform_hit_tests
5956    }
5957
5958    /// Sets [`transform_hit_tests`](Self::transform_hit_tests). Dart's plain field.
5959    pub fn set_transform_hit_tests(self: RenderHandle<Self>, app: &mut App, value: bool) {
5960        self.get_mut(app).transform_hit_tests = value;
5961    }
5962
5963    /// The translation in layout pixels: [`translation`](Self::translation) along the size.
5964    fn absolute_translation(self: RenderHandle<Self>, app: &App) -> Offset {
5965        let translation = self.get(app).translation;
5966        let size = self.size(app);
5967        Offset::new(
5968            translation.dx() * size.width(),
5969            translation.dy() * size.height(),
5970        )
5971    }
5972}
5973
5974impl RenderObjectWithChildMixin for RenderFractionalTranslation {
5975    type ChildType = AnyRenderBox;
5976
5977    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
5978        &self.get(app).child
5979    }
5980
5981    fn child_data_mut(
5982        self: RenderHandle<Self>,
5983        app: &mut App,
5984    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
5985        &mut self.get_mut(app).child
5986    }
5987}
5988
5989impl RenderProxyBoxMixin for RenderFractionalTranslation {}
5990
5991impl RenderObject for RenderFractionalTranslation {
5992    crate::render_object_accessors!();
5993
5994    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
5995        RenderProxyBoxMixin::perform_layout(self, app);
5996    }
5997
5998    fn paint(
5999        self: RenderHandle<Self>,
6000        app: &mut App,
6001        context: &mut PaintingContext,
6002        offset: Offset,
6003    ) {
6004        debug_assert!(!self.debug_needs_layout(app));
6005        if self.child(app).is_none() {
6006            return;
6007        }
6008        let translation = self.absolute_translation(app);
6009        RenderProxyBoxMixin::paint(self, app, context, offset + translation);
6010    }
6011
6012    fn visit_children(
6013        self: RenderHandle<Self>,
6014        app: &App,
6015        visitor: &mut dyn FnMut(AnyRenderObject),
6016    ) {
6017        if let Some(child) = self.child(app) {
6018            visitor(child.as_object());
6019        }
6020    }
6021}
6022
6023impl RenderBox for RenderFractionalTranslation {
6024    crate::render_box_accessors!();
6025
6026    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6027        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6028    }
6029
6030    fn apply_paint_transform(
6031        self: RenderHandle<Self>,
6032        app: &App,
6033        _child: AnyRenderObject,
6034        transform: &mut Matrix4,
6035    ) {
6036        let translation = self.absolute_translation(app);
6037        crate::object::translate(transform, translation.dx(), translation.dy());
6038    }
6039
6040    fn hit_test(
6041        self: RenderHandle<Self>,
6042        app: &mut App,
6043        result: &mut BoxHitTestResult<'_>,
6044        position: Offset,
6045    ) -> bool {
6046        // RenderFractionalTranslation objects don't check if they are
6047        // themselves hit, because it's confusing to think about
6048        // how the untransformed size and the child's transformed
6049        // position interact.
6050        RenderBox::hit_test_children(self, app, result, position)
6051    }
6052
6053    fn hit_test_children(
6054        self: RenderHandle<Self>,
6055        app: &mut App,
6056        result: &mut BoxHitTestResult<'_>,
6057        position: Offset,
6058    ) -> bool {
6059        debug_assert!(!self.debug_needs_layout(app));
6060        let offset = self
6061            .transform_hit_tests(app)
6062            .then(|| self.absolute_translation(app));
6063        result.add_with_paint_offset(offset, position, |result, position| {
6064            RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6065        })
6066    }
6067
6068    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6069        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6070    }
6071
6072    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6073        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6074    }
6075
6076    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6077        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6078    }
6079
6080    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6081        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6082    }
6083
6084    fn compute_distance_to_actual_baseline(
6085        self: RenderHandle<Self>,
6086        app: &mut App,
6087        baseline: TextBaseline,
6088    ) -> Option<f64> {
6089        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6090    }
6091
6092    fn compute_dry_baseline(
6093        self: RenderHandle<Self>,
6094        app: &mut App,
6095        constraints: BoxConstraints,
6096        baseline: TextBaseline,
6097    ) -> Option<f64> {
6098        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6099    }
6100
6101    fn compute_dry_layout(
6102        self: RenderHandle<Self>,
6103        app: &mut App,
6104        constraints: BoxConstraints,
6105    ) -> Size {
6106        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6107    }
6108}
6109
6110/// A render object that is invisible during hit testing.
6111///
6112/// When [`ignoring`](Self::ignoring) is true, this render object (and its subtree) is invisible
6113/// to hit testing. It still consumes space during layout and paints its child
6114/// as usual. It just cannot be the target of located events, because its render
6115/// object returns false from [`RenderBox::hit_test`].
6116///
6117/// See also:
6118///
6119///  * [`RenderAbsorbPointer`], which takes the pointer events but prevents any
6120///    nodes in the subtree from seeing them.
6121pub struct RenderIgnorePointer {
6122    render_object: RenderObjectData,
6123    render_box: RenderBoxData,
6124    child: RenderObjectWithChildData<AnyRenderBox>,
6125    ignoring: bool,
6126}
6127
6128impl RenderIgnorePointer {
6129    /// Creates a render object that is invisible to hit testing.
6130    pub fn new(
6131        app: &mut App,
6132        ignoring: bool,
6133        child: Option<AnyRenderBox>,
6134    ) -> RenderHandle<RenderIgnorePointer> {
6135        let this = RenderHandle::new_box(
6136            app,
6137            RenderIgnorePointer {
6138                render_object: RenderObjectData::new(),
6139                render_box: RenderBoxData::new(),
6140                child: RenderObjectWithChildData::new(),
6141                ignoring,
6142            },
6143        );
6144        this.set_child(app, child);
6145        this
6146    }
6147
6148    /// Whether this render object is ignored during hit testing.
6149    ///
6150    /// Regardless of whether this render object is ignored during hit testing, it
6151    /// will still consume space during layout and be visible during painting.
6152    pub fn ignoring(self: RenderHandle<Self>, app: &App) -> bool {
6153        self.get(app).ignoring
6154    }
6155
6156    /// Sets [`ignoring`](Self::ignoring).
6157    pub fn set_ignoring(self: RenderHandle<Self>, app: &mut App, value: bool) {
6158        if value == self.get(app).ignoring {
6159            return;
6160        }
6161        self.get_mut(app).ignoring = value;
6162    }
6163}
6164
6165impl RenderObjectWithChildMixin for RenderIgnorePointer {
6166    type ChildType = AnyRenderBox;
6167
6168    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6169        &self.get(app).child
6170    }
6171
6172    fn child_data_mut(
6173        self: RenderHandle<Self>,
6174        app: &mut App,
6175    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6176        &mut self.get_mut(app).child
6177    }
6178}
6179
6180impl RenderProxyBoxMixin for RenderIgnorePointer {}
6181
6182impl RenderObject for RenderIgnorePointer {
6183    crate::render_object_accessors!();
6184
6185    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6186        RenderProxyBoxMixin::perform_layout(self, app);
6187    }
6188
6189    fn paint(
6190        self: RenderHandle<Self>,
6191        app: &mut App,
6192        context: &mut PaintingContext,
6193        offset: Offset,
6194    ) {
6195        RenderProxyBoxMixin::paint(self, app, context, offset);
6196    }
6197
6198    fn visit_children(
6199        self: RenderHandle<Self>,
6200        app: &App,
6201        visitor: &mut dyn FnMut(AnyRenderObject),
6202    ) {
6203        if let Some(child) = self.child(app) {
6204            visitor(child.as_object());
6205        }
6206    }
6207}
6208
6209impl RenderBox for RenderIgnorePointer {
6210    crate::render_box_accessors!();
6211
6212    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6213        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6214    }
6215
6216    fn apply_paint_transform(
6217        self: RenderHandle<Self>,
6218        app: &App,
6219        child: AnyRenderObject,
6220        transform: &mut Matrix4,
6221    ) {
6222        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6223    }
6224
6225    fn hit_test(
6226        self: RenderHandle<Self>,
6227        app: &mut App,
6228        result: &mut BoxHitTestResult<'_>,
6229        position: Offset,
6230    ) -> bool {
6231        !self.ignoring(app) && RenderBoxBase::hit_test(self, app, result, position)
6232    }
6233
6234    fn hit_test_children(
6235        self: RenderHandle<Self>,
6236        app: &mut App,
6237        result: &mut BoxHitTestResult<'_>,
6238        position: Offset,
6239    ) -> bool {
6240        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6241    }
6242
6243    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6244        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6245    }
6246
6247    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6248        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6249    }
6250
6251    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6252        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6253    }
6254
6255    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6256        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6257    }
6258
6259    fn compute_distance_to_actual_baseline(
6260        self: RenderHandle<Self>,
6261        app: &mut App,
6262        baseline: TextBaseline,
6263    ) -> Option<f64> {
6264        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6265    }
6266
6267    fn compute_dry_baseline(
6268        self: RenderHandle<Self>,
6269        app: &mut App,
6270        constraints: BoxConstraints,
6271        baseline: TextBaseline,
6272    ) -> Option<f64> {
6273        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6274    }
6275
6276    fn compute_dry_layout(
6277        self: RenderHandle<Self>,
6278        app: &mut App,
6279        constraints: BoxConstraints,
6280    ) -> Size {
6281        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6282    }
6283}
6284
6285/// Lays the child out as if it was in the tree, but without painting anything,
6286/// without making the child available for hit testing, and without taking any
6287/// room in the parent.
6288pub struct RenderOffstage {
6289    render_object: RenderObjectData,
6290    render_box: RenderBoxData,
6291    child: RenderObjectWithChildData<AnyRenderBox>,
6292    offstage: bool,
6293}
6294
6295impl RenderOffstage {
6296    /// Creates an offstage render object.
6297    pub fn new(
6298        app: &mut App,
6299        offstage: bool,
6300        child: Option<AnyRenderBox>,
6301    ) -> RenderHandle<RenderOffstage> {
6302        let this = RenderHandle::new_box(
6303            app,
6304            RenderOffstage {
6305                render_object: RenderObjectData::new(),
6306                render_box: RenderBoxData::new(),
6307                child: RenderObjectWithChildData::new(),
6308                offstage,
6309            },
6310        );
6311        this.set_child(app, child);
6312        this
6313    }
6314
6315    /// Whether the child is hidden from the rest of the tree.
6316    ///
6317    /// If true, the child is laid out as if it was in the tree, but without
6318    /// painting anything, without making the child available for hit testing, and
6319    /// without taking any room in the parent.
6320    ///
6321    /// If false, the child is included in the tree as normal.
6322    pub fn offstage(self: RenderHandle<Self>, app: &App) -> bool {
6323        self.get(app).offstage
6324    }
6325
6326    /// Sets [`offstage`](Self::offstage).
6327    pub fn set_offstage(self: RenderHandle<Self>, app: &mut App, value: bool) {
6328        if value == self.get(app).offstage {
6329            return;
6330        }
6331        self.get_mut(app).offstage = value;
6332        self.as_object()
6333            .mark_needs_layout_for_sized_by_parent_change(app);
6334    }
6335
6336    /// Whether the given child would be painted if [`RenderObject::paint`] were called.
6337    ///
6338    /// Flutter's `RenderObject.paintsChild` is a virtual whose default is true; here only this
6339    /// override exists, as an inherent method (`PORTING.md`).
6340    pub fn paints_child(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> bool {
6341        debug_assert_eq!(child.as_object().parent(app), Some(self.as_object()));
6342        !self.get(app).offstage
6343    }
6344}
6345
6346impl RenderObjectWithChildMixin for RenderOffstage {
6347    type ChildType = AnyRenderBox;
6348
6349    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6350        &self.get(app).child
6351    }
6352
6353    fn child_data_mut(
6354        self: RenderHandle<Self>,
6355        app: &mut App,
6356    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6357        &mut self.get_mut(app).child
6358    }
6359}
6360
6361impl RenderProxyBoxMixin for RenderOffstage {}
6362
6363impl RenderObject for RenderOffstage {
6364    crate::render_object_accessors!();
6365
6366    fn sized_by_parent(self: RenderHandle<Self>, app: &App) -> bool {
6367        self.get(app).offstage
6368    }
6369
6370    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6371        if !self.get(app).offstage {
6372            RenderProxyBoxMixin::perform_layout(self, app);
6373            return;
6374        }
6375        if let Some(child) = self.child(app) {
6376            let constraints = self.constraints(app);
6377            child.layout(app, constraints, false);
6378        }
6379    }
6380
6381    fn paint(
6382        self: RenderHandle<Self>,
6383        app: &mut App,
6384        context: &mut PaintingContext,
6385        offset: Offset,
6386    ) {
6387        if self.get(app).offstage {
6388            return;
6389        }
6390        RenderProxyBoxMixin::paint(self, app, context, offset);
6391    }
6392
6393    fn visit_children(
6394        self: RenderHandle<Self>,
6395        app: &App,
6396        visitor: &mut dyn FnMut(AnyRenderObject),
6397    ) {
6398        if let Some(child) = self.child(app) {
6399            visitor(child.as_object());
6400        }
6401    }
6402}
6403
6404impl RenderBox for RenderOffstage {
6405    crate::render_box_accessors!();
6406
6407    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6408        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6409    }
6410
6411    fn apply_paint_transform(
6412        self: RenderHandle<Self>,
6413        app: &App,
6414        child: AnyRenderObject,
6415        transform: &mut Matrix4,
6416    ) {
6417        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6418    }
6419
6420    fn hit_test(
6421        self: RenderHandle<Self>,
6422        app: &mut App,
6423        result: &mut BoxHitTestResult<'_>,
6424        position: Offset,
6425    ) -> bool {
6426        !self.get(app).offstage && RenderBoxBase::hit_test(self, app, result, position)
6427    }
6428
6429    fn hit_test_children(
6430        self: RenderHandle<Self>,
6431        app: &mut App,
6432        result: &mut BoxHitTestResult<'_>,
6433        position: Offset,
6434    ) -> bool {
6435        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6436    }
6437
6438    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6439        if self.get(app).offstage {
6440            return 0.0;
6441        }
6442        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6443    }
6444
6445    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6446        if self.get(app).offstage {
6447            return 0.0;
6448        }
6449        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6450    }
6451
6452    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6453        if self.get(app).offstage {
6454            return 0.0;
6455        }
6456        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6457    }
6458
6459    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6460        if self.get(app).offstage {
6461            return 0.0;
6462        }
6463        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6464    }
6465
6466    fn compute_distance_to_actual_baseline(
6467        self: RenderHandle<Self>,
6468        app: &mut App,
6469        baseline: TextBaseline,
6470    ) -> Option<f64> {
6471        if self.get(app).offstage {
6472            return None;
6473        }
6474        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6475    }
6476
6477    fn compute_dry_baseline(
6478        self: RenderHandle<Self>,
6479        app: &mut App,
6480        constraints: BoxConstraints,
6481        baseline: TextBaseline,
6482    ) -> Option<f64> {
6483        if self.get(app).offstage {
6484            return None;
6485        }
6486        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6487    }
6488
6489    fn compute_dry_layout(
6490        self: RenderHandle<Self>,
6491        app: &mut App,
6492        constraints: BoxConstraints,
6493    ) -> Size {
6494        if self.get(app).offstage {
6495            return constraints.smallest();
6496        }
6497        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6498    }
6499
6500    /// Flutter's `performResize` asserts and calls `super.performResize`.
6501    fn perform_resize(self: RenderHandle<Self>, app: &mut App) {
6502        debug_assert!(self.get(app).offstage);
6503        RenderBoxBase::perform_resize(self, app);
6504    }
6505}
6506
6507/// A render object that absorbs pointers during hit testing.
6508///
6509/// When [`absorbing`](Self::absorbing) is true, this render object prevents its subtree from
6510/// receiving pointer events by terminating hit testing at itself. It still
6511/// consumes space during layout and paints its child as usual. It just prevents
6512/// its children from being the target of located events, because its render
6513/// object returns true from [`RenderBox::hit_test`].
6514///
6515/// See also:
6516///
6517///  * [`RenderIgnorePointer`], which has the opposite effect: removing the
6518///    subtree from considering entirely for the purposes of hit testing.
6519pub struct RenderAbsorbPointer {
6520    render_object: RenderObjectData,
6521    render_box: RenderBoxData,
6522    child: RenderObjectWithChildData<AnyRenderBox>,
6523    absorbing: bool,
6524}
6525
6526impl RenderAbsorbPointer {
6527    /// Creates a render object that absorbs pointers during hit testing.
6528    pub fn new(
6529        app: &mut App,
6530        absorbing: bool,
6531        child: Option<AnyRenderBox>,
6532    ) -> RenderHandle<RenderAbsorbPointer> {
6533        let this = RenderHandle::new_box(
6534            app,
6535            RenderAbsorbPointer {
6536                render_object: RenderObjectData::new(),
6537                render_box: RenderBoxData::new(),
6538                child: RenderObjectWithChildData::new(),
6539                absorbing,
6540            },
6541        );
6542        this.set_child(app, child);
6543        this
6544    }
6545
6546    /// Whether this render object absorbs pointers during hit testing.
6547    ///
6548    /// Regardless of whether this render object absorbs pointers during hit
6549    /// testing, it will still consume space during layout and be visible during
6550    /// painting.
6551    pub fn absorbing(self: RenderHandle<Self>, app: &App) -> bool {
6552        self.get(app).absorbing
6553    }
6554
6555    /// Sets [`absorbing`](Self::absorbing).
6556    pub fn set_absorbing(self: RenderHandle<Self>, app: &mut App, value: bool) {
6557        if self.get(app).absorbing == value {
6558            return;
6559        }
6560        self.get_mut(app).absorbing = value;
6561    }
6562}
6563
6564impl RenderObjectWithChildMixin for RenderAbsorbPointer {
6565    type ChildType = AnyRenderBox;
6566
6567    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6568        &self.get(app).child
6569    }
6570
6571    fn child_data_mut(
6572        self: RenderHandle<Self>,
6573        app: &mut App,
6574    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6575        &mut self.get_mut(app).child
6576    }
6577}
6578
6579impl RenderProxyBoxMixin for RenderAbsorbPointer {}
6580
6581impl RenderObject for RenderAbsorbPointer {
6582    crate::render_object_accessors!();
6583
6584    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6585        RenderProxyBoxMixin::perform_layout(self, app);
6586    }
6587
6588    fn paint(
6589        self: RenderHandle<Self>,
6590        app: &mut App,
6591        context: &mut PaintingContext,
6592        offset: Offset,
6593    ) {
6594        RenderProxyBoxMixin::paint(self, app, context, offset);
6595    }
6596
6597    fn visit_children(
6598        self: RenderHandle<Self>,
6599        app: &App,
6600        visitor: &mut dyn FnMut(AnyRenderObject),
6601    ) {
6602        if let Some(child) = self.child(app) {
6603            visitor(child.as_object());
6604        }
6605    }
6606}
6607
6608impl RenderBox for RenderAbsorbPointer {
6609    crate::render_box_accessors!();
6610
6611    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6612        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6613    }
6614
6615    fn apply_paint_transform(
6616        self: RenderHandle<Self>,
6617        app: &App,
6618        child: AnyRenderObject,
6619        transform: &mut Matrix4,
6620    ) {
6621        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6622    }
6623
6624    fn hit_test(
6625        self: RenderHandle<Self>,
6626        app: &mut App,
6627        result: &mut BoxHitTestResult<'_>,
6628        position: Offset,
6629    ) -> bool {
6630        if self.absorbing(app) {
6631            return self.size(app).contains(position);
6632        }
6633        RenderBoxBase::hit_test(self, app, result, position)
6634    }
6635
6636    fn hit_test_children(
6637        self: RenderHandle<Self>,
6638        app: &mut App,
6639        result: &mut BoxHitTestResult<'_>,
6640        position: Offset,
6641    ) -> bool {
6642        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6643    }
6644
6645    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6646        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6647    }
6648
6649    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6650        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6651    }
6652
6653    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6654        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6655    }
6656
6657    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6658        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6659    }
6660
6661    fn compute_distance_to_actual_baseline(
6662        self: RenderHandle<Self>,
6663        app: &mut App,
6664        baseline: TextBaseline,
6665    ) -> Option<f64> {
6666        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6667    }
6668
6669    fn compute_dry_baseline(
6670        self: RenderHandle<Self>,
6671        app: &mut App,
6672        constraints: BoxConstraints,
6673        baseline: TextBaseline,
6674    ) -> Option<f64> {
6675        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6676    }
6677
6678    fn compute_dry_layout(
6679        self: RenderHandle<Self>,
6680        app: &mut App,
6681        constraints: BoxConstraints,
6682    ) -> Size {
6683        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6684    }
6685}
6686
6687/// Paints its area with a specified [`Color`] and then draws its child on top of that color.
6688///
6689/// Flutter's `_RenderColoredBox`, the render object of the `ColoredBox` widget, in
6690/// `widgets/basic.dart`.
6691pub struct RenderColoredBox {
6692    render_object: RenderObjectData,
6693    render_box: RenderBoxData,
6694    child: RenderObjectWithChildData<AnyRenderBox>,
6695    color: Color,
6696    is_anti_alias: bool,
6697    behavior: HitTestBehavior,
6698}
6699
6700impl RenderColoredBox {
6701    /// Creates a render object that paints its area with `color`.
6702    pub fn new(
6703        app: &mut App,
6704        color: Color,
6705        is_anti_alias: bool,
6706        child: Option<AnyRenderBox>,
6707    ) -> RenderHandle<RenderColoredBox> {
6708        let this = RenderHandle::new_box(
6709            app,
6710            RenderColoredBox {
6711                render_object: RenderObjectData::new(),
6712                render_box: RenderBoxData::new(),
6713                child: RenderObjectWithChildData::new(),
6714                color,
6715                is_anti_alias,
6716                behavior: HitTestBehavior::Opaque,
6717            },
6718        );
6719        this.set_child(app, child);
6720        this
6721    }
6722
6723    /// The fill color for this render object.
6724    pub fn color(self: RenderHandle<Self>, app: &App) -> Color {
6725        self.get(app).color
6726    }
6727
6728    /// Sets [`color`](Self::color).
6729    pub fn set_color(self: RenderHandle<Self>, app: &mut App, value: Color) {
6730        if value == self.get(app).color {
6731            return;
6732        }
6733        self.get_mut(app).color = value;
6734        self.mark_needs_paint(app);
6735    }
6736
6737    /// Whether to apply anti-aliasing when painting the box.
6738    pub fn is_anti_alias(self: RenderHandle<Self>, app: &App) -> bool {
6739        self.get(app).is_anti_alias
6740    }
6741
6742    /// Sets [`is_anti_alias`](Self::is_anti_alias).
6743    pub fn set_is_anti_alias(self: RenderHandle<Self>, app: &mut App, value: bool) {
6744        if value == self.get(app).is_anti_alias {
6745            return;
6746        }
6747        self.get_mut(app).is_anti_alias = value;
6748        self.mark_needs_paint(app);
6749    }
6750}
6751
6752impl RenderObjectWithChildMixin for RenderColoredBox {
6753    type ChildType = AnyRenderBox;
6754
6755    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6756        &self.get(app).child
6757    }
6758
6759    fn child_data_mut(
6760        self: RenderHandle<Self>,
6761        app: &mut App,
6762    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6763        &mut self.get_mut(app).child
6764    }
6765}
6766
6767impl RenderProxyBoxMixin for RenderColoredBox {}
6768
6769impl RenderProxyBoxWithHitTestBehavior for RenderColoredBox {
6770    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
6771        self.get(app).behavior
6772    }
6773}
6774
6775impl RenderObject for RenderColoredBox {
6776    crate::render_object_accessors!();
6777
6778    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6779        RenderProxyBoxMixin::perform_layout(self, app);
6780    }
6781
6782    fn paint(
6783        self: RenderHandle<Self>,
6784        app: &mut App,
6785        context: &mut PaintingContext,
6786        offset: Offset,
6787    ) {
6788        // It's tempting to want to optimize out this `draw_rect()` call if the
6789        // color is transparent (alpha==0), but doing so would be incorrect. See
6790        // https://github.com/flutter/flutter/pull/72526#issuecomment-749185938 for
6791        // a good description of why.
6792        let size = self.size(app);
6793        if size.gt(&Size::ZERO) {
6794            let paint = Paint {
6795                color: self.get(app).color.into(),
6796                ..Paint::default()
6797            };
6798            context.canvas().draw_rect(offset & size, &paint);
6799        }
6800        if let Some(child) = self.child(app) {
6801            context.paint_child(app, child.as_object(), offset);
6802        }
6803    }
6804
6805    fn visit_children(
6806        self: RenderHandle<Self>,
6807        app: &App,
6808        visitor: &mut dyn FnMut(AnyRenderObject),
6809    ) {
6810        if let Some(child) = self.child(app) {
6811            visitor(child.as_object());
6812        }
6813    }
6814}
6815
6816impl RenderBox for RenderColoredBox {
6817    crate::render_box_accessors!();
6818
6819    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
6820        RenderProxyBoxMixin::setup_parent_data(self, app, child);
6821    }
6822
6823    fn apply_paint_transform(
6824        self: RenderHandle<Self>,
6825        app: &App,
6826        child: AnyRenderObject,
6827        transform: &mut Matrix4,
6828    ) {
6829        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
6830    }
6831
6832    fn hit_test(
6833        self: RenderHandle<Self>,
6834        app: &mut App,
6835        result: &mut BoxHitTestResult<'_>,
6836        position: Offset,
6837    ) -> bool {
6838        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
6839    }
6840
6841    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
6842        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
6843    }
6844
6845    fn hit_test_children(
6846        self: RenderHandle<Self>,
6847        app: &mut App,
6848        result: &mut BoxHitTestResult<'_>,
6849        position: Offset,
6850    ) -> bool {
6851        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
6852    }
6853
6854    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6855        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
6856    }
6857
6858    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
6859        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
6860    }
6861
6862    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6863        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
6864    }
6865
6866    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
6867        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
6868    }
6869
6870    fn compute_distance_to_actual_baseline(
6871        self: RenderHandle<Self>,
6872        app: &mut App,
6873        baseline: TextBaseline,
6874    ) -> Option<f64> {
6875        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
6876    }
6877
6878    fn compute_dry_baseline(
6879        self: RenderHandle<Self>,
6880        app: &mut App,
6881        constraints: BoxConstraints,
6882        baseline: TextBaseline,
6883    ) -> Option<f64> {
6884        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
6885    }
6886
6887    fn compute_dry_layout(
6888        self: RenderHandle<Self>,
6889        app: &mut App,
6890        constraints: BoxConstraints,
6891    ) -> Size {
6892        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
6893    }
6894}
6895
6896/// Holds opaque meta data in the render tree.
6897///
6898/// Useful for decorating the render tree with information that will be consumed
6899/// later. For example, you could store information in the render tree that will
6900/// be used when the user interacts with the render tree but has no visual impact
6901/// prior to the interaction.
6902pub struct RenderMetaData {
6903    render_object: RenderObjectData,
6904    render_box: RenderBoxData,
6905    child: RenderObjectWithChildData<AnyRenderBox>,
6906    meta_data: Option<Rc<dyn Any>>,
6907    behavior: HitTestBehavior,
6908}
6909
6910impl RenderMetaData {
6911    /// Creates a render object that hold opaque meta data.
6912    ///
6913    /// The `behavior` argument defaults to [`HitTestBehavior::DeferToChild`].
6914    pub fn new(
6915        app: &mut App,
6916        meta_data: Option<Rc<dyn Any>>,
6917        behavior: HitTestBehavior,
6918        child: Option<AnyRenderBox>,
6919    ) -> RenderHandle<Self> {
6920        let this = RenderHandle::new_box(
6921            app,
6922            RenderMetaData {
6923                render_object: RenderObjectData::new(),
6924                render_box: RenderBoxData::new(),
6925                child: RenderObjectWithChildData::new(),
6926                meta_data,
6927                behavior,
6928            },
6929        );
6930        this.set_child(app, child);
6931        this
6932    }
6933
6934    /// Opaque meta data ignored by the render tree.
6935    pub fn meta_data(self: RenderHandle<Self>, app: &App) -> Option<Rc<dyn Any>> {
6936        self.get(app).meta_data.clone()
6937    }
6938
6939    /// Sets [`meta_data`](Self::meta_data).
6940    pub fn set_meta_data(self: RenderHandle<Self>, app: &mut App, value: Option<Rc<dyn Any>>) {
6941        self.get_mut(app).meta_data = value;
6942    }
6943
6944    /// Sets [`behavior`](RenderProxyBoxWithHitTestBehavior::behavior).
6945    pub fn set_behavior(self: RenderHandle<Self>, app: &mut App, value: HitTestBehavior) {
6946        self.get_mut(app).behavior = value;
6947    }
6948}
6949
6950impl RenderObjectWithChildMixin for RenderMetaData {
6951    type ChildType = AnyRenderBox;
6952
6953    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
6954        &self.get(app).child
6955    }
6956
6957    fn child_data_mut(
6958        self: RenderHandle<Self>,
6959        app: &mut App,
6960    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
6961        &mut self.get_mut(app).child
6962    }
6963}
6964
6965impl RenderProxyBoxMixin for RenderMetaData {}
6966
6967impl RenderProxyBoxWithHitTestBehavior for RenderMetaData {
6968    fn behavior(self: RenderHandle<Self>, app: &App) -> HitTestBehavior {
6969        self.get(app).behavior
6970    }
6971}
6972
6973impl RenderObject for RenderMetaData {
6974    crate::render_object_accessors!();
6975
6976    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
6977        RenderProxyBoxMixin::perform_layout(self, app);
6978    }
6979
6980    fn paint(
6981        self: RenderHandle<Self>,
6982        app: &mut App,
6983        context: &mut PaintingContext,
6984        offset: Offset,
6985    ) {
6986        RenderProxyBoxMixin::paint(self, app, context, offset);
6987    }
6988
6989    fn visit_children(
6990        self: RenderHandle<Self>,
6991        app: &App,
6992        visitor: &mut dyn FnMut(AnyRenderObject),
6993    ) {
6994        if let Some(child) = self.child(app) {
6995            visitor(child.as_object());
6996        }
6997    }
6998}
6999
7000impl RenderBox for RenderMetaData {
7001    crate::render_box_accessors!();
7002
7003    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
7004        RenderProxyBoxMixin::setup_parent_data(self, app, child);
7005    }
7006
7007    fn apply_paint_transform(
7008        self: RenderHandle<Self>,
7009        app: &App,
7010        child: AnyRenderObject,
7011        transform: &mut Matrix4,
7012    ) {
7013        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
7014    }
7015
7016    fn hit_test(
7017        self: RenderHandle<Self>,
7018        app: &mut App,
7019        result: &mut BoxHitTestResult<'_>,
7020        position: Offset,
7021    ) -> bool {
7022        RenderProxyBoxWithHitTestBehavior::hit_test(self, app, result, position)
7023    }
7024
7025    fn hit_test_self(self: RenderHandle<Self>, app: &App, position: Offset) -> bool {
7026        RenderProxyBoxWithHitTestBehavior::hit_test_self(self, app, position)
7027    }
7028
7029    fn hit_test_children(
7030        self: RenderHandle<Self>,
7031        app: &mut App,
7032        result: &mut BoxHitTestResult<'_>,
7033        position: Offset,
7034    ) -> bool {
7035        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
7036    }
7037
7038    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7039        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
7040    }
7041
7042    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7043        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
7044    }
7045
7046    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7047        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
7048    }
7049
7050    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7051        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
7052    }
7053
7054    fn compute_distance_to_actual_baseline(
7055        self: RenderHandle<Self>,
7056        app: &mut App,
7057        baseline: TextBaseline,
7058    ) -> Option<f64> {
7059        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
7060    }
7061
7062    fn compute_dry_baseline(
7063        self: RenderHandle<Self>,
7064        app: &mut App,
7065        constraints: BoxConstraints,
7066        baseline: TextBaseline,
7067    ) -> Option<f64> {
7068        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
7069    }
7070
7071    fn compute_dry_layout(
7072        self: RenderHandle<Self>,
7073        app: &mut App,
7074        constraints: BoxConstraints,
7075    ) -> Size {
7076        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
7077    }
7078}
7079
7080/// Applies a filter to the existing painted content and then paints `child`.
7081///
7082/// This effect is relatively expensive, especially if the filter is non-local,
7083/// such as a blur.
7084pub struct RenderBackdropFilter {
7085    render_object: RenderObjectData,
7086    render_box: RenderBoxData,
7087    child: RenderObjectWithChildData<AnyRenderBox>,
7088    filter_config: ImageFilterConfig,
7089    blend_mode: BlendMode,
7090    enabled: bool,
7091    backdrop_key: Option<BackdropKey>,
7092}
7093
7094impl RenderBackdropFilter {
7095    /// Creates a backdrop filter.
7096    ///
7097    /// The `blend_mode` argument defaults to [`BlendMode::SrcOver`].
7098    pub fn new(
7099        app: &mut App,
7100        filter_config: ImageFilterConfig,
7101        blend_mode: BlendMode,
7102        enabled: bool,
7103        backdrop_key: Option<BackdropKey>,
7104        child: Option<AnyRenderBox>,
7105    ) -> RenderHandle<Self> {
7106        let this = RenderHandle::new_box(
7107            app,
7108            RenderBackdropFilter {
7109                render_object: RenderObjectData::new(),
7110                render_box: RenderBoxData::new(),
7111                child: RenderObjectWithChildData::new(),
7112                filter_config,
7113                blend_mode,
7114                enabled,
7115                backdrop_key,
7116            },
7117        );
7118        this.set_child(app, child);
7119        this
7120    }
7121
7122    /// Whether or not the backdrop filter operation will be applied to the child.
7123    pub fn enabled(self: RenderHandle<Self>, app: &App) -> bool {
7124        self.get(app).enabled
7125    }
7126
7127    /// Sets [`enabled`](Self::enabled).
7128    pub fn set_enabled(self: RenderHandle<Self>, app: &mut App, value: bool) {
7129        if self.get(app).enabled == value {
7130            return;
7131        }
7132        self.get_mut(app).enabled = value;
7133        self.mark_needs_paint(app);
7134    }
7135
7136    /// The image filter to apply to the existing painted content before painting the child.
7137    ///
7138    /// Dart's deprecated `filter` getter: only valid when the configuration was set through
7139    /// [`set_filter`](Self::set_filter).
7140    pub fn filter(self: RenderHandle<Self>, app: &App) -> ImageFilter {
7141        self.get(app)
7142            .filter_config
7143            .filter()
7144            .expect(
7145                "This getter should only be called when the filter is assigned via the \
7146                 `filter` setter.",
7147            )
7148            .clone()
7149    }
7150
7151    /// Sets the filter as a direct configuration (Dart's `filter` setter).
7152    pub fn set_filter(self: RenderHandle<Self>, app: &mut App, value: ImageFilter) {
7153        self.set_filter_config(app, ImageFilterConfig::new(value));
7154    }
7155
7156    /// The configuration that resolves the filter against the paint bounds.
7157    pub fn filter_config(self: RenderHandle<Self>, app: &App) -> &ImageFilterConfig {
7158        &self.get(app).filter_config
7159    }
7160
7161    /// Sets [`filter_config`](Self::filter_config).
7162    pub fn set_filter_config(self: RenderHandle<Self>, app: &mut App, value: ImageFilterConfig) {
7163        if self.get(app).filter_config == value {
7164            return;
7165        }
7166        self.get_mut(app).filter_config = value;
7167        self.mark_needs_paint(app);
7168    }
7169
7170    /// The blend mode to use to apply the filtered background content onto the background
7171    /// surface.
7172    pub fn blend_mode(self: RenderHandle<Self>, app: &App) -> BlendMode {
7173        self.get(app).blend_mode
7174    }
7175
7176    /// Sets [`blend_mode`](Self::blend_mode).
7177    pub fn set_blend_mode(self: RenderHandle<Self>, app: &mut App, value: BlendMode) {
7178        if self.get(app).blend_mode == value {
7179            return;
7180        }
7181        self.get_mut(app).blend_mode = value;
7182        self.mark_needs_paint(app);
7183    }
7184
7185    /// The backdrop key that identifies the shared backdrop this filter belongs to.
7186    pub fn backdrop_key(self: RenderHandle<Self>, app: &App) -> Option<BackdropKey> {
7187        self.get(app).backdrop_key
7188    }
7189
7190    /// Sets [`backdrop_key`](Self::backdrop_key).
7191    pub fn set_backdrop_key(self: RenderHandle<Self>, app: &mut App, value: Option<BackdropKey>) {
7192        if self.get(app).backdrop_key == value {
7193            return;
7194        }
7195        self.get_mut(app).backdrop_key = value;
7196        self.mark_needs_paint(app);
7197    }
7198}
7199
7200impl RenderObjectWithChildMixin for RenderBackdropFilter {
7201    type ChildType = AnyRenderBox;
7202
7203    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
7204        &self.get(app).child
7205    }
7206
7207    fn child_data_mut(
7208        self: RenderHandle<Self>,
7209        app: &mut App,
7210    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
7211        &mut self.get_mut(app).child
7212    }
7213}
7214
7215impl RenderProxyBoxMixin for RenderBackdropFilter {}
7216
7217impl RenderObject for RenderBackdropFilter {
7218    crate::render_object_accessors!();
7219
7220    fn always_needs_compositing(self: RenderHandle<Self>, app: &App) -> bool {
7221        self.child(app).is_some()
7222    }
7223
7224    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
7225        RenderProxyBoxMixin::perform_layout(self, app);
7226    }
7227
7228    fn paint(
7229        self: RenderHandle<Self>,
7230        app: &mut App,
7231        context: &mut PaintingContext,
7232        offset: Offset,
7233    ) {
7234        if !self.get(app).enabled {
7235            RenderProxyBoxMixin::paint(self, app, context, offset);
7236            return;
7237        }
7238        let bounds = offset & self.size(app);
7239        let effective_filter = self
7240            .get(app)
7241            .filter_config
7242            .resolve(ImageFilterContext { bounds });
7243        if self.child(app).is_some() {
7244            debug_assert!(self.as_object().needs_compositing(app));
7245            let (blend_mode, backdrop_key) = {
7246                let this = self.get(app);
7247                (this.blend_mode, this.backdrop_key)
7248            };
7249            let layer = match self.as_object().layer_as::<BackdropFilterLayer>(app) {
7250                Some(layer) => layer,
7251                None => {
7252                    let layer = BackdropFilterLayer::new(app);
7253                    self.as_object()
7254                        .set_layer(app, Some(layer.as_container_layer()));
7255                    layer
7256                }
7257            };
7258            layer.set_filter(app, Some(effective_filter));
7259            layer.set_blend_mode(app, blend_mode);
7260            layer.set_backdrop_key(app, backdrop_key);
7261            context.push_layer(
7262                app,
7263                layer.as_container_layer(),
7264                |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
7265                offset,
7266                None,
7267            );
7268        } else {
7269            self.as_object().set_layer(app, None);
7270        }
7271    }
7272
7273    fn visit_children(
7274        self: RenderHandle<Self>,
7275        app: &App,
7276        visitor: &mut dyn FnMut(AnyRenderObject),
7277    ) {
7278        if let Some(child) = self.child(app) {
7279            visitor(child.as_object());
7280        }
7281    }
7282}
7283
7284impl RenderBox for RenderBackdropFilter {
7285    crate::render_box_accessors!();
7286
7287    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
7288        RenderProxyBoxMixin::setup_parent_data(self, app, child);
7289    }
7290
7291    fn apply_paint_transform(
7292        self: RenderHandle<Self>,
7293        app: &App,
7294        child: AnyRenderObject,
7295        transform: &mut Matrix4,
7296    ) {
7297        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
7298    }
7299
7300    fn hit_test_children(
7301        self: RenderHandle<Self>,
7302        app: &mut App,
7303        result: &mut BoxHitTestResult<'_>,
7304        position: Offset,
7305    ) -> bool {
7306        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
7307    }
7308
7309    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7310        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
7311    }
7312
7313    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7314        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
7315    }
7316
7317    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7318        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
7319    }
7320
7321    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7322        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
7323    }
7324
7325    fn compute_distance_to_actual_baseline(
7326        self: RenderHandle<Self>,
7327        app: &mut App,
7328        baseline: TextBaseline,
7329    ) -> Option<f64> {
7330        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
7331    }
7332
7333    fn compute_dry_baseline(
7334        self: RenderHandle<Self>,
7335        app: &mut App,
7336        constraints: BoxConstraints,
7337        baseline: TextBaseline,
7338    ) -> Option<f64> {
7339        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
7340    }
7341
7342    fn compute_dry_layout(
7343        self: RenderHandle<Self>,
7344        app: &mut App,
7345        constraints: BoxConstraints,
7346    ) -> Size {
7347        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
7348    }
7349}
7350
7351/// Annotates a region of the layer tree with a value.
7352///
7353/// The value can be retrieved with [`AnyLayer::find`](crate::AnyLayer::find) at a
7354/// position; `AnnotatedRegion` is the widget that inserts one.
7355pub struct RenderAnnotatedRegion<T> {
7356    render_object: RenderObjectData,
7357    render_box: RenderBoxData,
7358    child: RenderObjectWithChildData<AnyRenderBox>,
7359    value: Rc<T>,
7360    sized: bool,
7361    layer_handle: LayerHandle<Handle<AnnotatedRegionLayer>>,
7362}
7363
7364impl<T: PartialEq + 'static> RenderAnnotatedRegion<T> {
7365    /// Creates a new [`RenderAnnotatedRegion`] to insert `value` into the layer tree.
7366    ///
7367    /// If `sized` is true, the layer is provided with the size of this render object to clip
7368    /// the results of [`AnyLayer::find`](crate::AnyLayer::find).
7369    pub fn new(
7370        app: &mut App,
7371        value: Rc<T>,
7372        sized: bool,
7373        child: Option<AnyRenderBox>,
7374    ) -> RenderHandle<RenderAnnotatedRegion<T>> {
7375        let this = RenderHandle::new_box(
7376            app,
7377            RenderAnnotatedRegion {
7378                render_object: RenderObjectData::new(),
7379                render_box: RenderBoxData::new(),
7380                child: RenderObjectWithChildData::new(),
7381                value,
7382                sized,
7383                layer_handle: LayerHandle::new(),
7384            },
7385        );
7386        this.set_child(app, child);
7387        this
7388    }
7389
7390    /// A value which can be retrieved using
7391    /// [`AnyLayer::find`](crate::AnyLayer::find).
7392    pub fn value(self: RenderHandle<Self>, app: &App) -> Rc<T> {
7393        Rc::clone(&self.get(app).value)
7394    }
7395
7396    /// Sets [`value`](Self::value).
7397    pub fn set_value(self: RenderHandle<Self>, app: &mut App, new_value: Rc<T>) {
7398        if *self.get(app).value == *new_value {
7399            return;
7400        }
7401        self.get_mut(app).value = new_value;
7402        self.mark_needs_paint(app);
7403    }
7404
7405    /// Whether the render object will pass its size to the annotated region.
7406    pub fn sized(self: RenderHandle<Self>, app: &App) -> bool {
7407        self.get(app).sized
7408    }
7409
7410    /// Sets [`sized`](Self::sized).
7411    pub fn set_sized(self: RenderHandle<Self>, app: &mut App, value: bool) {
7412        if self.get(app).sized == value {
7413            return;
7414        }
7415        self.get_mut(app).sized = value;
7416        self.mark_needs_paint(app);
7417    }
7418}
7419
7420impl<T: PartialEq + 'static> RenderObjectWithChildMixin for RenderAnnotatedRegion<T> {
7421    type ChildType = AnyRenderBox;
7422
7423    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
7424        &self.get(app).child
7425    }
7426
7427    fn child_data_mut(
7428        self: RenderHandle<Self>,
7429        app: &mut App,
7430    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
7431        &mut self.get_mut(app).child
7432    }
7433}
7434
7435impl<T: PartialEq + 'static> RenderProxyBoxMixin for RenderAnnotatedRegion<T> {}
7436
7437impl<T: PartialEq + 'static> RenderObject for RenderAnnotatedRegion<T> {
7438    crate::render_object_accessors!();
7439
7440    fn always_needs_compositing(self: RenderHandle<Self>, _app: &App) -> bool {
7441        true
7442    }
7443
7444    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
7445        RenderProxyBoxMixin::perform_layout(self, app);
7446    }
7447
7448    fn paint(
7449        self: RenderHandle<Self>,
7450        app: &mut App,
7451        context: &mut PaintingContext,
7452        offset: Offset,
7453    ) {
7454        let sized = self.sized(app);
7455        let value: Rc<dyn Any> = self.value(app);
7456        let layer = AnnotatedRegionLayer::new(app, value);
7457        if sized {
7458            layer.set_size(app, Some(self.size(app)));
7459            layer.set_offset(app, offset);
7460        }
7461        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).layer_handle, Some(layer));
7462        context.push_layer(
7463            app,
7464            layer.as_container_layer(),
7465            |app, context, offset| RenderProxyBoxMixin::paint(self, app, context, offset),
7466            offset,
7467            None,
7468        );
7469    }
7470
7471    fn dispose(self: RenderHandle<Self>, app: &mut App) {
7472        LayerHandle::set_layer(app, |app| &mut self.get_mut(app).layer_handle, None);
7473        crate::object::RenderObjectBase::dispose(self, app);
7474    }
7475
7476    fn visit_children(
7477        self: RenderHandle<Self>,
7478        app: &App,
7479        visitor: &mut dyn FnMut(AnyRenderObject),
7480    ) {
7481        if let Some(child) = self.child(app) {
7482            visitor(child.as_object());
7483        }
7484    }
7485}
7486
7487impl<T: PartialEq + 'static> RenderBox for RenderAnnotatedRegion<T> {
7488    crate::render_box_accessors!();
7489
7490    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
7491        RenderProxyBoxMixin::setup_parent_data(self, app, child);
7492    }
7493
7494    fn apply_paint_transform(
7495        self: RenderHandle<Self>,
7496        app: &App,
7497        child: AnyRenderObject,
7498        transform: &mut Matrix4,
7499    ) {
7500        RenderProxyBoxMixin::apply_paint_transform(self, app, child, transform);
7501    }
7502
7503    fn hit_test_children(
7504        self: RenderHandle<Self>,
7505        app: &mut App,
7506        result: &mut BoxHitTestResult<'_>,
7507        position: Offset,
7508    ) -> bool {
7509        RenderProxyBoxMixin::hit_test_children(self, app, result, position)
7510    }
7511
7512    fn compute_min_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7513        RenderProxyBoxMixin::compute_min_intrinsic_width(self, app, height)
7514    }
7515
7516    fn compute_max_intrinsic_width(self: RenderHandle<Self>, app: &mut App, height: f64) -> f64 {
7517        RenderProxyBoxMixin::compute_max_intrinsic_width(self, app, height)
7518    }
7519
7520    fn compute_min_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7521        RenderProxyBoxMixin::compute_min_intrinsic_height(self, app, width)
7522    }
7523
7524    fn compute_max_intrinsic_height(self: RenderHandle<Self>, app: &mut App, width: f64) -> f64 {
7525        RenderProxyBoxMixin::compute_max_intrinsic_height(self, app, width)
7526    }
7527
7528    fn compute_distance_to_actual_baseline(
7529        self: RenderHandle<Self>,
7530        app: &mut App,
7531        baseline: TextBaseline,
7532    ) -> Option<f64> {
7533        RenderProxyBoxMixin::compute_distance_to_actual_baseline(self, app, baseline)
7534    }
7535
7536    fn compute_dry_baseline(
7537        self: RenderHandle<Self>,
7538        app: &mut App,
7539        constraints: BoxConstraints,
7540        baseline: TextBaseline,
7541    ) -> Option<f64> {
7542        RenderProxyBoxMixin::compute_dry_baseline(self, app, constraints, baseline)
7543    }
7544
7545    fn compute_dry_layout(
7546        self: RenderHandle<Self>,
7547        app: &mut App,
7548        constraints: BoxConstraints,
7549    ) -> Size {
7550        RenderProxyBoxMixin::compute_dry_layout(self, app, constraints)
7551    }
7552}
7553
7554#[cfg(test)]
7555mod tests {
7556    use inset_animation::{k_always_complete_animation, k_always_dismissed_animation};
7557    use inset_embedder::ColorFilter;
7558    use inset_embedder::valo::{self, Op};
7559    use inset_foundation::AppCell;
7560    use inset_foundation::ValueNotifier;
7561    use inset_gestures::HitTestResult;
7562    use inset_painting::BoxDecoration;
7563
7564    use super::*;
7565    use crate::layer::{ErasedLayer, OffsetLayer, PictureLayer};
7566    use crate::pipeline_owner::PipelineOwner;
7567    use inset_embedder::SceneBuilder;
7568
7569    fn sized_box(app: &mut App, size: Size) -> RenderHandle<RenderConstrainedBox> {
7570        RenderConstrainedBox::new(app, BoxConstraints::tight(size), None)
7571    }
7572
7573    /// A leaf that reports fixed intrinsic dimensions and takes the size its constraints allow
7574    /// around them.
7575    struct IntrinsicTestBox {
7576        render_object: RenderObjectData,
7577        render_box: RenderBoxData,
7578        intrinsic: Size,
7579    }
7580
7581    impl RenderObject for IntrinsicTestBox {
7582        crate::render_object_accessors!();
7583
7584        fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
7585            let intrinsic = self.get(app).intrinsic;
7586            let size = self.constraints(app).constrain(intrinsic);
7587            self.set_size(app, size);
7588        }
7589    }
7590
7591    impl RenderBox for IntrinsicTestBox {
7592        crate::render_box_accessors!();
7593
7594        fn compute_min_intrinsic_width(
7595            self: RenderHandle<Self>,
7596            app: &mut App,
7597            _height: f64,
7598        ) -> f64 {
7599            self.get(app).intrinsic.width()
7600        }
7601
7602        fn compute_max_intrinsic_width(
7603            self: RenderHandle<Self>,
7604            app: &mut App,
7605            _height: f64,
7606        ) -> f64 {
7607            self.get(app).intrinsic.width()
7608        }
7609
7610        fn compute_min_intrinsic_height(
7611            self: RenderHandle<Self>,
7612            app: &mut App,
7613            _width: f64,
7614        ) -> f64 {
7615            self.get(app).intrinsic.height()
7616        }
7617
7618        fn compute_max_intrinsic_height(
7619            self: RenderHandle<Self>,
7620            app: &mut App,
7621            _width: f64,
7622        ) -> f64 {
7623            self.get(app).intrinsic.height()
7624        }
7625
7626        fn compute_dry_layout(
7627            self: RenderHandle<Self>,
7628            app: &mut App,
7629            constraints: BoxConstraints,
7630        ) -> Size {
7631            constraints.constrain(self.get(app).intrinsic)
7632        }
7633    }
7634
7635    fn intrinsic_box(app: &mut App, intrinsic: Size) -> RenderHandle<IntrinsicTestBox> {
7636        RenderHandle::new_box(
7637            app,
7638            IntrinsicTestBox {
7639                render_object: RenderObjectData::new(),
7640                render_box: RenderBoxData::new(),
7641                intrinsic,
7642            },
7643        )
7644    }
7645
7646    fn schedule_root_paint(app: &mut App, node: AnyRenderObject) {
7647        let root = OffsetLayer::new(app, Offset::ZERO);
7648        root.as_layer().attach(app, node.id());
7649        node.schedule_initial_paint(app, root.as_container_layer());
7650    }
7651
7652    /// The test binding's first frame: attach, lay the root out, schedule and flush paint.
7653    fn first_frame(app: &mut App, root: AnyRenderBox) -> Handle<PipelineOwner> {
7654        let owner = PipelineOwner::new(app, None, None);
7655        owner.set_root_node(app, Some(root.as_object()));
7656        root.layout(app, BoxConstraints::tight(Size::new(100.0, 100.0)), false);
7657        schedule_root_paint(app, root.as_object());
7658        owner.flush_compositing_bits(app);
7659        owner.flush_paint(app);
7660        owner
7661    }
7662
7663    fn pump_frame(app: &mut App, owner: Handle<PipelineOwner>) {
7664        owner.flush_layout(app);
7665        owner.flush_compositing_bits(app);
7666        owner.flush_paint(app);
7667    }
7668
7669    /// `box_test.dart`: a `RenderConstrainedBox` reports its child's intrinsics enforced by its
7670    /// additional constraints, and a tight axis reports that tight extent.
7671    #[test]
7672    fn constrained_box_intrinsics_enforce_the_additional_constraints() {
7673        let cell = AppCell::new();
7674        let mut app = cell.borrow_mut();
7675        let child = intrinsic_box(&mut app, Size::new(20.0, 30.0));
7676        let loose = RenderConstrainedBox::new(
7677            &mut app,
7678            BoxConstraints::new().min_width(50.0).max_width(60.0),
7679            Some(child.as_box()),
7680        );
7681        assert_eq!(loose.as_box().get_min_intrinsic_width(&mut app, 0.0), 50.0);
7682        assert_eq!(loose.as_box().get_max_intrinsic_width(&mut app, 0.0), 50.0);
7683        assert_eq!(loose.as_box().get_min_intrinsic_height(&mut app, 0.0), 30.0);
7684
7685        let child = intrinsic_box(&mut app, Size::new(20.0, 30.0));
7686        let tight = RenderConstrainedBox::new(
7687            &mut app,
7688            BoxConstraints::tight(Size::new(80.0, 90.0)),
7689            Some(child.as_box()),
7690        );
7691        assert_eq!(tight.as_box().get_max_intrinsic_width(&mut app, 0.0), 80.0);
7692        assert_eq!(tight.as_box().get_max_intrinsic_height(&mut app, 0.0), 90.0);
7693    }
7694
7695    /// `intrinsic_width_test.dart`: the child is sized to its maximum intrinsic width, snapped to
7696    /// `step_width` when there is one.
7697    #[test]
7698    fn intrinsic_width_sizes_the_child_to_its_max_intrinsic_width() {
7699        let cell = AppCell::new();
7700        let mut app = cell.borrow_mut();
7701        let child = intrinsic_box(&mut app, Size::new(100.0, 40.0));
7702        let intrinsic = RenderIntrinsicWidth::new(&mut app, None, None, Some(child.as_box()));
7703        intrinsic.layout(&mut app, BoxConstraints::new().max_width(500.0), false);
7704        assert_eq!(intrinsic.size(&app), Size::new(100.0, 40.0));
7705        assert_eq!(child.size(&app), Size::new(100.0, 40.0));
7706
7707        intrinsic.set_step_width(&mut app, Some(30.0));
7708        intrinsic.layout(&mut app, BoxConstraints::new().max_width(500.0), false);
7709        assert_eq!(intrinsic.size(&app), Size::new(120.0, 40.0));
7710    }
7711
7712    /// The dry layout of a `RenderIntrinsicWidth` is the size it lays out to.
7713    #[test]
7714    fn intrinsic_width_dry_layout_matches_its_layout() {
7715        let cell = AppCell::new();
7716        let mut app = cell.borrow_mut();
7717        let child = intrinsic_box(&mut app, Size::new(100.0, 40.0));
7718        let intrinsic = RenderIntrinsicWidth::new(&mut app, None, None, Some(child.as_box()));
7719        let constraints = BoxConstraints::new().max_width(500.0);
7720        let dry = intrinsic.as_box().get_dry_layout(&mut app, constraints);
7721        intrinsic.layout(&mut app, constraints, false);
7722        assert_eq!(dry, intrinsic.size(&app));
7723    }
7724
7725    /// `intrinsic_height_test.dart`: the child is sized to its maximum intrinsic height.
7726    #[test]
7727    fn intrinsic_height_sizes_the_child_to_its_max_intrinsic_height() {
7728        let cell = AppCell::new();
7729        let mut app = cell.borrow_mut();
7730        let child = intrinsic_box(&mut app, Size::new(100.0, 40.0));
7731        let intrinsic = RenderIntrinsicHeight::new(&mut app, Some(child.as_box()));
7732        intrinsic.layout(&mut app, BoxConstraints::new().max_height(500.0), false);
7733        assert_eq!(intrinsic.size(&app), Size::new(100.0, 40.0));
7734        assert_eq!(
7735            intrinsic
7736                .as_box()
7737                .get_max_intrinsic_width(&mut app, f64::INFINITY),
7738            100.0
7739        );
7740    }
7741
7742    /// `fitted_box_test.dart`: a `BoxFit::Contain` child is scaled into the box, and the scale
7743    /// shows up in the paint transform.
7744    #[test]
7745    fn fitted_box_scales_its_child_into_itself() {
7746        let cell = AppCell::new();
7747        let mut app = cell.borrow_mut();
7748        let child = sized_box(&mut app, Size::new(100.0, 100.0));
7749        let fitted = RenderFittedBox::new(
7750            &mut app,
7751            BoxFit::Contain,
7752            AlignmentGeometry::CENTER,
7753            None,
7754            Some(child.as_box()),
7755        );
7756        fitted.layout(
7757            &mut app,
7758            BoxConstraints::tight(Size::new(50.0, 50.0)),
7759            false,
7760        );
7761        assert_eq!(fitted.size(&app), Size::new(50.0, 50.0));
7762        assert_eq!(child.size(&app), Size::new(100.0, 100.0));
7763
7764        let mut transform = Matrix4::IDENTITY;
7765        RenderBox::apply_paint_transform(fitted, &app, child.as_object(), &mut transform);
7766        assert_eq!(
7767            inset_painting::transform_point(&transform, Offset::new(100.0, 100.0)),
7768            Offset::new(50.0, 50.0)
7769        );
7770    }
7771
7772    /// `aspect_ratio_test.dart`: the widest width the constraints allow, with the height from the
7773    /// ratio.
7774    #[test]
7775    fn aspect_ratio_sizes_itself_from_the_width() {
7776        let cell = AppCell::new();
7777        let mut app = cell.borrow_mut();
7778        let child = sized_box(&mut app, Size::new(10.0, 10.0));
7779        let aspect = RenderAspectRatio::new(&mut app, 2.0, Some(child.as_box()));
7780        aspect.layout(
7781            &mut app,
7782            BoxConstraints::new().max_width(200.0).max_height(200.0),
7783            false,
7784        );
7785        assert_eq!(aspect.size(&app), Size::new(200.0, 100.0));
7786        assert_eq!(child.size(&app), Size::new(200.0, 100.0));
7787        assert_eq!(
7788            aspect.as_box().get_min_intrinsic_width(&mut app, 50.0),
7789            100.0
7790        );
7791        assert_eq!(
7792            aspect.as_box().get_min_intrinsic_height(&mut app, 50.0),
7793            25.0
7794        );
7795    }
7796
7797    /// An aspect ratio box infers its width from the height when the width is unbounded.
7798    #[test]
7799    fn aspect_ratio_infers_the_width_from_an_unbounded_axis() {
7800        let cell = AppCell::new();
7801        let mut app = cell.borrow_mut();
7802        let aspect = RenderAspectRatio::new(&mut app, 0.5, None);
7803        aspect.layout(&mut app, BoxConstraints::new().max_height(100.0), false);
7804        assert_eq!(aspect.size(&app), Size::new(50.0, 100.0));
7805    }
7806
7807    #[test]
7808    fn constrained_box_without_child() {
7809        let cell = AppCell::new();
7810        let mut app = cell.borrow_mut();
7811        let box_ =
7812            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(80.0, 40.0)), None);
7813        box_.layout(&mut app, BoxConstraints::new(), false);
7814        assert_eq!(box_.size(&app), Size::new(80.0, 40.0));
7815    }
7816
7817    #[test]
7818    fn additional_constraints_change_marks_layout() {
7819        let cell = AppCell::new();
7820        let mut app = cell.borrow_mut();
7821        let box_ =
7822            RenderConstrainedBox::new(&mut app, BoxConstraints::tight(Size::new(10.0, 10.0)), None);
7823        box_.layout(&mut app, BoxConstraints::new(), false);
7824        assert!(!box_.debug_needs_layout(&app));
7825        box_.set_additional_constraints(&mut app, BoxConstraints::tight(Size::new(20.0, 20.0)));
7826        assert!(box_.debug_needs_layout(&app));
7827        box_.layout(&mut app, BoxConstraints::new(), false);
7828        assert_eq!(box_.size(&app), Size::new(20.0, 20.0));
7829    }
7830
7831    /// Flutter's `RenderProxyBoxMixin.setupParentData` gives the child plain `ParentData`.
7832    #[test]
7833    fn proxy_box_child_gets_empty_parent_data() {
7834        let cell = AppCell::new();
7835        let mut app = cell.borrow_mut();
7836        let child = sized_box(&mut app, Size::new(10.0, 10.0));
7837        let parent = RenderConstrainedBox::new(
7838            &mut app,
7839            BoxConstraints::tight(Size::new(10.0, 10.0)),
7840            Some(child.as_box()),
7841        );
7842        parent.layout(&mut app, BoxConstraints::new(), false);
7843        assert!(child.as_box().parent_data_is::<EmptyParentData>(&app));
7844    }
7845
7846    /// `proxy_box_test.dart`: `RenderOpacity does not composite if it is transparent` and the
7847    /// opaque / partially opaque cases. Ours: whether it is a repaint boundary.
7848    #[test]
7849    fn render_opacity_composites_only_when_visible() {
7850        let cell = AppCell::new();
7851        let mut app = cell.borrow_mut();
7852        for (opacity, composites) in [(0.0, false), (1.0, true), (0.1, true)] {
7853            let child = sized_box(&mut app, Size::new(1.0, 1.0));
7854            let opacity = RenderOpacity::new(&mut app, opacity, Some(child.as_box()));
7855            assert_eq!(opacity.as_object().is_repaint_boundary(&app), composites);
7856        }
7857    }
7858
7859    /// `layers_test.dart`: `non-painted layers are detached`.
7860    #[test]
7861    fn non_painted_layers_are_detached() {
7862        let cell = AppCell::new();
7863        let mut app = cell.borrow_mut();
7864        let inner = RenderDecoratedBox::new(
7865            &mut app,
7866            Box::new(BoxDecoration::new()),
7867            DecorationPosition::Background,
7868            ImageConfiguration::EMPTY,
7869            None,
7870        );
7871        let boundary = RenderRepaintBoundary::new(&mut app, Some(inner.as_box()));
7872        let opacity = RenderOpacity::new(&mut app, 1.0, Some(boundary.as_box()));
7873        // Flutter's test binding puts a `RenderView` above; a root must stay a repaint boundary.
7874        let root = RenderRepaintBoundary::new(&mut app, Some(opacity.as_box()));
7875        let owner = first_frame(&mut app, root.as_box());
7876        assert!(!inner.as_object().is_repaint_boundary(&app));
7877        assert!(inner.as_object().debug_layer(&app).is_none());
7878        assert!(boundary.as_object().is_repaint_boundary(&app));
7879        let layer = boundary.as_object().debug_layer(&app).expect("painted");
7880        assert!(layer.as_layer().attached(&app), "this time it painted");
7881
7882        opacity.set_opacity(&mut app, 0.0);
7883        pump_frame(&mut app, owner);
7884        assert!(inner.as_object().debug_layer(&app).is_none());
7885        let layer = boundary.as_object().debug_layer(&app).expect("kept");
7886        assert!(!layer.as_layer().attached(&app), "this time it did not");
7887
7888        opacity.set_opacity(&mut app, 0.5);
7889        pump_frame(&mut app, owner);
7890        let layer = boundary.as_object().debug_layer(&app).expect("kept");
7891        assert!(layer.as_layer().attached(&app), "this time it did again");
7892    }
7893
7894    #[test]
7895    fn animated_opacity_follows_its_animation() {
7896        let cell = AppCell::new();
7897        let mut app = cell.borrow_mut();
7898        let child = sized_box(&mut app, Size::new(1.0, 1.0));
7899        let dismissed = k_always_dismissed_animation(&mut app);
7900        let complete = k_always_complete_animation(&mut app);
7901        let fade = RenderAnimatedOpacity::new(&mut app, dismissed, Some(child.as_box()));
7902        assert!(!fade.as_object().is_repaint_boundary(&app));
7903        let root = RenderRepaintBoundary::new(&mut app, Some(fade.as_box()));
7904        let owner = first_frame(&mut app, root.as_box());
7905
7906        fade.set_opacity(&mut app, complete);
7907        assert!(fade.as_object().is_repaint_boundary(&app));
7908        assert!(fade.as_object().debug_needs_paint(&app));
7909        pump_frame(&mut app, owner);
7910        let layer = fade.as_object().debug_layer(&app).expect("a boundary now");
7911        let opacity = app
7912            .handle::<OpacityLayer>(layer.id())
7913            .expect("an OpacityLayer");
7914        assert_eq!(opacity.alpha(&app), Some(255));
7915    }
7916
7917    #[test]
7918    fn decorated_box_paints_its_decoration() {
7919        let cell = AppCell::new();
7920        let mut app = cell.borrow_mut();
7921        let decorated = RenderDecoratedBox::new(
7922            &mut app,
7923            Box::new(BoxDecoration::new().color(Color::from_argb(255, 255, 0, 0))),
7924            DecorationPosition::Background,
7925            ImageConfiguration::EMPTY,
7926            None,
7927        );
7928        let root = RenderRepaintBoundary::new(&mut app, Some(decorated.as_box()));
7929        first_frame(&mut app, root.as_box());
7930        let ops = scene_ops(&mut app, root.as_object());
7931        assert!(
7932            ops.iter()
7933                .any(|op| matches!(op, inset_embedder::valo::Op::DrawDisplayList { .. })),
7934            "{ops:?}"
7935        );
7936    }
7937
7938    /// A leaf that fills the constraints it is given and is hit anywhere within them.
7939    fn opaque_leaf(app: &mut App) -> RenderHandle<RenderPointerListener> {
7940        RenderPointerListener::new(app, HitTestBehavior::Opaque, None)
7941    }
7942
7943    const RED: Color = Color::from_argb(255, 255, 0, 0);
7944    const BLUE: Color = Color::from_argb(255, 0, 0, 255);
7945
7946    fn red_box(app: &mut App) -> RenderHandle<RenderColoredBox> {
7947        RenderColoredBox::new(app, RED, true, None)
7948    }
7949
7950    /// Hit tests `target` at `position`: whether the hit was absorbed, and the path's length.
7951    fn hit_test(app: &mut App, target: AnyRenderBox, position: Offset) -> (bool, usize) {
7952        let mut result = HitTestResult::new();
7953        let is_hit = target.hit_test(app, &mut BoxHitTestResult::wrap(&mut result), position);
7954        (is_hit, result.path().len())
7955    }
7956
7957    /// Every canvas operation of the pictures in a repaint boundary's layer tree.
7958    fn picture_ops(app: &App, boundary: AnyRenderObject) -> Vec<Op> {
7959        let layer = boundary.debug_layer(app).expect("painted");
7960        layer
7961            .depth_first_iterate_children(app)
7962            .into_iter()
7963            .filter_map(|child| {
7964                app.handle::<PictureLayer>(child.id())
7965                    .and_then(|picture| picture.picture(app).map(|p| p.ops().to_vec()))
7966            })
7967            .flatten()
7968            .collect()
7969    }
7970
7971    fn picture_has_clip(app: &App, boundary: AnyRenderObject) -> bool {
7972        picture_ops(app, boundary)
7973            .iter()
7974            .any(|op| matches!(op, Op::ClipPath { .. }))
7975    }
7976
7977    /// The rect and color of every fill in a repaint boundary's recording.
7978    fn drawn_rects(app: &App, boundary: AnyRenderObject) -> Vec<(valo::Rect, valo::Color)> {
7979        picture_ops(app, boundary)
7980            .iter()
7981            .filter_map(|op| match op {
7982                Op::DrawRect { rect, paint, .. } => Some((*rect, paint.color)),
7983                _ => None,
7984            })
7985            .collect()
7986    }
7987
7988    fn fill(rect: Rect, color: Color) -> (valo::Rect, valo::Color) {
7989        (rect.into(), color.into())
7990    }
7991
7992    #[test]
7993    fn limited_box_limits_only_unbounded_constraints() {
7994        let cell = AppCell::new();
7995        let mut app = cell.borrow_mut();
7996        let child = opaque_leaf(&mut app);
7997        let limited = RenderLimitedBox::new(&mut app, 100.0, 50.0, Some(child.as_box()));
7998
7999        limited.layout(&mut app, BoxConstraints::new(), false);
8000        assert_eq!(limited.size(&app), Size::new(100.0, 50.0));
8001
8002        limited.layout(
8003            &mut app,
8004            BoxConstraints::loose(Size::new(30.0, 30.0)),
8005            false,
8006        );
8007        assert_eq!(
8008            limited.size(&app),
8009            Size::new(30.0, 30.0),
8010            "a bounded constraint is left alone"
8011        );
8012    }
8013
8014    #[test]
8015    fn limited_box_without_child_is_empty() {
8016        let cell = AppCell::new();
8017        let mut app = cell.borrow_mut();
8018        let limited = RenderLimitedBox::new(&mut app, 100.0, 50.0, None);
8019        limited.layout(&mut app, BoxConstraints::new(), false);
8020        assert_eq!(limited.size(&app), Size::ZERO);
8021    }
8022
8023    /// Clips to the left half of the box, so a test can tell the clip from the bounds.
8024    struct LeftHalfClipper;
8025
8026    impl CustomClipper<Rect> for LeftHalfClipper {
8027        fn get_clip(&self, size: Size) -> Rect {
8028            Rect::from_ltwh(0.0, 0.0, size.width() / 2.0, size.height())
8029        }
8030
8031        fn should_reclip(&self, _old_clipper: &dyn CustomClipper<Rect>) -> bool {
8032            false
8033        }
8034
8035        fn as_any(&self) -> &dyn Any {
8036            self
8037        }
8038    }
8039
8040    impl CustomClipper<RRect> for LeftHalfClipper {
8041        fn get_clip(&self, size: Size) -> RRect {
8042            RRect::from_rect_xy(
8043                Rect::from_ltwh(0.0, 0.0, size.width() / 2.0, size.height()),
8044                0.0,
8045                0.0,
8046            )
8047        }
8048
8049        fn should_reclip(&self, _old_clipper: &dyn CustomClipper<RRect>) -> bool {
8050            false
8051        }
8052
8053        fn as_any(&self) -> &dyn Any {
8054            self
8055        }
8056    }
8057
8058    /// A clipper of the whole box whose `reclip` listenable a test can notify.
8059    struct NotifyingClipper {
8060        reclip: Rc<dyn Listenable>,
8061    }
8062
8063    impl CustomClipper<Rect> for NotifyingClipper {
8064        fn reclip(&self) -> Option<&Rc<dyn Listenable>> {
8065            Some(&self.reclip)
8066        }
8067
8068        fn get_clip(&self, size: Size) -> Rect {
8069            Offset::ZERO & size
8070        }
8071
8072        fn should_reclip(&self, _old_clipper: &dyn CustomClipper<Rect>) -> bool {
8073            false
8074        }
8075
8076        fn as_any(&self) -> &dyn Any {
8077            self
8078        }
8079    }
8080
8081    #[test]
8082    fn clip_rect_pushes_its_clipper_and_clips_hit_tests() {
8083        let cell = AppCell::new();
8084        let mut app = cell.borrow_mut();
8085        let child = opaque_leaf(&mut app);
8086        let clipper: Rc<dyn CustomClipper<Rect>> = Rc::new(LeftHalfClipper);
8087        let clip = RenderClipRect::new(
8088            &mut app,
8089            Some(clipper),
8090            Clip::HardEdge,
8091            Some(child.as_box()),
8092        );
8093        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8094        first_frame(&mut app, root.as_box());
8095
8096        let ops = picture_ops(&app, root.as_object());
8097        let clip_path = ops
8098            .iter()
8099            .find_map(|op| match op {
8100                Op::ClipPath { path, .. } => Some(path),
8101                _ => None,
8102            })
8103            .expect("the recording clips");
8104        assert_eq!(
8105            clip_path.bounds(),
8106            Rect::from_ltwh(0.0, 0.0, 50.0, 100.0).into()
8107        );
8108
8109        assert!(hit_test(&mut app, clip.as_box(), Offset::new(25.0, 50.0)).0);
8110        assert!(
8111            !hit_test(&mut app, clip.as_box(), Offset::new(75.0, 50.0)).0,
8112            "outside the clipper's clip"
8113        );
8114    }
8115
8116    #[test]
8117    fn clip_rect_without_clipping_paints_its_child_directly() {
8118        let cell = AppCell::new();
8119        let mut app = cell.borrow_mut();
8120        let child = red_box(&mut app);
8121        let clip = RenderClipRect::new(&mut app, None, Clip::None, Some(child.as_box()));
8122        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8123        first_frame(&mut app, root.as_box());
8124
8125        assert!(
8126            !picture_has_clip(&app, root.as_object()),
8127            "Clip::None paints the child directly"
8128        );
8129        assert_eq!(
8130            drawn_rects(&app, root.as_object()),
8131            [fill(Rect::from_ltwh(0.0, 0.0, 100.0, 100.0), RED)]
8132        );
8133    }
8134
8135    #[test]
8136    fn clip_rrect_pushes_its_border_radius() {
8137        let cell = AppCell::new();
8138        let mut app = cell.borrow_mut();
8139        let child = opaque_leaf(&mut app);
8140        let clip = RenderClipRRect::new(
8141            &mut app,
8142            BorderRadiusGeometry::circular(20.0),
8143            None,
8144            Clip::AntiAlias,
8145            None,
8146            Some(child.as_box()),
8147        );
8148        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8149        first_frame(&mut app, root.as_box());
8150
8151        let bounds = Rect::from_ltwh(0.0, 0.0, 100.0, 100.0);
8152        let ops = picture_ops(&app, root.as_object());
8153        let clip_path = ops
8154            .iter()
8155            .find_map(|op| match op {
8156                Op::ClipPath { path, .. } => Some(path),
8157                _ => None,
8158            })
8159            .expect("the recording starts with the clip");
8160        assert_eq!(clip_path.bounds(), bounds.into());
8161
8162        assert!(
8163            hit_test(&mut app, clip.as_box(), Offset::new(99.0, 99.0)).0,
8164            "without a clipper the hit test is not clipped, as in Dart"
8165        );
8166    }
8167
8168    #[test]
8169    fn clip_rrect_clips_hit_tests_to_its_clipper() {
8170        let cell = AppCell::new();
8171        let mut app = cell.borrow_mut();
8172        let child = opaque_leaf(&mut app);
8173        let clipper: Rc<dyn CustomClipper<RRect>> = Rc::new(LeftHalfClipper);
8174        let clip = RenderClipRRect::new(
8175            &mut app,
8176            BorderRadiusGeometry::ZERO,
8177            Some(clipper),
8178            Clip::AntiAlias,
8179            None,
8180            Some(child.as_box()),
8181        );
8182        clip.layout(
8183            &mut app,
8184            BoxConstraints::tight(Size::new(100.0, 100.0)),
8185            false,
8186        );
8187
8188        assert!(hit_test(&mut app, clip.as_box(), Offset::new(25.0, 50.0)).0);
8189        assert!(!hit_test(&mut app, clip.as_box(), Offset::new(75.0, 50.0)).0);
8190    }
8191
8192    /// The cached clip is dropped when the clipper notifies and when the box is resized.
8193    #[test]
8194    fn clip_rect_reclips_on_notification_and_on_resize() {
8195        let cell = AppCell::new();
8196        let mut app = cell.borrow_mut();
8197        let reclip = app.create(ValueNotifier::new(0));
8198        let clipper: Rc<dyn CustomClipper<Rect>> = Rc::new(NotifyingClipper {
8199            reclip: Rc::new(reclip),
8200        });
8201        let child = red_box(&mut app);
8202        let clip = RenderClipRect::new(
8203            &mut app,
8204            Some(clipper),
8205            Clip::HardEdge,
8206            Some(child.as_box()),
8207        );
8208        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8209        let owner = first_frame(&mut app, root.as_box());
8210        assert!(clip.custom_clip_data(&app).clip.is_some());
8211
8212        reclip.set_value(&mut app, 1);
8213        assert!(
8214            clip.custom_clip_data(&app).clip.is_none(),
8215            "the clipper's notification dropped the cached clip"
8216        );
8217        assert!(clip.as_object().debug_needs_paint(&app));
8218        pump_frame(&mut app, owner);
8219        assert!(clip.custom_clip_data(&app).clip.is_some());
8220
8221        clip.layout(
8222            &mut app,
8223            BoxConstraints::tight(Size::new(50.0, 50.0)),
8224            false,
8225        );
8226        assert!(
8227            clip.custom_clip_data(&app).clip.is_none(),
8228            "a new size dropped the cached clip"
8229        );
8230    }
8231
8232    #[test]
8233    fn transform_paints_under_its_matrix() {
8234        let cell = AppCell::new();
8235        let mut app = cell.borrow_mut();
8236        let child = red_box(&mut app);
8237        let transform = RenderTransform::new(
8238            &mut app,
8239            Matrix4::scale(2.0, 2.0),
8240            None,
8241            None,
8242            None,
8243            true,
8244            Some(child.as_box()),
8245        );
8246        let root = RenderRepaintBoundary::new(&mut app, Some(transform.as_box()));
8247        first_frame(&mut app, root.as_box());
8248
8249        let ops = picture_ops(&app, root.as_object());
8250        let pushed = ops.iter().find_map(|op| match op {
8251            Op::Transform(transform) => Some(*transform),
8252            _ => None,
8253        });
8254        assert_eq!(pushed, Some(Matrix4::scale(2.0, 2.0)));
8255    }
8256
8257    /// A translation is folded into the child's paint offset instead of a pushed transform.
8258    #[test]
8259    fn transform_by_a_translation_paints_at_an_offset() {
8260        let cell = AppCell::new();
8261        let mut app = cell.borrow_mut();
8262        let child = red_box(&mut app);
8263        let transform = RenderTransform::new(
8264            &mut app,
8265            Matrix4::translation(10.0, 20.0),
8266            None,
8267            None,
8268            None,
8269            true,
8270            Some(child.as_box()),
8271        );
8272        let root = RenderRepaintBoundary::new(&mut app, Some(transform.as_box()));
8273        first_frame(&mut app, root.as_box());
8274
8275        assert!(
8276            !picture_ops(&app, root.as_object())
8277                .iter()
8278                .any(|op| matches!(op, Op::Transform(_))),
8279            "a translation is folded into the child's paint offset"
8280        );
8281        assert_eq!(
8282            drawn_rects(&app, root.as_object()),
8283            [fill(Rect::from_ltwh(10.0, 20.0, 100.0, 100.0), RED)]
8284        );
8285    }
8286
8287    #[test]
8288    fn transform_hit_tests_through_its_matrix() {
8289        let cell = AppCell::new();
8290        let mut app = cell.borrow_mut();
8291        let child = opaque_leaf(&mut app);
8292        let transform = RenderTransform::new(
8293            &mut app,
8294            Matrix4::scale(2.0, 2.0),
8295            None,
8296            None,
8297            None,
8298            true,
8299            Some(child.as_box()),
8300        );
8301        transform.layout(
8302            &mut app,
8303            BoxConstraints::tight(Size::new(100.0, 100.0)),
8304            false,
8305        );
8306
8307        assert_eq!(
8308            hit_test(&mut app, transform.as_box(), Offset::new(150.0, 50.0)),
8309            (true, 1),
8310            "the child covers twice the box, and the transform does not add itself"
8311        );
8312
8313        transform.set_transform_hit_tests(&mut app, false);
8314        assert!(!hit_test(&mut app, transform.as_box(), Offset::new(150.0, 50.0)).0);
8315        assert!(hit_test(&mut app, transform.as_box(), Offset::new(50.0, 50.0)).0);
8316    }
8317
8318    /// `Transform.scale(alignment: Alignment.center)`: the child grows around the box's centre.
8319    #[test]
8320    fn transform_scales_around_its_alignment_and_origin() {
8321        let cell = AppCell::new();
8322        let mut app = cell.borrow_mut();
8323        let child = opaque_leaf(&mut app);
8324        let transform = RenderTransform::new(
8325            &mut app,
8326            Matrix4::scale(2.0, 2.0),
8327            None,
8328            Some(AlignmentGeometry::CENTER),
8329            None,
8330            true,
8331            Some(child.as_box()),
8332        );
8333        transform.layout(
8334            &mut app,
8335            BoxConstraints::tight(Size::new(100.0, 100.0)),
8336            false,
8337        );
8338        assert!(hit_test(&mut app, transform.as_box(), Offset::new(140.0, 140.0)).0);
8339        assert!(!hit_test(&mut app, transform.as_box(), Offset::new(160.0, 160.0)).0);
8340
8341        transform.set_alignment(&mut app, None);
8342        transform.set_origin(&mut app, Some(Offset::new(50.0, 50.0)));
8343        assert!(
8344            hit_test(&mut app, transform.as_box(), Offset::new(140.0, 140.0)).0,
8345            "an origin at the centre is the same conjugation"
8346        );
8347        assert!(!hit_test(&mut app, transform.as_box(), Offset::new(160.0, 160.0)).0);
8348    }
8349
8350    #[test]
8351    fn transform_applies_its_paint_transform_to_the_child() {
8352        let cell = AppCell::new();
8353        let mut app = cell.borrow_mut();
8354        let child = opaque_leaf(&mut app);
8355        let transform = RenderTransform::new(
8356            &mut app,
8357            Matrix4::translation(10.0, 20.0),
8358            None,
8359            None,
8360            None,
8361            true,
8362            Some(child.as_box()),
8363        );
8364        let mut matrix = Matrix4::IDENTITY;
8365        RenderBox::apply_paint_transform(transform, &app, child.as_object(), &mut matrix);
8366        assert_eq!(matrix, Matrix4::translation(10.0, 20.0));
8367    }
8368
8369    #[test]
8370    fn fractional_translation_offsets_paint_and_hits() {
8371        let cell = AppCell::new();
8372        let mut app = cell.borrow_mut();
8373        let child = red_box(&mut app);
8374        let translated = RenderFractionalTranslation::new(
8375            &mut app,
8376            Offset::new(0.5, 0.0),
8377            true,
8378            Some(child.as_box()),
8379        );
8380        let root = RenderRepaintBoundary::new(&mut app, Some(translated.as_box()));
8381        first_frame(&mut app, root.as_box());
8382
8383        assert_eq!(
8384            drawn_rects(&app, root.as_object()),
8385            [fill(Rect::from_ltwh(50.0, 0.0, 100.0, 100.0), RED)],
8386            "half the width to the right"
8387        );
8388
8389        assert!(hit_test(&mut app, translated.as_box(), Offset::new(75.0, 50.0)).0);
8390        assert!(!hit_test(&mut app, translated.as_box(), Offset::new(25.0, 50.0)).0);
8391
8392        translated.set_transform_hit_tests(&mut app, false);
8393        assert!(
8394            hit_test(&mut app, translated.as_box(), Offset::new(25.0, 50.0)).0,
8395            "an untransformed hit test reaches the child where it was laid out"
8396        );
8397    }
8398
8399    #[test]
8400    fn ignore_pointer_is_invisible_to_hit_testing() {
8401        let cell = AppCell::new();
8402        let mut app = cell.borrow_mut();
8403        let child = opaque_leaf(&mut app);
8404        let ignoring = RenderIgnorePointer::new(&mut app, true, Some(child.as_box()));
8405        ignoring.layout(
8406            &mut app,
8407            BoxConstraints::tight(Size::new(100.0, 100.0)),
8408            false,
8409        );
8410
8411        assert_eq!(
8412            hit_test(&mut app, ignoring.as_box(), Offset::new(50.0, 50.0)),
8413            (false, 0)
8414        );
8415
8416        ignoring.set_ignoring(&mut app, false);
8417        assert_eq!(
8418            hit_test(&mut app, ignoring.as_box(), Offset::new(50.0, 50.0)),
8419            (true, 2),
8420            "the child and the ignore pointer itself"
8421        );
8422    }
8423
8424    #[test]
8425    fn absorb_pointer_takes_the_hit_from_its_subtree() {
8426        let cell = AppCell::new();
8427        let mut app = cell.borrow_mut();
8428        let child = opaque_leaf(&mut app);
8429        let absorbing = RenderAbsorbPointer::new(&mut app, true, Some(child.as_box()));
8430        absorbing.layout(
8431            &mut app,
8432            BoxConstraints::tight(Size::new(100.0, 100.0)),
8433            false,
8434        );
8435
8436        assert_eq!(
8437            hit_test(&mut app, absorbing.as_box(), Offset::new(50.0, 50.0)),
8438            (true, 0),
8439            "hit testing stops here, and nothing is added to the path"
8440        );
8441        assert_eq!(
8442            hit_test(&mut app, absorbing.as_box(), Offset::new(150.0, 50.0)),
8443            (false, 0)
8444        );
8445
8446        absorbing.set_absorbing(&mut app, false);
8447        assert_eq!(
8448            hit_test(&mut app, absorbing.as_box(), Offset::new(50.0, 50.0)),
8449            (true, 2)
8450        );
8451    }
8452
8453    #[test]
8454    fn offstage_lays_out_without_painting_or_hit_testing() {
8455        let cell = AppCell::new();
8456        let mut app = cell.borrow_mut();
8457        let child = red_box(&mut app);
8458        let offstage = RenderOffstage::new(&mut app, true, Some(child.as_box()));
8459        let root = RenderRepaintBoundary::new(&mut app, Some(offstage.as_box()));
8460        let owner = first_frame(&mut app, root.as_box());
8461
8462        assert!(RenderObject::sized_by_parent(offstage, &app));
8463        assert_eq!(child.size(&app), Size::new(100.0, 100.0), "still laid out");
8464        assert!(
8465            !picture_has_clip(&app, root.as_object()),
8466            "offstage paints nothing"
8467        );
8468        assert_eq!(
8469            hit_test(&mut app, offstage.as_box(), Offset::new(50.0, 50.0)),
8470            (false, 0)
8471        );
8472        assert!(!offstage.paints_child(&app, child.as_box()));
8473
8474        offstage.set_offstage(&mut app, false);
8475        pump_frame(&mut app, owner);
8476        assert_eq!(
8477            drawn_rects(&app, root.as_object()),
8478            [fill(Rect::from_ltwh(0.0, 0.0, 100.0, 100.0), RED)]
8479        );
8480        assert!(hit_test(&mut app, offstage.as_box(), Offset::new(50.0, 50.0)).0);
8481        assert!(offstage.paints_child(&app, child.as_box()));
8482    }
8483
8484    #[test]
8485    fn colored_box_fills_its_bounds() {
8486        let cell = AppCell::new();
8487        let mut app = cell.borrow_mut();
8488        let colored = red_box(&mut app);
8489        let root = RenderRepaintBoundary::new(&mut app, Some(colored.as_box()));
8490        first_frame(&mut app, root.as_box());
8491
8492        assert_eq!(
8493            drawn_rects(&app, root.as_object()),
8494            [fill(Rect::from_ltwh(0.0, 0.0, 100.0, 100.0), RED)]
8495        );
8496        assert_eq!(
8497            hit_test(&mut app, colored.as_box(), Offset::new(50.0, 50.0)),
8498            (true, 1),
8499            "an opaque box is hit by itself"
8500        );
8501    }
8502
8503    #[test]
8504    fn colored_box_paints_its_child_over_the_color() {
8505        let cell = AppCell::new();
8506        let mut app = cell.borrow_mut();
8507        let child = red_box(&mut app);
8508        let colored = RenderColoredBox::new(&mut app, BLUE, true, Some(child.as_box()));
8509        let root = RenderRepaintBoundary::new(&mut app, Some(colored.as_box()));
8510        first_frame(&mut app, root.as_box());
8511
8512        let bounds = Rect::from_ltwh(0.0, 0.0, 100.0, 100.0);
8513        assert_eq!(
8514            drawn_rects(&app, root.as_object()),
8515            [fill(bounds, BLUE), fill(bounds, RED)]
8516        );
8517    }
8518
8519    #[test]
8520    fn meta_data_carries_its_payload_and_hit_tests_by_behavior() {
8521        let cell = AppCell::new();
8522        let mut app = cell.borrow_mut();
8523        let payload: Rc<dyn Any> = Rc::new(42u32);
8524        let opaque = RenderMetaData::new(
8525            &mut app,
8526            Some(Rc::clone(&payload)),
8527            HitTestBehavior::Opaque,
8528            None,
8529        );
8530        opaque.layout(
8531            &mut app,
8532            BoxConstraints::tight(Size::new(10.0, 10.0)),
8533            false,
8534        );
8535        assert_eq!(
8536            opaque
8537                .meta_data(&app)
8538                .and_then(|data| data.downcast::<u32>().ok())
8539                .as_deref(),
8540            Some(&42)
8541        );
8542        let mut result = HitTestResult::new();
8543        assert!(opaque.as_box().hit_test(
8544            &mut app,
8545            &mut BoxHitTestResult::wrap(&mut result),
8546            Offset::new(5.0, 5.0)
8547        ));
8548        assert_eq!(result.path().len(), 1);
8549
8550        let deferring = RenderMetaData::new(&mut app, None, HitTestBehavior::DeferToChild, None);
8551        deferring.layout(
8552            &mut app,
8553            BoxConstraints::tight(Size::new(10.0, 10.0)),
8554            false,
8555        );
8556        let mut result = HitTestResult::new();
8557        assert!(!deferring.as_box().hit_test(
8558            &mut app,
8559            &mut BoxHitTestResult::wrap(&mut result),
8560            Offset::new(5.0, 5.0)
8561        ));
8562        assert!(result.path().is_empty());
8563
8564        // Deferring to a child that is hit puts the meta data on the path above it.
8565        let child = opaque_leaf(&mut app);
8566        deferring.set_child(&mut app, Some(child.as_box()));
8567        deferring.layout(
8568            &mut app,
8569            BoxConstraints::tight(Size::new(10.0, 10.0)),
8570            false,
8571        );
8572        let mut result = HitTestResult::new();
8573        assert!(deferring.as_box().hit_test(
8574            &mut app,
8575            &mut BoxHitTestResult::wrap(&mut result),
8576            Offset::new(5.0, 5.0)
8577        ));
8578        assert_eq!(result.path().len(), 2, "the child, then the meta data");
8579    }
8580
8581    /// The scene of a repaint-boundary root after a frame, as display-list ops.
8582    fn scene_ops(app: &mut App, root: AnyRenderObject) -> Vec<Op> {
8583        let scene = root
8584            .debug_layer(app)
8585            .expect("painted")
8586            .build_scene(app, SceneBuilder::new());
8587        inset_embedder::flattened_ops(&scene.picture)
8588    }
8589
8590    #[test]
8591    fn a_backdrop_filter_blurs_under_its_bounds_before_its_child_paints() {
8592        let cell = AppCell::new();
8593        let mut app = cell.borrow_mut();
8594        let child = RenderColoredBox::new(&mut app, Color::new(0xFF00FF00), true, None);
8595        let filter = RenderBackdropFilter::new(
8596            &mut app,
8597            ImageFilterConfig::new(ImageFilter::blur(6.0, 6.0)),
8598            BlendMode::SrcOver,
8599            true,
8600            None,
8601            Some(child.as_box()),
8602        );
8603        let root = RenderRepaintBoundary::new(&mut app, Some(filter.as_box()));
8604        let owner = first_frame(&mut app, root.as_box());
8605        let ops = scene_ops(&mut app, root.as_object());
8606        let blur = ops
8607            .iter()
8608            .position(|op| {
8609                matches!(
8610                    op,
8611                    Op::SaveLayer {
8612                        backdrop: Some(_),
8613                        ..
8614                    }
8615                )
8616            })
8617            .expect("a backdrop layer");
8618        let draw = ops
8619            .iter()
8620            .position(|op| matches!(op, Op::DrawRect { .. }))
8621            .expect("the child's paint");
8622        assert!(blur < draw, "the blur precedes the child: {ops:?}");
8623        if let Op::SaveLayer {
8624            backdrop: Some(backdrop),
8625            ..
8626        } = &ops[blur]
8627        {
8628            assert_eq!(
8629                backdrop.filter,
8630                inset_embedder::valo::ImageFilter::blur(6.0, 6.0)
8631            );
8632            assert_eq!(backdrop.shared_key, None);
8633        }
8634
8635        let key = BackdropKey::new();
8636        filter.set_backdrop_key(&mut app, Some(key));
8637        pump_frame(&mut app, owner);
8638        let ops = scene_ops(&mut app, root.as_object());
8639        assert!(
8640            ops.iter().any(|op| matches!(
8641                op,
8642                Op::SaveLayer {
8643                    backdrop: Some(valo::Backdrop {
8644                        shared_key: Some(_),
8645                        ..
8646                    }),
8647                    ..
8648                }
8649            )),
8650            "a keyed filter shares its blur: {ops:?}"
8651        );
8652
8653        filter.set_enabled(&mut app, false);
8654        pump_frame(&mut app, owner);
8655        let ops = scene_ops(&mut app, root.as_object());
8656        assert!(
8657            !ops.iter().any(|op| matches!(
8658                op,
8659                Op::SaveLayer {
8660                    backdrop: Some(_),
8661                    ..
8662                }
8663            )),
8664            "disabled paints the child only: {ops:?}"
8665        );
8666    }
8667
8668    #[test]
8669    fn a_composed_backdrop_filter_reaches_the_backdrop_whole() {
8670        let cell = AppCell::new();
8671        let mut app = cell.borrow_mut();
8672        let child = RenderColoredBox::new(&mut app, Color::new(0xFF00FF00), true, None);
8673        let saturation = ColorFilter::saturation(1.8);
8674        let filter = RenderBackdropFilter::new(
8675            &mut app,
8676            ImageFilterConfig::compose(
8677                ImageFilterConfig::new(ImageFilter::Color(saturation)),
8678                ImageFilterConfig::blur().sigma_x(4.0),
8679            ),
8680            BlendMode::SrcOver,
8681            true,
8682            None,
8683            Some(child.as_box()),
8684        );
8685        let root = RenderRepaintBoundary::new(&mut app, Some(filter.as_box()));
8686        first_frame(&mut app, root.as_box());
8687        let ops = scene_ops(&mut app, root.as_object());
8688        let composed = valo::ImageFilter::compose(
8689            valo::ImageFilter::Color(saturation.to_valo()),
8690            valo::ImageFilter::blur(4.0, 0.0),
8691        );
8692        assert!(
8693            ops.iter().any(|op| matches!(
8694                op,
8695                Op::SaveLayer {
8696                    backdrop: Some(backdrop),
8697                    ..
8698                } if backdrop.filter == composed
8699            )),
8700            "the saturation and the blur reach the backdrop in their order: {ops:?}"
8701        );
8702    }
8703
8704    #[test]
8705    fn clip_oval_hit_tests_inside_the_inscribed_oval_and_clips_with_its_path() {
8706        let cell = AppCell::new();
8707        let mut app = cell.borrow_mut();
8708        let child = opaque_leaf(&mut app);
8709        let oval = RenderClipOval::new(&mut app, None, Clip::AntiAlias, Some(child.as_box()));
8710        let root = RenderRepaintBoundary::new(&mut app, Some(oval.as_box()));
8711        first_frame(&mut app, root.as_box());
8712        let hit = |app: &mut App, x: f64, y: f64| {
8713            let mut result = HitTestResult::new();
8714            oval.as_box().hit_test(
8715                app,
8716                &mut BoxHitTestResult::wrap(&mut result),
8717                Offset::new(x, y),
8718            )
8719        };
8720        assert!(hit(&mut app, 50.0, 50.0), "the center is inside");
8721        assert!(!hit(&mut app, 2.0, 2.0), "a corner is outside the oval");
8722        assert!(
8723            picture_has_clip(&app, root.as_object()),
8724            "an oval clips with a path"
8725        );
8726    }
8727
8728    #[test]
8729    fn clip_path_uses_its_clipper_for_hit_tests_and_the_rect_by_default() {
8730        struct Triangle;
8731        impl CustomClipper<Arc<Path>> for Triangle {
8732            fn get_clip(&self, size: Size) -> Arc<Path> {
8733                let mut path = PathBuilder::new();
8734                path.move_to(Point::new(0.0, 0.0));
8735                path.line_to(Point::new(size.width() as f32, 0.0));
8736                path.line_to(Point::new(0.0, size.height() as f32));
8737                path.close();
8738                path.build()
8739            }
8740
8741            fn should_reclip(&self, _old: &dyn CustomClipper<Arc<Path>>) -> bool {
8742                false
8743            }
8744
8745            fn as_any(&self) -> &dyn Any {
8746                self
8747            }
8748        }
8749        let cell = AppCell::new();
8750        let mut app = cell.borrow_mut();
8751        let child = opaque_leaf(&mut app);
8752        let clip = RenderClipPath::new(
8753            &mut app,
8754            Some(Rc::new(Triangle)),
8755            Clip::AntiAlias,
8756            Some(child.as_box()),
8757        );
8758        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8759        first_frame(&mut app, root.as_box());
8760        let hit = |app: &mut App, x: f64, y: f64| {
8761            let mut result = HitTestResult::new();
8762            clip.as_box().hit_test(
8763                app,
8764                &mut BoxHitTestResult::wrap(&mut result),
8765                Offset::new(x, y),
8766            )
8767        };
8768        assert!(hit(&mut app, 10.0, 10.0), "inside the triangle");
8769        assert!(!hit(&mut app, 90.0, 90.0), "outside the triangle");
8770
8771        let plain = RenderClipPath::new(&mut app, None, Clip::HardEdge, None);
8772        plain.layout(
8773            &mut app,
8774            BoxConstraints::tight(Size::new(30.0, 20.0)),
8775            false,
8776        );
8777        assert!(
8778            plain
8779                .default_clip(&app)
8780                .contains(Point::new(29.0, 19.0), FillRule::NonZero),
8781            "the default clip is the box's rect"
8782        );
8783    }
8784
8785    #[test]
8786    fn clip_rsuperellipse_resolves_its_border_radius_and_clips_with_a_path() {
8787        let cell = AppCell::new();
8788        let mut app = cell.borrow_mut();
8789        let child = RenderConstrainedBox::new(&mut app, BoxConstraints::expand(None, None), None);
8790        let clip = RenderClipRSuperellipse::new(
8791            &mut app,
8792            BorderRadiusGeometry::circular(12.0),
8793            None,
8794            Clip::AntiAlias,
8795            Some(TextDirection::Ltr),
8796            Some(child.as_box()),
8797        );
8798        let root = RenderRepaintBoundary::new(&mut app, Some(clip.as_box()));
8799        first_frame(&mut app, root.as_box());
8800        clip.update_clip(&mut app);
8801        assert_eq!(clip.clip(&app).tl_radius_x, 12.0);
8802        assert_eq!(
8803            clip.clip(&app).outer_rect(),
8804            Rect::from_ltwh(0.0, 0.0, 100.0, 100.0)
8805        );
8806        assert!(
8807            picture_has_clip(&app, root.as_object()),
8808            "a superellipse clips with its path"
8809        );
8810        clip.set_border_radius(&mut app, BorderRadiusGeometry::circular(4.0));
8811        assert!(
8812            clip.custom_clip_data(&app).clip.is_none(),
8813            "a new radius marks the clip"
8814        );
8815    }
8816
8817    #[test]
8818    fn a_shape_border_clipper_clips_to_the_shape_and_reclips_when_it_changes() {
8819        let square: Box<dyn ShapeBorder> = Box::new(inset_painting::RoundedRectangleBorder::new(
8820            inset_painting::BorderSide::NONE,
8821            inset_painting::BorderRadiusGeometry::circular(10.0),
8822        ));
8823        let clipper = ShapeBorderClipper::new(square.clone_box(), Some(TextDirection::Ltr));
8824        let clip = clipper.get_clip(Size::new(40.0, 40.0));
8825        assert!(clip.contains(Point::new(20.0, 20.0), FillRule::NonZero));
8826        assert!(
8827            !clip.contains(Point::new(0.5, 0.5), FillRule::NonZero),
8828            "a rounded corner"
8829        );
8830        let same = ShapeBorderClipper::new(square.clone_box(), Some(TextDirection::Ltr));
8831        assert!(!clipper.should_reclip(&same));
8832        let other = ShapeBorderClipper::new(square, Some(TextDirection::Rtl));
8833        assert!(clipper.should_reclip(&other));
8834    }
8835}