From c3f5dbb1010d6f5e54468b563efdc39f9a627435 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Fri, 23 Feb 2024 22:10:35 +0100 Subject: [PATCH] LibWeb: Paint page only if something that requires repaint happened Resolves a performance regression from 8ba18dfd404543290774f21ee3ed6c802e3371cd, where moving paint scheduling to `EventLoop::process()` led to unnecessary repaints. This update introduces a flag to trigger repaints only when necessary, addressing the issue where repaints previously occurred with each event loop process, irrespective of actual changes. --- Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp | 8 +++++--- Userland/Libraries/LibWeb/HTML/Navigable.cpp | 6 ++++++ Userland/Libraries/LibWeb/HTML/Navigable.h | 4 ++++ Userland/Services/WebContent/PageClient.cpp | 1 - 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index 85442591d6..f60ea51c64 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -256,9 +256,11 @@ void EventLoop::process() // 16. For each fully active Document in docs, update the rendering or user interface of that Document and its browsing context to reflect the current state. for_each_fully_active_document_in_docs([&](DOM::Document& document) { - auto* browsing_context = document.browsing_context(); - auto& page = browsing_context->page(); - page.client().schedule_repaint(); + if (document.navigable() && document.navigable()->needs_repaint()) { + auto* browsing_context = document.browsing_context(); + auto& page = browsing_context->page(); + page.client().schedule_repaint(); + } }); // 13. If all of the following are true diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.cpp b/Userland/Libraries/LibWeb/HTML/Navigable.cpp index e9f73bed96..555b3e1772 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigable.cpp @@ -1980,12 +1980,14 @@ void Navigable::set_viewport_rect(CSSPixelRect const& rect) document->set_needs_layout(); } did_change = true; + m_needs_repaint = true; } if (m_viewport_scroll_offset != rect.location()) { m_viewport_scroll_offset = rect.location(); scroll_offset_did_change(); did_change = true; + m_needs_repaint = true; } if (did_change && active_document()) { @@ -2036,6 +2038,8 @@ void Navigable::set_needs_display(CSSPixelRect const& rect) // FIXME: Ignore updates outside the visible viewport rect. // This requires accounting for fixed-position elements in the input rect, which we don't do yet. + m_needs_repaint = true; + if (is(*this)) { static_cast(this)->page().client().page_did_invalidate(to_top_level_rect(rect)); return; @@ -2128,6 +2132,8 @@ void Navigable::paint(Painting::RecordingPainter& recording_painter, PaintConfig } recording_painter.commands_list().apply_scroll_offsets(scroll_offsets_by_frame_id); } + + m_needs_repaint = false; } // https://html.spec.whatwg.org/multipage/browsing-the-web.html#event-uni diff --git a/Userland/Libraries/LibWeb/HTML/Navigable.h b/Userland/Libraries/LibWeb/HTML/Navigable.h index 7c9554284f..5c3bdfd56d 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigable.h +++ b/Userland/Libraries/LibWeb/HTML/Navigable.h @@ -173,6 +173,8 @@ public: [[nodiscard]] TargetSnapshotParams snapshot_target_snapshot_params(); + [[nodiscard]] bool needs_repaint() const { return m_needs_repaint; } + struct PaintConfig { bool paint_overlay { false }; bool should_show_line_box_borders { false }; @@ -221,6 +223,8 @@ private: CSSPixelSize m_size; CSSPixelPoint m_viewport_scroll_offset; + + bool m_needs_repaint { false }; }; HashTable& all_navigables(); diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index faf1f24b1c..9fc012c270 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -222,7 +222,6 @@ void PageClient::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& ta void PageClient::set_viewport_rect(Web::DevicePixelRect const& rect) { page().top_level_traversable()->set_viewport_rect(page().device_to_css_rect(rect)); - Web::HTML::main_thread_event_loop().schedule(); } void PageClient::page_did_invalidate(Web::CSSPixelRect const&)