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::new().scroll_offset_correction(-scroll_offset),
265 );
266 return;
267 };
268
269 let first_child = self.first_child(app).expect("the child list is not empty");
270 let first_child_scroll_offset =
271 earliest_scroll_offset - self.paint_extent_of(app, first_child);
272 if first_child_scroll_offset < -PRECISION_ERROR_TOLERANCE {
274 self.set_geometry(
277 app,
278 SliverGeometry::new().scroll_offset_correction(-first_child_scroll_offset),
279 );
280 first_child
281 .as_object()
282 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
283 .set_layout_offset(Some(0.0));
284 return;
285 }
286
287 inserted
288 .as_object()
289 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
290 .set_layout_offset(Some(first_child_scroll_offset));
291 debug_assert_eq!(Some(inserted), self.first_child(app));
292 leading_child_with_layout = Some(inserted);
293 trailing_child_with_layout.get_or_insert(inserted);
294 }
295
296 debug_assert!(
297 RenderSliver::child_scroll_offset(
298 self,
299 app,
300 self.first_child(app).expect("not empty").as_object()
301 )
302 .expect("laid out")
303 > -PRECISION_ERROR_TOLERANCE
304 );
305
306 if scroll_offset < PRECISION_ERROR_TOLERANCE {
309 loop {
311 let first_child = self.first_child(app).expect("the child list is not empty");
312 if self.index_of(app, first_child) <= 0 {
313 break;
314 }
315 let earliest_scroll_offset =
316 RenderSliver::child_scroll_offset(self, app, first_child.as_object())
317 .expect("laid out");
318 let inserted = self.insert_and_layout_leading_child(app, child_constraints, true);
321 debug_assert!(inserted.is_some());
322 let first_child = self.first_child(app).expect("the child list is not empty");
323 let first_child_scroll_offset =
324 earliest_scroll_offset - self.paint_extent_of(app, first_child);
325 first_child
326 .as_object()
327 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app)
328 .set_layout_offset(Some(0.0));
329 if first_child_scroll_offset < -PRECISION_ERROR_TOLERANCE {
331 self.set_geometry(
332 app,
333 SliverGeometry::new().scroll_offset_correction(-first_child_scroll_offset),
334 );
335 return;
336 }
337 }
338 }
339
340 let earliest_useful_child = self.first_child(app).expect("the child list is not empty");
346
347 if leading_child_with_layout.is_none() {
350 earliest_useful_child.layout(app, child_constraints, true);
351 trailing_child_with_layout = Some(earliest_useful_child);
352 }
353
354 let mut in_layout_range = true;
359 let mut child = Some(earliest_useful_child);
360 let mut index = self.index_of(app, earliest_useful_child);
361 let mut end_scroll_offset =
362 RenderSliver::child_scroll_offset(self, app, earliest_useful_child.as_object())
363 .expect("laid out")
364 + self.paint_extent_of(app, earliest_useful_child);
365
366 let advance = |app: &mut App,
368 child: &mut Option<AnyRenderBox>,
369 index: &mut i32,
370 end_scroll_offset: &mut f64,
371 in_layout_range: &mut bool,
372 trailing_child_with_layout: &mut Option<AnyRenderBox>|
373 -> bool {
374 let current = child.expect("advance is only called with a child");
376 if Some(current) == *trailing_child_with_layout {
377 *in_layout_range = false;
378 }
379 *child = self.child_after(app, current);
380 if child.is_none() {
381 *in_layout_range = false;
382 }
383 *index += 1;
384 if !*in_layout_range {
385 if child.is_none_or(|current| self.index_of(app, current) != *index) {
386 *child = self.insert_and_layout_child(
388 app,
389 child_constraints,
390 *trailing_child_with_layout,
391 true,
392 );
393 if child.is_none() {
394 return false;
396 }
397 } else {
398 child.expect("checked").layout(app, child_constraints, true);
400 }
401 *trailing_child_with_layout = *child;
402 }
403 let current = child.expect("set above");
404 let child_parent_data = current
405 .as_object()
406 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(app);
407 child_parent_data.set_layout_offset(Some(*end_scroll_offset));
408 debug_assert_eq!(child_parent_data.index, Some(*index));
409 *end_scroll_offset = RenderSliver::child_scroll_offset(self, app, current.as_object())
410 .expect("just set")
411 + self.paint_extent_of(app, current);
412 true
413 };
414
415 while end_scroll_offset < scroll_offset {
417 leading_garbage += 1;
418 if !advance(
419 app,
420 &mut child,
421 &mut index,
422 &mut end_scroll_offset,
423 &mut in_layout_range,
424 &mut trailing_child_with_layout,
425 ) {
426 debug_assert_eq!(leading_garbage, self.child_count(app));
427 debug_assert!(child.is_none());
428 self.collect_garbage(app, leading_garbage - 1, 0);
431 debug_assert_eq!(self.first_child(app), self.last_child(app));
432 let last_child = self.last_child(app).expect("one child is kept");
433 let extent = RenderSliver::child_scroll_offset(self, app, last_child.as_object())
434 .expect("laid out")
435 + self.paint_extent_of(app, last_child);
436 self.set_geometry(
437 app,
438 SliverGeometry::new()
439 .scroll_extent(extent)
440 .max_paint_extent(extent),
441 );
442 return;
443 }
444 }
445
446 while end_scroll_offset < target_end_scroll_offset {
448 if !advance(
449 app,
450 &mut child,
451 &mut index,
452 &mut end_scroll_offset,
453 &mut in_layout_range,
454 &mut trailing_child_with_layout,
455 ) {
456 reached_end = true;
457 break;
458 }
459 }
460
461 if let Some(current) = child {
463 let mut walker = self.child_after(app, current);
464 while let Some(current) = walker {
465 trailing_garbage += 1;
466 walker = self.child_after(app, current);
467 }
468 }
469
470 self.collect_garbage(app, leading_garbage, trailing_garbage);
473
474 debug_assert!(self.debug_assert_child_list_is_non_empty_and_contiguous(app));
475 let first_child = self.first_child(app).expect("not empty");
476 let last_child = self.last_child(app).expect("not empty");
477 let leading_scroll_offset =
478 RenderSliver::child_scroll_offset(self, app, first_child.as_object())
479 .expect("laid out");
480 let estimated_max_scroll_offset = if reached_end {
481 end_scroll_offset
482 } else {
483 let estimated = child_manager.estimate_max_scroll_offset(
484 app,
485 constraints,
486 Some(self.index_of(app, first_child)),
487 Some(self.index_of(app, last_child)),
488 Some(leading_scroll_offset),
489 Some(end_scroll_offset),
490 );
491 debug_assert!(estimated >= end_scroll_offset - leading_scroll_offset);
492 estimated
493 };
494 let paint_extent =
495 self.calculate_paint_offset(app, constraints, leading_scroll_offset, end_scroll_offset);
496 let cache_extent =
497 self.calculate_cache_offset(app, constraints, leading_scroll_offset, end_scroll_offset);
498 let target_end_scroll_offset_for_paint =
499 constraints.scroll_offset + constraints.remaining_paint_extent;
500 self.set_geometry(
501 app,
502 SliverGeometry::new()
503 .scroll_extent(estimated_max_scroll_offset)
504 .paint_extent(paint_extent)
505 .cache_extent(cache_extent)
506 .max_paint_extent(estimated_max_scroll_offset)
507 .has_visual_overflow(
509 end_scroll_offset > target_end_scroll_offset_for_paint
510 || constraints.scroll_offset > 0.0,
511 ),
512 );
513
514 if estimated_max_scroll_offset == end_scroll_offset {
517 child_manager.set_did_underflow(app, true);
518 }
519 child_manager.did_finish_layout(app);
520 }
521}
522
523impl RenderSliver for RenderSliverList {
524 crate::render_sliver_accessors!();
525
526 fn hit_test_children(
527 self: RenderHandle<Self>,
528 app: &mut App,
529 result: &mut SliverHitTestResult<'_>,
530 main_axis_position: f64,
531 cross_axis_position: f64,
532 ) -> bool {
533 RenderSliverMultiBoxAdaptor::hit_test_children(
534 self,
535 app,
536 result,
537 main_axis_position,
538 cross_axis_position,
539 )
540 }
541
542 fn child_main_axis_position(
543 self: RenderHandle<Self>,
544 app: &App,
545 child: AnyRenderObject,
546 ) -> f64 {
547 RenderSliverMultiBoxAdaptor::child_main_axis_position(self, app, child)
548 }
549
550 fn child_scroll_offset(
551 self: RenderHandle<Self>,
552 app: &App,
553 child: AnyRenderObject,
554 ) -> Option<f64> {
555 RenderSliverMultiBoxAdaptor::child_scroll_offset(self, app, child)
556 }
557}
558
559#[cfg(test)]
560mod tests {
561 use inset_embedder::Size;
562 use inset_foundation::AppCell;
563 use inset_gestures::HitTestResult;
564
565 use super::*;
566 use crate::sliver_multi_box_adaptor::test_support::TestChildManager;
567 use crate::sliver_multi_box_adaptor::viewport_test_support::ScrollHarness;
568
569 const VIEWPORT: Size = Size::new(100.0, 200.0);
570
571 fn sliver_list(
572 app: &mut App,
573 extents: Vec<f64>,
574 ) -> (
575 RenderHandle<RenderSliverList>,
576 Rc<TestChildManager<RenderSliverList>>,
577 ScrollHarness,
578 ) {
579 let manager = TestChildManager::new(extents);
580 let list = RenderSliverList::new(app, manager.clone());
581 manager.attach(list);
582 let harness = ScrollHarness::new(app, list.as_sliver(), VIEWPORT);
583 (list, manager, harness)
584 }
585
586 #[test]
589 fn a_sliver_list_stacks_children_of_differing_extents() {
590 let cell = AppCell::new();
591 let mut app = cell.borrow_mut();
592 let (list, _, _harness) = sliver_list(&mut app, vec![40.0, 60.0, 80.0, 100.0, 120.0]);
593
594 let first = list.first_child(&app).expect("children were created");
595 let second = list.child_after(&app, first).expect("two children");
596 let third = list.child_after(&app, second).expect("three children");
597 assert_eq!(
598 RenderSliver::child_scroll_offset(list, &app, first.as_object()),
599 Some(0.0)
600 );
601 assert_eq!(
602 RenderSliver::child_scroll_offset(list, &app, second.as_object()),
603 Some(40.0)
604 );
605 assert_eq!(
606 RenderSliver::child_scroll_offset(list, &app, third.as_object()),
607 Some(100.0)
608 );
609 assert_eq!(list.geometry(&app).paint_extent, 200.0);
610 assert!(list.geometry(&app).has_visual_overflow);
611 }
612
613 #[test]
615 fn a_short_sliver_list_reports_its_exact_extent() {
616 let cell = AppCell::new();
617 let mut app = cell.borrow_mut();
618 let (list, manager, _harness) = sliver_list(&mut app, vec![40.0, 60.0]);
619
620 let geometry = list.geometry(&app);
621 assert_eq!(geometry.scroll_extent, 100.0);
622 assert_eq!(geometry.paint_extent, 100.0);
623 assert!(!geometry.has_visual_overflow);
624 assert_eq!(list.child_count(&app), 2);
625 assert!(manager.did_underflow.get());
626 }
627
628 #[test]
630 fn scrolling_a_sliver_list_replaces_its_children() {
631 let cell = AppCell::new();
632 let mut app = cell.borrow_mut();
633 let (list, _, harness) = sliver_list(&mut app, vec![100.0; 30]);
634 assert_eq!(
635 list.index_of(&app, list.first_child(&app).expect("built")),
636 0
637 );
638
639 harness.scroll_to(&mut app, 1500.0);
640
641 let first = list.first_child(&app).expect("children were created");
642 assert_eq!(list.index_of(&app, first), 12);
644 assert!(list.geometry(&app).has_visual_overflow);
645 }
646
647 #[test]
649 fn a_sliver_list_hit_tests_its_children() {
650 let cell = AppCell::new();
651 let mut app = cell.borrow_mut();
652 let (list, _, _harness) = sliver_list(&mut app, vec![50.0; 20]);
653
654 let mut result = HitTestResult::new();
655 let hit = list.hit_test(
656 &mut app,
657 &mut SliverHitTestResult::wrap(&mut result),
658 120.0,
659 10.0,
660 );
661
662 assert!(hit);
663 assert_eq!(result.path().len(), 2);
664 }
665
666 #[test]
668 fn a_sliver_list_keeps_a_child_alive() {
669 let cell = AppCell::new();
670 let mut app = cell.borrow_mut();
671 let (list, _, harness) = sliver_list(&mut app, vec![100.0; 30]);
672 let first = list.first_child(&app).expect("children were created");
673 first
674 .as_object()
675 .parent_data_of_mut::<SliverMultiBoxAdaptorParentData>(&mut app)
676 .set_keep_alive(true);
677
678 harness.scroll_to(&mut app, 2000.0);
679
680 assert_eq!(list.keep_alive_children(&app), vec![first]);
681 assert!(first.as_object().attached(&app));
682 }
683}