From 9b0ca75f84666abb3c81b752d676d2056e399e1d Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 30 Jan 2021 12:25:33 +0100 Subject: [PATCH] LibWeb: Add Frame::ViewportClient and use it for Layout::ImageBox Image boxes want to know whether they are inside the visible viewport. This is used to pause/resume animations, and to update the purgeable memory volatility state. Previously we would traverse the entire layout tree on every resize, calling a helper on each ImageBox. Make those boxes register with the frame they are interested in instead, saving us all that traversal. This also makes it easier for other parts of the code to learn about viewport changes in the future. :^) --- Userland/Libraries/LibWeb/Layout/ImageBox.cpp | 7 ++++-- Userland/Libraries/LibWeb/Layout/ImageBox.h | 9 ++++--- .../Layout/InitialContainingBlockBox.cpp | 9 ------- .../LibWeb/Layout/InitialContainingBlockBox.h | 2 -- Userland/Libraries/LibWeb/Page/Frame.cpp | 24 ++++++++++++++----- Userland/Libraries/LibWeb/Page/Frame.h | 10 ++++++++ 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/ImageBox.cpp b/Userland/Libraries/LibWeb/Layout/ImageBox.cpp index aefd465eda..92b5986cae 100644 --- a/Userland/Libraries/LibWeb/Layout/ImageBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/ImageBox.cpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace Web::Layout { @@ -37,10 +38,12 @@ ImageBox::ImageBox(DOM::Document& document, DOM::Element& element, NonnullRefPtr : ReplacedBox(document, element, move(style)) , m_image_loader(image_loader) { + frame().register_viewport_client(*this); } ImageBox::~ImageBox() { + frame().unregister_viewport_client(*this); } int ImageBox::preferred_width() const @@ -127,9 +130,9 @@ bool ImageBox::renders_as_alt_text() const return false; } -void ImageBox::set_visible_in_viewport(Badge, bool visible_in_viewport) +void ImageBox::frame_did_set_viewport_rect(const Gfx::IntRect& viewport_rect) { - m_image_loader.set_visible_in_viewport(visible_in_viewport); + m_image_loader.set_visible_in_viewport(viewport_rect.to().intersects(absolute_rect())); } } diff --git a/Userland/Libraries/LibWeb/Layout/ImageBox.h b/Userland/Libraries/LibWeb/Layout/ImageBox.h index a404ca1ca0..d96db80ec5 100644 --- a/Userland/Libraries/LibWeb/Layout/ImageBox.h +++ b/Userland/Libraries/LibWeb/Layout/ImageBox.h @@ -28,10 +28,13 @@ #include #include +#include namespace Web::Layout { -class ImageBox : public ReplacedBox { +class ImageBox + : public ReplacedBox + , public Frame::ViewportClient { public: ImageBox(DOM::Document&, DOM::Element&, NonnullRefPtr, const ImageLoader&); virtual ~ImageBox() override; @@ -43,9 +46,9 @@ public: bool renders_as_alt_text() const; - void set_visible_in_viewport(Badge, bool); - private: + virtual void frame_did_set_viewport_rect(const Gfx::IntRect&) final; + int preferred_width() const; int preferred_height() const; diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp index 320f0f770c..3a71495d8d 100644 --- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp @@ -63,15 +63,6 @@ void InitialContainingBlockBox::build_stacking_context_tree() }); } -void InitialContainingBlockBox::did_set_viewport_rect(Badge, const Gfx::IntRect& a_viewport_rect) -{ - Gfx::FloatRect viewport_rect(a_viewport_rect.x(), a_viewport_rect.y(), a_viewport_rect.width(), a_viewport_rect.height()); - for_each_in_subtree_of_type([&](auto& layout_image) { - const_cast(layout_image).set_visible_in_viewport({}, viewport_rect.intersects(layout_image.absolute_rect())); - return IterationDecision::Continue; - }); -} - void InitialContainingBlockBox::paint_all_phases(PaintContext& context) { paint(context, PaintPhase::Background); diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h index b7b4810364..92d2746ef4 100644 --- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h +++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h @@ -47,8 +47,6 @@ public: void set_selection(const LayoutRange&); void set_selection_end(const LayoutPosition&); - void did_set_viewport_rect(Badge, const Gfx::IntRect&); - void build_stacking_context_tree(); void recompute_selection_states(); diff --git a/Userland/Libraries/LibWeb/Page/Frame.cpp b/Userland/Libraries/LibWeb/Page/Frame.cpp index 2b8d5ddb63..bea214f768 100644 --- a/Userland/Libraries/LibWeb/Page/Frame.cpp +++ b/Userland/Libraries/LibWeb/Page/Frame.cpp @@ -110,11 +110,11 @@ void Frame::set_size(const Gfx::IntSize& size) if (m_size == size) return; m_size = size; - if (m_document) { + if (m_document) m_document->update_layout(); - if (m_document->layout_node()) - m_document->layout_node()->did_set_viewport_rect({}, viewport_rect()); - } + + for (auto* client : m_viewport_clients) + client->frame_did_set_viewport_rect(viewport_rect()); } void Frame::set_viewport_scroll_offset(const Gfx::IntPoint& offset) @@ -123,8 +123,8 @@ void Frame::set_viewport_scroll_offset(const Gfx::IntPoint& offset) return; m_viewport_scroll_offset = offset; - if (m_document && m_document->layout_node()) - m_document->layout_node()->did_set_viewport_rect({}, viewport_rect()); + for (auto* client : m_viewport_clients) + client->frame_did_set_viewport_rect(viewport_rect()); } void Frame::set_needs_display(const Gfx::IntRect& rect) @@ -274,4 +274,16 @@ String Frame::selected_text() const return builder.to_string(); } +void Frame::register_viewport_client(ViewportClient& client) +{ + auto result = m_viewport_clients.set(&client); + ASSERT(result == AK::HashSetResult::InsertedNewEntry); +} + +void Frame::unregister_viewport_client(ViewportClient& client) +{ + bool was_removed = m_viewport_clients.remove(&client); + ASSERT(was_removed); +} + } diff --git a/Userland/Libraries/LibWeb/Page/Frame.h b/Userland/Libraries/LibWeb/Page/Frame.h index d6ba5eea8d..c98554b4aa 100644 --- a/Userland/Libraries/LibWeb/Page/Frame.h +++ b/Userland/Libraries/LibWeb/Page/Frame.h @@ -47,6 +47,14 @@ public: static NonnullRefPtr create(Page& page) { return adopt(*new Frame(page)); } ~Frame(); + class ViewportClient { + public: + virtual ~ViewportClient() { } + virtual void frame_did_set_viewport_rect(const Gfx::IntRect&) = 0; + }; + void register_viewport_client(ViewportClient&); + void unregister_viewport_client(ViewportClient&); + bool is_main_frame() const { return this == &m_main_frame; } bool is_focused_frame() const; @@ -116,6 +124,8 @@ private: DOM::Position m_cursor_position; RefPtr m_cursor_blink_timer; bool m_cursor_blink_state { false }; + + HashTable m_viewport_clients; }; }