Przeglądaj źródła

LibWeb: Coalesce layouts that happen in response to style changes

Instead of doing a forced layout synchronously whenever an element's
style is changed, use a zero-timer to do the forced relayout on next
event loop iteration.

This effectively coalesces a lot of layouts and makes many pages such
as GitHub spend way less time doing redundant layout work.
Andreas Kling 4 lat temu
rodzic
commit
1d75e82101

+ 11 - 0
Libraries/LibWeb/DOM/Document.cpp

@@ -78,6 +78,10 @@ Document::Document(const URL& url)
     m_style_update_timer = Core::Timer::create_single_shot(0, [this] {
         update_style();
     });
+
+    m_forced_layout_timer = Core::Timer::create_single_shot(0, [this] {
+        force_layout();
+    });
 }
 
 Document::~Document()
@@ -156,6 +160,13 @@ void Document::schedule_style_update()
     m_style_update_timer->start();
 }
 
+void Document::schedule_forced_layout()
+{
+    if (m_forced_layout_timer->is_active())
+        return;
+    m_forced_layout_timer->start();
+}
+
 bool Document::is_child_allowed(const Node& node) const
 {
     switch (node.type()) {

+ 2 - 0
Libraries/LibWeb/DOM/Document.h

@@ -132,6 +132,7 @@ public:
     Layout::InitialContainingBlockBox* layout_node();
 
     void schedule_style_update();
+    void schedule_forced_layout();
 
     NonnullRefPtrVector<Element> get_elements_by_name(const String&) const;
     NonnullRefPtrVector<Element> get_elements_by_tag_name(const FlyString&) const;
@@ -262,6 +263,7 @@ private:
     Optional<Color> m_visited_link_color;
 
     RefPtr<Core::Timer> m_style_update_timer;
+    RefPtr<Core::Timer> m_forced_layout_timer;
 
     String m_source;
 

+ 1 - 1
Libraries/LibWeb/DOM/Element.cpp

@@ -221,7 +221,7 @@ void Element::recompute_style()
         return;
     layout_node()->apply_style(*new_specified_css_values);
     if (diff == StyleDifference::NeedsRelayout) {
-        document().force_layout();
+        document().schedule_forced_layout();
         return;
     }
     if (diff == StyleDifference::NeedsRepaint) {