mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibWeb: Only update paint-only properties in affected subtrees
Before this change, we always updated paint-only properties for every single paintable after layout or style changes. This could get very expensive in large documents, so this patch makes it something we can do partially based on "repaint" invalidations. This cuts down time spent in paint-only property update when scrolling https://imdb.com/ from 19% to 5%.
This commit is contained in:
parent
beb70d2112
commit
eff9989aeb
|
|
@ -694,8 +694,9 @@ AnimationUpdateContext::~AnimationUpdateContext()
|
|||
}
|
||||
}
|
||||
if (invalidation.repaint) {
|
||||
if (target->paintable())
|
||||
target->paintable()->set_needs_paint_only_properties_update(true);
|
||||
element.document().set_needs_display();
|
||||
element.document().set_needs_to_resolve_paint_only_properties();
|
||||
}
|
||||
if (invalidation.rebuild_stacking_context_tree)
|
||||
element.document().invalidate_stacking_context_tree();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <LibWeb/DOMURL/DOMURL.h>
|
||||
#include <LibWeb/Fetch/Fetching/Fetching.h>
|
||||
#include <LibWeb/HTML/SharedResourceRequest.h>
|
||||
#include <LibWeb/Painting/ViewportPaintable.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
|
|
@ -131,7 +132,8 @@ GC::Ptr<HTML::SharedResourceRequest> fetch_an_external_image_for_a_stylesheet(St
|
|||
|
||||
if (auto navigable = document->navigable()) {
|
||||
// Once the image has loaded, we need to re-resolve CSS properties that depend on the image's dimensions.
|
||||
document->set_needs_to_resolve_paint_only_properties();
|
||||
if (auto paintable = document->paintable())
|
||||
paintable->set_needs_paint_only_properties_update(true);
|
||||
|
||||
// FIXME: Do less than a full repaint if possible?
|
||||
document->set_needs_display();
|
||||
|
|
|
|||
|
|
@ -762,14 +762,16 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style(bool& did_cha
|
|||
if (invalidation.is_none())
|
||||
return invalidation;
|
||||
|
||||
if (invalidation.repaint)
|
||||
document().set_needs_to_resolve_paint_only_properties();
|
||||
if (invalidation.repaint && paintable())
|
||||
paintable()->set_needs_paint_only_properties_update(true);
|
||||
|
||||
if (!invalidation.rebuild_layout_tree && layout_node()) {
|
||||
// If we're keeping the layout tree, we can just apply the new style to the existing layout tree.
|
||||
layout_node()->apply_style(*m_computed_properties);
|
||||
if (invalidation.repaint && paintable())
|
||||
if (invalidation.repaint && paintable()) {
|
||||
paintable()->set_needs_paint_only_properties_update(true);
|
||||
paintable()->set_needs_display();
|
||||
}
|
||||
|
||||
// Do the same for pseudo-elements.
|
||||
for (auto i = 0; i < to_underlying(CSS::PseudoElement::KnownPseudoElementCount); i++) {
|
||||
|
|
@ -784,8 +786,10 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style(bool& did_cha
|
|||
|
||||
if (auto node_with_style = pseudo_element->layout_node()) {
|
||||
node_with_style->apply_style(*pseudo_element_style);
|
||||
if (invalidation.repaint && node_with_style->first_paintable())
|
||||
if (invalidation.repaint && node_with_style->first_paintable()) {
|
||||
node_with_style->first_paintable()->set_needs_paint_only_properties_update(true);
|
||||
node_with_style->first_paintable()->set_needs_display();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,4 +303,16 @@ Painting::BorderRadiiData normalize_border_radii_data(Layout::Node const& node,
|
|||
return radii_px;
|
||||
}
|
||||
|
||||
void Paintable::set_needs_paint_only_properties_update(bool needs_update)
|
||||
{
|
||||
if (needs_update == m_needs_paint_only_properties_update)
|
||||
return;
|
||||
|
||||
m_needs_paint_only_properties_update = needs_update;
|
||||
|
||||
if (needs_update) {
|
||||
document().set_needs_to_resolve_paint_only_properties();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,8 @@ public:
|
|||
GC::Ptr<HTML::Navigable> navigable() const;
|
||||
|
||||
virtual void set_needs_display(InvalidateDisplayList = InvalidateDisplayList::Yes);
|
||||
void set_needs_paint_only_properties_update(bool);
|
||||
[[nodiscard]] bool needs_paint_only_properties_update() const { return m_needs_paint_only_properties_update; }
|
||||
|
||||
PaintableBox* containing_block() const;
|
||||
|
||||
|
|
@ -177,6 +179,7 @@ private:
|
|||
bool m_absolutely_positioned : 1 { false };
|
||||
bool m_floating : 1 { false };
|
||||
bool m_inline : 1 { false };
|
||||
bool m_needs_paint_only_properties_update : 1 { true };
|
||||
};
|
||||
|
||||
inline DOM::Node* HitTestResult::dom_node()
|
||||
|
|
|
|||
|
|
@ -302,6 +302,15 @@ void ViewportPaintable::refresh_scroll_state()
|
|||
});
|
||||
}
|
||||
|
||||
static void resolve_paint_only_properties_in_subtree(Paintable& root)
|
||||
{
|
||||
root.for_each_in_inclusive_subtree([&](auto& paintable) {
|
||||
paintable.resolve_paint_properties();
|
||||
paintable.set_needs_paint_only_properties_update(false);
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
void ViewportPaintable::resolve_paint_only_properties()
|
||||
{
|
||||
// Resolves layout-dependent properties not handled during layout and stores them in the paint tree.
|
||||
|
|
@ -313,7 +322,10 @@ void ViewportPaintable::resolve_paint_only_properties()
|
|||
// - Transform origins
|
||||
// - Outlines
|
||||
for_each_in_inclusive_subtree([&](Paintable& paintable) {
|
||||
paintable.resolve_paint_properties();
|
||||
if (paintable.needs_paint_only_properties_update()) {
|
||||
resolve_paint_only_properties_in_subtree(paintable);
|
||||
return TraversalDecision::SkipChildrenAndContinue;
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user