[gtk/matthiasc/for-master] Speed up gtk_text_buffer_insert_markup




commit fa53525f2e19c0057e72cb1cc301949eaf139308
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Aug 12 22:51:59 2020 -0400

    Speed up gtk_text_buffer_insert_markup
    
    Instead of blindly creating new tags for every attribute,
    reuse existing tags. For the syntax highlighting of the
    ui file of the cursors demo, this gets us down from
    20.000 tags to 6, and from 1.1s to 69ms for the
    gtk_text_buffer_insert_with_attributes() call.

 gtk/gtktextbuffer.c | 313 +++++++++++++++++++++++++++-------------------------
 1 file changed, 165 insertions(+), 148 deletions(-)
---
diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c
index 33d9b4a8c4..67eda3cdd2 100644
--- a/gtk/gtktextbuffer.c
+++ b/gtk/gtktextbuffer.c
@@ -1837,7 +1837,7 @@ gtk_text_buffer_insert_with_tags (GtkTextBuffer *buffer,
   g_return_if_fail (iter != NULL);
   g_return_if_fail (text != NULL);
   g_return_if_fail (gtk_text_iter_get_buffer (iter) == buffer);
-  
+
   start_offset = gtk_text_iter_get_offset (iter);
 
   gtk_text_buffer_insert (buffer, iter, text, len);
@@ -4379,161 +4379,180 @@ _gtk_text_buffer_spew (GtkTextBuffer *buffer)
   _gtk_text_btree_spew (get_btree (buffer));
 }
 
-static GtkTextTag *
-get_tag_for_attributes (PangoAttrIterator *iter)
+/* FIXME: pango should really have an accessor for
+ * all the current attributes.
+ */
+struct _PangoAttrIterator
 {
-  PangoAttribute *attr;
-  GtkTextTag *tag;
-
-  tag = gtk_text_tag_new (NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_LANGUAGE);
-  if (attr)
-    g_object_set (tag, "language", pango_language_to_string (((PangoAttrLanguage*)attr)->value), NULL);
+  GPtrArray *attrs; /* From the list */
+  guint n_attrs; /* Copied from the list */
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_FAMILY);
-  if (attr)
-    g_object_set (tag, "family", ((PangoAttrString*)attr)->value, NULL);
+  GPtrArray *attribute_stack;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_STYLE);
-  if (attr)
-    g_object_set (tag, "style", ((PangoAttrInt*)attr)->value, NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_WEIGHT);
-  if (attr)
-    g_object_set (tag, "weight", ((PangoAttrInt*)attr)->value, NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_VARIANT);
-  if (attr)
-    g_object_set (tag, "variant", ((PangoAttrInt*)attr)->value, NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRETCH);
-  if (attr)
-    g_object_set (tag, "stretch", ((PangoAttrInt*)attr)->value, NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_SIZE);
-  if (attr)
-    g_object_set (tag, "size", ((PangoAttrInt*)attr)->value, NULL);
+  guint attr_index;
+  guint start_index;
+  guint end_index;
+};
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_DESC);
-  if (attr)
-    g_object_set (tag, "font-desc", ((PangoAttrFontDesc*)attr)->desc, NULL);
+static void
+insert_tags_for_attributes (GtkTextBuffer     *buffer,
+                            PangoAttrIterator *iter,
+                            GtkTextIter       *start,
+                            GtkTextIter       *end)
+{
+  GtkTextTagTable *table;
+  PangoAttribute *attr;
+  GtkTextTag *tag;
+  char name[256];
+  GPtrArray *stack = ((struct _PangoAttrIterator *)iter)->attribute_stack;
+  int i;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_FOREGROUND);
-  if (attr)
-    {
-      PangoColor *color;
-      GdkRGBA rgba;
-     
-      color = &((PangoAttrColor*)attr)->color;
-      rgba.red = color->red / 65535.;
-      rgba.green = color->green / 65535.;
-      rgba.blue = color->blue / 65535.;
-      rgba.alpha = 1.;
-      g_object_set (tag, "foreground-rgba", &rgba, NULL);
-    };
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_BACKGROUND);
-  if (attr)
-    {
-      PangoColor *color;
-      GdkRGBA rgba;
-     
-      color = &((PangoAttrColor*)attr)->color;
-      rgba.red = color->red / 65535.;
-      rgba.green = color->green / 65535.;
-      rgba.blue = color->blue / 65535.;
-      rgba.alpha = 1.;
-      g_object_set (tag, "background-rgba", &rgba, NULL);
-    };
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE);
-  if (attr)
-    g_object_set (tag, "underline", ((PangoAttrInt*)attr)->value, NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_UNDERLINE_COLOR);
-  if (attr)
-    {
-      PangoColor *color;
-      GdkRGBA rgba;
-
-      color = &((PangoAttrColor*)attr)->color;
-      rgba.red = color->red / 65535.;
-      rgba.green = color->green / 65535.;
-      rgba.blue = color->blue / 65535.;
-      rgba.alpha = 1.;
-      g_object_set (tag, "underline-rgba", &rgba, NULL);
-    }
+  if (!stack)
+    return;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_OVERLINE);
-  if (attr)
-    g_object_set (tag, "overline", ((PangoAttrInt*)attr)->value, NULL);
+  table = gtk_text_buffer_get_tag_table (buffer);
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_OVERLINE_COLOR);
-  if (attr)
+  for (i = 0; i < stack->len; i++)
     {
-      PangoColor *color;
-      GdkRGBA rgba;
-
-      color = &((PangoAttrColor*)attr)->color;
-      rgba.red = color->red / 65535.;
-      rgba.green = color->green / 65535.;
-      rgba.blue = color->blue / 65535.;
-      rgba.alpha = 1.;
-      g_object_set (tag, "overline-rgba", &rgba, NULL);
-    }
+      attr = g_ptr_array_index (stack, i);
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH);
-  if (attr)
-    g_object_set (tag, "strikethrough", (gboolean) (((PangoAttrInt*)attr)->value != 0), NULL);
-
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_STRIKETHROUGH_COLOR);
-  if (attr)
-    {
-      PangoColor *color;
-      GdkRGBA rgba;
-
-      color = &((PangoAttrColor*)attr)->color;
-      rgba.red = color->red / 65535.;
-      rgba.green = color->green / 65535.;
-      rgba.blue = color->blue / 65535.;
-      rgba.alpha = 1.;
-      g_object_set (tag, "strikethrough-rgba", &rgba, NULL);
-    }
+      switch ((int)attr->klass->type)
+        {
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_RISE);
-  if (attr)
-    g_object_set (tag, "rise", ((PangoAttrInt*)attr)->value, NULL);
+#define STRING_ATTR(pango_attr_name, attr_name) \
+        case pango_attr_name: \
+        { \
+          const char *string = ((PangoAttrString*)attr)->value; \
+          g_snprintf (name, 256, #attr_name "=%s", string); \
+          tag = gtk_text_tag_table_lookup (table, name); \
+          if (!tag) \
+            { \
+              tag = gtk_text_tag_new (name); \
+              g_object_set (tag, #attr_name, string, NULL); \
+              gtk_text_tag_table_add (table, tag); \
+              g_object_unref (tag); \
+            } \
+        } \
+        break;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_SCALE);
-  if (attr)
-    g_object_set (tag, "scale", ((PangoAttrFloat*)attr)->value, NULL);
+#define INT_ATTR(pango_attr_name, attr_name) \
+        case pango_attr_name: \
+        { \
+          int value = ((PangoAttrInt*)attr)->value; \
+          g_snprintf (name, 256, #attr_name "=%d", value); \
+          tag = gtk_text_tag_table_lookup (table, name); \
+          if (!tag) \
+            { \
+              tag = gtk_text_tag_new (name); \
+              g_object_set (tag, #attr_name, value, NULL); \
+              gtk_text_tag_table_add (table, tag); \
+              g_object_unref (tag); \
+            } \
+        } \
+        break;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_FALLBACK);
-  if (attr)
-    g_object_set (tag, "fallback", (gboolean) (((PangoAttrInt*)attr)->value != 0), NULL);
+#define FLOAT_ATTR(pango_attr_name, attr_name) \
+        case pango_attr_name: \
+        { \
+          float value = ((PangoAttrFloat*)attr)->value; \
+          g_snprintf (name, 256, #attr_name "=%g", value); \
+          tag = gtk_text_tag_table_lookup (table, name); \
+          if (!tag) \
+            { \
+              tag = gtk_text_tag_new (name); \
+              g_object_set (tag, #attr_name, value, NULL); \
+              gtk_text_tag_table_add (table, tag); \
+              g_object_unref (tag); \
+            } \
+        } \
+        break;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_LETTER_SPACING);
-  if (attr)
-    g_object_set (tag, "letter-spacing", ((PangoAttrInt*)attr)->value, NULL);
+#define RGBA_ATTR(pango_attr_name, attr_name) \
+        case pango_attr_name: \
+        { \
+          PangoColor *color; \
+          GdkRGBA rgba; \
+          color = &((PangoAttrColor*)attr)->color; \
+          rgba.red = color->red / 65535.; \
+          rgba.green = color->green / 65535.; \
+          rgba.blue = color->blue / 65535.; \
+          rgba.alpha = 1.; \
+          char *str = gdk_rgba_to_string (&rgba); \
+          g_snprintf (name, 256, #attr_name "=%s", str); \
+          g_free (str); \
+          tag = gtk_text_tag_table_lookup (table, name); \
+          if (!tag) \
+            { \
+              tag = gtk_text_tag_new (name); \
+              g_object_set (tag, #attr_name, &rgba, NULL); \
+              gtk_text_tag_table_add (table, tag); \
+              g_object_unref (tag); \
+            } \
+        } \
+        break;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_FONT_FEATURES);
-  if (attr)
-    g_object_set (tag, "font-features", ((PangoAttrString*)attr)->value, NULL);
+        case PANGO_ATTR_LANGUAGE:
+        {
+          const char *language = pango_language_to_string (((PangoAttrLanguage*)attr)->value);
+          g_snprintf (name, 256, "language=%s", language);
+          tag = gtk_text_tag_table_lookup (table, name);
+          if (!tag)
+            {
+              tag = gtk_text_tag_new (name);
+              g_object_set (tag, "language", language, NULL);
+              gtk_text_tag_table_add (table, tag);
+              g_object_unref (tag);
+            }
+        }
+        break;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_ALLOW_BREAKS);
-  if (attr)
-    g_object_set (tag, "allow-breaks", ((PangoAttrInt*)attr)->value, NULL);
+        STRING_ATTR (PANGO_ATTR_FAMILY, family)
+        INT_ATTR    (PANGO_ATTR_STYLE, style)
+        INT_ATTR    (PANGO_ATTR_WEIGHT, weight)
+        INT_ATTR    (PANGO_ATTR_VARIANT, variant)
+        INT_ATTR    (PANGO_ATTR_STRETCH, stretch)
+        INT_ATTR    (PANGO_ATTR_SIZE, size)
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_SHOW);
-  if (attr)
-    g_object_set (tag, "show-spaces", ((PangoAttrInt*)attr)->value, NULL);
+        case PANGO_ATTR_FONT_DESC:
+        {
+          PangoFontDescription *desc = ((PangoAttrFontDesc*)attr)->desc;
+          char *str = pango_font_description_to_string (desc);
+          g_snprintf (name, 256, "font-desc=%s", str);
+          g_free (str);
+          tag = gtk_text_tag_table_lookup (table, name);
+          if (!tag)
+            {
+              tag = gtk_text_tag_new (name);
+              g_object_set (tag, "font-desc", desc, NULL);
+              gtk_text_tag_table_add (table, tag);
+              g_object_unref (tag);
+            }
+        }
+        break;
 
-  attr = pango_attr_iterator_get (iter, PANGO_ATTR_INSERT_HYPHENS);
-  if (attr)
-    g_object_set (tag, "insert-hyphens", ((PangoAttrInt*)attr)->value, NULL);
+        RGBA_ATTR   (PANGO_ATTR_FOREGROUND, foreground_rgba)
+        RGBA_ATTR   (PANGO_ATTR_BACKGROUND, background_rgba)
+        INT_ATTR    (PANGO_ATTR_UNDERLINE, underline)
+        RGBA_ATTR   (PANGO_ATTR_UNDERLINE_COLOR, underline_rgba)
+        INT_ATTR    (PANGO_ATTR_OVERLINE, overline)
+        RGBA_ATTR   (PANGO_ATTR_OVERLINE_COLOR, overline_rgba)
+        INT_ATTR    (PANGO_ATTR_STRIKETHROUGH, strikethrough)
+        RGBA_ATTR   (PANGO_ATTR_STRIKETHROUGH_COLOR, strikethrough_rgba)
+        INT_ATTR    (PANGO_ATTR_RISE, rise)
+        FLOAT_ATTR  (PANGO_ATTR_SCALE, scale)
+        INT_ATTR    (PANGO_ATTR_FALLBACK, fallback)
+        INT_ATTR    (PANGO_ATTR_LETTER_SPACING, letter_spacing)
+        STRING_ATTR (PANGO_ATTR_FONT_FEATURES, font_features)
+        INT_ATTR    (PANGO_ATTR_ALLOW_BREAKS, allow_breaks)
+        INT_ATTR    (PANGO_ATTR_SHOW, show_spaces)
+        INT_ATTR    (PANGO_ATTR_INSERT_HYPHENS, insert_hyphens)
+
+        default:
+          continue;
+        }
 
-  return tag;
+      gtk_text_buffer_apply_tag (buffer, tag, start, end);
+    }
 }
 
 static void
@@ -4544,7 +4563,6 @@ gtk_text_buffer_insert_with_attributes (GtkTextBuffer *buffer,
 {
   GtkTextMark *mark;
   PangoAttrIterator *attr;
-  GtkTextTagTable *tags;
 
   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
 
@@ -4557,32 +4575,31 @@ gtk_text_buffer_insert_with_attributes (GtkTextBuffer *buffer,
   /* create mark with right gravity */
   mark = gtk_text_buffer_create_mark (buffer, NULL, iter, FALSE);
   attr = pango_attr_list_get_iterator (attributes);
-  tags = gtk_text_buffer_get_tag_table (buffer);
 
   do
     {
-      GtkTextTag *tag;
       int start, end;
+      int start_offset;
+      GtkTextIter start_iter;
 
       pango_attr_iterator_range (attr, &start, &end);
 
       if (end == G_MAXINT) /* last chunk */
         end = start - 1; /* resulting in -1 to be passed to _insert */
 
-      tag = get_tag_for_attributes (attr);
-      gtk_text_tag_table_add (tags, tag);
+      start_offset = gtk_text_iter_get_offset (iter);
+      gtk_text_buffer_insert (buffer, iter, text + start, end - start);
+      gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
 
-      gtk_text_buffer_insert_with_tags (buffer, iter, text + start, end - start, tag, NULL);
+      insert_tags_for_attributes (buffer, attr, &start_iter, iter);
 
       gtk_text_buffer_get_iter_at_mark (buffer, iter, mark);
-
-       g_object_unref (tag);
     }
   while (pango_attr_iterator_next (attr));
-  
+
   gtk_text_buffer_delete_mark (buffer, mark);
   pango_attr_iterator_destroy (attr);
-} 
+}
 
 /**
  * gtk_text_buffer_insert_markup:


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