mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-01 21:59:07 +00:00
LibWeb: Don't traverse entire layout tree in every HTML::EventLoop tick
Instead, collect a list of all the elements with content-visibility:auto after layout. This way we can skip the tree traversal when updating the rendering. This was previously eating up ~300 µs of the 60fps frame budget on our GitHub repo pages (and even more on large pages).
This commit is contained in:
parent
df0dc32006
commit
07ff75bbec
Notes:
github-actions[bot]
2025-06-11 14:26:45 +00:00
Author: https://github.com/awesomekling
Commit: 07ff75bbec
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5059
4 changed files with 22 additions and 8 deletions
|
@ -1414,6 +1414,18 @@ void Document::update_layout(UpdateLayoutReason reason)
|
||||||
paintable()->recompute_selection_states(*range);
|
paintable()->recompute_selection_states(*range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect elements with content-visibility: auto. This is used in the HTML event loop to avoid traversing the whole tree every time.
|
||||||
|
Vector<GC::Ref<Painting::PaintableBox>> paintable_boxes_with_auto_content_visibility;
|
||||||
|
paintable()->for_each_in_subtree_of_type<Painting::PaintableBox>([&](auto& paintable_box) {
|
||||||
|
if (paintable_box.dom_node()
|
||||||
|
&& paintable_box.dom_node()->is_element()
|
||||||
|
&& paintable_box.computed_values().content_visibility() == CSS::ContentVisibility::Auto) {
|
||||||
|
paintable_boxes_with_auto_content_visibility.append(paintable_box);
|
||||||
|
}
|
||||||
|
return TraversalDecision::Continue;
|
||||||
|
});
|
||||||
|
paintable()->set_paintable_boxes_with_auto_content_visibility(move(paintable_boxes_with_auto_content_visibility));
|
||||||
|
|
||||||
m_layout_root->for_each_in_inclusive_subtree([](auto& node) {
|
m_layout_root->for_each_in_inclusive_subtree([](auto& node) {
|
||||||
node.reset_needs_layout_update();
|
node.reset_needs_layout_update();
|
||||||
return TraversalDecision::Continue;
|
return TraversalDecision::Continue;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
|
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
|
||||||
#include <LibWeb/Page/Page.h>
|
#include <LibWeb/Page/Page.h>
|
||||||
#include <LibWeb/Painting/PaintableBox.h>
|
#include <LibWeb/Painting/PaintableBox.h>
|
||||||
|
#include <LibWeb/Painting/ViewportPaintable.h>
|
||||||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||||||
#include <LibWeb/Platform/Timer.h>
|
#include <LibWeb/Platform/Timer.h>
|
||||||
|
|
||||||
|
@ -408,11 +409,8 @@ void EventLoop::update_the_rendering()
|
||||||
// 3. For each element element with 'auto' used value of 'content-visibility':
|
// 3. For each element element with 'auto' used value of 'content-visibility':
|
||||||
auto* document_element = document->document_element();
|
auto* document_element = document->document_element();
|
||||||
if (document_element) {
|
if (document_element) {
|
||||||
document_element->for_each_in_inclusive_subtree_of_type<Web::DOM::Element>([&](auto& element) {
|
for (auto& paintable_box : document->paintable()->paintable_boxes_with_auto_content_visibility()) {
|
||||||
auto const& paintable_box = element.paintable_box();
|
auto& element = as<DOM::Element>(*paintable_box->dom_node());
|
||||||
if (!paintable_box || paintable_box->computed_values().content_visibility() != CSS::ContentVisibility::Auto) {
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. Let checkForInitialDetermination be true if element's proximity to the viewport is not determined and it is not relevant to the user. Otherwise, let checkForInitialDetermination be false.
|
// 1. Let checkForInitialDetermination be true if element's proximity to the viewport is not determined and it is not relevant to the user. Otherwise, let checkForInitialDetermination be false.
|
||||||
bool check_for_initial_determination = element.proximity_to_the_viewport() == Web::DOM::ProximityToTheViewport::NotDetermined && !element.is_relevant_to_the_user();
|
bool check_for_initial_determination = element.proximity_to_the_viewport() == Web::DOM::ProximityToTheViewport::NotDetermined && !element.is_relevant_to_the_user();
|
||||||
|
@ -424,9 +422,7 @@ void EventLoop::update_the_rendering()
|
||||||
if (check_for_initial_determination && element.is_relevant_to_the_user()) {
|
if (check_for_initial_determination && element.is_relevant_to_the_user()) {
|
||||||
had_initial_visible_content_visibility_determination = true;
|
had_initial_visible_content_visibility_determination = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return TraversalDecision::Continue;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. If hadInitialVisibleContentVisibilityDetermination is true, then continue.
|
// 4. If hadInitialVisibleContentVisibilityDetermination is true, then continue.
|
||||||
|
|
|
@ -395,6 +395,7 @@ void ViewportPaintable::visit_edges(Visitor& visitor)
|
||||||
{
|
{
|
||||||
Base::visit_edges(visitor);
|
Base::visit_edges(visitor);
|
||||||
visitor.visit(clip_state);
|
visitor.visit(clip_state);
|
||||||
|
visitor.visit(m_paintable_boxes_with_auto_content_visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,9 @@ public:
|
||||||
|
|
||||||
ScrollState const& scroll_state() const { return m_scroll_state; }
|
ScrollState const& scroll_state() const { return m_scroll_state; }
|
||||||
|
|
||||||
|
void set_paintable_boxes_with_auto_content_visibility(Vector<GC::Ref<PaintableBox>> paintable_boxes) { m_paintable_boxes_with_auto_content_visibility = move(paintable_boxes); }
|
||||||
|
ReadonlySpan<GC::Ref<PaintableBox>> paintable_boxes_with_auto_content_visibility() const { return m_paintable_boxes_with_auto_content_visibility; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void build_stacking_context_tree();
|
void build_stacking_context_tree();
|
||||||
|
|
||||||
|
@ -49,6 +52,8 @@ private:
|
||||||
|
|
||||||
ScrollState m_scroll_state;
|
ScrollState m_scroll_state;
|
||||||
bool m_needs_to_refresh_scroll_state { true };
|
bool m_needs_to_refresh_scroll_state { true };
|
||||||
|
|
||||||
|
Vector<GC::Ref<PaintableBox>> m_paintable_boxes_with_auto_content_visibility;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue