From 309259aeb62c287cee2c9a4dbd2b44792373dcd5 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 22 Feb 2024 02:09:16 +0100 Subject: [PATCH] LibWeb: Clamp scroll offset into valid range after relayout If the layout has been recalculated and the sizes of scrollable overflow rectangles could have changed, we need to ensure that scroll offsets remain within the valid range. --- .../Text/expected/resize-scrollable-box.txt | 2 ++ .../Text/input/resize-scrollable-box.html | 36 +++++++++++++++++++ .../Libraries/LibWeb/Layout/LayoutState.cpp | 7 ++++ 3 files changed, 45 insertions(+) create mode 100644 Tests/LibWeb/Text/expected/resize-scrollable-box.txt create mode 100644 Tests/LibWeb/Text/input/resize-scrollable-box.html diff --git a/Tests/LibWeb/Text/expected/resize-scrollable-box.txt b/Tests/LibWeb/Text/expected/resize-scrollable-box.txt new file mode 100644 index 0000000000..0e5e11a619 --- /dev/null +++ b/Tests/LibWeb/Text/expected/resize-scrollable-box.txt @@ -0,0 +1,2 @@ + Item 1Item 2Item 3Item 4Item 5Item 6Item 7Item 8Item 9Item 10Item 11Item 12 scrollLeft (before resize): 1130 +scrollLeft (after resize): 830 diff --git a/Tests/LibWeb/Text/input/resize-scrollable-box.html b/Tests/LibWeb/Text/input/resize-scrollable-box.html new file mode 100644 index 0000000000..27487dbb69 --- /dev/null +++ b/Tests/LibWeb/Text/input/resize-scrollable-box.html @@ -0,0 +1,36 @@ + + +
+ Item 1Item 2Item 3Item 4Item 5Item 6Item 7Item 8Item 9Item 10Item 11Item 12 +
+ + + diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp index 10243fb0e1..115b7b10ac 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp @@ -352,6 +352,13 @@ void LayoutState::commit(Box& root) continue; auto const& box = static_cast(used_values.node()); measure_scrollable_overflow(box); + + // The scroll offset can become invalid if the scrollable overflow rectangle has changed after layout. + // For example, if the scroll container has been scrolled to the very end and is then resized to become larger + // (scrollable overflow rect become smaller), the scroll offset would be out of bounds. + auto& paintable_box = const_cast(*box.paintable_box()); + if (!paintable_box.scroll_offset().is_zero()) + paintable_box.set_scroll_offset(paintable_box.scroll_offset()); } }