[gtksourceview] buffer: avoid damage to full buffer when removing matching brackets



commit 4ed97b31f69fc2ddb291d9f67872472c37450770
Author: Christian Hergert <chergert redhat com>
Date:   Fri Apr 22 01:48:38 2016 -0700

    buffer: avoid damage to full buffer when removing matching brackets
    
    When cleaning up matching brackets, gtk_text_buffer_remove_tag() is called
    for the entire buffer. This causes a damage in the view causing the entire
    pixelcache to be dropped.
    
    Further more, on every ::insert-text we perform the bracket updating
    meaning we damage the views on every keystroke.
    
    This walks the tag toggles manually to to reduce the ranges we damage
    to just the locations containing the tag.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=765363

 gtksourceview/gtksourcebuffer.c |   86 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 82 insertions(+), 4 deletions(-)
---
diff --git a/gtksourceview/gtksourcebuffer.c b/gtksourceview/gtksourcebuffer.c
index cf07ccd..c9a4ebd 100644
--- a/gtksourceview/gtksourcebuffer.c
+++ b/gtksourceview/gtksourcebuffer.c
@@ -904,6 +904,84 @@ bracket_pair (gunichar  base_char,
        return pair;
 }
 
+/*
+ * This function works similar to gtk_text_buffer_remove_tag() except that
+ * instead of taking the optimization to make removing tags fast in terms
+ * of wall clock time, it tries to avoiding to much time of the screen
+ * by minimizing the damage regions. This results in fewer full-redraws
+ * when updating the text marks. To see the difference, compare this to
+ * gtk_text_buffer_remove_tag() and enable the "show pixel cache" feature
+ * the GTK+ inspector.
+ */
+static void
+remove_tag_with_minimal_damage (GtkSourceBuffer   *buffer,
+                                GtkTextTag        *tag,
+                                const GtkTextIter *begin,
+                                const GtkTextIter *end)
+{
+       GtkTextIter tag_begin = *start;
+       GtkTextIter tag_end;
+
+       if (!gtk_text_iter_starts_tag (&tag_begin, tag))
+       {
+               if (!gtk_text_iter_forward_to_tag_toggle (&tag_begin, tag))
+               {
+                       return;
+               }
+       }
+
+       while (gtk_text_iter_starts_tag (&tag_begin, tag) &&
+              gtk_text_iter_compare (&tag_begin, end) < 0)
+       {
+               gint count = 1;
+
+               tag_end = tag_begin;
+
+               /*
+                * We might have found the start of another tag embedded
+                * inside this tag. So keep scanning forward until we have
+                * reached the right number of end tags.
+                */
+
+               while (gtk_text_iter_forward_to_tag_toggle (&tag_end, tag))
+               {
+                       if (gtk_text_iter_starts_tag (&tag_end, tag))
+                       {
+                               count++;
+                       }
+                       else if (gtk_text_iter_ends_tag (&tag_end, tag))
+                       {
+                               if (--count == 0)
+                               {
+                                       break;
+                               }
+                       }
+               }
+
+               if (gtk_text_iter_ends_tag (&tag_end, tag))
+               {
+                       gtk_text_buffer_remove_tag (buffer, tag, &tag_begin, &tag_end);
+
+                       tag_begin = tag_end;
+
+                       /*
+                        * Move to the next start tag. It's possible to have an overlapped
+                        * end tag, which would be non-ideal, but possible.
+                        */
+                       if (!gtk_text_iter_starts_tag (&tag_begin, tag))
+                       {
+                               while (gtk_text_iter_forward_to_tag_toggle (&tag_begin, tag))
+                               {
+                                       if (gtk_text_iter_starts_tag (&tag_begin, tag))
+                                       {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
 static void
 update_bracket_highlighting (GtkSourceBuffer *source_buffer)
 {
@@ -922,10 +1000,10 @@ update_bracket_highlighting (GtkSourceBuffer *source_buffer)
 
                gtk_text_buffer_get_bounds (buffer, &start, &end);
 
-               gtk_text_buffer_remove_tag (buffer,
-                                           source_buffer->priv->bracket_match_tag,
-                                           &start,
-                                           &end);
+               remove_tag_with_minimal_damage (source_buffer,
+                                               source_buffer->priv->bracket_match_tag,
+                                               &start,
+                                               &end);
        }
 
        if (!source_buffer->priv->highlight_brackets)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]