Skip to content

Commit

Permalink
Fix infinite loop with very large ListView
Browse files Browse the repository at this point in the history
  • Loading branch information
ogoffart committed Jan 20, 2025
1 parent 4da79ac commit e11ef5c
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 7 deletions.
12 changes: 5 additions & 7 deletions internal/core/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@ impl<C: RepeatedItemTree + 'static> Repeater<C> {
(inner.offset, first_item_y + vp_y)
};

let mut loop_count = 0;
loop {
// If there is a gap before the new_offset and the beginning of the visible viewport,
// try to fill it with items. First look at items that are before new_offset in the
Expand Down Expand Up @@ -1154,15 +1155,12 @@ impl<C: RepeatedItemTree + 'static> Repeater<C> {
inner.instances.push((RepeatedInstanceState::Clean, Some(new_instance)));
idx += 1;
}
if y < listview_height && vp_y < zero {
if y < listview_height && vp_y < zero && loop_count < 3 {
assert!(idx >= row_count);
// we reached the end of the model, and we still have room. scroll a bit up.
let new_vp_y = vp_y + (listview_height - y);
// check that we actually did scroll (for very large lists we can exceed the precision of f32 and have an infinite loop)
if new_vp_y != vp_y {
vp_y = new_vp_y;
continue;
}
vp_y += listview_height - y;
loop_count += 1;
continue;
}

// Let's cleanup the instances that are not shown.
Expand Down
8 changes: 8 additions & 0 deletions tests/cases/elements/listview-millions.slint
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ assert_eq!(clicked.borrow().as_slice(), &[210000012]);
slint_testing::send_mouse_click(&instance, 5., 263.);
slint_testing::send_mouse_click(&instance, 5., 239.);
assert_eq!(clicked.borrow().as_slice(), &[210000012, 210000013, 210000011]);
// go all the way to the end, it shouldn't crash or loop forever
instance.set_viewport_y(-20. * (2130000000. - 5.));
slint_testing::send_mouse_click(&instance, 5., 250.);
```
```cpp
Expand Down Expand Up @@ -124,6 +128,10 @@ assert.deepEqual(clicked, [210000012]);
slintlib.private_api.send_mouse_click(instance, 5., 263.);
slintlib.private_api.send_mouse_click(instance, 5., 239.);
assert.deepEqual(clicked, [210000012, 210000013, 210000011]);
// go all the way to the end, it shouldn't crash or loop forever
instance.viewport_y=(-20. * (2130000000. - 5.));
slintlib.private_api.send_mouse_click(instance, 5., 250.);
```
Expand Down

0 comments on commit e11ef5c

Please sign in to comment.