[gtk/matthiasc/for-master] Speed up gtk_text_buffer_insert_markup
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/for-master] Speed up gtk_text_buffer_insert_markup
- Date: Thu, 13 Aug 2020 03:43:07 +0000 (UTC)
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]