1use std::rc::Rc;
4
5use inset_embedder::{Matrix4, Offset};
6use inset_foundation::{App, Handle, PRECISION_ERROR_TOLERANCE};
7
8use crate::box_::AnyRenderBox;
9use crate::object::{
10 AnyRenderObject, ContainerRenderObjectData, ContainerRenderObjectMixin, RenderHandle,
11 RenderObject, RenderObjectData,
12};
13use crate::painting_context::PaintingContext;
14use crate::pipeline_owner::PipelineOwner;
15use crate::sliver::{
16 RenderSliver, RenderSliverData, RenderSliverHelpers, SliverGeometry, SliverHitTestResult,
17};
18use crate::sliver_multi_box_adaptor::{
19 RenderSliverBoxChildManager, RenderSliverMultiBoxAdaptor, RenderSliverMultiBoxAdaptorData,
20 RenderSliverWithKeepAliveMixin, SliverMultiBoxAdaptorParentData,
21};
22
23pub struct RenderSliverList {
33 render_object: RenderObjectData,
34 render_sliver: RenderSliverData,
35 container: ContainerRenderObjectData<AnyRenderBox>,
36 adaptor: RenderSliverMultiBoxAdaptorData,
37}
38
39impl RenderSliverList {
40 pub fn new(
42 app: &mut App,
43 child_manager: Rc<dyn RenderSliverBoxChildManager>,
44 ) -> RenderHandle<RenderSliverList> {
45 RenderHandle::new_sliver(
46 app,
47 RenderSliverList {
48 render_object: RenderObjectData::new(),
49 render_sliver: RenderSliverData::new(),
50 container: ContainerRenderObjectData::new(),
51 adaptor: RenderSliverMultiBoxAdaptorData::new(child_manager),
52 },
53 )
54 }
55}
56
57impl ContainerRenderObjectMixin for RenderSliverList {
58 type ChildType = AnyRenderBox;
59 type ParentDataType = SliverMultiBoxAdaptorParentData;
60
61 fn container_data(
62 self: RenderHandle<Self>,
63 app: &App,
64 ) -> &ContainerRenderObjectData<AnyRenderBox> {
65 &self.get(app).container
66 }
67
68 fn container_data_mut(
69 self: RenderHandle<Self>,
70 app: &mut App,
71 ) -> &mut ContainerRenderObjectData<AnyRenderBox> {
72 &mut self.get_mut(app).container
73 }
74
75 fn insert(
76 self: RenderHandle<Self>,
77 app: &mut App,
78 child: AnyRenderBox,
79 after: Option<AnyRenderBox>,
80 ) {
81 RenderSliverMultiBoxAdaptor::insert(self, app, child, after)
82 }
83
84 fn move_child(
85 self: RenderHandle<Self>,
86 app: &mut App,
87 child: AnyRenderBox,
88 after: Option<AnyRenderBox>,
89 ) {
90 RenderSliverMultiBoxAdaptor::move_child(self, app, child, after)
91 }
92
93 fn remove(self: RenderHandle<Self>, app: &mut App, child: AnyRenderBox) {
94 RenderSliverMultiBoxAdaptor::remove(self, app, child)
95 }
96
97 fn remove_all(self: RenderHandle<Self>, app: &mut App) {
98 RenderSliverMultiBoxAdaptor::remove_all(self, app)
99 }
100}
101
102impl RenderSliverHelpers for RenderSliverList {}
103
104impl RenderSliverWithKeepAliveMixin for RenderSliverList {}
105
106impl RenderSliverMultiBoxAdaptor for RenderSliverList {
107 crate::render_sliver_multi_box_adaptor_accessors!();
108}
109
110impl RenderObject for RenderSliverList {
111 crate::render_object_accessors!();
112
113 fn setup_parent_data(self: RenderHandle<Self>, app: &mut App, child: AnyRenderObject) {
114 RenderSliverMultiBoxAdaptor::setup_parent_data(self, app, child);
115 RenderSliverWithKeepAliveMixin::setup_parent_data(self, app, child);
116 }
117
118 fn visit_children(
119 self: RenderHandle<Self>,
120 app: &App,
121 visitor: &mut dyn FnMut(AnyRenderObject),
122 ) {
123 RenderSliverMultiBoxAdaptor::visit_children(self, app, visitor)
124 }
125
126 fn did_attach(self: RenderHandle<Self>, app: &mut App, owner: Handle<PipelineOwner>) {
127 RenderSliverMultiBoxAdaptor::did_attach(self, app, owner)
128 }
129
130 fn did_detach(self: RenderHandle<Self>, app: &mut App) {
131 RenderSliverMultiBoxAdaptor::did_detach(self, app)
132 }
133
134 fn redepth_children(self: RenderHandle<Self>, app: &mut App) {
135 RenderSliverMultiBoxAdaptor::redepth_children(self, app)
136 }
137
138 fn apply_paint_transform(
139 self: RenderHandle<Self>,
140 app: &App,
141 child: AnyRenderObject,
142 transform: &mut Matrix4,
143 ) {
144 RenderSliverMultiBoxAdaptor::apply_paint_transform(self, app, child, transform)
145 }
146
147 fn paint(
148 self: RenderHandle<Self>,
149 app: &mut App,
150 context: &mut PaintingContext,
151 offset: Offset,
152 ) {
153 RenderSliverMultiBoxAdaptor::paint(self, app, context, offset)
154 }
155
156 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
157 let constraints = self.constraints(app);
158 let child_manager = self.child_manager(app);
159 child_manager.did_start_layout(app);
160 child_manager.set_did_underflow(app, false);
161
162 let scroll_offset = constraints.scroll_offset + constraints.cache_origin;
163 debug_assert!(scroll_offset >= 0.0);
164 let remaining_extent = constraints.remaining_cache_extent;
165 debug_assert!(remaining_extent >= 0.0);
166 let target_end_scroll_offset = scroll_offset + remaining_extent;
167 let child_constraints = constraints.as_box_constraints(0.0, f64::INFINITY, None);
168 let mut leading_garbage = 0;
169 let mut trailing_garbage = 0;
170 let mut reached_end = false;
171
172 if self.first_child(app).is_none() && !self.add_initial_child(app, 0, 0.0) {
188 self.set_geometry(app, SliverGeometry::ZERO);
190 child_manager.did_finish_layout(app);
191 return;
192 }
193
194 let mut leading_child_with_layout: Option<AnyRenderBox> = None;
200 let mut trailing_child_with_layout: Option<AnyRenderBox> = None;
201
202 let mut earliest_useful_child = self.first_child(app);
203
204 let first_child = self.first_child(app).expect("checked above");
209 if RenderSliver::child_scroll_offset(self, app, first_child.as_object()).is_none() {
210 let mut leading_children_without_layout_offset = 0;
211 while let Some(current) = earliest_useful_child {
212 if RenderSliver::child_scroll_offset(self, app, current.as_object()).is_some() {
213 break;
214 }
215 earliest_useful_child = self.child_after(app, current);
216 leading_children_without_layout_offset += 1;
217 }
218 self.collect_garbage(app, leading_children_without_layout_offset, 0);
221 if self.first_child(app).is_none() && !self.add_initial_child(app, 0, 0.0) {
223 self.set_geometry(app, SliverGeometry::ZERO);
225 child_manager.did_finish_layout(app);
226 return;
227 }
228 }
229
230 earliest_useful_child = self.first_child(app);
232 loop {
233 let current = earliest_useful_child.expect("the child list is not empty");
234 let earliest_scroll_offset =
235 RenderSliver::child_scroll_offset(self, app, current.as_object())
236 .expect("a laid-out child has a scroll offset");
237 if earliest_scroll_offset <= scroll_offset {
238 break;
239 }
240 earliest_useful_child =
242 self.insert_and_layout_leading_child(app, child_constraints, true);
243 let Some(inserted) = earliest_useful_child else {
244 let first_child = self.first_child(app).expect("the child list is not empty");
245 first_child
246 .as_object()
247 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
248 .set_layout_offset(Some(0.0));
249
250 if scroll_offset == 0.0 {
251 first_child.layout(app, child_constraints, true);
255 leading_child_with_layout = Some(first_child);
256 trailing_child_with_layout.get_or_insert(first_child);
257 break;
258 }
259 self.set_geometry(
263 app,
264 SliverGeometry::builder()
265 .scroll_offset_correction(-scroll_offset)
266 .build(),
267 );
268 return;
269 };
270
271 let first_child = self.first_child(app).expect("the child list is not empty");
272 let first_child_scroll_offset =
273 earliest_scroll_offset - self.paint_extent_of(app, first_child);
274 if first_child_scroll_offset < -PRECISION_ERROR_TOLERANCE {
276 self.set_geometry(
279 app,
280 SliverGeometry::builder()
281 .scroll_offset_correction(-first_child_scroll_offset)
282 .build(),
283 );
284 first_child
285 .as_object()
286 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
287 .set_layout_offset(Some(0.0));
288 return;
289 }
290
291 inserted
292 .as_object()
293 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
294 .set_layout_offset(Some(first_child_scroll_offset));
295 debug_assert_eq!(Some(inserted), self.first_child(app));
296 leading_child_with_layout = Some(inserted);
297 trailing_child_with_layout.get_or_insert(inserted);
298 }
299
300 debug_assert!(
301 RenderSliver::child_scroll_offset(
302 self,
303 app,
304 self.first_child(app).expect("not empty").as_object()
305 )
306 .expect("laid out")
307 > -PRECISION_ERROR_TOLERANCE
308 );
309
310 if scroll_offset < PRECISION_ERROR_TOLERANCE {
313 loop {
315 let first_child = self.first_child(app).expect("the child list is not empty");
316 if self.index_of(app, first_child) <= 0 {
317 break;
318 }
319 let earliest_scroll_offset =
320 RenderSliver::child_scroll_offset(self, app, first_child.as_object())
321 .expect("laid out");
322 let inserted = self.insert_and_layout_leading_child(app, child_constraints, true);
325 debug_assert!(inserted.is_some());
326 let first_child = self.first_child(app).expect("the child list is not empty");
327 let first_child_scroll_offset =
328 earliest_scroll_offset - self.paint_extent_of(app, first_child);
329 first_child
330 .as_object()
331 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
332 .set_layout_offset(Some(0.0));
333 if first_child_scroll_offset < -PRECISION_ERROR_TOLERANCE {
335 self.set_geometry(
336 app,
337 SliverGeometry::builder()
338 .scroll_offset_correction(-first_child_scroll_offset)
339 .build(),
340 );
341 return;
342 }
343 }
344 }
345
346 let earliest_useful_child = self.first_child(app).expect("the child list is not empty");
352
353 if leading_child_with_layout.is_none() {
356 earliest_useful_child.layout(app, child_constraints, true);
357 trailing_child_with_layout = Some(earliest_useful_child);
358 }
359
360 let mut in_layout_range = true;
365 let mut child = Some(earliest_useful_child);
366 let mut index = self.index_of(app, earliest_useful_child);
367 let mut end_scroll_offset =
368 RenderSliver::child_scroll_offset(self, app, earliest_useful_child.as_object())
369 .expect("laid out")
370 + self.paint_extent_of(app, earliest_useful_child);
371
372 let advance = |app: &mut App,
374 child: &mut Option<AnyRenderBox>,
375 index: &mut i32,
376 end_scroll_offset: &mut f64,
377 in_layout_range: &mut bool,
378 trailing_child_with_layout: &mut Option<AnyRenderBox>|
379 -> bool {
380 let current = child.expect("advance is only called with a child");
382 if Some(current) == *trailing_child_with_layout {
383 *in_layout_range = false;
384 }
385 *child = self.child_after(app, current);
386 if child.is_none() {
387 *in_layout_range = false;
388 }
389 *index += 1;
390 if !*in_layout_range {
391 if child.is_none_or(|current| self.index_of(app, current) != *index) {
392 *child = self.insert_and_layout_child(
394 app,
395 child_constraints,
396 *trailing_child_with_layout,
397 true,
398 );
399 if child.is_none() {
400 return false;
402 }
403 } else {
404 child.expect("checked").layout(app, child_constraints, true);
406 }
407 *trailing_child_with_layout = *child;
408 }
409 let current = child.expect("set above");
410 let child_parent_data = current
411 .as_object()
412 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app);
413 child_parent_data.set_layout_offset(Some(*end_scroll_offset));
414 debug_assert_eq!(child_parent_data.index, Some(*index));
415 *end_scroll_offset = RenderSliver::child_scroll_offset(self, app, current.as_object())
416 .expect("just set")
417 + self.paint_extent_of(app, current);
418 true
419 };
420
421 while end_scroll_offset < scroll_offset {
423 leading_garbage += 1;
424 if !advance(
425 app,
426 &mut child,
427 &mut index,
428 &mut end_scroll_offset,
429 &mut in_layout_range,
430 &mut trailing_child_with_layout,
431 ) {
432 debug_assert_eq!(leading_garbage, self.child_count(app));
433 debug_assert!(child.is_none());
434 self.collect_garbage(app, leading_garbage - 1, 0);
437 debug_assert_eq!(self.first_child(app), self.last_child(app));
438 let last_child = self.last_child(app).expect("one child is kept");
439 let extent = RenderSliver::child_scroll_offset(self, app, last_child.as_object())
440 .expect("laid out")
441 + self.paint_extent_of(app, last_child);
442 self.set_geometry(
443 app,
444 SliverGeometry::builder()
445 .scroll_extent(extent)
446 .max_paint_extent(extent)
447 .build(),
448 );
449 return;
450 }
451 }
452
453 while end_scroll_offset < target_end_scroll_offset {
455 if !advance(
456 app,
457 &mut child,
458 &mut index,
459 &mut end_scroll_offset,
460 &mut in_layout_range,
461 &mut trailing_child_with_layout,
462 ) {
463 reached_end = true;
464 break;
465 }
466 }
467
468 if let Some(current) = child {
470 let mut walker = self.child_after(app, current);
471 while let Some(current) = walker {
472 trailing_garbage += 1;
473 walker = self.child_after(app, current);
474 }
475 }
476
477 self.collect_garbage(app, leading_garbage, trailing_garbage);
480
481 debug_assert!(self.debug_assert_child_list_is_non_empty_and_contiguous(app));
482 let first_child = self.first_child(app).expect("not empty");
483 let last_child = self.last_child(app).expect("not empty");
484 let leading_scroll_offset =
485 RenderSliver::child_scroll_offset(self, app, first_child.as_object())
486 .expect("laid out");
487 let estimated_max_scroll_offset = if reached_end {
488 end_scroll_offset
489 } else {
490 let estimated = child_manager.estimate_max_scroll_offset(
491 app,
492 constraints,
493 Some(self.index_of(app, first_child)),
494 Some(self.index_of(app, last_child)),
495 Some(leading_scroll_offset),
496 Some(end_scroll_offset),
497 );
498 debug_assert!(estimated >= end_scroll_offset - leading_scroll_offset);
499 estimated
500 };
501 let paint_extent =
502 self.calculate_paint_offset(app, constraints, leading_scroll_offset, end_scroll_offset);
503 let cache_extent =
504 self.calculate_cache_offset(app, constraints, leading_scroll_offset, end_scroll_offset);
505 let target_end_scroll_offset_for_paint =
506 constraints.scroll_offset + constraints.remaining_paint_extent;
507 self.set_geometry(
508 app,
509 SliverGeometry::builder()
510 .scroll_extent(estimated_max_scroll_offset)
511 .paint_extent(paint_extent)
512 .cache_extent(cache_extent)
513 .max_paint_extent(estimated_max_scroll_offset)
514 .has_visual_overflow(
516 end_scroll_offset > target_end_scroll_offset_for_paint
517 || constraints.scroll_offset > 0.0,
518 )
519 .build(),
520 );
521
522 if estimated_max_scroll_offset == end_scroll_offset {
525 child_manager.set_did_underflow(app, true);
526 }
527 child_manager.did_finish_layout(app);
528 }
529}
530
531impl RenderSliver for RenderSliverList {
532 crate::render_sliver_accessors!();
533
534 fn hit_test_children(
535 self: RenderHandle<Self>,
536 app: &mut App,
537 result: &mut SliverHitTestResult<'_>,
538 main_axis_position: f64,
539 cross_axis_position: f64,
540 ) -> bool {
541 RenderSliverMultiBoxAdaptor::hit_test_children(
542 self,
543 app,
544 result,
545 main_axis_position,
546 cross_axis_position,
547 )
548 }
549
550 fn child_main_axis_position(
551 self: RenderHandle<Self>,
552 app: &App,
553 child: AnyRenderObject,
554 ) -> f64 {
555 RenderSliverMultiBoxAdaptor::child_main_axis_position(self, app, child)
556 }
557
558 fn child_scroll_offset(
559 self: RenderHandle<Self>,
560 app: &App,
561 child: AnyRenderObject,
562 ) -> Option<f64> {
563 RenderSliverMultiBoxAdaptor::child_scroll_offset(self, app, child)
564 }
565}
566
567#[cfg(test)]
568mod tests {
569 use inset_embedder::Size;
570 use inset_foundation::AppCell;
571 use inset_gestures::HitTestResult;
572
573 use super::*;
574 use crate::sliver_multi_box_adaptor::test_support::TestChildManager;
575 use crate::sliver_multi_box_adaptor::viewport_test_support::ScrollHarness;
576
577 const VIEWPORT: Size = Size::new(100.0, 200.0);
578
579 fn sliver_list(
580 app: &mut App,
581 extents: Vec<f64>,
582 ) -> (
583 RenderHandle<RenderSliverList>,
584 Rc<TestChildManager<RenderSliverList>>,
585 ScrollHarness,
586 ) {
587 let manager = TestChildManager::new(extents);
588 let list = RenderSliverList::new(app, manager.clone());
589 manager.attach(list);
590 let harness = ScrollHarness::new(app, list.as_sliver(), VIEWPORT);
591 (list, manager, harness)
592 }
593
594 #[test]
597 fn a_sliver_list_stacks_children_of_differing_extents() {
598 let cell = AppCell::new();
599 let mut app = cell.borrow_mut();
600 let (list, _, _harness) = sliver_list(&mut app, vec![40.0, 60.0, 80.0, 100.0, 120.0]);
601
602 let first = list.first_child(&app).expect("children were created");
603 let second = list.child_after(&app, first).expect("two children");
604 let third = list.child_after(&app, second).expect("three children");
605 assert_eq!(
606 RenderSliver::child_scroll_offset(list, &app, first.as_object()),
607 Some(0.0)
608 );
609 assert_eq!(
610 RenderSliver::child_scroll_offset(list, &app, second.as_object()),
611 Some(40.0)
612 );
613 assert_eq!(
614 RenderSliver::child_scroll_offset(list, &app, third.as_object()),
615 Some(100.0)
616 );
617 assert_eq!(list.geometry(&app).paint_extent, 200.0);
618 assert!(list.geometry(&app).has_visual_overflow);
619 }
620
621 #[test]
623 fn a_short_sliver_list_reports_its_exact_extent() {
624 let cell = AppCell::new();
625 let mut app = cell.borrow_mut();
626 let (list, manager, _harness) = sliver_list(&mut app, vec![40.0, 60.0]);
627
628 let geometry = list.geometry(&app);
629 assert_eq!(geometry.scroll_extent, 100.0);
630 assert_eq!(geometry.paint_extent, 100.0);
631 assert!(!geometry.has_visual_overflow);
632 assert_eq!(list.child_count(&app), 2);
633 assert!(manager.did_underflow.get());
634 }
635
636 #[test]
638 fn scrolling_a_sliver_list_replaces_its_children() {
639 let cell = AppCell::new();
640 let mut app = cell.borrow_mut();
641 let (list, _, harness) = sliver_list(&mut app, vec![100.0; 30]);
642 assert_eq!(
643 list.index_of(&app, list.first_child(&app).expect("built")),
644 0
645 );
646
647 harness.scroll_to(&mut app, 1500.0);
648
649 let first = list.first_child(&app).expect("children were created");
650 assert_eq!(list.index_of(&app, first), 12);
652 assert!(list.geometry(&app).has_visual_overflow);
653 }
654
655 #[test]
657 fn a_sliver_list_hit_tests_its_children() {
658 let cell = AppCell::new();
659 let mut app = cell.borrow_mut();
660 let (list, _, _harness) = sliver_list(&mut app, vec![50.0; 20]);
661
662 let mut result = HitTestResult::new();
663 let hit = list.hit_test(
664 &mut app,
665 &mut SliverHitTestResult::wrap(&mut result),
666 120.0,
667 10.0,
668 );
669
670 assert!(hit);
671 assert_eq!(result.path().len(), 2);
672 }
673
674 #[test]
676 fn a_sliver_list_keeps_a_child_alive() {
677 let cell = AppCell::new();
678 let mut app = cell.borrow_mut();
679 let (list, _, harness) = sliver_list(&mut app, vec![100.0; 30]);
680 let first = list.first_child(&app).expect("children were created");
681 first
682 .as_object()
683 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(&mut app)
684 .set_keep_alive(true);
685
686 harness.scroll_to(&mut app, 2000.0);
687
688 assert_eq!(list.keep_alive_children(&app), vec![first]);
689 assert!(first.as_object().attached(&app));
690 }
691}