1use std::any::{Any, TypeId};
6use std::fmt::{self, Debug, Display};
7use std::rc::Rc;
8
9use indexmap::IndexMap;
10use inset_embedder::{Matrix4, Offset};
11use inset_foundation::{App, Handle};
12use inset_painting::{Axis, AxisDirection};
13
14use crate::box_::{AnyRenderBox, BoxConstraints, BoxHitTestResult};
15use crate::object::{
16 AnyRenderObject, ContainerParentData, ContainerParentDataMixin, ContainerRenderObjectBase,
17 ContainerRenderObjectMixin, ParentData, RenderHandle, RenderObject, zero_matrix,
18};
19use crate::painting_context::PaintingContext;
20use crate::pipeline_owner::PipelineOwner;
21use crate::sliver::{
22 RenderSliver, RenderSliverHelpers, SliverConstraints, SliverHitTestResult,
23 SliverLogicalParentData, apply_growth_direction_to_axis_direction,
24};
25
26pub trait RenderSliverBoxChildManager {
36 fn create_child(&self, app: &mut App, index: i32, after: Option<AnyRenderBox>);
58
59 fn remove_child(&self, app: &mut App, child: AnyRenderBox);
67
68 fn estimate_max_scroll_offset(
73 &self,
74 app: &App,
75 constraints: SliverConstraints,
76 first_index: Option<i32>,
77 last_index: Option<i32>,
78 leading_scroll_offset: Option<f64>,
79 trailing_scroll_offset: Option<f64>,
80 ) -> f64;
81
82 fn child_count(&self, app: &mut App) -> i32;
91
92 fn estimated_child_count(&self, app: &App) -> Option<i32> {
95 let _ = app;
96 None
97 }
98
99 fn did_adopt_child(&self, app: &mut App, child: AnyRenderBox);
106
107 fn set_did_underflow(&self, app: &mut App, value: bool);
115
116 fn did_start_layout(&self, app: &mut App) {
118 let _ = app;
119 }
120
121 fn did_finish_layout(&self, app: &mut App) {
123 let _ = app;
124 }
125
126 fn debug_assert_child_list_locked(&self, app: &App) -> bool {
131 let _ = app;
132 true
133 }
134}
135
136#[derive(Clone, Copy, Debug, Default)]
141pub struct KeepAliveParentData {
142 pub keep_alive: bool,
144 kept_alive: bool,
145}
146
147impl KeepAliveParentData {
148 pub const fn new() -> KeepAliveParentData {
150 KeepAliveParentData {
151 keep_alive: false,
152 kept_alive: false,
153 }
154 }
155
156 pub fn kept_alive(&self) -> bool {
159 self.kept_alive
160 }
161}
162
163pub trait RenderSliverWithKeepAliveMixin: RenderSliver {
168 fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
171 let _ = self;
172 debug_assert!(
173 child
174 .parent_data(app)
175 .is_some_and(|parent_data| parent_data.part::<KeepAliveParentData>().is_some())
176 );
177 }
178}
179
180#[derive(Debug)]
182pub struct SliverMultiBoxAdaptorParentData {
183 sliver_logical: SliverLogicalParentData,
184 container: ContainerParentData<AnyRenderBox>,
185 keep_alive: KeepAliveParentData,
186 pub index: Option<i32>,
188}
189
190impl SliverMultiBoxAdaptorParentData {
191 pub const fn new() -> SliverMultiBoxAdaptorParentData {
193 SliverMultiBoxAdaptorParentData {
194 sliver_logical: SliverLogicalParentData::new(),
195 container: ContainerParentData::new(),
196 keep_alive: KeepAliveParentData::new(),
197 index: None,
198 }
199 }
200
201 pub fn layout_offset(&self) -> Option<f64> {
203 self.sliver_logical.layout_offset
204 }
205
206 pub fn set_layout_offset(&mut self, value: Option<f64>) {
208 self.sliver_logical.layout_offset = value;
209 }
210
211 pub fn keep_alive(&self) -> bool {
213 self.keep_alive.keep_alive
214 }
215
216 pub fn set_keep_alive(&mut self, value: bool) {
218 self.keep_alive.keep_alive = value;
219 }
220
221 pub fn kept_alive(&self) -> bool {
223 self.keep_alive.kept_alive
224 }
225}
226
227impl Default for SliverMultiBoxAdaptorParentData {
228 fn default() -> SliverMultiBoxAdaptorParentData {
229 SliverMultiBoxAdaptorParentData::new()
230 }
231}
232
233impl ParentData for SliverMultiBoxAdaptorParentData {
234 fn detach(&mut self) {
235 ContainerParentDataMixin::detach(self);
236 }
237
238 fn provide(&self, id: TypeId) -> Option<&dyn Any> {
239 if id == TypeId::of::<SliverMultiBoxAdaptorParentData>() {
240 return Some(self);
241 }
242 if id == TypeId::of::<KeepAliveParentData>() {
243 return Some(&self.keep_alive);
244 }
245 self.sliver_logical.provide(id)
246 }
247
248 fn provide_mut(&mut self, id: TypeId) -> Option<&mut dyn Any> {
249 if id == TypeId::of::<SliverMultiBoxAdaptorParentData>() {
250 return Some(self);
251 }
252 if id == TypeId::of::<KeepAliveParentData>() {
253 return Some(&mut self.keep_alive);
254 }
255 self.sliver_logical.provide_mut(id)
256 }
257}
258
259impl ContainerParentDataMixin for SliverMultiBoxAdaptorParentData {
260 type ChildType = AnyRenderBox;
261
262 fn container_parent_data(&self) -> &ContainerParentData<AnyRenderBox> {
263 &self.container
264 }
265
266 fn container_parent_data_mut(&mut self) -> &mut ContainerParentData<AnyRenderBox> {
267 &mut self.container
268 }
269}
270
271impl Display for SliverMultiBoxAdaptorParentData {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 write!(f, "index={:?}; ", self.index)?;
274 if self.keep_alive() {
275 f.write_str("keepAlive; ")?;
276 }
277 Display::fmt(&self.sliver_logical, f)
278 }
279}
280
281fn restore_parent_data<T: RenderSliverMultiBoxAdaptor>(
290 sliver: RenderHandle<T>,
291 app: &mut App,
292 child: AnyRenderBox,
293 saved: KeptSlot,
294) {
295 RenderObject::setup_parent_data(sliver, app, child.as_object());
296 let restored = child
297 .as_object()
298 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app);
299 restored.set_layout_offset(saved.layout_offset);
300 restored.set_keep_alive(saved.keep_alive);
301 restored.index = saved.index;
302 restored.keep_alive.kept_alive = true;
303}
304
305#[derive(Clone, Copy)]
308struct KeptSlot {
309 layout_offset: Option<f64>,
310 keep_alive: bool,
311 index: Option<i32>,
312}
313
314impl KeptSlot {
315 fn of(parent_data: &SliverMultiBoxAdaptorParentData) -> KeptSlot {
316 KeptSlot {
317 layout_offset: parent_data.layout_offset(),
318 keep_alive: parent_data.keep_alive(),
319 index: parent_data.index,
320 }
321 }
322}
323
324pub struct RenderSliverMultiBoxAdaptorData {
326 child_manager: Rc<dyn RenderSliverBoxChildManager>,
327 keep_alive_bucket: IndexMap<i32, AnyRenderBox>,
329 debug_dangling_keep_alives: Vec<AnyRenderBox>,
330 debug_child_integrity_enabled: bool,
331}
332
333impl RenderSliverMultiBoxAdaptorData {
334 pub fn new(
336 child_manager: Rc<dyn RenderSliverBoxChildManager>,
337 ) -> RenderSliverMultiBoxAdaptorData {
338 RenderSliverMultiBoxAdaptorData {
339 child_manager,
340 keep_alive_bucket: IndexMap::new(),
341 debug_dangling_keep_alives: Vec::new(),
342 debug_child_integrity_enabled: true,
343 }
344 }
345}
346
347#[macro_export]
349macro_rules! render_sliver_multi_box_adaptor_accessors {
350 () => {
351 fn adaptor_data(
352 self: $crate::RenderHandle<Self>,
353 app: &::inset_foundation::App,
354 ) -> &$crate::RenderSliverMultiBoxAdaptorData {
355 &self.get(app).adaptor
356 }
357 fn adaptor_data_mut(
358 self: $crate::RenderHandle<Self>,
359 app: &mut ::inset_foundation::App,
360 ) -> &mut $crate::RenderSliverMultiBoxAdaptorData {
361 &mut self.get_mut(app).adaptor
362 }
363 };
364}
365
366pub trait RenderSliverMultiBoxAdaptor:
389 RenderSliver
390 + RenderSliverHelpers
391 + RenderSliverWithKeepAliveMixin
392 + ContainerRenderObjectMixin<
393 ChildType = AnyRenderBox,
394 ParentDataType = SliverMultiBoxAdaptorParentData,
395 >
396{
397 fn adaptor_data(self: RenderHandle<Self>, app: &App) -> &RenderSliverMultiBoxAdaptorData;
399
400 fn adaptor_data_mut(
402 self: RenderHandle<Self>,
403 app: &mut App,
404 ) -> &mut RenderSliverMultiBoxAdaptorData;
405
406 fn child_manager(self: RenderHandle<Self>, app: &App) -> Rc<dyn RenderSliverBoxChildManager> {
412 Rc::clone(&self.adaptor_data(app).child_manager)
413 }
414
415 fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
417 if !child.parent_data_is::<SliverMultiBoxAdaptorParentData>(app) {
418 child.set_parent_data(app, SliverMultiBoxAdaptorParentData::new());
419 }
420 }
421
422 fn debug_child_integrity_enabled(self: RenderHandle<Self>, app: &App) -> bool {
430 self.adaptor_data(app).debug_child_integrity_enabled
431 }
432
433 fn set_debug_child_integrity_enabled(self: RenderHandle<Self>, app: &mut App, enabled: bool) {
436 if !cfg!(debug_assertions) {
437 return;
438 }
439 self.adaptor_data_mut(app).debug_child_integrity_enabled = enabled;
440 debug_assert!(self.debug_verify_child_order(app));
441 debug_assert!(
442 !enabled || self.adaptor_data(app).debug_dangling_keep_alives.is_empty(),
443 "a keep-alive child was left dangling by move_child"
444 );
445 }
446
447 fn debug_assert_child_list_locked(self: RenderHandle<Self>, app: &App) -> bool {
449 self.child_manager(app).debug_assert_child_list_locked(app)
450 }
451
452 fn debug_verify_child_order(self: RenderHandle<Self>, app: &App) -> bool {
456 if self.debug_child_integrity_enabled(app) {
457 let mut child = self.first_child(app);
458 while let Some(current) = child {
459 let index = self.index_of(app, current);
460 child = self.child_after(app, current);
461 debug_assert!(child.is_none_or(|next| self.index_of(app, next) > index));
462 }
463 }
464 true
465 }
466
467 fn insert(
469 self: RenderHandle<Self>,
470 app: &mut App,
471 child: AnyRenderBox,
472 after: Option<AnyRenderBox>,
473 ) {
474 debug_assert!(
475 !self
476 .adaptor_data(app)
477 .keep_alive_bucket
478 .values()
479 .any(|kept| *kept == child)
480 );
481 ContainerRenderObjectBase::insert(self, app, child, after);
482 self.did_adopt_child(app, child);
483 debug_assert!(self.first_child(app).is_some());
484 debug_assert!(self.debug_verify_child_order(app));
485 }
486
487 fn did_adopt_child(self: RenderHandle<Self>, app: &mut App, child: AnyRenderBox) {
493 let kept_alive = child
494 .as_object()
495 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
496 .kept_alive();
497 if !kept_alive {
498 self.child_manager(app).did_adopt_child(app, child);
499 }
500 }
501
502 fn move_child(
514 self: RenderHandle<Self>,
515 app: &mut App,
516 child: AnyRenderBox,
517 after: Option<AnyRenderBox>,
518 ) {
519 let child_parent_data = child
520 .as_object()
521 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app);
522 let (kept_alive, index) = (child_parent_data.kept_alive(), child_parent_data.index);
523 if !kept_alive {
524 ContainerRenderObjectBase::move_child(self, app, child, after);
525 self.child_manager(app).did_adopt_child(app, child);
527 self.mark_needs_layout(app);
530 return;
531 }
532 if let Some(index) = index
535 && self.adaptor_data(app).keep_alive_bucket.get(&index) == Some(&child)
536 {
537 self.adaptor_data_mut(app)
538 .keep_alive_bucket
539 .shift_remove(&index);
540 }
541 if cfg!(debug_assertions) {
542 self.adaptor_data_mut(app)
543 .debug_dangling_keep_alives
544 .retain(|dangling| *dangling != child);
545 }
546 self.child_manager(app).did_adopt_child(app, child);
548 let new_index = child
552 .as_object()
553 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
554 .index
555 .expect("did_adopt_child sets the index");
556 if cfg!(debug_assertions)
557 && let Some(existing) = self
558 .adaptor_data(app)
559 .keep_alive_bucket
560 .get(&new_index)
561 .copied()
562 {
563 self.adaptor_data_mut(app)
564 .debug_dangling_keep_alives
565 .push(existing);
566 }
567 self.adaptor_data_mut(app)
568 .keep_alive_bucket
569 .insert(new_index, child);
570 }
571
572 fn remove(self: RenderHandle<Self>, app: &mut App, child: AnyRenderBox) {
574 let child_parent_data = child
575 .as_object()
576 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app);
577 let (kept_alive, index) = (child_parent_data.kept_alive(), child_parent_data.index);
578 if !kept_alive {
579 ContainerRenderObjectBase::remove(self, app, child);
580 return;
581 }
582 let index = index.expect("a kept-alive child has an index");
583 debug_assert_eq!(
584 self.adaptor_data(app).keep_alive_bucket.get(&index),
585 Some(&child)
586 );
587 if cfg!(debug_assertions) {
588 self.adaptor_data_mut(app)
589 .debug_dangling_keep_alives
590 .retain(|dangling| *dangling != child);
591 }
592 self.adaptor_data_mut(app)
593 .keep_alive_bucket
594 .shift_remove(&index);
595 self.drop_child(app, child.as_object());
596 }
597
598 fn remove_all(self: RenderHandle<Self>, app: &mut App) {
600 ContainerRenderObjectBase::remove_all(self, app);
601 for child in self.keep_alive_children(app) {
602 self.drop_child(app, child.as_object());
603 }
604 self.adaptor_data_mut(app).keep_alive_bucket.clear();
605 }
606
607 fn keep_alive_children(self: RenderHandle<Self>, app: &App) -> Vec<AnyRenderBox> {
609 self.adaptor_data(app)
610 .keep_alive_bucket
611 .values()
612 .copied()
613 .collect()
614 }
615
616 fn create_or_obtain_child(
618 self: RenderHandle<Self>,
619 app: &mut App,
620 index: i32,
621 after: Option<AnyRenderBox>,
622 ) {
623 self.as_object().invoke_layout_callback(app, |app| {
624 let cached = self
625 .adaptor_data(app)
626 .keep_alive_bucket
627 .get(&index)
628 .copied();
629 let Some(child) = cached else {
630 self.child_manager(app).create_child(app, index, after);
631 return;
632 };
633 self.adaptor_data_mut(app)
634 .keep_alive_bucket
635 .shift_remove(&index);
636 let child_parent_data = child
637 .as_object()
638 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app);
639 debug_assert!(child_parent_data.kept_alive());
640 let saved = KeptSlot::of(child_parent_data);
641 self.drop_child(app, child.as_object());
642 restore_parent_data(self, app, child, saved);
643 RenderSliverMultiBoxAdaptor::insert(self, app, child, after);
644 child
645 .as_object()
646 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
647 .keep_alive
648 .kept_alive = false;
649 });
650 }
651
652 fn destroy_or_cache_child(self: RenderHandle<Self>, app: &mut App, child: AnyRenderBox) {
654 let child_parent_data = child
655 .as_object()
656 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app);
657 if !child_parent_data.keep_alive() {
658 debug_assert_eq!(child.as_object().parent(app), Some(self.as_object()));
659 self.child_manager(app).remove_child(app, child);
660 debug_assert!(child.as_object().parent(app).is_none());
661 return;
662 }
663 debug_assert!(!child_parent_data.kept_alive());
664 let saved = KeptSlot::of(child_parent_data);
665 let index = saved.index.expect("a cached child has an index");
666 RenderSliverMultiBoxAdaptor::remove(self, app, child);
667 self.adaptor_data_mut(app)
668 .keep_alive_bucket
669 .insert(index, child);
670 restore_parent_data(self, app, child, saved);
671 self.as_object().adopt_child(app, child.as_object());
674 }
675
676 fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
678 ContainerRenderObjectMixin::did_attach(self, app, owner);
679 for child in self.keep_alive_children(app) {
680 child.as_object().attach(app, owner);
681 }
682 }
683
684 fn did_detach(self: RenderHandle<Self>, app: &mut App) {
686 ContainerRenderObjectMixin::did_detach(self, app);
687 for child in self.keep_alive_children(app) {
688 child.as_object().detach(app);
689 }
690 }
691
692 fn redepth_children(self: RenderHandle<Self>, app: &mut App) {
694 ContainerRenderObjectMixin::redepth_children(self, app);
695 for child in self.keep_alive_children(app) {
696 self.as_object().redepth_child(app, child.as_object());
697 }
698 }
699
700 fn visit_children(
702 self: RenderHandle<Self>,
703 app: &App,
704 visitor: &mut dyn FnMut(AnyRenderObject),
705 ) {
706 ContainerRenderObjectMixin::visit_children(self, app, visitor);
707 for child in self.keep_alive_children(app) {
708 visitor(child.as_object());
709 }
710 }
711
712 fn add_initial_child(
723 self: RenderHandle<Self>,
724 app: &mut App,
725 index: i32,
726 layout_offset: f64,
727 ) -> bool {
728 debug_assert!(self.debug_assert_child_list_locked(app));
729 debug_assert!(self.first_child(app).is_none());
730 self.create_or_obtain_child(app, index, None);
731 if let Some(first_child) = self.first_child(app) {
732 debug_assert_eq!(Some(first_child), self.last_child(app));
733 debug_assert_eq!(self.index_of(app, first_child), index);
734 first_child
735 .as_object()
736 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
737 .set_layout_offset(Some(layout_offset));
738 return true;
739 }
740 self.child_manager(app).set_did_underflow(app, true);
741 false
742 }
743
744 fn insert_and_layout_leading_child(
752 self: RenderHandle<Self>,
753 app: &mut App,
754 child_constraints: BoxConstraints,
755 parent_uses_size: bool,
756 ) -> Option<AnyRenderBox> {
757 debug_assert!(self.debug_assert_child_list_locked(app));
758 let first_child = self.first_child(app).expect("there is a leading child");
759 let index = self.index_of(app, first_child) - 1;
760 self.create_or_obtain_child(app, index, None);
761 let first_child = self.first_child(app).expect("the child list is not empty");
762 if self.index_of(app, first_child) == index {
763 first_child.layout(app, child_constraints, parent_uses_size);
764 return Some(first_child);
765 }
766 self.child_manager(app).set_did_underflow(app, true);
767 None
768 }
769
770 fn insert_and_layout_child(
778 self: RenderHandle<Self>,
779 app: &mut App,
780 child_constraints: BoxConstraints,
781 after: Option<AnyRenderBox>,
782 parent_uses_size: bool,
783 ) -> Option<AnyRenderBox> {
784 debug_assert!(self.debug_assert_child_list_locked(app));
785 let after = after.expect("insert_and_layout_child needs a preceding child");
786 let index = self.index_of(app, after) + 1;
787 self.create_or_obtain_child(app, index, Some(after));
788 let child = self.child_after(app, after);
789 if let Some(child) = child
790 && self.index_of(app, child) == index
791 {
792 child.layout(app, child_constraints, parent_uses_size);
793 return Some(child);
794 }
795 self.child_manager(app).set_did_underflow(app, true);
796 None
797 }
798
799 fn calculate_leading_garbage(self: RenderHandle<Self>, app: &App, first_index: i32) -> usize {
802 let mut walker = self.first_child(app);
803 let mut leading_garbage = 0;
804 while let Some(current) = walker {
805 if self.index_of(app, current) >= first_index {
806 break;
807 }
808 leading_garbage += 1;
809 walker = self.child_after(app, current);
810 }
811 leading_garbage
812 }
813
814 fn calculate_trailing_garbage(self: RenderHandle<Self>, app: &App, last_index: i32) -> usize {
817 let mut walker = self.last_child(app);
818 let mut trailing_garbage = 0;
819 while let Some(current) = walker {
820 if self.index_of(app, current) <= last_index {
821 break;
822 }
823 trailing_garbage += 1;
824 walker = self.child_before(app, current);
825 }
826 trailing_garbage
827 }
828
829 fn collect_garbage(
839 self: RenderHandle<Self>,
840 app: &mut App,
841 leading_garbage: usize,
842 trailing_garbage: usize,
843 ) {
844 debug_assert!(self.debug_assert_child_list_locked(app));
845 debug_assert!(self.child_count(app) >= leading_garbage + trailing_garbage);
846 self.as_object().invoke_layout_callback(app, |app| {
847 for _ in 0..leading_garbage {
848 let first_child = self.first_child(app).expect("counted above");
849 self.destroy_or_cache_child(app, first_child);
850 }
851 for _ in 0..trailing_garbage {
852 let last_child = self.last_child(app).expect("counted above");
853 self.destroy_or_cache_child(app, last_child);
854 }
855 let expired: Vec<AnyRenderBox> = self
859 .keep_alive_children(app)
860 .into_iter()
861 .filter(|child| {
862 !child
863 .as_object()
864 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
865 .keep_alive()
866 })
867 .collect();
868 let child_manager = self.child_manager(app);
869 for child in expired {
870 child_manager.remove_child(app, child);
871 }
872 debug_assert!(self.keep_alive_children(app).iter().all(|child| {
873 child
874 .as_object()
875 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
876 .keep_alive()
877 }));
878 });
879 }
880
881 fn index_of(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> i32 {
884 child
885 .as_object()
886 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
887 .index
888 .expect("a reified child has an index")
889 }
890
891 fn paint_extent_of(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> f64 {
895 debug_assert!(child.has_size(app));
896 match self.constraints(app).axis() {
897 Axis::Horizontal => child.size(app).width(),
898 Axis::Vertical => child.size(app).height(),
899 }
900 }
901
902 fn hit_test_children(
904 self: RenderHandle<Self>,
905 app: &mut App,
906 result: &mut SliverHitTestResult<'_>,
907 main_axis_position: f64,
908 cross_axis_position: f64,
909 ) -> bool {
910 let mut child = self.last_child(app);
911 while let Some(current) = child {
912 let previous = self.child_before(app, current);
913 if self.hit_test_box_child(
914 app,
915 &mut BoxHitTestResult::wrap(result),
916 current,
917 main_axis_position,
918 cross_axis_position,
919 ) {
920 return true;
921 }
922 child = previous;
923 }
924 false
925 }
926
927 fn child_main_axis_position(
929 self: RenderHandle<Self>,
930 app: &App,
931 child: AnyRenderObject,
932 ) -> f64 {
933 RenderSliverMultiBoxAdaptor::child_scroll_offset(self, app, child)
934 .expect("a laid-out child has a scroll offset")
935 - self.constraints(app).scroll_offset
936 }
937
938 fn child_scroll_offset(
940 self: RenderHandle<Self>,
941 app: &App,
942 child: AnyRenderObject,
943 ) -> Option<f64> {
944 debug_assert_eq!(child.parent(app), Some(self.as_object()));
945 child
946 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
947 .layout_offset()
948 }
949
950 fn paints_child(self: RenderHandle<Self>, app: &App, child: AnyRenderBox) -> bool {
955 let child = child.as_object();
956 let index = child
957 .parent_data_is::<SliverMultiBoxAdaptorParentData>(app)
958 .then(|| {
959 child
960 .parent_data_of::<SliverMultiBoxAdaptorParentData>(app)
961 .index
962 })
963 .flatten();
964 match index {
965 None => false,
966 Some(index) => !self
967 .adaptor_data(app)
968 .keep_alive_bucket
969 .contains_key(&index),
970 }
971 }
972
973 fn apply_paint_transform(
975 self: RenderHandle<Self>,
976 app: &App,
977 child: AnyRenderObject,
978 transform: &mut Matrix4,
979 ) {
980 let child = child.as_box().expect("the children are boxes");
981 if self.paints_child(app, child) {
982 self.apply_paint_transform_for_box_child(app, child, transform);
983 } else {
984 *transform = zero_matrix();
991 }
992 }
993
994 fn paint(
996 self: RenderHandle<Self>,
997 app: &mut App,
998 context: &mut PaintingContext,
999 offset: Offset,
1000 ) {
1001 if self.first_child(app).is_none() {
1002 return;
1003 }
1004 let constraints = self.constraints(app);
1008 let paint_extent = self.geometry(app).paint_extent;
1009 let (main_axis_unit, cross_axis_unit, origin_offset, add_extent) =
1010 match apply_growth_direction_to_axis_direction(
1011 constraints.axis_direction,
1012 constraints.growth_direction,
1013 ) {
1014 AxisDirection::Up => (
1015 Offset::new(0.0, -1.0),
1016 Offset::new(1.0, 0.0),
1017 offset + Offset::new(0.0, paint_extent),
1018 true,
1019 ),
1020 AxisDirection::Right => {
1021 (Offset::new(1.0, 0.0), Offset::new(0.0, 1.0), offset, false)
1022 }
1023 AxisDirection::Down => {
1024 (Offset::new(0.0, 1.0), Offset::new(1.0, 0.0), offset, false)
1025 }
1026 AxisDirection::Left => (
1027 Offset::new(-1.0, 0.0),
1028 Offset::new(0.0, 1.0),
1029 offset + Offset::new(paint_extent, 0.0),
1030 true,
1031 ),
1032 };
1033 let mut child = self.first_child(app);
1034 while let Some(current) = child {
1035 let main_axis_delta = RenderSliverMultiBoxAdaptor::child_main_axis_position(
1036 self,
1037 app,
1038 current.as_object(),
1039 );
1040 let cross_axis_delta = self.child_cross_axis_position(app, current.as_object());
1041 let mut child_offset = Offset::new(
1042 origin_offset.dx()
1043 + main_axis_unit.dx() * main_axis_delta
1044 + cross_axis_unit.dx() * cross_axis_delta,
1045 origin_offset.dy()
1046 + main_axis_unit.dy() * main_axis_delta
1047 + cross_axis_unit.dy() * cross_axis_delta,
1048 );
1049 let child_paint_extent = self.paint_extent_of(app, current);
1050 if add_extent {
1051 child_offset = child_offset + main_axis_unit * child_paint_extent;
1052 }
1053
1054 if main_axis_delta < constraints.remaining_paint_extent
1058 && main_axis_delta + child_paint_extent > 0.0
1059 {
1060 context.paint_child(app, current.as_object(), child_offset);
1061 }
1062
1063 child = self.child_after(app, current);
1064 }
1065 }
1066
1067 fn debug_assert_child_list_is_non_empty_and_contiguous(
1071 self: RenderHandle<Self>,
1072 app: &App,
1073 ) -> bool {
1074 if cfg!(debug_assertions) {
1075 let first_child = self.first_child(app).expect("the child list is not empty");
1076 let mut index = self.index_of(app, first_child);
1077 let mut child = self.child_after(app, first_child);
1078 while let Some(current) = child {
1079 index += 1;
1080 debug_assert_eq!(self.index_of(app, current), index);
1081 child = self.child_after(app, current);
1082 }
1083 }
1084 true
1085 }
1086}
1087
1088#[cfg(test)]
1089pub(crate) mod test_support {
1090 use std::cell::{Cell, RefCell};
1091
1092 use inset_embedder::Size;
1093
1094 use super::*;
1095 use crate::box_::{RenderBox, RenderBoxData};
1096 use crate::object::{RenderObject, RenderObjectData};
1097
1098 pub(crate) struct TestChild {
1100 render_object: RenderObjectData,
1101 render_box: RenderBoxData,
1102 preferred_extent: f64,
1103 }
1104
1105 impl RenderObject for TestChild {
1106 crate::render_object_accessors!();
1107
1108 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
1109 let extent = self.get(app).preferred_extent;
1110 let size = self.constraints(app).constrain(Size::new(extent, extent));
1111 self.set_size(app, size);
1112 }
1113 }
1114
1115 impl RenderBox for TestChild {
1116 crate::render_box_accessors!();
1117
1118 fn hit_test_self(self: RenderHandle<Self>, _app: &App, _position: Offset) -> bool {
1119 let _ = self;
1120 true
1121 }
1122 }
1123
1124 pub(crate) fn hit_testable_box(app: &mut App, extent: f64) -> AnyRenderBox {
1127 RenderHandle::new_box(
1128 app,
1129 TestChild {
1130 render_object: RenderObjectData::new(),
1131 render_box: RenderBoxData::new(),
1132 preferred_extent: extent,
1133 },
1134 )
1135 .as_box()
1136 }
1137
1138 pub(crate) struct TestChildManager<T: RenderSliverMultiBoxAdaptor> {
1141 render_object: Cell<Option<RenderHandle<T>>>,
1142 extents: Vec<f64>,
1143 currently_updating_child_index: Cell<Option<i32>>,
1144 pub(crate) created: RefCell<Vec<i32>>,
1146 pub(crate) did_underflow: Cell<bool>,
1148 }
1149
1150 impl<T: RenderSliverMultiBoxAdaptor> TestChildManager<T> {
1151 pub(crate) fn new(extents: Vec<f64>) -> Rc<TestChildManager<T>> {
1152 Rc::new(TestChildManager {
1153 render_object: Cell::new(None),
1154 extents,
1155 currently_updating_child_index: Cell::new(None),
1156 created: RefCell::new(Vec::new()),
1157 did_underflow: Cell::new(false),
1158 })
1159 }
1160
1161 pub(crate) fn attach(&self, render_object: RenderHandle<T>) {
1162 self.render_object.set(Some(render_object));
1163 }
1164
1165 fn adaptor(&self) -> RenderHandle<T> {
1166 self.render_object.get().expect("attached before layout")
1167 }
1168
1169 fn total_extent(&self) -> f64 {
1170 self.extents.iter().sum()
1171 }
1172 }
1173
1174 impl<T: RenderSliverMultiBoxAdaptor> RenderSliverBoxChildManager for TestChildManager<T> {
1175 fn create_child(&self, app: &mut App, index: i32, after: Option<AnyRenderBox>) {
1176 self.created.borrow_mut().push(index);
1177 let Ok(slot) = usize::try_from(index) else {
1178 return;
1179 };
1180 let Some(extent) = self.extents.get(slot).copied() else {
1181 return;
1182 };
1183 let child = RenderHandle::new_box(
1184 app,
1185 TestChild {
1186 render_object: RenderObjectData::new(),
1187 render_box: RenderBoxData::new(),
1188 preferred_extent: extent,
1189 },
1190 )
1191 .as_box();
1192 self.currently_updating_child_index.set(Some(index));
1193 RenderSliverMultiBoxAdaptor::insert(self.adaptor(), app, child, after);
1194 self.currently_updating_child_index.set(None);
1195 }
1196
1197 fn remove_child(&self, app: &mut App, child: AnyRenderBox) {
1198 RenderSliverMultiBoxAdaptor::remove(self.adaptor(), app, child);
1201 }
1202
1203 fn estimate_max_scroll_offset(
1204 &self,
1205 _app: &App,
1206 _constraints: SliverConstraints,
1207 _first_index: Option<i32>,
1208 _last_index: Option<i32>,
1209 _leading_scroll_offset: Option<f64>,
1210 _trailing_scroll_offset: Option<f64>,
1211 ) -> f64 {
1212 self.total_extent()
1213 }
1214
1215 fn child_count(&self, _app: &mut App) -> i32 {
1216 self.extents.len() as i32
1217 }
1218
1219 fn estimated_child_count(&self, _app: &App) -> Option<i32> {
1220 Some(self.extents.len() as i32)
1221 }
1222
1223 fn did_adopt_child(&self, app: &mut App, child: AnyRenderBox) {
1224 child
1225 .as_object()
1226 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
1227 .index = self.currently_updating_child_index.get();
1228 }
1229
1230 fn set_did_underflow(&self, _app: &mut App, value: bool) {
1231 self.did_underflow.set(value);
1232 }
1233 }
1234}
1235
1236#[cfg(test)]
1237pub(crate) mod viewport_test_support {
1238 use std::rc::Rc;
1239
1240 use inset_embedder::{Size, View, ViewId, ViewMetrics, ViewRef};
1241 use inset_foundation::Handle;
1242
1243 use super::*;
1244 use crate::box_::RenderBox;
1245 use crate::pipeline_owner::PipelineOwner;
1246 use crate::sliver::AnyRenderSliver;
1247 use crate::view::{RenderView, ViewConfiguration};
1248 use crate::viewport::RenderViewport;
1249 use crate::viewport_offset::{FixedViewportOffset, ViewportOffset};
1250 use inset_test::TestViewHost;
1251
1252 #[derive(Default)]
1253 struct TestView {
1254 host: TestViewHost,
1255 }
1256
1257 impl View for TestView {
1258 fn id(&self) -> ViewId {
1259 ViewId(0)
1260 }
1261
1262 fn metrics(&self) -> ViewMetrics {
1263 ViewMetrics::default()
1264 }
1265
1266 fn present(&self, _scene: std::sync::Arc<inset_embedder::Scene>) {}
1267
1268 fn host(&self) -> &dyn inset_embedder::ViewHost {
1269 &self.host
1270 }
1271 }
1272
1273 pub(crate) struct ScrollHarness {
1276 pub(crate) owner: Handle<PipelineOwner>,
1277 pub(crate) viewport: RenderHandle<RenderViewport>,
1278 pub(crate) offset: Handle<FixedViewportOffset>,
1279 }
1280
1281 impl ScrollHarness {
1282 pub(crate) fn new(app: &mut App, sliver: AnyRenderSliver, size: Size) -> ScrollHarness {
1284 let offset = FixedViewportOffset::zero(app);
1285 let viewport = RenderViewport::new(
1286 app,
1287 AxisDirection::Right,
1288 offset.as_viewport_offset(),
1289 Some(vec![sliver]),
1290 None,
1291 );
1292 let constraints = BoxConstraints::tight(size);
1293 let configuration = ViewConfiguration::new(constraints, constraints, 1.0);
1294 let view = RenderView::new(
1295 app,
1296 Some(viewport.as_box()),
1297 Some(configuration),
1298 Rc::new(TestView::default()) as ViewRef,
1299 );
1300 let owner = PipelineOwner::new(app, None, None);
1301 owner.set_root_node(app, Some(view.as_object()));
1302 view.prepare_initial_frame(app);
1303 owner.flush_layout(app);
1304 ScrollHarness {
1305 owner,
1306 viewport,
1307 offset,
1308 }
1309 }
1310
1311 pub(crate) fn scroll_to(&self, app: &mut App, pixels: f64) {
1313 let current = self.offset.pixels(app);
1314 self.offset.correct_by(app, pixels - current);
1315 self.viewport.mark_needs_layout(app);
1316 self.owner.flush_layout(app);
1317 }
1318 }
1319}