LibWeb: Do not mutate display list while scroll offset application

Copy a display list item and apply scroll offset instead of mutating
display list directly.

It's a preparation for upcoming changes where a display list will be
cached across repaints and used multiple times with different scroll
offsets.
This commit is contained in:
Aliaksandr Kalenik 2024-08-11 16:46:35 +02:00 committed by Andreas Kling
commit e2ad568095
Notes: github-actions[bot] 2024-08-19 16:58:23 +00:00
3 changed files with 32 additions and 24 deletions

View file

@ -2128,13 +2128,15 @@ RefPtr<Painting::DisplayList> Navigable::record_display_list(PaintConfig config)
viewport_paintable.paint_all_phases(context);
Vector<Gfx::IntPoint> scroll_offsets_by_frame_id;
scroll_offsets_by_frame_id.resize(viewport_paintable.scroll_state.size());
for (auto [_, scrollable_frame] : viewport_paintable.scroll_state) {
auto scroll_offset = context.rounded_device_point(scrollable_frame->cumulative_offset).to_type<int>();
scroll_offsets_by_frame_id[scrollable_frame->id] = scroll_offset;
display_list->set_device_pixels_per_css_pixel(page.client().device_pixels_per_css_pixel());
Vector<RefPtr<Painting::ScrollFrame>> scroll_state;
scroll_state.resize(viewport_paintable.scroll_state.size());
for (auto& [_, scrollable_frame] : viewport_paintable.scroll_state) {
scroll_state[scrollable_frame->id] = scrollable_frame;
}
display_list_recorder.display_list().apply_scroll_offsets(scroll_offsets_by_frame_id);
display_list->set_scroll_state(move(scroll_state));
m_needs_repaint = false;

View file

@ -24,28 +24,26 @@ static Optional<Gfx::IntRect> command_bounding_rectangle(Command const& command)
});
}
void DisplayList::apply_scroll_offsets(Vector<Gfx::IntPoint> const& offsets_by_frame_id)
{
for (auto& command_with_scroll_id : m_commands) {
if (command_with_scroll_id.scroll_frame_id.has_value()) {
auto const& scroll_frame_id = command_with_scroll_id.scroll_frame_id.value();
auto const& scroll_offset = offsets_by_frame_id[scroll_frame_id];
command_with_scroll_id.command.visit(
[&](auto& command) {
if constexpr (requires { command.translate_by(scroll_offset); })
command.translate_by(scroll_offset);
});
}
}
}
void DisplayListPlayer::execute(DisplayList& display_list)
{
auto const& commands = display_list.commands();
auto const& scroll_state = display_list.scroll_state();
auto device_pixels_per_css_pixel = display_list.device_pixels_per_css_pixel();
size_t next_command_index = 0;
while (next_command_index < commands.size()) {
auto const& command = commands[next_command_index++].command;
auto scroll_frame_id = commands[next_command_index].scroll_frame_id;
auto command = commands[next_command_index++].command;
if (scroll_frame_id.has_value()) {
auto const& scroll_offset = scroll_state[scroll_frame_id.value()]->cumulative_offset.to_type<double>().scaled(device_pixels_per_css_pixel).to_type<int>();
command.visit(
[&](auto& command) {
if constexpr (requires { command.translate_by(scroll_offset); }) {
command.translate_by(scroll_offset);
}
});
}
auto bounding_rect = command_bounding_rectangle(command);
if (bounding_rect.has_value() && (bounding_rect->is_empty() || would_be_fully_clipped_by_painter(*bounding_rect))) {
continue;

View file

@ -29,6 +29,7 @@
#include <LibWeb/Painting/Command.h>
#include <LibWeb/Painting/GradientData.h>
#include <LibWeb/Painting/PaintBoxShadowParams.h>
#include <LibWeb/Painting/ScrollFrame.h>
namespace Web::Painting {
@ -83,8 +84,6 @@ public:
void append(Command&& command, Optional<i32> scroll_frame_id);
void apply_scroll_offsets(Vector<Gfx::IntPoint> const& offsets_by_frame_id);
struct CommandListItem {
Optional<i32> scroll_frame_id;
Command command;
@ -92,10 +91,19 @@ public:
AK::SegmentedVector<CommandListItem, 512> const& commands() const { return m_commands; }
void set_scroll_state(Vector<RefPtr<ScrollFrame>> scroll_state) { m_scroll_state = move(scroll_state); }
Vector<RefPtr<ScrollFrame>> const& scroll_state() const { return m_scroll_state; }
void set_device_pixels_per_css_pixel(double device_pixels_per_css_pixel) { m_device_pixels_per_css_pixel = device_pixels_per_css_pixel; }
double device_pixels_per_css_pixel() const { return m_device_pixels_per_css_pixel; }
private:
DisplayList() = default;
AK::SegmentedVector<CommandListItem, 512> m_commands;
Vector<RefPtr<ScrollFrame>> m_scroll_state;
double m_device_pixels_per_css_pixel;
};
}