From 866608532a743df9e3d10c0dae9aacd7d0b89ce6 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Sat, 24 Aug 2024 19:11:01 +0200 Subject: [PATCH] LibWeb: Add parent-child relationship between scroll frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the calculation of the cumulative scroll offset for a scroll frame by adding its scroll offset to the parent’s scroll offset, rather than traversing the containing block chain. While it doesn't greatly simplify calculations for typical scroll frames, it serves as a preparation for supporting "position: sticky". --- Userland/Libraries/LibWeb/Painting/ClipFrame.cpp | 4 ++-- .../LibWeb/Painting/ClippableAndScrollable.cpp | 2 +- .../LibWeb/Painting/ClippableAndScrollable.h | 1 + .../Libraries/LibWeb/Painting/DisplayList.cpp | 2 +- .../Libraries/LibWeb/Painting/PaintableBox.cpp | 11 +++++++++++ Userland/Libraries/LibWeb/Painting/PaintableBox.h | 2 ++ Userland/Libraries/LibWeb/Painting/ScrollFrame.h | 9 ++++++++- .../LibWeb/Painting/ViewportPaintable.cpp | 15 ++++----------- 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Userland/Libraries/LibWeb/Painting/ClipFrame.cpp b/Userland/Libraries/LibWeb/Painting/ClipFrame.cpp index 09df6d0e145..ba9fae1f2c3 100644 --- a/Userland/Libraries/LibWeb/Painting/ClipFrame.cpp +++ b/Userland/Libraries/LibWeb/Painting/ClipFrame.cpp @@ -24,12 +24,12 @@ CSSPixelRect ClipFrame::clip_rect_for_hit_testing() const VERIFY(!m_clip_rects.is_empty()); auto rect = m_clip_rects[0].rect; if (m_clip_rects[0].enclosing_scroll_frame) { - rect.translate_by(m_clip_rects[0].enclosing_scroll_frame->cumulative_offset); + rect.translate_by(m_clip_rects[0].enclosing_scroll_frame->cumulative_offset()); } for (size_t i = 1; i < m_clip_rects.size(); ++i) { auto clip_rect = m_clip_rects[i].rect; if (m_clip_rects[i].enclosing_scroll_frame) { - clip_rect.translate_by(m_clip_rects[i].enclosing_scroll_frame->cumulative_offset); + clip_rect.translate_by(m_clip_rects[i].enclosing_scroll_frame->cumulative_offset()); } rect.intersect(clip_rect); } diff --git a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp index 785f8514006..566da53f0f2 100644 --- a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.cpp @@ -26,7 +26,7 @@ Optional ClippableAndScrollable::scroll_frame_id() const CSSPixelPoint ClippableAndScrollable::cumulative_offset_of_enclosing_scroll_frame() const { if (m_enclosing_scroll_frame) - return m_enclosing_scroll_frame->cumulative_offset; + return m_enclosing_scroll_frame->cumulative_offset(); return {}; } diff --git a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h index 023a73c7a85..dbca508c403 100644 --- a/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h +++ b/Userland/Libraries/LibWeb/Painting/ClippableAndScrollable.h @@ -23,6 +23,7 @@ public: [[nodiscard]] CSSPixelPoint cumulative_offset_of_enclosing_scroll_frame() const; [[nodiscard]] Optional clip_rect_for_hit_testing() const; + [[nodiscard]] RefPtr own_scroll_frame() const { return m_own_scroll_frame; } [[nodiscard]] Optional own_scroll_frame_id() const; [[nodiscard]] CSSPixelPoint own_scroll_frame_offset() const { diff --git a/Userland/Libraries/LibWeb/Painting/DisplayList.cpp b/Userland/Libraries/LibWeb/Painting/DisplayList.cpp index ed93a344ef1..065ff3183da 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayList.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayList.cpp @@ -48,7 +48,7 @@ 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().scaled(device_pixels_per_css_pixel).to_type(); + auto const& scroll_offset = scroll_state[scroll_frame_id.value()]->cumulative_offset().to_type().scaled(device_pixels_per_css_pixel).to_type(); command.visit( [&](auto& command) { if constexpr (requires { command.translate_by(scroll_offset); }) { diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index f68d0bf4ac4..55713b2f48a 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -1100,4 +1100,15 @@ void PaintableWithLines::resolve_paint_properties() } } +RefPtr PaintableBox::nearest_scroll_frame() const +{ + auto const* paintable = this->containing_block(); + while (paintable) { + if (paintable->own_scroll_frame()) + return paintable->own_scroll_frame(); + paintable = paintable->containing_block(); + } + return nullptr; +} + } diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index bbcee6a5a6b..e854c1425f5 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -210,6 +210,8 @@ public: virtual void resolve_paint_properties() override; + RefPtr nearest_scroll_frame() const; + protected: explicit PaintableBox(Layout::Box const&); diff --git a/Userland/Libraries/LibWeb/Painting/ScrollFrame.h b/Userland/Libraries/LibWeb/Painting/ScrollFrame.h index afdc8b3ebc8..0c639cc749f 100644 --- a/Userland/Libraries/LibWeb/Painting/ScrollFrame.h +++ b/Userland/Libraries/LibWeb/Painting/ScrollFrame.h @@ -12,8 +12,15 @@ namespace Web::Painting { struct ScrollFrame : public RefCounted { i32 id { -1 }; - CSSPixelPoint cumulative_offset; CSSPixelPoint own_offset; + RefPtr parent; + + CSSPixelPoint cumulative_offset() const + { + if (parent) + return parent->cumulative_offset() + own_offset; + return own_offset; + } }; } diff --git a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp index ed1b4b1ed19..64473423e56 100644 --- a/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp @@ -71,6 +71,7 @@ void ViewportPaintable::assign_scroll_frames() if (paintable_box.has_scrollable_overflow() || is(paintable_box)) { auto scroll_frame = adopt_ref(*new ScrollFrame()); scroll_frame->id = next_id++; + scroll_frame->parent = paintable_box.nearest_scroll_frame(); paintable_box.set_own_scroll_frame(scroll_frame); scroll_state.set(paintable_box, move(scroll_frame)); } @@ -82,13 +83,13 @@ void ViewportPaintable::assign_scroll_frames() return TraversalDecision::Continue; } for (auto block = paintable.containing_block(); block; block = block->containing_block()) { - if (auto scroll_frame = scroll_state.get(block); scroll_frame.has_value()) { + if (auto scroll_frame = block->own_scroll_frame(); scroll_frame) { if (paintable.is_paintable_box()) { auto const& paintable_box = static_cast(paintable); - const_cast(paintable_box).set_enclosing_scroll_frame(scroll_frame.value()); + const_cast(paintable_box).set_enclosing_scroll_frame(*scroll_frame); } else if (paintable.is_inline_paintable()) { auto const& inline_paintable = static_cast(paintable); - const_cast(inline_paintable).set_enclosing_scroll_frame(scroll_frame.value()); + const_cast(inline_paintable).set_enclosing_scroll_frame(*scroll_frame); } return TraversalDecision::Continue; } @@ -162,14 +163,6 @@ void ViewportPaintable::refresh_scroll_state() for (auto& it : scroll_state) { auto const& paintable_box = *it.key; auto& scroll_frame = *it.value; - CSSPixelPoint cumulative_offset; - for (auto const* block = &paintable_box.layout_box(); block; block = block->containing_block()) { - auto const& block_paintable_box = *block->paintable_box(); - cumulative_offset.translate_by(block_paintable_box.scroll_offset()); - if (block->is_fixed_position()) - break; - } - scroll_frame.cumulative_offset = -cumulative_offset; scroll_frame.own_offset = -paintable_box.scroll_offset(); } }