LibWeb: Store scroll and sticky frames state in single vector

This way we don't have to allocate separate vector with both scroll and
sticky frame that is used for display list player (scroll and sticky
frames share id pool), so player could access offset by frame id.

No behavior change.
This commit is contained in:
Aliaksandr Kalenik 2024-10-11 20:31:19 +02:00 committed by Alexander Kalenik
commit 6452bfb612
Notes: github-actions[bot] 2024-10-12 11:14:07 +00:00
7 changed files with 50 additions and 35 deletions

View file

@ -5582,17 +5582,7 @@ RefPtr<Painting::DisplayList> Document::record_display_list(PaintConfig config)
viewport_paintable.paint_all_phases(context);
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().scroll_frames().size() + viewport_paintable.scroll_state().sticky_frames().size());
for (auto const& scroll_frame : viewport_paintable.scroll_state().scroll_frames()) {
scroll_state[scroll_frame->id()] = scroll_frame;
}
for (auto const& scroll_frame : viewport_paintable.scroll_state().sticky_frames()) {
scroll_state[scroll_frame->id()] = scroll_frame;
}
display_list->set_scroll_state(move(scroll_state));
display_list->set_scroll_state(viewport_paintable.scroll_state());
m_needs_repaint = false;

View file

@ -37,7 +37,7 @@ void DisplayListPlayer::execute(DisplayList& display_list)
if (command.has<PaintScrollBar>()) {
auto& paint_scroll_bar = command.get<PaintScrollBar>();
auto const& scroll_offset = scroll_state[paint_scroll_bar.scroll_frame_id]->own_offset();
auto scroll_offset = scroll_state.own_offset_for_frame_with_id(paint_scroll_bar.scroll_frame_id);
if (paint_scroll_bar.vertical) {
auto offset = scroll_offset.y() * paint_scroll_bar.scroll_size;
paint_scroll_bar.rect.translate_by(0, -offset.to_int() * device_pixels_per_css_pixel);
@ -48,7 +48,8 @@ void DisplayListPlayer::execute(DisplayList& display_list)
}
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>();
auto cumulative_offset = scroll_state.cumulative_offset_for_frame_with_id(scroll_frame_id.value());
auto scroll_offset = 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); }) {

View file

@ -30,6 +30,7 @@
#include <LibWeb/Painting/GradientData.h>
#include <LibWeb/Painting/PaintBoxShadowParams.h>
#include <LibWeb/Painting/ScrollFrame.h>
#include <LibWeb/Painting/ScrollState.h>
namespace Web::Painting {
@ -96,9 +97,8 @@ 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_scroll_state(ScrollState scroll_state) { m_scroll_state = move(scroll_state); }
ScrollState 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; }
@ -107,7 +107,7 @@ private:
DisplayList() = default;
AK::SegmentedVector<CommandListItem, 512> m_commands;
Vector<RefPtr<ScrollFrame>> m_scroll_state;
ScrollState m_scroll_state;
double m_device_pixels_per_css_pixel;
};

View file

@ -9,9 +9,10 @@
namespace Web::Painting {
ScrollFrame::ScrollFrame(PaintableBox const& paintable_box, size_t id, RefPtr<ScrollFrame const> parent)
ScrollFrame::ScrollFrame(PaintableBox const& paintable_box, size_t id, bool sticky, RefPtr<ScrollFrame const> parent)
: m_paintable_box(paintable_box)
, m_id(id)
, m_sticky(sticky)
, m_parent(move(parent))
{
}

View file

@ -13,12 +13,14 @@ namespace Web::Painting {
class ScrollFrame : public RefCounted<ScrollFrame> {
public:
ScrollFrame(PaintableBox const& paintable_box, size_t id, RefPtr<ScrollFrame const> parent);
ScrollFrame(PaintableBox const& paintable_box, size_t id, bool sticky, RefPtr<ScrollFrame const> parent);
PaintableBox const& paintable_box() const { return *m_paintable_box; }
size_t id() const { return m_id; }
bool is_sticky() const { return m_sticky; }
CSSPixelPoint cumulative_offset() const
{
if (!m_cached_cumulative_offset.has_value()) {
@ -40,6 +42,7 @@ public:
private:
WeakPtr<PaintableBox> m_paintable_box;
size_t m_id { 0 };
bool m_sticky { false };
RefPtr<ScrollFrame const> m_parent;
CSSPixelPoint m_own_offset;

View file

@ -12,32 +12,52 @@ namespace Web::Painting {
class ScrollState {
public:
NonnullRefPtr<ScrollFrame> create_scroll_frame_for(PaintableBox const& paintable, RefPtr<ScrollFrame const> parent)
NonnullRefPtr<ScrollFrame> create_scroll_frame_for(PaintableBox const& paintable_box, RefPtr<ScrollFrame const> parent)
{
auto scroll_frame = adopt_ref(*new ScrollFrame(paintable, m_next_id++, parent));
auto scroll_frame = adopt_ref(*new ScrollFrame(paintable_box, m_scroll_frames.size(), false, move(parent)));
m_scroll_frames.append(scroll_frame);
return scroll_frame;
}
NonnullRefPtr<ScrollFrame> create_sticky_frame_for(PaintableBox const& paintable, RefPtr<ScrollFrame const> parent)
NonnullRefPtr<ScrollFrame> create_sticky_frame_for(PaintableBox const& paintable_box, RefPtr<ScrollFrame const> parent)
{
auto scroll_frame = adopt_ref(*new ScrollFrame(paintable, m_next_id++, parent));
m_sticky_frames.append(scroll_frame);
auto scroll_frame = adopt_ref(*new ScrollFrame(paintable_box, m_scroll_frames.size(), true, move(parent)));
m_scroll_frames.append(scroll_frame);
return scroll_frame;
}
void clear()
CSSPixelPoint cumulative_offset_for_frame_with_id(size_t id) const
{
m_scroll_frames.clear();
return m_scroll_frames[id]->cumulative_offset();
}
Vector<NonnullRefPtr<ScrollFrame>> const& scroll_frames() const { return m_scroll_frames; }
Vector<NonnullRefPtr<ScrollFrame>> const& sticky_frames() const { return m_sticky_frames; }
CSSPixelPoint own_offset_for_frame_with_id(size_t id) const
{
return m_scroll_frames[id]->own_offset();
}
template<typename Callback>
void for_each_scroll_frame(Callback callback) const
{
for (auto const& scroll_frame : m_scroll_frames) {
if (scroll_frame->is_sticky())
continue;
callback(scroll_frame);
}
}
template<typename Callback>
void for_each_sticky_frame(Callback callback) const
{
for (auto const& scroll_frame : m_scroll_frames) {
if (!scroll_frame->is_sticky())
continue;
callback(scroll_frame);
}
}
private:
size_t m_next_id { 0 };
Vector<NonnullRefPtr<ScrollFrame>> m_scroll_frames;
Vector<NonnullRefPtr<ScrollFrame>> m_sticky_frames;
};
}

View file

@ -179,13 +179,13 @@ void ViewportPaintable::refresh_scroll_state()
return;
m_needs_to_refresh_scroll_state = false;
for (auto const& scroll_frame : m_scroll_state.sticky_frames()) {
m_scroll_state.for_each_sticky_frame([&](auto& scroll_frame) {
auto const& sticky_box = scroll_frame->paintable_box();
auto const& sticky_insets = sticky_box.sticky_insets();
auto const* nearest_scrollable_ancestor = sticky_box.nearest_scrollable_ancestor();
if (!nearest_scrollable_ancestor) {
continue;
return;
}
// Min and max offsets are needed to clamp the sticky box's position to stay within bounds of containing block.
@ -250,11 +250,11 @@ void ViewportPaintable::refresh_scroll_state()
}
scroll_frame->set_own_offset(sticky_offset);
}
});
for (auto const& scroll_frame : m_scroll_state.scroll_frames()) {
m_scroll_state.for_each_scroll_frame([&](auto& scroll_frame) {
scroll_frame->set_own_offset(-scroll_frame->paintable_box().scroll_offset());
}
});
}
void ViewportPaintable::resolve_paint_only_properties()