Skip to main content

inset_rendering/
sliver.rs

1//! Flutter counterpart: `rendering/sliver.dart`.
2
3use std::any::{Any, TypeId};
4use std::fmt::{self, Debug, Display};
5use std::hash::Hasher;
6use std::ops::{Deref, DerefMut};
7
8use inset_embedder::{Matrix4, Offset, Rect, Size, clamp_double};
9use inset_foundation::{App, Handle, HandleId, PRECISION_ERROR_TOLERANCE};
10use inset_gestures::{HitTestEntry, HitTestResult, HitTestTarget, PointerEvent};
11use inset_painting::{
12    Axis, AxisDirection, axis_direction_is_reversed, axis_direction_to_axis, flip_axis_direction,
13};
14
15use crate::box_::{AnyRenderBox, BoxConstraints, BoxHitTestResult};
16use crate::object::{
17    AnyRenderObject, Constraints, ContainerParentData, ContainerParentDataMixin, ParentData,
18    RenderHandle, RenderObject, RenderObjectVTable, RenderObjectWithChildData,
19    RenderObjectWithChildMixin, create, resolve, translate,
20};
21use crate::painting_context::PaintingContext;
22use crate::pipeline_owner::PipelineOwner;
23use crate::viewport_offset::{ScrollDirection, flip_scroll_direction};
24
25/// Signature for a callback that reports the main-axis extent of the item at `index`.
26///
27/// Used by `ListView.itemExtentBuilder` and `SliverVariedExtentList.itemExtentBuilder`.
28///
29/// Dart compares two builders with `==`; an [`Rc`](std::rc::Rc) compares by pointer.
30pub type ItemExtentBuilder = std::rc::Rc<dyn Fn(i32, SliverLayoutDimensions) -> Option<f64>>;
31
32/// Relates the dimensions of the [`RenderSliver`] during layout.
33#[derive(Clone, Copy, Debug, PartialEq)]
34pub struct SliverLayoutDimensions {
35    /// Scroll offset in this sliver's coordinate system of the earliest visible part of this
36    /// sliver.
37    pub scroll_offset: f64,
38
39    /// Scroll distance consumed by all slivers that came before this one.
40    pub preceding_scroll_extent: f64,
41
42    /// The number of pixels the viewport can display in the main axis.
43    ///
44    /// For a vertical list, this is the height of the viewport.
45    pub viewport_main_axis_extent: f64,
46
47    /// The number of pixels in the cross-axis.
48    ///
49    /// For a vertical list, this is the width of the sliver.
50    pub cross_axis_extent: f64,
51}
52
53impl SliverLayoutDimensions {
54    /// Constructs the layout dimensions with the specified parameters.
55    pub const fn new(
56        scroll_offset: f64,
57        preceding_scroll_extent: f64,
58        viewport_main_axis_extent: f64,
59        cross_axis_extent: f64,
60    ) -> SliverLayoutDimensions {
61        SliverLayoutDimensions {
62            scroll_offset,
63            preceding_scroll_extent,
64            viewport_main_axis_extent,
65            cross_axis_extent,
66        }
67    }
68}
69
70impl Display for SliverLayoutDimensions {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        write!(
73            f,
74            "scrollOffset: {} precedingScrollExtent: {} viewportMainAxisExtent: {} \
75             crossAxisExtent: {}",
76            self.scroll_offset,
77            self.preceding_scroll_extent,
78            self.viewport_main_axis_extent,
79            self.cross_axis_extent
80        )
81    }
82}
83
84/// The direction in which a sliver's contents are ordered, relative to the
85/// scroll offset axis.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
87pub enum GrowthDirection {
88    /// Contents are ordered in the same direction as the [`AxisDirection`].
89    Forward,
90
91    /// Contents are ordered in the opposite direction of the [`AxisDirection`].
92    Reverse,
93}
94
95/// Flips the [`AxisDirection`] if the [`GrowthDirection`] is
96/// [`GrowthDirection::Reverse`].
97pub fn apply_growth_direction_to_axis_direction(
98    axis_direction: AxisDirection,
99    growth_direction: GrowthDirection,
100) -> AxisDirection {
101    match growth_direction {
102        GrowthDirection::Forward => axis_direction,
103        GrowthDirection::Reverse => flip_axis_direction(axis_direction),
104    }
105}
106
107/// Flips the [`ScrollDirection`] if the [`GrowthDirection`] is
108/// [`GrowthDirection::Reverse`].
109pub fn apply_growth_direction_to_scroll_direction(
110    scroll_direction: ScrollDirection,
111    growth_direction: GrowthDirection,
112) -> ScrollDirection {
113    match growth_direction {
114        GrowthDirection::Forward => scroll_direction,
115        GrowthDirection::Reverse => flip_scroll_direction(scroll_direction),
116    }
117}
118
119/// Immutable layout constraints for [`RenderSliver`] layout.
120#[derive(Clone, Copy, Debug)]
121pub struct SliverConstraints {
122    /// The direction in which [`scroll_offset`](Self::scroll_offset) and
123    /// [`remaining_paint_extent`](Self::remaining_paint_extent) increase.
124    pub axis_direction: AxisDirection,
125    /// The direction in which the contents of slivers are ordered.
126    pub growth_direction: GrowthDirection,
127    /// The direction in which the user is attempting to scroll.
128    pub user_scroll_direction: ScrollDirection,
129    /// Scroll offset in this sliver's coordinate system of the earliest visible
130    /// part of this sliver.
131    pub scroll_offset: f64,
132    /// Scroll distance consumed by all slivers that came before this one.
133    pub preceding_scroll_extent: f64,
134    /// Pixels from the painted [`scroll_offset`](Self::scroll_offset) up to the
135    /// first pixel not yet painted by an earlier sliver.
136    pub overlap: f64,
137    /// Pixels of content the sliver should consider providing.
138    pub remaining_paint_extent: f64,
139    /// Pixels in the cross-axis.
140    pub cross_axis_extent: f64,
141    /// Direction in which children should be placed in the cross axis.
142    pub cross_axis_direction: AxisDirection,
143    /// Pixels the viewport can display in the main axis.
144    pub viewport_main_axis_extent: f64,
145    /// How much content the sliver should provide starting from
146    /// [`cache_origin`](Self::cache_origin).
147    pub remaining_cache_extent: f64,
148    /// Where the cache area starts relative to the
149    /// [`scroll_offset`](Self::scroll_offset). Always negative or zero.
150    pub cache_origin: f64,
151}
152
153impl SliverConstraints {
154    /// Creates sliver constraints with the given information.
155    #[allow(clippy::too_many_arguments)]
156    pub const fn new(
157        axis_direction: AxisDirection,
158        growth_direction: GrowthDirection,
159        user_scroll_direction: ScrollDirection,
160        scroll_offset: f64,
161        preceding_scroll_extent: f64,
162        overlap: f64,
163        remaining_paint_extent: f64,
164        cross_axis_extent: f64,
165        cross_axis_direction: AxisDirection,
166        viewport_main_axis_extent: f64,
167        remaining_cache_extent: f64,
168        cache_origin: f64,
169    ) -> SliverConstraints {
170        SliverConstraints {
171            axis_direction,
172            growth_direction,
173            user_scroll_direction,
174            scroll_offset,
175            preceding_scroll_extent,
176            overlap,
177            remaining_paint_extent,
178            cross_axis_extent,
179            cross_axis_direction,
180            viewport_main_axis_extent,
181            remaining_cache_extent,
182            cache_origin,
183        }
184    }
185
186    /// Creates a copy of this object. Chain field replacements.
187    pub const fn copy_with(self) -> SliverConstraints {
188        self
189    }
190
191    /// Sets [`axis_direction`](Self::axis_direction).
192    pub const fn axis_direction(mut self, value: AxisDirection) -> SliverConstraints {
193        self.axis_direction = value;
194        self
195    }
196
197    /// Sets [`growth_direction`](Self::growth_direction).
198    pub const fn growth_direction(mut self, value: GrowthDirection) -> SliverConstraints {
199        self.growth_direction = value;
200        self
201    }
202
203    /// Sets [`user_scroll_direction`](Self::user_scroll_direction).
204    pub const fn user_scroll_direction(mut self, value: ScrollDirection) -> SliverConstraints {
205        self.user_scroll_direction = value;
206        self
207    }
208
209    /// Sets [`scroll_offset`](Self::scroll_offset).
210    pub const fn scroll_offset(mut self, value: f64) -> SliverConstraints {
211        self.scroll_offset = value;
212        self
213    }
214
215    /// Sets [`preceding_scroll_extent`](Self::preceding_scroll_extent).
216    pub const fn preceding_scroll_extent(mut self, value: f64) -> SliverConstraints {
217        self.preceding_scroll_extent = value;
218        self
219    }
220
221    /// Sets [`overlap`](Self::overlap).
222    pub const fn overlap(mut self, value: f64) -> SliverConstraints {
223        self.overlap = value;
224        self
225    }
226
227    /// Sets [`remaining_paint_extent`](Self::remaining_paint_extent).
228    pub const fn remaining_paint_extent(mut self, value: f64) -> SliverConstraints {
229        self.remaining_paint_extent = value;
230        self
231    }
232
233    /// Sets [`cross_axis_extent`](Self::cross_axis_extent).
234    pub const fn cross_axis_extent(mut self, value: f64) -> SliverConstraints {
235        self.cross_axis_extent = value;
236        self
237    }
238
239    /// Sets [`cross_axis_direction`](Self::cross_axis_direction).
240    pub const fn cross_axis_direction(mut self, value: AxisDirection) -> SliverConstraints {
241        self.cross_axis_direction = value;
242        self
243    }
244
245    /// Sets [`viewport_main_axis_extent`](Self::viewport_main_axis_extent).
246    pub const fn viewport_main_axis_extent(mut self, value: f64) -> SliverConstraints {
247        self.viewport_main_axis_extent = value;
248        self
249    }
250
251    /// Sets [`remaining_cache_extent`](Self::remaining_cache_extent).
252    pub const fn remaining_cache_extent(mut self, value: f64) -> SliverConstraints {
253        self.remaining_cache_extent = value;
254        self
255    }
256
257    /// Sets [`cache_origin`](Self::cache_origin).
258    pub const fn cache_origin(mut self, value: f64) -> SliverConstraints {
259        self.cache_origin = value;
260        self
261    }
262
263    /// The axis along which the scroll offset is measured.
264    pub fn axis(self) -> Axis {
265        axis_direction_to_axis(self.axis_direction)
266    }
267
268    /// [`growth_direction`](Self::growth_direction) as if the axis were down or
269    /// right.
270    pub fn normalized_growth_direction(self) -> GrowthDirection {
271        if axis_direction_is_reversed(self.axis_direction) {
272            match self.growth_direction {
273                GrowthDirection::Forward => GrowthDirection::Reverse,
274                GrowthDirection::Reverse => GrowthDirection::Forward,
275            }
276        } else {
277            self.growth_direction
278        }
279    }
280
281    /// [`BoxConstraints`] that reflect these sliver constraints.
282    ///
283    /// Dart named defaults: `min_extent` 0, `max_extent` infinity, `cross_axis_extent`
284    /// this sliver's cross extent.
285    pub fn as_box_constraints(
286        self,
287        min_extent: f64,
288        max_extent: f64,
289        cross_axis_extent: Option<f64>,
290    ) -> BoxConstraints {
291        let cross = cross_axis_extent.unwrap_or(self.cross_axis_extent);
292        match self.axis() {
293            Axis::Horizontal => BoxConstraints {
294                min_width: min_extent,
295                max_width: max_extent,
296                min_height: cross,
297                max_height: cross,
298            },
299            Axis::Vertical => BoxConstraints {
300                min_width: cross,
301                max_width: cross,
302                min_height: min_extent,
303                max_height: max_extent,
304            },
305        }
306    }
307}
308
309impl Constraints for SliverConstraints {
310    fn is_tight(&self) -> bool {
311        false
312    }
313
314    fn is_normalized(&self) -> bool {
315        self.scroll_offset >= 0.0
316            && self.cross_axis_extent >= 0.0
317            && axis_direction_to_axis(self.axis_direction)
318                != axis_direction_to_axis(self.cross_axis_direction)
319            && self.viewport_main_axis_extent >= 0.0
320            && self.remaining_paint_extent >= 0.0
321    }
322}
323
324impl PartialEq for SliverConstraints {
325    fn eq(&self, other: &SliverConstraints) -> bool {
326        debug_assert!(self.debug_assert_is_valid(false));
327        debug_assert!(other.debug_assert_is_valid(false));
328        self.axis_direction == other.axis_direction
329            && self.growth_direction == other.growth_direction
330            && self.user_scroll_direction == other.user_scroll_direction
331            && self.scroll_offset == other.scroll_offset
332            && self.preceding_scroll_extent == other.preceding_scroll_extent
333            && self.overlap == other.overlap
334            && self.remaining_paint_extent == other.remaining_paint_extent
335            && self.cross_axis_extent == other.cross_axis_extent
336            && self.cross_axis_direction == other.cross_axis_direction
337            && self.viewport_main_axis_extent == other.viewport_main_axis_extent
338            && self.remaining_cache_extent == other.remaining_cache_extent
339            && self.cache_origin == other.cache_origin
340    }
341}
342
343/// The amount of space a sliver occupies.
344#[derive(Clone, Copy, Debug)]
345pub struct SliverGeometry {
346    /// Estimated total scrollable extent this sliver has content for.
347    pub scroll_extent: f64,
348    /// Visual location of the first visible part relative to the layout
349    /// position.
350    pub paint_origin: f64,
351    /// Currently visible visual space taken by this sliver.
352    pub paint_extent: f64,
353    /// Distance from the first visible part of this sliver to the first visible
354    /// part of the next.
355    pub layout_extent: f64,
356    /// Estimated total paint extent if remaining paint extent were infinite.
357    pub max_paint_extent: f64,
358    /// Maximum extent by which a pinned sliver can reduce the scrollable area.
359    pub max_scroll_obstruction_extent: f64,
360    /// Distance from where this sliver started painting to the bottom of where
361    /// it should accept hits.
362    pub hit_test_extent: f64,
363    /// Whether this sliver should be painted.
364    pub visible: bool,
365    /// Whether this sliver has visual overflow.
366    pub has_visual_overflow: bool,
367    /// Non-zero asks the parent to correct the scroll offset and relayout.
368    pub scroll_offset_correction: Option<f64>,
369    /// Pixels consumed in the remaining cache extent.
370    pub cache_extent: f64,
371    /// Cross-axis extent, if the sliver reports one.
372    pub cross_axis_extent: Option<f64>,
373}
374
375impl SliverGeometry {
376    /// A sliver that occupies no space at all.
377    pub const ZERO: SliverGeometry = SliverGeometry {
378        scroll_extent: 0.0,
379        paint_origin: 0.0,
380        paint_extent: 0.0,
381        layout_extent: 0.0,
382        max_paint_extent: 0.0,
383        max_scroll_obstruction_extent: 0.0,
384        hit_test_extent: 0.0,
385        visible: false,
386        has_visual_overflow: false,
387        scroll_offset_correction: None,
388        cache_extent: 0.0,
389        cross_axis_extent: None,
390    };
391
392    /// Starts geometry with Flutter's constructor defaults. Extents left out are filled in by
393    /// [`SliverGeometryBuilder::build`], as Flutter's constructor fills them.
394    pub const fn builder() -> SliverGeometryBuilder {
395        SliverGeometryBuilder {
396            scroll_extent: 0.0,
397            paint_origin: 0.0,
398            paint_extent: 0.0,
399            layout_extent: None,
400            max_paint_extent: 0.0,
401            max_scroll_obstruction_extent: 0.0,
402            hit_test_extent: None,
403            visible: None,
404            has_visual_overflow: false,
405            scroll_offset_correction: None,
406            cache_extent: None,
407            cross_axis_extent: None,
408        }
409    }
410
411    /// Dart `copyWith`: a builder holding this geometry's values, for fields to be replaced.
412    pub const fn copy_with(self) -> SliverGeometryBuilder {
413        SliverGeometryBuilder {
414            scroll_extent: self.scroll_extent,
415            paint_origin: self.paint_origin,
416            paint_extent: self.paint_extent,
417            layout_extent: Some(self.layout_extent),
418            max_paint_extent: self.max_paint_extent,
419            max_scroll_obstruction_extent: self.max_scroll_obstruction_extent,
420            hit_test_extent: Some(self.hit_test_extent),
421            visible: Some(self.visible),
422            has_visual_overflow: self.has_visual_overflow,
423            scroll_offset_correction: self.scroll_offset_correction,
424            cache_extent: Some(self.cache_extent),
425            cross_axis_extent: self.cross_axis_extent,
426        }
427    }
428
429    /// Dart's `geometry == SliverGeometry.zero`: whether this geometry occupies no space at
430    /// all.
431    pub fn is_zero(&self) -> bool {
432        self.scroll_extent == SliverGeometry::ZERO.scroll_extent
433            && self.paint_origin == SliverGeometry::ZERO.paint_origin
434            && self.paint_extent == SliverGeometry::ZERO.paint_extent
435            && self.layout_extent == SliverGeometry::ZERO.layout_extent
436            && self.max_paint_extent == SliverGeometry::ZERO.max_paint_extent
437            && self.max_scroll_obstruction_extent
438                == SliverGeometry::ZERO.max_scroll_obstruction_extent
439            && self.hit_test_extent == SliverGeometry::ZERO.hit_test_extent
440            && self.visible == SliverGeometry::ZERO.visible
441            && self.has_visual_overflow == SliverGeometry::ZERO.has_visual_overflow
442            && self.scroll_offset_correction == SliverGeometry::ZERO.scroll_offset_correction
443            && self.cache_extent == SliverGeometry::ZERO.cache_extent
444            && self.cross_axis_extent == SliverGeometry::ZERO.cross_axis_extent
445    }
446
447    /// Asserts that this geometry is internally consistent.
448    ///
449    /// Does nothing if asserts are disabled. Always returns true.
450    pub fn debug_assert_is_valid(&self) -> bool {
451        debug_assert!(self.scroll_extent >= 0.0, "The scroll_extent is negative.");
452        debug_assert!(self.paint_extent >= 0.0, "The paint_extent is negative.");
453        debug_assert!(self.layout_extent >= 0.0, "The layout_extent is negative.");
454        debug_assert!(self.cache_extent >= 0.0, "The cache_extent is negative.");
455        debug_assert!(
456            self.layout_extent <= self.paint_extent,
457            "The layout_extent ({}) exceeds the paint_extent ({}).",
458            self.layout_extent,
459            self.paint_extent
460        );
461        // If the paint_extent is slightly more than the max_paint_extent, but the difference is
462        // still less than PRECISION_ERROR_TOLERANCE, we will not fail the assert below.
463        debug_assert!(
464            self.paint_extent - self.max_paint_extent <= PRECISION_ERROR_TOLERANCE,
465            "The max_paint_extent ({}) is less than the paint_extent ({}). By definition, a \
466             sliver can't paint more than the maximum that it can paint!",
467            self.max_paint_extent,
468            self.paint_extent
469        );
470        debug_assert!(
471            self.hit_test_extent >= 0.0,
472            "The hit_test_extent is negative."
473        );
474        debug_assert!(
475            self.scroll_offset_correction != Some(0.0),
476            "The scroll_offset_correction is zero."
477        );
478        true
479    }
480}
481
482/// `SliverGeometryBuilder` collects a [`SliverGeometry`]'s values, as Dart's constructor takes
483/// them, and fills in the ones left out when it builds.
484#[derive(Clone, Copy, Debug)]
485pub struct SliverGeometryBuilder {
486    scroll_extent: f64,
487    paint_origin: f64,
488    paint_extent: f64,
489    layout_extent: Option<f64>,
490    max_paint_extent: f64,
491    max_scroll_obstruction_extent: f64,
492    hit_test_extent: Option<f64>,
493    visible: Option<bool>,
494    has_visual_overflow: bool,
495    scroll_offset_correction: Option<f64>,
496    cache_extent: Option<f64>,
497    cross_axis_extent: Option<f64>,
498}
499
500impl SliverGeometryBuilder {
501    /// Sets [`SliverGeometry::scroll_extent`].
502    pub const fn scroll_extent(mut self, value: f64) -> SliverGeometryBuilder {
503        self.scroll_extent = value;
504        self
505    }
506
507    /// Sets [`SliverGeometry::paint_origin`].
508    pub const fn paint_origin(mut self, value: f64) -> SliverGeometryBuilder {
509        self.paint_origin = value;
510        self
511    }
512
513    /// Sets [`SliverGeometry::paint_extent`].
514    pub const fn paint_extent(mut self, value: f64) -> SliverGeometryBuilder {
515        self.paint_extent = value;
516        self
517    }
518
519    /// Sets [`SliverGeometry::layout_extent`].
520    pub const fn layout_extent(mut self, value: f64) -> SliverGeometryBuilder {
521        self.layout_extent = Some(value);
522        self
523    }
524
525    /// Sets [`SliverGeometry::max_paint_extent`].
526    pub const fn max_paint_extent(mut self, value: f64) -> SliverGeometryBuilder {
527        self.max_paint_extent = value;
528        self
529    }
530
531    /// Sets [`SliverGeometry::max_scroll_obstruction_extent`].
532    pub const fn max_scroll_obstruction_extent(mut self, value: f64) -> SliverGeometryBuilder {
533        self.max_scroll_obstruction_extent = value;
534        self
535    }
536
537    /// Sets [`SliverGeometry::hit_test_extent`].
538    pub const fn hit_test_extent(mut self, value: f64) -> SliverGeometryBuilder {
539        self.hit_test_extent = Some(value);
540        self
541    }
542
543    /// Sets [`SliverGeometry::visible`].
544    pub const fn visible(mut self, value: bool) -> SliverGeometryBuilder {
545        self.visible = Some(value);
546        self
547    }
548
549    /// Sets [`SliverGeometry::has_visual_overflow`].
550    pub const fn has_visual_overflow(mut self, value: bool) -> SliverGeometryBuilder {
551        self.has_visual_overflow = value;
552        self
553    }
554
555    /// Sets [`SliverGeometry::scroll_offset_correction`].
556    pub fn scroll_offset_correction(mut self, value: f64) -> SliverGeometryBuilder {
557        debug_assert!(value != 0.0);
558        self.scroll_offset_correction = Some(value);
559        self
560    }
561
562    /// Sets [`SliverGeometry::cache_extent`].
563    pub const fn cache_extent(mut self, value: f64) -> SliverGeometryBuilder {
564        self.cache_extent = Some(value);
565        self
566    }
567
568    /// Sets [`SliverGeometry::cross_axis_extent`].
569    pub const fn cross_axis_extent(mut self, value: f64) -> SliverGeometryBuilder {
570        self.cross_axis_extent = Some(value);
571        self
572    }
573
574    /// `build` makes the geometry, filling the extents left out as Dart's constructor does:
575    /// the layout and hit-test extents and `visible` from the paint extent, and the cache
576    /// extent from the layout extent.
577    pub fn build(self) -> SliverGeometry {
578        SliverGeometry {
579            scroll_extent: self.scroll_extent,
580            paint_origin: self.paint_origin,
581            paint_extent: self.paint_extent,
582            layout_extent: self.layout_extent.unwrap_or(self.paint_extent),
583            max_paint_extent: self.max_paint_extent,
584            max_scroll_obstruction_extent: self.max_scroll_obstruction_extent,
585            hit_test_extent: self.hit_test_extent.unwrap_or(self.paint_extent),
586            visible: self.visible.unwrap_or(self.paint_extent > 0.0),
587            has_visual_overflow: self.has_visual_overflow,
588            scroll_offset_correction: self.scroll_offset_correction,
589            cache_extent: self
590                .cache_extent
591                .or(self.layout_extent)
592                .unwrap_or(self.paint_extent),
593            cross_axis_extent: self.cross_axis_extent,
594        }
595    }
596}
597
598impl Default for SliverGeometry {
599    fn default() -> SliverGeometry {
600        SliverGeometry::builder().build()
601    }
602}
603
604impl Display for SliverGeometry {
605    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
606        write!(
607            f,
608            "SliverGeometry({}x{})",
609            self.scroll_extent, self.paint_extent
610        )
611    }
612}
613
614/// Method signature for hit testing a [`RenderSliver`].
615///
616/// Used by [`SliverHitTestResult::add_with_axis_offset`] to hit test [`RenderSliver`] children.
617///
618/// See also:
619///
620///  * [`RenderSliver::hit_test`], which documents more details around hit testing slivers.
621pub type SliverHitTest<'r> = dyn FnOnce(&mut SliverHitTestResult<'r>, f64, f64) -> bool;
622
623/// The result of performing a hit test on [`RenderSliver`]s.
624///
625/// A view over a [`HitTestResult`]: Dart's `SliverHitTestResult.wrap`. Dart's bare
626/// `SliverHitTestResult()` constructor is `wrap` over a fresh [`HitTestResult`].
627pub struct SliverHitTestResult<'a>(&'a mut HitTestResult);
628
629impl<'a> SliverHitTestResult<'a> {
630    /// Wraps `result` to create a [`SliverHitTestResult`] that shares its path.
631    ///
632    /// This is used by render objects that adapt between the sliver world and the non-sliver
633    /// world.
634    pub fn wrap(result: &'a mut HitTestResult) -> SliverHitTestResult<'a> {
635        SliverHitTestResult(result)
636    }
637
638    /// Transforms `main_axis_position` and `cross_axis_position` to the local coordinate system
639    /// of a child for hit-testing the child.
640    ///
641    /// The actual hit testing of the child needs to be implemented in the provided `hit_test`
642    /// callback, which is invoked with the transformed positions as arguments.
643    ///
644    /// For the transform `main_axis_offset` is subtracted from `main_axis_position` and
645    /// `cross_axis_offset` is subtracted from `cross_axis_position`.
646    ///
647    /// The `paint_offset` describes how the paint position of a point painted at the provided
648    /// `main_axis_position` and `cross_axis_position` would change after `main_axis_offset` and
649    /// `cross_axis_offset` have been applied. It is used to properly convert pointer events to
650    /// the local coordinate system of the event receiver.
651    ///
652    /// The `paint_offset` may be `None` if `main_axis_offset` and `cross_axis_offset` are both
653    /// zero.
654    ///
655    /// The function returns the return value of `hit_test`.
656    pub fn add_with_axis_offset(
657        &mut self,
658        paint_offset: Option<Offset>,
659        main_axis_offset: f64,
660        cross_axis_offset: f64,
661        main_axis_position: f64,
662        cross_axis_position: f64,
663        hit_test: impl FnOnce(&mut SliverHitTestResult<'_>, f64, f64) -> bool,
664    ) -> bool {
665        if let Some(paint_offset) = paint_offset {
666            self.0.push_offset(Offset::ZERO - paint_offset);
667        }
668        let is_hit = hit_test(
669            self,
670            main_axis_position - main_axis_offset,
671            cross_axis_position - cross_axis_offset,
672        );
673        if paint_offset.is_some() {
674            self.0.pop_transform();
675        }
676        is_hit
677    }
678}
679
680impl Deref for SliverHitTestResult<'_> {
681    type Target = HitTestResult;
682
683    fn deref(&self) -> &HitTestResult {
684        self.0
685    }
686}
687
688impl DerefMut for SliverHitTestResult<'_> {
689    fn deref_mut(&mut self) -> &mut HitTestResult {
690        self.0
691    }
692}
693
694/// A hit test entry used by [`RenderSliver`].
695///
696/// The coordinate system used by this hit test entry is relative to the [`AxisDirection`] of
697/// the target sliver.
698///
699/// Dart's `SliverHitTestEntry` subclasses `HitTestEntry`; here it is the entry's target,
700/// carrying the sliver and the two positions. It becomes a [`HitTestEntry`] with [`From`].
701#[derive(Clone, Copy, Debug)]
702pub struct SliverHitTestEntry {
703    target: AnyRenderSliver,
704    main_axis_position: f64,
705    cross_axis_position: f64,
706}
707
708impl SliverHitTestEntry {
709    /// Creates a sliver hit test entry.
710    pub fn new(
711        target: AnyRenderSliver,
712        main_axis_position: f64,
713        cross_axis_position: f64,
714    ) -> SliverHitTestEntry {
715        SliverHitTestEntry {
716            target,
717            main_axis_position,
718            cross_axis_position,
719        }
720    }
721
722    /// The [`RenderSliver`] that was hit.
723    pub fn target(&self) -> AnyRenderSliver {
724        self.target
725    }
726
727    /// The distance in the [`AxisDirection`] from the edge of the sliver's painted area (as
728    /// given by the [`SliverConstraints::scroll_offset`]) to the hit point.
729    ///
730    /// This can be an unusual direction, for example in the [`AxisDirection::Up`] case this is
731    /// a distance from the _bottom_ of the sliver's painted area.
732    pub fn main_axis_position(&self) -> f64 {
733        self.main_axis_position
734    }
735
736    /// The distance to the hit point in the axis opposite the [`SliverConstraints::axis`].
737    ///
738    /// If the cross axis is horizontal (i.e. the [`SliverConstraints::axis_direction`] is
739    /// either [`AxisDirection::Down`] or [`AxisDirection::Up`]), then this is a distance from
740    /// the left edge of the sliver. If the cross axis is vertical, then this is a distance
741    /// from the top edge of the sliver.
742    ///
743    /// This is always a distance from the left or top of the parent, never a distance from the
744    /// right or bottom.
745    pub fn cross_axis_position(&self) -> f64 {
746        self.cross_axis_position
747    }
748}
749
750impl HitTestTarget for SliverHitTestEntry {
751    fn retained_handle(&self) -> Option<HandleId> {
752        Some(self.target.id)
753    }
754
755    fn handle_event(&self, app: &mut App, event: &PointerEvent, _entry: &HitTestEntry) {
756        self.target.handle_event(app, event, self);
757    }
758}
759
760impl From<SliverHitTestEntry> for HitTestEntry {
761    fn from(entry: SliverHitTestEntry) -> HitTestEntry {
762        HitTestEntry::new(entry)
763    }
764}
765
766/// Parent data structure used by parents of slivers that position their children using layout
767/// offsets.
768///
769/// This data structure is optimized for fast layout. It is best used by parents that expect to
770/// have many children whose relative positions don't change even when the scroll offset does.
771#[derive(Clone, Copy, Debug, Default)]
772pub struct SliverLogicalParentData {
773    /// The position of the child relative to the zero scroll offset.
774    ///
775    /// The number of pixels from the zero scroll offset of the parent sliver (the line at
776    /// which its [`SliverConstraints::scroll_offset`] is zero) to the side of the child closest
777    /// to that offset. It can be `None` when it cannot be determined. The value will be set
778    /// after layout.
779    ///
780    /// In a typical list, this does not change as the parent is scrolled.
781    pub layout_offset: Option<f64>,
782}
783
784impl SliverLogicalParentData {
785    /// Creates parent data with no layout offset.
786    pub const fn new() -> SliverLogicalParentData {
787        SliverLogicalParentData {
788            layout_offset: None,
789        }
790    }
791}
792
793impl ParentData for SliverLogicalParentData {
794    fn provide(&self, id: TypeId) -> Option<&dyn Any> {
795        (id == TypeId::of::<SliverLogicalParentData>()).then_some(self)
796    }
797
798    fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
799        (id == TypeId::of::<SliverLogicalParentData>()).then_some(self)
800    }
801}
802
803impl Display for SliverLogicalParentData {
804    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
805        match self.layout_offset {
806            None => f.write_str("layoutOffset=None"),
807            Some(offset) => write!(f, "layoutOffset={offset:.1}"),
808        }
809    }
810}
811
812/// Parent data for slivers that have multiple children and that position their children using
813/// layout offsets.
814#[derive(Debug)]
815pub struct SliverLogicalContainerParentData {
816    sliver_logical: SliverLogicalParentData,
817    container: ContainerParentData<AnyRenderSliver>,
818}
819
820impl SliverLogicalContainerParentData {
821    /// Creates parent data with no layout offset and no siblings.
822    pub const fn new() -> SliverLogicalContainerParentData {
823        SliverLogicalContainerParentData {
824            sliver_logical: SliverLogicalParentData::new(),
825            container: ContainerParentData::new(),
826        }
827    }
828
829    /// The [`SliverLogicalParentData`] half.
830    pub fn sliver_logical_parent_data(&self) -> &SliverLogicalParentData {
831        &self.sliver_logical
832    }
833
834    /// See [`sliver_logical_parent_data`](Self::sliver_logical_parent_data).
835    pub fn sliver_logical_parent_data_mut(&mut self) -> &mut SliverLogicalParentData {
836        &mut self.sliver_logical
837    }
838
839    /// See [`SliverLogicalParentData::layout_offset`].
840    pub fn layout_offset(&self) -> Option<f64> {
841        self.sliver_logical.layout_offset
842    }
843
844    /// Sets [`layout_offset`](Self::layout_offset).
845    pub fn set_layout_offset(&mut self, value: Option<f64>) {
846        self.sliver_logical.layout_offset = value;
847    }
848}
849
850impl Default for SliverLogicalContainerParentData {
851    fn default() -> SliverLogicalContainerParentData {
852        SliverLogicalContainerParentData::new()
853    }
854}
855
856impl ParentData for SliverLogicalContainerParentData {
857    fn detach(&mut self) {
858        ContainerParentDataMixin::detach(self);
859    }
860
861    fn provide(&self, id: TypeId) -> Option<&dyn Any> {
862        if id == TypeId::of::<SliverLogicalContainerParentData>() {
863            return Some(self);
864        }
865        self.sliver_logical.provide(id)
866    }
867
868    fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
869        if id == TypeId::of::<SliverLogicalContainerParentData>() {
870            return Some(self);
871        }
872        self.sliver_logical.provide_mut(id)
873    }
874}
875
876impl ContainerParentDataMixin for SliverLogicalContainerParentData {
877    type ChildType = AnyRenderSliver;
878
879    fn container_parent_data(&self) -> &ContainerParentData<AnyRenderSliver> {
880        &self.container
881    }
882
883    fn container_parent_data_mut(&mut self) -> &mut ContainerParentData<AnyRenderSliver> {
884        &mut self.container
885    }
886}
887
888impl Display for SliverLogicalContainerParentData {
889    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
890        Display::fmt(&self.sliver_logical, f)
891    }
892}
893
894/// Parent data structure used by parents of slivers that position their children using absolute
895/// coordinates.
896///
897/// For example, used by [`crate::RenderViewport`].
898///
899/// This data structure is optimized for fast painting, at the cost of requiring additional work
900/// during layout when the children change their offsets. It is best used by parents that expect
901/// to have few children, especially if those children will themselves be very tall relative to
902/// the parent.
903#[derive(Clone, Copy, Debug)]
904pub struct SliverPhysicalParentData {
905    /// The position of the child relative to the parent.
906    ///
907    /// This is the distance from the top left visible corner of the parent to the top left
908    /// visible corner of the sliver.
909    pub paint_offset: Offset,
910
911    /// The cross axis flex factor to use for this sliver child.
912    ///
913    /// If used outside of a `SliverCrossAxisGroup` widget, this value has no meaning.
914    ///
915    /// If `None` or zero, the child is inflexible and determines its own size in the cross
916    /// axis. If non-zero, the amount of space the child can occupy in the cross axis is
917    /// determined by dividing the free space (after placing the inflexible children) according
918    /// to the flex factors of the flexible children.
919    pub cross_axis_flex: Option<i32>,
920}
921
922impl SliverPhysicalParentData {
923    /// Creates parent data with a zero paint offset.
924    pub const fn new() -> SliverPhysicalParentData {
925        SliverPhysicalParentData {
926            paint_offset: Offset::ZERO,
927            cross_axis_flex: None,
928        }
929    }
930
931    /// Apply the [`paint_offset`](Self::paint_offset) to the given `transform`.
932    ///
933    /// Used to implement [`RenderObject::apply_paint_transform`] by slivers that use
934    /// [`SliverPhysicalParentData`].
935    pub fn apply_paint_transform(&self, transform: &mut Matrix4) {
936        // Hit test logic relies on this always providing an invertible matrix.
937        translate(transform, self.paint_offset.dx(), self.paint_offset.dy());
938    }
939}
940
941impl Default for SliverPhysicalParentData {
942    fn default() -> SliverPhysicalParentData {
943        SliverPhysicalParentData::new()
944    }
945}
946
947impl ParentData for SliverPhysicalParentData {
948    fn provide(&self, id: TypeId) -> Option<&dyn Any> {
949        (id == TypeId::of::<SliverPhysicalParentData>()).then_some(self)
950    }
951
952    fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
953        (id == TypeId::of::<SliverPhysicalParentData>()).then_some(self)
954    }
955}
956
957impl Display for SliverPhysicalParentData {
958    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
959        write!(f, "paintOffset={:?}", self.paint_offset)
960    }
961}
962
963/// Parent data for slivers that have multiple children and that position their children using
964/// absolute coordinates.
965#[derive(Debug)]
966pub struct SliverPhysicalContainerParentData {
967    sliver_physical: SliverPhysicalParentData,
968    container: ContainerParentData<AnyRenderSliver>,
969}
970
971impl SliverPhysicalContainerParentData {
972    /// Creates parent data with a zero paint offset and no siblings.
973    pub const fn new() -> SliverPhysicalContainerParentData {
974        SliverPhysicalContainerParentData {
975            sliver_physical: SliverPhysicalParentData::new(),
976            container: ContainerParentData::new(),
977        }
978    }
979
980    /// The [`SliverPhysicalParentData`] half.
981    pub fn sliver_physical_parent_data(&self) -> &SliverPhysicalParentData {
982        &self.sliver_physical
983    }
984
985    /// See [`sliver_physical_parent_data`](Self::sliver_physical_parent_data).
986    pub fn sliver_physical_parent_data_mut(&mut self) -> &mut SliverPhysicalParentData {
987        &mut self.sliver_physical
988    }
989
990    /// See [`SliverPhysicalParentData::paint_offset`].
991    pub fn paint_offset(&self) -> Offset {
992        self.sliver_physical.paint_offset
993    }
994
995    /// Sets [`paint_offset`](Self::paint_offset).
996    pub fn set_paint_offset(&mut self, value: Offset) {
997        self.sliver_physical.paint_offset = value;
998    }
999
1000    /// See [`SliverPhysicalParentData::apply_paint_transform`].
1001    pub fn apply_paint_transform(&self, transform: &mut Matrix4) {
1002        self.sliver_physical.apply_paint_transform(transform);
1003    }
1004}
1005
1006impl Default for SliverPhysicalContainerParentData {
1007    fn default() -> SliverPhysicalContainerParentData {
1008        SliverPhysicalContainerParentData::new()
1009    }
1010}
1011
1012impl ParentData for SliverPhysicalContainerParentData {
1013    fn detach(&mut self) {
1014        ContainerParentDataMixin::detach(self);
1015    }
1016
1017    fn provide(&self, id: TypeId) -> Option<&dyn Any> {
1018        if id == TypeId::of::<SliverPhysicalContainerParentData>() {
1019            return Some(self);
1020        }
1021        self.sliver_physical.provide(id)
1022    }
1023
1024    fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
1025        if id == TypeId::of::<SliverPhysicalContainerParentData>() {
1026            return Some(self);
1027        }
1028        self.sliver_physical.provide_mut(id)
1029    }
1030}
1031
1032impl ContainerParentDataMixin for SliverPhysicalContainerParentData {
1033    type ChildType = AnyRenderSliver;
1034
1035    fn container_parent_data(&self) -> &ContainerParentData<AnyRenderSliver> {
1036        &self.container
1037    }
1038
1039    fn container_parent_data_mut(&mut self) -> &mut ContainerParentData<AnyRenderSliver> {
1040        &mut self.container
1041    }
1042}
1043
1044impl Display for SliverPhysicalContainerParentData {
1045    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1046        Display::fmt(&self.sliver_physical, f)
1047    }
1048}
1049
1050/// The body of [`RenderSliver::calculate_paint_offset`], reachable without a sliver.
1051pub(crate) fn calculate_paint_offset(constraints: SliverConstraints, from: f64, to: f64) -> f64 {
1052    debug_assert!(from <= to);
1053    let a = constraints.scroll_offset;
1054    let b = constraints.scroll_offset + constraints.remaining_paint_extent;
1055    // the clamp on the next line is to avoid floating point rounding errors
1056    clamp_double(
1057        clamp_double(to, a, b) - clamp_double(from, a, b),
1058        0.0,
1059        constraints.remaining_paint_extent,
1060    )
1061}
1062
1063/// The body of [`RenderSliver::calculate_cache_offset`], reachable without a sliver.
1064pub(crate) fn calculate_cache_offset(constraints: SliverConstraints, from: f64, to: f64) -> f64 {
1065    debug_assert!(from <= to);
1066    let a = constraints.scroll_offset + constraints.cache_origin;
1067    let b = constraints.scroll_offset + constraints.remaining_cache_extent;
1068    // the clamp on the next line is to avoid floating point rounding errors
1069    clamp_double(
1070        clamp_double(to, a, b) - clamp_double(from, a, b),
1071        0.0,
1072        constraints.remaining_cache_extent,
1073    )
1074}
1075
1076/// Flutter's `RenderSliver` fields.
1077pub struct RenderSliverData {
1078    pub(crate) geometry: Option<SliverGeometry>,
1079    pub(crate) constraints: Option<SliverConstraints>,
1080}
1081
1082impl RenderSliverData {
1083    /// Unlaid-out sliver state.
1084    pub fn new() -> RenderSliverData {
1085        RenderSliverData {
1086            geometry: None,
1087            constraints: None,
1088        }
1089    }
1090}
1091
1092impl Default for RenderSliverData {
1093    fn default() -> RenderSliverData {
1094        RenderSliverData::new()
1095    }
1096}
1097
1098/// Implements [`RenderSliver`] field accessors for a `render_sliver` field.
1099#[macro_export]
1100macro_rules! render_sliver_accessors {
1101    () => {
1102        fn render_sliver_data(
1103            self: $crate::RenderHandle<Self>,
1104            app: &::inset_foundation::App,
1105        ) -> &$crate::RenderSliverData {
1106            &self.get(app).render_sliver
1107        }
1108        fn render_sliver_data_mut(
1109            self: $crate::RenderHandle<Self>,
1110            app: &mut ::inset_foundation::App,
1111        ) -> &mut $crate::RenderSliverData {
1112            &mut self.get_mut(app).render_sliver
1113        }
1114    };
1115}
1116
1117/// A render object using the sliver protocol.
1118///
1119/// Flutter's counterpart is `RenderSliver`. [`RenderObject::perform_layout`] is the leaf
1120/// override; [`AnyRenderSliver::layout`] is the framework wrapper. `RenderObject`'s tree
1121/// operations are provided here and forward to [`as_object`](Self::as_object).
1122pub trait RenderSliver: RenderObject {
1123    /// Mixin field access.
1124    fn render_sliver_data(self: RenderHandle<Self>, app: &App) -> &RenderSliverData;
1125
1126    /// See [`render_sliver_data`](Self::render_sliver_data).
1127    fn render_sliver_data_mut(self: RenderHandle<Self>, app: &mut App) -> &mut RenderSliverData;
1128
1129    /// The sliver constraints most recently supplied by the parent.
1130    fn constraints(self: RenderHandle<Self>, app: &App) -> SliverConstraints {
1131        self.render_sliver_data(app).constraints.unwrap_or_else(|| {
1132            panic!("A RenderObject does not have any constraints before it has been laid out.")
1133        })
1134    }
1135
1136    /// The amount of space this sliver occupies.
1137    fn geometry(self: RenderHandle<Self>, app: &App) -> SliverGeometry {
1138        self.as_sliver().geometry(app)
1139    }
1140
1141    /// Sets the geometry of this sliver. Call from [`RenderObject::perform_layout`].
1142    fn set_geometry(self: RenderHandle<Self>, app: &mut App, geometry: SliverGeometry) {
1143        self.as_sliver().set_geometry(app, geometry)
1144    }
1145
1146    /// An estimate of the bounds within which this render object will paint: the paint extent
1147    /// along the main axis by the cross axis extent.
1148    fn paint_bounds(self: RenderHandle<Self>, app: &App) -> Rect {
1149        let constraints = self.constraints(app);
1150        let geometry = self.geometry(app);
1151        match constraints.axis() {
1152            Axis::Horizontal => Rect::from_ltwh(
1153                0.0,
1154                0.0,
1155                geometry.paint_extent,
1156                constraints.cross_axis_extent,
1157            ),
1158            Axis::Vertical => Rect::from_ltwh(
1159                0.0,
1160                0.0,
1161                constraints.cross_axis_extent,
1162                geometry.paint_extent,
1163            ),
1164        }
1165    }
1166
1167    /// For a center sliver, the distance before the absolute zero scroll offset that this
1168    /// sliver can cover.
1169    ///
1170    /// For example, if an [`AxisDirection::Down`] viewport with a
1171    /// [`crate::RenderViewport::anchor`] of 0.5 has a single sliver with a height of 100.0 and
1172    /// its `center_offset_adjustment` returns 50.0, then the sliver will be centered in the
1173    /// viewport when the scroll offset is 0.0.
1174    ///
1175    /// The distance here is in the opposite direction of the viewport's axis direction, so
1176    /// values will typically be positive.
1177    fn center_offset_adjustment(self: RenderHandle<Self>, _app: &App) -> f64 {
1178        let _ = self;
1179        0.0
1180    }
1181
1182    /// Determines the set of render objects located at the given position.
1183    ///
1184    /// Returns true if the given point is contained in this render object or one of its
1185    /// descendants. Adds any render objects that contain the point to the given hit test
1186    /// result.
1187    ///
1188    /// The caller is responsible for providing the position in the local coordinate space of
1189    /// the callee. The callee is responsible for checking whether the given position is within
1190    /// its bounds.
1191    ///
1192    /// # Coordinates for `RenderSliver` objects
1193    ///
1194    /// The `main_axis_position` is the distance in the [`AxisDirection`] (after applying the
1195    /// [`GrowthDirection`]) from the edge of the sliver's painted area. This can be an unusual
1196    /// direction, for example in the [`AxisDirection::Up`] case this is a distance from the
1197    /// _bottom_ of the sliver's painted area.
1198    ///
1199    /// The `cross_axis_position` is the distance in the other axis. If the cross axis is
1200    /// horizontal (i.e. the [`SliverConstraints::axis_direction`] is either
1201    /// [`AxisDirection::Down`] or [`AxisDirection::Up`]), then the `cross_axis_position` is a
1202    /// distance from the left edge of the sliver. Otherwise it is a distance from the top edge.
1203    ///
1204    /// # Implementing hit testing for slivers
1205    ///
1206    /// The most straight-forward way to implement hit testing for a new sliver render object is
1207    /// to override its [`hit_test_self`](Self::hit_test_self) and
1208    /// [`hit_test_children`](Self::hit_test_children) methods.
1209    fn hit_test(
1210        self: RenderHandle<Self>,
1211        app: &mut App,
1212        result: &mut SliverHitTestResult<'_>,
1213        main_axis_position: f64,
1214        cross_axis_position: f64,
1215    ) -> bool {
1216        if main_axis_position >= 0.0
1217            && main_axis_position < self.geometry(app).hit_test_extent
1218            && cross_axis_position >= 0.0
1219            && cross_axis_position < self.constraints(app).cross_axis_extent
1220            && (self.hit_test_children(app, result, main_axis_position, cross_axis_position)
1221                || self.hit_test_self(app, main_axis_position, cross_axis_position))
1222        {
1223            result.add(
1224                SliverHitTestEntry::new(self.as_sliver(), main_axis_position, cross_axis_position)
1225                    .into(),
1226            );
1227            return true;
1228        }
1229        false
1230    }
1231
1232    /// Override this method if this render object can be hit even if its children were not hit.
1233    ///
1234    /// Used by [`hit_test`](Self::hit_test). If you override `hit_test` and do not call this
1235    /// function, then you don't need to implement this function.
1236    fn hit_test_self(
1237        self: RenderHandle<Self>,
1238        _app: &App,
1239        _main_axis_position: f64,
1240        _cross_axis_position: f64,
1241    ) -> bool {
1242        let _ = self;
1243        false
1244    }
1245
1246    /// Override this method to check whether any children are located at the given position.
1247    ///
1248    /// Typically children should be hit-tested in reverse paint order so that hit tests at
1249    /// locations where children overlap hit the child that is visually "on top" (i.e., paints
1250    /// later).
1251    ///
1252    /// Used by [`hit_test`](Self::hit_test). If you override `hit_test` and do not call this
1253    /// function, then you don't need to implement this function.
1254    fn hit_test_children(
1255        self: RenderHandle<Self>,
1256        _app: &mut App,
1257        _result: &mut SliverHitTestResult<'_>,
1258        _main_axis_position: f64,
1259        _cross_axis_position: f64,
1260    ) -> bool {
1261        let _ = self;
1262        false
1263    }
1264
1265    /// Override to handle pointer events that hit this render object.
1266    fn handle_event(
1267        self: RenderHandle<Self>,
1268        _app: &mut App,
1269        _event: &PointerEvent,
1270        _entry: &SliverHitTestEntry,
1271    ) {
1272        let _ = self;
1273    }
1274
1275    /// Computes the portion of the region from `from` to `to` that is visible, assuming that
1276    /// only the region from the [`SliverConstraints::scroll_offset`] that is
1277    /// [`SliverConstraints::remaining_paint_extent`] high is visible, and that the relationship
1278    /// between scroll offsets and paint offsets is linear.
1279    ///
1280    /// For example, if the constraints have a scroll offset of 100 and a remaining paint extent
1281    /// of 100, and the arguments to this method describe the region 50..150, then the returned
1282    /// value would be 50 (from scroll offset 100 to scroll offset 150).
1283    ///
1284    /// This method is not useful if there is not a 1:1 relationship between consumed scroll
1285    /// offset and consumed paint extent.
1286    fn calculate_paint_offset(
1287        self: RenderHandle<Self>,
1288        _app: &App,
1289        constraints: SliverConstraints,
1290        from: f64,
1291        to: f64,
1292    ) -> f64 {
1293        let _ = self;
1294        calculate_paint_offset(constraints, from, to)
1295    }
1296
1297    /// Computes the portion of the region from `from` to `to` that is within the cache extent
1298    /// of the viewport, assuming that only the region from the
1299    /// [`SliverConstraints::cache_origin`] that is
1300    /// [`SliverConstraints::remaining_cache_extent`] high is visible, and that the relationship
1301    /// between scroll offsets and paint offsets is linear.
1302    ///
1303    /// This method is not useful if there is not a 1:1 relationship between consumed scroll
1304    /// offset and consumed cache extent.
1305    fn calculate_cache_offset(
1306        self: RenderHandle<Self>,
1307        _app: &App,
1308        constraints: SliverConstraints,
1309        from: f64,
1310        to: f64,
1311    ) -> f64 {
1312        let _ = self;
1313        calculate_cache_offset(constraints, from, to)
1314    }
1315
1316    /// Returns the distance from the leading _visible_ edge of the sliver to the side of the
1317    /// given child closest to that edge.
1318    ///
1319    /// For example, if the [`constraints`](Self::constraints) describe this sliver as having an
1320    /// axis direction of [`AxisDirection::Down`], then this is the distance from the top of the
1321    /// visible portion of the sliver to the top of the child. On the other hand, if the axis
1322    /// direction is [`AxisDirection::Up`], then this is the distance from the bottom of the
1323    /// visible portion of the sliver to the bottom of the child. In both cases, this is the
1324    /// direction of increasing [`SliverConstraints::scroll_offset`] and
1325    /// [`SliverLogicalParentData::layout_offset`].
1326    ///
1327    /// For children that are slivers, the leading edge of the _child_ will be the leading
1328    /// _visible_ edge of the child, not the part of the child that would locally be at scroll
1329    /// offset 0.0. For box children it is the actual distance to the edge of the box, since
1330    /// those boxes do not know how to handle being scrolled.
1331    ///
1332    /// This method differs from [`child_scroll_offset`](Self::child_scroll_offset) in that it
1333    /// gives the distance from the leading _visible_ edge of the sliver whereas
1334    /// `child_scroll_offset` gives the distance from the sliver's zero scroll offset.
1335    ///
1336    /// Calling this for a child that is not visible is not valid.
1337    fn child_main_axis_position(
1338        self: RenderHandle<Self>,
1339        _app: &App,
1340        _child: AnyRenderObject,
1341    ) -> f64 {
1342        let _ = self;
1343        panic!("this RenderSliver does not implement child_main_axis_position")
1344    }
1345
1346    /// Returns the distance along the cross axis from the zero of the cross axis in this
1347    /// sliver's paint coordinate space to the nearest side of the given child.
1348    ///
1349    /// For example, if the [`constraints`](Self::constraints) describe this sliver as having an
1350    /// axis direction of [`AxisDirection::Down`] or [`AxisDirection::Up`], then this is the
1351    /// distance from the left of the sliver to the left of the child. If the axis direction is
1352    /// [`AxisDirection::Left`] or [`AxisDirection::Right`], then it is the distance from the
1353    /// top of the sliver to the top of the child.
1354    ///
1355    /// Calling this for a child that is not visible is not valid.
1356    fn child_cross_axis_position(
1357        self: RenderHandle<Self>,
1358        _app: &App,
1359        _child: AnyRenderObject,
1360    ) -> f64 {
1361        let _ = self;
1362        0.0
1363    }
1364
1365    /// Returns the scroll offset for the leading edge of the given child.
1366    ///
1367    /// The `child` must be a child of this sliver.
1368    ///
1369    /// If there are pinned slivers before `child`, the offset should be reduced by the extent
1370    /// of the pinned children.
1371    ///
1372    /// This method differs from [`child_main_axis_position`](Self::child_main_axis_position) in
1373    /// that `child_main_axis_position` gives the distance from the leading _visible_ edge of
1374    /// the sliver whereas this gives the distance from the sliver's zero scroll offset.
1375    fn child_scroll_offset(
1376        self: RenderHandle<Self>,
1377        app: &App,
1378        child: AnyRenderObject,
1379    ) -> Option<f64> {
1380        debug_assert_eq!(child.parent(app), Some(self.as_object()));
1381        Some(0.0)
1382    }
1383
1384    /// This returns a [`Size`] with dimensions relative to the leading edge of the sliver,
1385    /// specifically the same offset that is given to the [`RenderObject::paint`] method. This
1386    /// means that the dimensions may be negative.
1387    ///
1388    /// This is only valid after layout has completed.
1389    ///
1390    /// See also:
1391    ///
1392    ///  * [`get_absolute_size`](Self::get_absolute_size), which returns absolute size.
1393    fn get_absolute_size_relative_to_origin(self: RenderHandle<Self>, app: &App) -> Size {
1394        debug_assert!(!self.as_object().debug_needs_layout(app));
1395        let constraints = self.constraints(app);
1396        let paint_extent = self.geometry(app).paint_extent;
1397        match apply_growth_direction_to_axis_direction(
1398            constraints.axis_direction,
1399            constraints.growth_direction,
1400        ) {
1401            AxisDirection::Up => Size::new(constraints.cross_axis_extent, -paint_extent),
1402            AxisDirection::Down => Size::new(constraints.cross_axis_extent, paint_extent),
1403            AxisDirection::Left => Size::new(-paint_extent, constraints.cross_axis_extent),
1404            AxisDirection::Right => Size::new(paint_extent, constraints.cross_axis_extent),
1405        }
1406    }
1407
1408    /// This returns the absolute [`Size`] of the sliver.
1409    ///
1410    /// The dimensions are always positive and calling this is only valid after layout has
1411    /// completed.
1412    ///
1413    /// See also:
1414    ///
1415    ///  * [`get_absolute_size_relative_to_origin`](Self::get_absolute_size_relative_to_origin),
1416    ///    which returns the size relative to the leading edge of the sliver.
1417    fn get_absolute_size(self: RenderHandle<Self>, app: &App) -> Size {
1418        debug_assert!(!self.as_object().debug_needs_layout(app));
1419        let constraints = self.constraints(app);
1420        let paint_extent = self.geometry(app).paint_extent;
1421        match constraints.axis_direction {
1422            AxisDirection::Up | AxisDirection::Down => {
1423                Size::new(constraints.cross_axis_extent, paint_extent)
1424            }
1425            AxisDirection::Right | AxisDirection::Left => {
1426                Size::new(paint_extent, constraints.cross_axis_extent)
1427            }
1428        }
1429    }
1430
1431    /// Returns the [`Rect`] that covers the total paint extent of the sliver.
1432    ///
1433    /// The rect is expressed in the sliver's local coordinate system, which is axis-aligned
1434    /// with the painting context's canvas. The coordinate system's origin (0,0) corresponds to
1435    /// the `offset` argument passed to [`RenderObject::paint`].
1436    fn get_max_paint_rect(self: RenderHandle<Self>, app: &App) -> Rect {
1437        let Some(geometry) = self.render_sliver_data(app).geometry else {
1438            return Rect::ZERO;
1439        };
1440        if geometry.is_zero() {
1441            return Rect::ZERO;
1442        }
1443        let constraints = self.constraints(app);
1444        let mut max_paint_extent = geometry.max_paint_extent;
1445        if max_paint_extent.is_infinite() {
1446            max_paint_extent =
1447                constraints.scroll_offset + geometry.cache_extent + constraints.cache_origin;
1448        }
1449        let paint_extent = geometry.paint_extent;
1450        // To ensure the computed rect remains visible when pinned, the leading offset is capped
1451        // at the sliver's `scroll_extent - max_scroll_obstruction_extent`.
1452        let leading_offset = clamp_double(
1453            constraints.scroll_offset,
1454            0.0,
1455            geometry.scroll_extent - geometry.max_scroll_obstruction_extent,
1456        );
1457        let cross_axis_extent = geometry
1458            .cross_axis_extent
1459            .unwrap_or(constraints.cross_axis_extent);
1460
1461        let rect = match constraints.axis() {
1462            Axis::Horizontal => {
1463                Rect::from_ltwh(-leading_offset, 0.0, max_paint_extent, cross_axis_extent)
1464            }
1465            Axis::Vertical => {
1466                Rect::from_ltwh(0.0, -leading_offset, cross_axis_extent, max_paint_extent)
1467            }
1468        };
1469
1470        match apply_growth_direction_to_axis_direction(
1471            constraints.axis_direction,
1472            constraints.growth_direction,
1473        ) {
1474            AxisDirection::Right | AxisDirection::Down => rect,
1475            AxisDirection::Left => Rect::from_ltrb(
1476                paint_extent - rect.right,
1477                rect.top,
1478                paint_extent - rect.left,
1479                rect.bottom,
1480            ),
1481            AxisDirection::Up => Rect::from_ltrb(
1482                rect.left,
1483                paint_extent - rect.bottom,
1484                rect.right,
1485                paint_extent - rect.top,
1486            ),
1487        }
1488    }
1489
1490    /// See [`AnyRenderSliver::layout`].
1491    fn layout(
1492        self: RenderHandle<Self>,
1493        app: &mut App,
1494        constraints: SliverConstraints,
1495        parent_uses_size: bool,
1496    ) {
1497        self.as_sliver().layout(app, constraints, parent_uses_size)
1498    }
1499
1500    /// The type-erased `RenderSliver` handle. Free: the vtable is a `const`, and the id is copied.
1501    fn as_sliver(self: RenderHandle<Self>) -> AnyRenderSliver {
1502        AnyRenderSliver {
1503            id: self.id(),
1504            vtable: const { &RenderSliverVTable::of::<Self>() },
1505        }
1506    }
1507
1508    /// The type-erased `RenderObject` handle, through [`as_sliver`](Self::as_sliver).
1509    fn as_object(self: RenderHandle<Self>) -> AnyRenderObject {
1510        self.as_sliver().as_object()
1511    }
1512
1513    /// See [`AnyRenderObject::adopt_child`].
1514    fn adopt_child(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1515        self.as_object().adopt_child(app, child)
1516    }
1517
1518    /// See [`AnyRenderObject::drop_child`].
1519    fn drop_child(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1520        self.as_object().drop_child(app, child)
1521    }
1522
1523    /// See [`AnyRenderObject::mark_needs_layout`].
1524    fn mark_needs_layout(self: RenderHandle<Self>, app: &mut App) {
1525        self.as_object().mark_needs_layout(app)
1526    }
1527
1528    /// See [`AnyRenderObject::mark_needs_paint`].
1529    fn mark_needs_paint(self: RenderHandle<Self>, app: &mut App) {
1530        self.as_object().mark_needs_paint(app)
1531    }
1532
1533    /// See [`AnyRenderObject::mark_needs_composited_layer_update`].
1534    fn mark_needs_composited_layer_update(self: RenderHandle<Self>, app: &mut App) {
1535        self.as_object().mark_needs_composited_layer_update(app)
1536    }
1537
1538    /// See [`AnyRenderObject::schedule_initial_layout`].
1539    fn schedule_initial_layout(self: RenderHandle<Self>, app: &mut App) {
1540        self.as_object().schedule_initial_layout(app)
1541    }
1542
1543    /// See [`AnyRenderObject::parent`].
1544    fn parent(self: RenderHandle<Self>, app: &App) -> Option<AnyRenderObject> {
1545        self.as_object().parent(app)
1546    }
1547
1548    /// See [`AnyRenderObject::owner`].
1549    fn owner(self: RenderHandle<Self>, app: &App) -> Option<Handle<PipelineOwner>> {
1550        self.as_object().owner(app)
1551    }
1552
1553    /// See [`AnyRenderObject::attached`].
1554    fn attached(self: RenderHandle<Self>, app: &App) -> bool {
1555        self.as_object().attached(app)
1556    }
1557
1558    /// See [`AnyRenderObject::debug_needs_layout`].
1559    fn debug_needs_layout(self: RenderHandle<Self>, app: &App) -> bool {
1560        self.as_object().debug_needs_layout(app)
1561    }
1562}
1563
1564/// The vtable of an [`AnyRenderSliver`]: the object vtable plus the sliver accessors.
1565pub(crate) struct RenderSliverVTable {
1566    pub object: RenderObjectVTable,
1567    pub sliver_data: fn(&App, HandleId) -> &RenderSliverData,
1568    pub sliver_data_mut: fn(&mut App, HandleId) -> &mut RenderSliverData,
1569    pub hit_test: fn(&mut App, HandleId, &mut SliverHitTestResult<'_>, f64, f64) -> bool,
1570    pub handle_event: fn(&mut App, HandleId, &PointerEvent, &SliverHitTestEntry),
1571    pub center_offset_adjustment: fn(&App, HandleId) -> f64,
1572    pub child_scroll_offset: fn(&App, HandleId, AnyRenderObject) -> Option<f64>,
1573    pub child_main_axis_position: fn(&App, HandleId, AnyRenderObject) -> f64,
1574}
1575
1576impl RenderSliverVTable {
1577    const fn of<T: RenderSliver>() -> RenderSliverVTable {
1578        RenderSliverVTable {
1579            object: RenderObjectVTable::of::<T>(
1580                |app, id, child| <T as RenderObject>::setup_parent_data(resolve(id), app, child),
1581                |app, id| T::paint_bounds(resolve(id), app),
1582                |app, id, child, transform| {
1583                    <T as RenderObject>::apply_paint_transform(resolve(id), app, child, transform)
1584                },
1585                |app, id| <T as RenderObject>::perform_resize(resolve(id), app),
1586                |app, id| crate::object::RenderObjectBase::mark_needs_layout(resolve::<T>(id), app),
1587                None,
1588                Some(|| const { &RenderSliverVTable::of::<T>() }),
1589            ),
1590            sliver_data: |app, id| T::render_sliver_data(resolve(id), app),
1591            sliver_data_mut: |app, id| T::render_sliver_data_mut(resolve(id), app),
1592            hit_test: |app, id, result, main, cross| {
1593                T::hit_test(resolve(id), app, result, main, cross)
1594            },
1595            handle_event: |app, id, event, entry| T::handle_event(resolve(id), app, event, entry),
1596            center_offset_adjustment: |app, id| T::center_offset_adjustment(resolve(id), app),
1597            child_scroll_offset: |app, id, child| T::child_scroll_offset(resolve(id), app, child),
1598            child_main_axis_position: |app, id, child| {
1599                T::child_main_axis_position(resolve(id), app, child)
1600            },
1601        }
1602    }
1603}
1604
1605impl<T: RenderSliver> RenderHandle<T> {
1606    /// Creates a sliver-protocol render object in `app`.
1607    pub fn new_sliver(app: &mut App, object: T) -> RenderHandle<T> {
1608        let this = create(app, object);
1609        let data = this.render_object_data_mut(app);
1610        data.object_vtable = Some(&const { RenderSliverVTable::of::<T>() }.object);
1611        // Flutter's `RenderObject()` constructor:
1612        // `_needsCompositing = isRepaintBoundary || alwaysNeedsCompositing` and
1613        // `_wasRepaintBoundary = isRepaintBoundary`.
1614        let is_repaint_boundary = this.is_repaint_boundary(app);
1615        let always_needs_compositing = this.always_needs_compositing(app);
1616        let data = this.render_object_data_mut(app);
1617        data.was_repaint_boundary = is_repaint_boundary;
1618        data.needs_compositing = is_repaint_boundary || always_needs_compositing;
1619        this
1620    }
1621}
1622
1623/// Erased `RenderSliver`.
1624#[derive(Clone, Copy)]
1625pub struct AnyRenderSliver {
1626    id: HandleId,
1627    vtable: &'static RenderSliverVTable,
1628}
1629
1630impl PartialEq for AnyRenderSliver {
1631    fn eq(&self, other: &AnyRenderSliver) -> bool {
1632        self.id == other.id
1633    }
1634}
1635
1636impl Eq for AnyRenderSliver {}
1637
1638impl std::hash::Hash for AnyRenderSliver {
1639    fn hash<H: Hasher>(&self, state: &mut H) {
1640        self.id.hash(state);
1641    }
1642}
1643
1644impl Debug for AnyRenderSliver {
1645    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1646        write!(f, "AnyRenderSliver({:?})", self.id)
1647    }
1648}
1649
1650impl AnyRenderSliver {
1651    pub(crate) fn from_vtable(
1652        id: HandleId,
1653        vtable: &'static RenderSliverVTable,
1654    ) -> AnyRenderSliver {
1655        AnyRenderSliver { id, vtable }
1656    }
1657
1658    /// The `RenderObject` view of this sliver. Free: points into the nested table.
1659    pub fn as_object(self) -> AnyRenderObject {
1660        AnyRenderObject::from_vtable(self.id, &self.vtable.object)
1661    }
1662
1663    fn sliver_data(self, app: &App) -> &RenderSliverData {
1664        (self.vtable.sliver_data)(app, self.id)
1665    }
1666
1667    fn sliver_data_mut(self, app: &mut App) -> &mut RenderSliverData {
1668        (self.vtable.sliver_data_mut)(app, self.id)
1669    }
1670
1671    /// Compute the layout for this sliver.
1672    pub fn layout(self, app: &mut App, constraints: SliverConstraints, parent_uses_size: bool) {
1673        debug_assert!(constraints.debug_assert_is_valid(true));
1674        let same = self.sliver_data(app).constraints == Some(constraints);
1675        self.as_object()
1676            .run_layout(app, parent_uses_size, constraints.is_tight(), same, |app| {
1677                self.sliver_data_mut(app).constraints = Some(constraints)
1678            });
1679    }
1680
1681    /// The sliver constraints most recently supplied by the parent.
1682    ///
1683    /// # Panics
1684    ///
1685    /// If this sliver has not been laid out.
1686    pub fn constraints(self, app: &App) -> SliverConstraints {
1687        self.sliver_data(app).constraints.unwrap_or_else(|| {
1688            panic!("A RenderObject does not have any constraints before it has been laid out.")
1689        })
1690    }
1691
1692    /// See [`RenderSliver::hit_test`].
1693    pub fn hit_test(
1694        self,
1695        app: &mut App,
1696        result: &mut SliverHitTestResult<'_>,
1697        main_axis_position: f64,
1698        cross_axis_position: f64,
1699    ) -> bool {
1700        (self.vtable.hit_test)(
1701            app,
1702            self.id,
1703            result,
1704            main_axis_position,
1705            cross_axis_position,
1706        )
1707    }
1708
1709    /// See [`RenderSliver::handle_event`].
1710    pub fn handle_event(self, app: &mut App, event: &PointerEvent, entry: &SliverHitTestEntry) {
1711        (self.vtable.handle_event)(app, self.id, event, entry)
1712    }
1713
1714    /// See [`RenderSliver::center_offset_adjustment`].
1715    pub fn center_offset_adjustment(self, app: &App) -> f64 {
1716        (self.vtable.center_offset_adjustment)(app, self.id)
1717    }
1718
1719    /// See [`RenderSliver::child_scroll_offset`].
1720    pub fn child_scroll_offset(self, app: &App, child: AnyRenderObject) -> Option<f64> {
1721        (self.vtable.child_scroll_offset)(app, self.id, child)
1722    }
1723
1724    /// See [`RenderSliver::child_main_axis_position`].
1725    pub fn child_main_axis_position(self, app: &App, child: AnyRenderObject) -> f64 {
1726        (self.vtable.child_main_axis_position)(app, self.id, child)
1727    }
1728
1729    /// The amount of space this sliver occupies.
1730    ///
1731    /// # Panics
1732    ///
1733    /// If this sliver has not been laid out.
1734    pub fn geometry(self, app: &App) -> SliverGeometry {
1735        self.sliver_data(app)
1736            .geometry
1737            .unwrap_or_else(|| panic!("RenderSliver was not laid out: {self:?}"))
1738    }
1739
1740    /// Sets the geometry of this sliver.
1741    pub fn set_geometry(self, app: &mut App, geometry: SliverGeometry) {
1742        self.sliver_data_mut(app).geometry = Some(geometry);
1743    }
1744}
1745
1746impl crate::object::ErasedRenderObject for AnyRenderSliver {
1747    fn as_object(self) -> AnyRenderObject {
1748        AnyRenderSliver::as_object(self)
1749    }
1750
1751    fn from_object(object: AnyRenderObject) -> AnyRenderSliver {
1752        object
1753            .as_sliver()
1754            .expect("the render object is not a RenderSliver")
1755    }
1756}
1757
1758impl From<AnyRenderSliver> for AnyRenderObject {
1759    fn from(sliver: AnyRenderSliver) -> AnyRenderObject {
1760        sliver.as_object()
1761    }
1762}
1763
1764/// Whether the sliver's growth direction and axis direction agree, so that a box child is
1765/// positioned from the sliver's leading edge.
1766///
1767/// Flutter's private `RenderSliverHelpers._getRightWayUp`.
1768fn get_right_way_up(constraints: SliverConstraints) -> bool {
1769    let reversed = axis_direction_is_reversed(constraints.axis_direction);
1770    match constraints.growth_direction {
1771        GrowthDirection::Forward => !reversed,
1772        GrowthDirection::Reverse => reversed,
1773    }
1774}
1775
1776/// Mixin for [`RenderSliver`] subclasses that provides some utility functions.
1777pub trait RenderSliverHelpers: RenderSliver {
1778    /// Utility function for [`RenderSliver::hit_test_children`] for use when the children are
1779    /// [`crate::RenderBox`] widgets.
1780    ///
1781    /// This function takes care of converting the position from the sliver coordinate system to
1782    /// the Cartesian coordinate system used by the box protocol.
1783    ///
1784    /// This function relies on [`RenderSliver::child_main_axis_position`] to determine the
1785    /// position of the child in question.
1786    ///
1787    /// Calling this for a child that is not visible is not valid.
1788    fn hit_test_box_child(
1789        self: RenderHandle<Self>,
1790        app: &mut App,
1791        result: &mut BoxHitTestResult<'_>,
1792        child: AnyRenderBox,
1793        main_axis_position: f64,
1794        cross_axis_position: f64,
1795    ) -> bool {
1796        let constraints = self.constraints(app);
1797        let right_way_up = get_right_way_up(constraints);
1798        let mut delta = self.child_main_axis_position(app, child.as_object());
1799        let cross_axis_delta = self.child_cross_axis_position(app, child.as_object());
1800        let mut absolute_position = main_axis_position - delta;
1801        let absolute_cross_axis_position = cross_axis_position - cross_axis_delta;
1802        let size = child.size(app);
1803        let paint_extent = self.geometry(app).paint_extent;
1804        let (paint_offset, transformed_position) = match constraints.axis() {
1805            Axis::Horizontal => {
1806                if !right_way_up {
1807                    absolute_position = size.width() - absolute_position;
1808                    delta = paint_extent - size.width() - delta;
1809                }
1810                (
1811                    Offset::new(delta, cross_axis_delta),
1812                    Offset::new(absolute_position, absolute_cross_axis_position),
1813                )
1814            }
1815            Axis::Vertical => {
1816                if !right_way_up {
1817                    absolute_position = size.height() - absolute_position;
1818                    delta = paint_extent - size.height() - delta;
1819                }
1820                (
1821                    Offset::new(cross_axis_delta, delta),
1822                    Offset::new(absolute_cross_axis_position, absolute_position),
1823                )
1824            }
1825        };
1826        result.add_with_out_of_band_position(Some(paint_offset), None, None, |result| {
1827            child.hit_test(app, result, transformed_position)
1828        })
1829    }
1830
1831    /// Utility function for [`RenderObject::apply_paint_transform`] for use when the children
1832    /// are [`crate::RenderBox`] widgets.
1833    ///
1834    /// This function turns the value returned by [`RenderSliver::child_main_axis_position`] and
1835    /// [`RenderSliver::child_cross_axis_position`] for the child in question into a translation
1836    /// that it then applies to the given matrix.
1837    ///
1838    /// Calling this for a child that is not visible is not valid.
1839    fn apply_paint_transform_for_box_child(
1840        self: RenderHandle<Self>,
1841        app: &App,
1842        child: AnyRenderBox,
1843        transform: &mut Matrix4,
1844    ) {
1845        let constraints = self.constraints(app);
1846        let right_way_up = get_right_way_up(constraints);
1847        let mut delta = self.child_main_axis_position(app, child.as_object());
1848        let cross_axis_delta = self.child_cross_axis_position(app, child.as_object());
1849        let size = child.size(app);
1850        let paint_extent = self.geometry(app).paint_extent;
1851        match constraints.axis() {
1852            Axis::Horizontal => {
1853                if !right_way_up {
1854                    delta = paint_extent - size.width() - delta;
1855                }
1856                translate(transform, delta, cross_axis_delta);
1857            }
1858            Axis::Vertical => {
1859                if !right_way_up {
1860                    delta = paint_extent - size.height() - delta;
1861                }
1862                translate(transform, cross_axis_delta, delta);
1863            }
1864        }
1865    }
1866}
1867
1868// ADAPTER FOR RENDER BOXES INSIDE SLIVERS
1869// Transitions from the RenderSliver world to the RenderBox world.
1870
1871/// A [`RenderSliver`] that contains a single [`crate::RenderBox`].
1872///
1873/// See also:
1874///
1875///  * [`RenderSliverToBoxAdapter`], which implements this trait to size the child according to
1876///    its preferred size.
1877pub trait RenderSliverSingleBoxAdapter:
1878    RenderSliver + RenderObjectWithChildMixin<ChildType = AnyRenderBox> + RenderSliverHelpers
1879{
1880    /// The body of Flutter's `setupParentData` override; call it from
1881    /// [`RenderObject::setup_parent_data`].
1882    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
1883        if !child.parent_data_is::<SliverPhysicalParentData>(app) {
1884            child.set_parent_data(app, SliverPhysicalParentData::new());
1885        }
1886    }
1887
1888    /// Sets the [`SliverPhysicalParentData::paint_offset`] for the given child according to the
1889    /// [`SliverConstraints::axis_direction`] and [`SliverConstraints::growth_direction`] and
1890    /// the given geometry.
1891    fn set_child_parent_data(
1892        self: RenderHandle<Self>,
1893        app: &mut App,
1894        child: AnyRenderObject,
1895        constraints: SliverConstraints,
1896        geometry: SliverGeometry,
1897    ) {
1898        let paint_offset = match apply_growth_direction_to_axis_direction(
1899            constraints.axis_direction,
1900            constraints.growth_direction,
1901        ) {
1902            AxisDirection::Up => Offset::new(
1903                0.0,
1904                geometry.paint_extent + constraints.scroll_offset - geometry.scroll_extent,
1905            ),
1906            AxisDirection::Left => Offset::new(
1907                geometry.paint_extent + constraints.scroll_offset - geometry.scroll_extent,
1908                0.0,
1909            ),
1910            AxisDirection::Right => Offset::new(-constraints.scroll_offset, 0.0),
1911            AxisDirection::Down => Offset::new(0.0, -constraints.scroll_offset),
1912        };
1913        child
1914            .parent_data_of_mut::<SliverPhysicalParentData>(app)
1915            .paint_offset = paint_offset;
1916    }
1917
1918    /// The body of Flutter's `hitTestChildren` override.
1919    fn hit_test_children(
1920        self: RenderHandle<Self>,
1921        app: &mut App,
1922        result: &mut SliverHitTestResult<'_>,
1923        main_axis_position: f64,
1924        cross_axis_position: f64,
1925    ) -> bool {
1926        debug_assert!(self.geometry(app).hit_test_extent > 0.0);
1927        let Some(child) = self.child(app) else {
1928            return false;
1929        };
1930        self.hit_test_box_child(
1931            app,
1932            &mut BoxHitTestResult::wrap(result),
1933            child,
1934            main_axis_position,
1935            cross_axis_position,
1936        )
1937    }
1938
1939    /// The body of Flutter's `childMainAxisPosition` override.
1940    fn child_main_axis_position(
1941        self: RenderHandle<Self>,
1942        app: &App,
1943        child: AnyRenderObject,
1944    ) -> f64 {
1945        debug_assert_eq!(Some(child), self.child(app).map(AnyRenderBox::as_object));
1946        -self.constraints(app).scroll_offset
1947    }
1948
1949    /// The body of Flutter's `applyPaintTransform` override.
1950    fn apply_paint_transform(
1951        self: RenderHandle<Self>,
1952        app: &App,
1953        child: AnyRenderObject,
1954        transform: &mut Matrix4,
1955    ) {
1956        debug_assert_eq!(Some(child), self.child(app).map(AnyRenderBox::as_object));
1957        child
1958            .parent_data_of::<SliverPhysicalParentData>(app)
1959            .apply_paint_transform(transform);
1960    }
1961
1962    /// The body of Flutter's `paint` override.
1963    fn paint(
1964        self: RenderHandle<Self>,
1965        app: &mut App,
1966        context: &mut PaintingContext,
1967        offset: Offset,
1968    ) {
1969        let Some(child) = self.child(app) else {
1970            return;
1971        };
1972        if !self.geometry(app).visible {
1973            return;
1974        }
1975        let paint_offset = child
1976            .as_object()
1977            .parent_data_of::<SliverPhysicalParentData>(app)
1978            .paint_offset;
1979        context.paint_child(app, child.as_object(), offset + paint_offset);
1980    }
1981}
1982
1983/// A [`RenderSliver`] that contains a single [`crate::RenderBox`].
1984///
1985/// The child will not be laid out if it is not visible. It is sized according to the child's
1986/// preferences in the main axis, and with a tight constraint forcing it to the dimensions of
1987/// the viewport in the cross axis.
1988///
1989/// See also:
1990///
1991///  * [`crate::RenderViewport`], which allows [`RenderSliver`] objects to be placed inside a
1992///    [`crate::RenderBox`] (the opposite of this class).
1993pub struct RenderSliverToBoxAdapter {
1994    render_object: crate::object::RenderObjectData,
1995    render_sliver: RenderSliverData,
1996    child: RenderObjectWithChildData<AnyRenderBox>,
1997}
1998
1999impl RenderSliverToBoxAdapter {
2000    /// Creates a [`RenderSliver`] that wraps a [`crate::RenderBox`].
2001    pub fn new(
2002        app: &mut App,
2003        child: Option<AnyRenderBox>,
2004    ) -> RenderHandle<RenderSliverToBoxAdapter> {
2005        let this = RenderHandle::new_sliver(
2006            app,
2007            RenderSliverToBoxAdapter {
2008                render_object: crate::object::RenderObjectData::new(),
2009                render_sliver: RenderSliverData::new(),
2010                child: RenderObjectWithChildData::new(),
2011            },
2012        );
2013        this.set_child(app, child);
2014        this
2015    }
2016}
2017
2018impl RenderObjectWithChildMixin for RenderSliverToBoxAdapter {
2019    type ChildType = AnyRenderBox;
2020
2021    fn child_data(self: RenderHandle<Self>, app: &App) -> &RenderObjectWithChildData<AnyRenderBox> {
2022        &self.get(app).child
2023    }
2024
2025    fn child_data_mut(
2026        self: RenderHandle<Self>,
2027        app: &mut App,
2028    ) -> &mut RenderObjectWithChildData<AnyRenderBox> {
2029        &mut self.get_mut(app).child
2030    }
2031}
2032
2033impl RenderSliverHelpers for RenderSliverToBoxAdapter {}
2034
2035impl RenderSliverSingleBoxAdapter for RenderSliverToBoxAdapter {}
2036
2037impl RenderObject for RenderSliverToBoxAdapter {
2038    crate::render_object_accessors!();
2039
2040    fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
2041        RenderSliverSingleBoxAdapter::setup_parent_data(self, app, child)
2042    }
2043
2044    fn visit_children(
2045        self: RenderHandle<Self>,
2046        app: &App,
2047        visitor: &mut dyn FnMut(AnyRenderObject),
2048    ) {
2049        if let Some(child) = self.child(app) {
2050            visitor(child.as_object());
2051        }
2052    }
2053
2054    fn apply_paint_transform(
2055        self: RenderHandle<Self>,
2056        app: &App,
2057        child: AnyRenderObject,
2058        transform: &mut Matrix4,
2059    ) {
2060        RenderSliverSingleBoxAdapter::apply_paint_transform(self, app, child, transform)
2061    }
2062
2063    fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2064        let Some(child) = self.child(app) else {
2065            self.set_geometry(app, SliverGeometry::ZERO);
2066            return;
2067        };
2068        let constraints = self.constraints(app);
2069        child.layout(
2070            app,
2071            constraints.as_box_constraints(0.0, f64::INFINITY, None),
2072            true,
2073        );
2074        let child_extent = match constraints.axis() {
2075            Axis::Horizontal => child.size(app).width(),
2076            Axis::Vertical => child.size(app).height(),
2077        };
2078        let painted_child_size = calculate_paint_offset(constraints, 0.0, child_extent);
2079        let cache_extent = calculate_cache_offset(constraints, 0.0, child_extent);
2080
2081        debug_assert!(painted_child_size.is_finite());
2082        debug_assert!(painted_child_size >= 0.0);
2083        let geometry = SliverGeometry::builder()
2084            .scroll_extent(child_extent)
2085            .paint_extent(painted_child_size)
2086            .cache_extent(cache_extent)
2087            .max_paint_extent(child_extent)
2088            .hit_test_extent(painted_child_size)
2089            .has_visual_overflow(
2090                child_extent > constraints.remaining_paint_extent
2091                    || constraints.scroll_offset > 0.0,
2092            )
2093            .build();
2094        self.set_geometry(app, geometry);
2095        self.set_child_parent_data(app, child.as_object(), constraints, geometry);
2096    }
2097
2098    fn paint(
2099        self: RenderHandle<Self>,
2100        app: &mut App,
2101        context: &mut PaintingContext,
2102        offset: Offset,
2103    ) {
2104        RenderSliverSingleBoxAdapter::paint(self, app, context, offset)
2105    }
2106}
2107
2108impl RenderSliver for RenderSliverToBoxAdapter {
2109    render_sliver_accessors!();
2110
2111    fn hit_test_children(
2112        self: RenderHandle<Self>,
2113        app: &mut App,
2114        result: &mut SliverHitTestResult<'_>,
2115        main_axis_position: f64,
2116        cross_axis_position: f64,
2117    ) -> bool {
2118        RenderSliverSingleBoxAdapter::hit_test_children(
2119            self,
2120            app,
2121            result,
2122            main_axis_position,
2123            cross_axis_position,
2124        )
2125    }
2126
2127    fn child_main_axis_position(
2128        self: RenderHandle<Self>,
2129        app: &App,
2130        child: AnyRenderObject,
2131    ) -> f64 {
2132        RenderSliverSingleBoxAdapter::child_main_axis_position(self, app, child)
2133    }
2134}
2135
2136#[cfg(test)]
2137mod tests {
2138    use inset_foundation::AppCell;
2139    use inset_gestures::HitTestResult;
2140
2141    use super::*;
2142    use crate::box_::{RenderBox, RenderBoxData};
2143    use crate::proxy_box::RenderConstrainedBox;
2144
2145    struct TestSliver {
2146        render_object: crate::object::RenderObjectData,
2147        render_sliver: RenderSliverData,
2148    }
2149
2150    impl RenderObject for TestSliver {
2151        crate::render_object_accessors!();
2152
2153        fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2154            let constraints = self.constraints(app);
2155            let extent = constraints.remaining_paint_extent.min(20.0);
2156            self.set_geometry(
2157                app,
2158                SliverGeometry::builder()
2159                    .scroll_extent(20.0)
2160                    .paint_extent(extent)
2161                    .max_paint_extent(20.0)
2162                    .build(),
2163            );
2164        }
2165    }
2166
2167    impl RenderSliver for TestSliver {
2168        render_sliver_accessors!();
2169    }
2170
2171    fn vertical_constraints(remaining_paint: f64) -> SliverConstraints {
2172        SliverConstraints::new(
2173            AxisDirection::Down,
2174            GrowthDirection::Forward,
2175            ScrollDirection::Idle,
2176            0.0,
2177            0.0,
2178            0.0,
2179            remaining_paint,
2180            100.0,
2181            AxisDirection::Right,
2182            400.0,
2183            remaining_paint,
2184            0.0,
2185        )
2186    }
2187
2188    #[test]
2189    fn sliver_layout_sets_geometry() {
2190        let cell = AppCell::new();
2191        let mut app = cell.borrow_mut();
2192        let sliver = RenderHandle::new_sliver(
2193            &mut app,
2194            TestSliver {
2195                render_object: crate::object::RenderObjectData::new(),
2196                render_sliver: RenderSliverData::new(),
2197            },
2198        );
2199        sliver.layout(&mut app, vertical_constraints(50.0), false);
2200        let geometry = sliver.geometry(&app);
2201        assert_eq!(geometry.scroll_extent, 20.0);
2202        assert_eq!(geometry.paint_extent, 20.0);
2203        assert!(geometry.visible);
2204    }
2205
2206    /// A box that fills the constraints it is given and accepts hits, so that a hit test walks
2207    /// all the way through the sliver adapter.
2208    struct HitTestableBox {
2209        render_object: crate::object::RenderObjectData,
2210        render_box: RenderBoxData,
2211    }
2212
2213    impl RenderObject for HitTestableBox {
2214        crate::render_object_accessors!();
2215
2216        fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
2217            let size = self.constraints(app).constrain(Size::new(60.0, 60.0));
2218            self.set_size(app, size);
2219        }
2220    }
2221
2222    impl RenderBox for HitTestableBox {
2223        crate::render_box_accessors!();
2224
2225        fn hit_test_self(self: RenderHandle<Self>, _app: &App, _position: Offset) -> bool {
2226            let _ = self;
2227            true
2228        }
2229    }
2230
2231    fn hit_testable_box(app: &mut App) -> AnyRenderBox {
2232        RenderHandle::new_box(
2233            app,
2234            HitTestableBox {
2235                render_object: crate::object::RenderObjectData::new(),
2236                render_box: RenderBoxData::new(),
2237            },
2238        )
2239        .as_box()
2240    }
2241
2242    fn adapter_constraints(scroll_offset: f64, remaining_paint: f64) -> SliverConstraints {
2243        SliverConstraints::new(
2244            AxisDirection::Down,
2245            GrowthDirection::Forward,
2246            ScrollDirection::Idle,
2247            scroll_offset,
2248            0.0,
2249            0.0,
2250            remaining_paint,
2251            100.0,
2252            AxisDirection::Right,
2253            remaining_paint,
2254            remaining_paint,
2255            0.0,
2256        )
2257    }
2258
2259    /// `sliver_test.dart`: a `RenderSliverToBoxAdapter` sizes itself to its box child in the main
2260    /// axis and reports the visible portion as its paint extent.
2261    #[test]
2262    fn a_box_adapter_reports_its_child_extent() {
2263        let cell = AppCell::new();
2264        let mut app = cell.borrow_mut();
2265        let child =
2266            RenderConstrainedBox::new(&mut app, BoxConstraints::tight_for(None, Some(60.0)), None);
2267        let adapter = RenderSliverToBoxAdapter::new(&mut app, Some(child.as_box()));
2268
2269        adapter.layout(&mut app, adapter_constraints(0.0, 400.0), true);
2270
2271        let geometry = adapter.geometry(&app);
2272        assert_eq!(geometry.scroll_extent, 60.0);
2273        assert_eq!(geometry.paint_extent, 60.0);
2274        assert_eq!(geometry.max_paint_extent, 60.0);
2275        assert!(!geometry.has_visual_overflow);
2276        // The cross axis is tight to the sliver's cross axis extent.
2277        assert_eq!(child.size(&app), Size::new(100.0, 60.0));
2278        assert_eq!(
2279            child
2280                .as_box()
2281                .as_object()
2282                .parent_data_of::<SliverPhysicalParentData>(&app)
2283                .paint_offset,
2284            Offset::ZERO
2285        );
2286    }
2287
2288    /// A scrolled adapter moves its child up by the scroll offset and shrinks its paint extent.
2289    #[test]
2290    fn a_scrolled_box_adapter_offsets_its_child() {
2291        let cell = AppCell::new();
2292        let mut app = cell.borrow_mut();
2293        let child =
2294            RenderConstrainedBox::new(&mut app, BoxConstraints::tight_for(None, Some(60.0)), None);
2295        let adapter = RenderSliverToBoxAdapter::new(&mut app, Some(child.as_box()));
2296
2297        adapter.layout(&mut app, adapter_constraints(20.0, 400.0), true);
2298
2299        let geometry = adapter.geometry(&app);
2300        assert_eq!(geometry.scroll_extent, 60.0);
2301        assert_eq!(geometry.paint_extent, 40.0);
2302        assert!(geometry.has_visual_overflow);
2303        assert_eq!(
2304            child
2305                .as_box()
2306                .as_object()
2307                .parent_data_of::<SliverPhysicalParentData>(&app)
2308                .paint_offset,
2309            Offset::new(0.0, -20.0)
2310        );
2311        assert_eq!(
2312            RenderSliver::child_main_axis_position(adapter, &app, child.as_object()),
2313            -20.0
2314        );
2315    }
2316
2317    /// An empty adapter reports zero geometry.
2318    #[test]
2319    fn a_childless_box_adapter_is_zero() {
2320        let cell = AppCell::new();
2321        let mut app = cell.borrow_mut();
2322        let adapter = RenderSliverToBoxAdapter::new(&mut app, None);
2323        adapter.layout(&mut app, adapter_constraints(0.0, 400.0), true);
2324        assert!(adapter.geometry(&app).is_zero());
2325    }
2326
2327    /// A hit inside the visible part of the child lands on both the child and the sliver.
2328    #[test]
2329    fn a_box_adapter_hit_tests_its_child() {
2330        let cell = AppCell::new();
2331        let mut app = cell.borrow_mut();
2332        let child = hit_testable_box(&mut app);
2333        let adapter = RenderSliverToBoxAdapter::new(&mut app, Some(child));
2334        adapter.layout(&mut app, adapter_constraints(0.0, 400.0), true);
2335
2336        let mut result = HitTestResult::new();
2337        let hit = adapter.hit_test(
2338            &mut app,
2339            &mut SliverHitTestResult::wrap(&mut result),
2340            30.0,
2341            50.0,
2342        );
2343
2344        assert!(hit);
2345        assert_eq!(result.path().len(), 2);
2346    }
2347
2348    /// `calculate_paint_offset` clamps the requested region to the visible window.
2349    #[test]
2350    fn paint_and_cache_offsets_clamp_to_the_window() {
2351        let constraints = adapter_constraints(20.0, 50.0);
2352        assert_eq!(calculate_paint_offset(constraints, 0.0, 100.0), 50.0);
2353        assert_eq!(calculate_paint_offset(constraints, 0.0, 30.0), 10.0);
2354        assert_eq!(calculate_paint_offset(constraints, 0.0, 10.0), 0.0);
2355        assert_eq!(calculate_cache_offset(constraints, 0.0, 100.0), 50.0);
2356    }
2357
2358    /// `SliverGeometry.debugAssertIsValid` accepts a consistent geometry.
2359    #[test]
2360    fn a_consistent_geometry_is_valid() {
2361        let geometry = SliverGeometry::builder()
2362            .scroll_extent(100.0)
2363            .paint_extent(40.0)
2364            .max_paint_extent(100.0)
2365            .build();
2366        assert!(geometry.debug_assert_is_valid());
2367        assert!(!geometry.is_zero());
2368        assert!(SliverGeometry::ZERO.is_zero());
2369    }
2370
2371    #[test]
2372    fn extents_left_out_follow_the_ones_given_in_any_order() {
2373        let geometry = SliverGeometry::builder()
2374            .layout_extent(10.0)
2375            .hit_test_extent(20.0)
2376            .paint_extent(40.0)
2377            .build();
2378        assert_eq!(geometry.layout_extent, 10.0);
2379        assert_eq!(geometry.hit_test_extent, 20.0);
2380        assert_eq!(geometry.cache_extent, 10.0);
2381        assert!(geometry.visible);
2382        let geometry = SliverGeometry::builder()
2383            .cache_extent(5.0)
2384            .layout_extent(10.0)
2385            .paint_extent(40.0)
2386            .build();
2387        assert_eq!(geometry.cache_extent, 5.0);
2388    }
2389
2390    #[test]
2391    fn a_copy_keeps_the_extents_it_was_made_with() {
2392        let copy = SliverGeometry::builder()
2393            .paint_extent(40.0)
2394            .layout_extent(10.0)
2395            .build()
2396            .copy_with()
2397            .paint_extent(0.0)
2398            .build();
2399        assert_eq!(copy.layout_extent, 10.0);
2400        assert_eq!(copy.cache_extent, 10.0);
2401        assert!(copy.visible);
2402    }
2403}