Browse Source

LibGUI: Defer line reflow during text insertion

Add a deferral counter and defer reflowing the visual lines until the
counter is at zero. Use this to defer reflow when inserting text.

This fixes glacial slowdown while paste large amounts of text.
Andreas Kling 5 years ago
parent
commit
a8f0e4d56e
2 changed files with 42 additions and 0 deletions
  1. 21 0
      Libraries/LibGUI/TextEditor.cpp
  2. 21 0
      Libraries/LibGUI/TextEditor.h

+ 21 - 0
Libraries/LibGUI/TextEditor.cpp

@@ -1197,6 +1197,7 @@ void TextEditor::delete_selection()
 
 
 void TextEditor::insert_at_cursor_or_replace_selection(const StringView& text)
 void TextEditor::insert_at_cursor_or_replace_selection(const StringView& text)
 {
 {
+    ReflowDeferrer defer(*this);
     ASSERT(!is_readonly());
     ASSERT(!is_readonly());
     if (has_selection())
     if (has_selection())
         delete_selection();
         delete_selection();
@@ -1224,6 +1225,7 @@ void TextEditor::paste()
 {
 {
     if (is_readonly())
     if (is_readonly())
         return;
         return;
+
     auto paste_text = Clipboard::the().data();
     auto paste_text = Clipboard::the().data();
     printf("Paste: \"%s\"\n", paste_text.characters());
     printf("Paste: \"%s\"\n", paste_text.characters());
 
 
@@ -1231,6 +1233,20 @@ void TextEditor::paste()
     insert_at_cursor_or_replace_selection(paste_text);
     insert_at_cursor_or_replace_selection(paste_text);
 }
 }
 
 
+void TextEditor::defer_reflow()
+{
+    ++m_reflow_deferred;
+}
+
+void TextEditor::undefer_reflow()
+{
+    ASSERT(m_reflow_deferred);
+    if (!--m_reflow_deferred) {
+        if (m_reflow_requested)
+            recompute_all_visual_lines();
+    }
+}
+
 void TextEditor::enter_event(Core::Event&)
 void TextEditor::enter_event(Core::Event&)
 {
 {
     ASSERT(window());
     ASSERT(window());
@@ -1359,6 +1375,11 @@ void TextEditor::clear_selection()
 
 
 void TextEditor::recompute_all_visual_lines()
 void TextEditor::recompute_all_visual_lines()
 {
 {
+    if (m_reflow_deferred) {
+        m_reflow_requested = true;
+        return;
+    }
+
     int y_offset = 0;
     int y_offset = 0;
     for (size_t line_index = 0; line_index < line_count(); ++line_index) {
     for (size_t line_index = 0; line_index < line_count(); ++line_index) {
         recompute_visual_lines(line_index);
         recompute_visual_lines(line_index);

+ 21 - 0
Libraries/LibGUI/TextEditor.h

@@ -172,6 +172,24 @@ private:
     void did_change();
     void did_change();
     int fixed_glyph_width() const;
     int fixed_glyph_width() const;
 
 
+    void defer_reflow();
+    void undefer_reflow();
+
+    class ReflowDeferrer {
+    public:
+        ReflowDeferrer(TextEditor& editor)
+            : m_editor(editor)
+        {
+            m_editor.defer_reflow();
+        }
+        ~ReflowDeferrer()
+        {
+            m_editor.undefer_reflow();
+        }
+    private:
+        TextEditor& m_editor;
+    };
+
     Gfx::Rect line_content_rect(size_t item_index) const;
     Gfx::Rect line_content_rect(size_t item_index) const;
     Gfx::Rect line_widget_rect(size_t line_index) const;
     Gfx::Rect line_widget_rect(size_t line_index) const;
     Gfx::Rect cursor_content_rect() const;
     Gfx::Rect cursor_content_rect() const;
@@ -238,6 +256,9 @@ private:
     Core::ElapsedTimer m_triple_click_timer;
     Core::ElapsedTimer m_triple_click_timer;
     NonnullRefPtrVector<Action> m_custom_context_menu_actions;
     NonnullRefPtrVector<Action> m_custom_context_menu_actions;
 
 
+    size_t m_reflow_deferred { 0 };
+    size_t m_reflow_requested { 0 };
+
     RefPtr<TextDocument> m_document;
     RefPtr<TextDocument> m_document;
 
 
     template<typename Callback>
     template<typename Callback>