From 6c8d47f5855cfbed8298a65d9d5315a4655468d3 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Wed, 18 Mar 2020 11:32:46 -0700 Subject: [PATCH] textbtree: short-circuit visibility check when possible If we have never seen a GtkTextTag in the GtkTextTagTable with the invisible bit set, then we do not need to go through the process of checking the accumulated tags. Not using invisible tags is overwhelmingly the common case. --- gtk/gtktextbtree.c | 9 ++++++++- gtk/gtktexttagtable.c | 27 +++++++++++++++++++++++++++ gtk/gtktexttagtableprivate.h | 15 ++++++++------- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c index 1ab7878539..65aae142e1 100644 --- a/gtk/gtktextbtree.c +++ b/gtk/gtktextbtree.c @@ -60,7 +60,7 @@ #include "gtktextbufferprivate.h" #include "gtktexttag.h" #include "gtktexttagprivate.h" -#include "gtktexttagtable.h" +#include "gtktexttagtableprivate.h" #include "gtktextlayoutprivate.h" #include "gtktextiterprivate.h" #include "gtkdebug.h" @@ -2491,6 +2491,13 @@ _gtk_text_btree_char_is_invisible (const GtkTextIter *iter) line = _gtk_text_iter_get_text_line (iter); tree = _gtk_text_iter_get_btree (iter); + + /* Short-circuit if we've never seen a visibility tag within the + * tag table (meaning everything must be visible). + */ + if G_LIKELY (!_gtk_text_tag_table_affects_visibility (tree->table)) + return FALSE; + byte_index = gtk_text_iter_get_line_index (iter); numTags = gtk_text_tag_table_get_size (tree->table); diff --git a/gtk/gtktexttagtable.c b/gtk/gtktexttagtable.c index 81a852ccc3..c28621edd6 100644 --- a/gtk/gtktexttagtable.c +++ b/gtk/gtktexttagtable.c @@ -88,6 +88,8 @@ struct _GtkTextTagTablePrivate GSList *buffers; gint anon_count; + + guint seen_invisible : 1; }; enum { @@ -180,6 +182,22 @@ gtk_text_tag_table_init (GtkTextTagTable *table) table->priv->hash = g_hash_table_new (g_str_hash, g_str_equal); } +static void +check_visible (GtkTextTagTable *table, + GtkTextTag *tag) +{ + if (table->priv->seen_invisible) + return; + + if (tag->priv->invisible_set) + { + gboolean invisible; + + g_object_get (tag, "invisible", &invisible, NULL); + table->priv->seen_invisible = invisible; + } +} + /** * gtk_text_tag_table_new: * @@ -301,6 +319,8 @@ gtk_text_tag_table_add (GtkTextTagTable *table, g_assert (size > 0); tag->priv->priority = size - 1; + check_visible (table, tag); + g_signal_emit (table, signals[TAG_ADDED], 0, tag); return TRUE; } @@ -490,5 +510,12 @@ _gtk_text_tag_table_tag_changed (GtkTextTagTable *table, GtkTextTag *tag, gboolean size_changed) { + check_visible (table, tag); g_signal_emit (table, signals[TAG_CHANGED], 0, tag, size_changed); } + +gboolean +_gtk_text_tag_table_affects_visibility (GtkTextTagTable *table) +{ + return table->priv->seen_invisible; +} diff --git a/gtk/gtktexttagtableprivate.h b/gtk/gtktexttagtableprivate.h index 0a8401e695..4bf0d5773c 100644 --- a/gtk/gtktexttagtableprivate.h +++ b/gtk/gtktexttagtableprivate.h @@ -29,13 +29,14 @@ G_BEGIN_DECLS -void _gtk_text_tag_table_add_buffer (GtkTextTagTable *table, - gpointer buffer); -void _gtk_text_tag_table_remove_buffer (GtkTextTagTable *table, - gpointer buffer); -void _gtk_text_tag_table_tag_changed (GtkTextTagTable *table, - GtkTextTag *tag, - gboolean size_changed); +void _gtk_text_tag_table_add_buffer (GtkTextTagTable *table, + gpointer buffer); +void _gtk_text_tag_table_remove_buffer (GtkTextTagTable *table, + gpointer buffer); +void _gtk_text_tag_table_tag_changed (GtkTextTagTable *table, + GtkTextTag *tag, + gboolean size_changed); +gboolean _gtk_text_tag_table_affects_visibility (GtkTextTagTable *table); G_END_DECLS