stylecontext: Add a parent style cache

We now cache the results of lookups on the parent GtkCssStyle. This
allows sharing styles between widgets (recursively). However, this
only works if the styles can't potentially depend on siblings -
neither directly via sibling selectors or via position pseudo-classes
like :first-child.
Unfortunately, Adwaita currently uses first-child a lot, and in
particular for labels, which are the most common widgets.

The big benefits of this change are both less CPU - due to not needing
to compute styles again - and less memory usage - due to sharing of
the styles between widgets. Here's some nonscientific numbers I
collected while pondering the usefulness of this patch:

                    glade   glade   widget
                    demo    demo    factory
                    runtime styles  styles
Adwaita before      19.1s   5800    1150
Adwaita now         18.9s   3800     970
Adwaita hacked now  14.5s   3100     910
simple before       11.3s   5800    1150
simple now          10.8s   1300     590

Adwaita: Adwaita as provided by GTK
Adwaita hacked: Adwaita with the first/last-child for GtkLabel removed
simple: A 250 lines simple GTK theme I use for testing
before: This patch not applied
now: this patch applied

glade demo runtime: Starting glade opening a large file and closing it
glade demo styles: GtkCssStaticStyle objects after opening glade with
                   the large file as per inspector
widget factory styles: GtkCssStaticStyle objects after startup as per
                       inspector
This commit is contained in:
Benjamin Otte 2015-01-06 00:38:54 +01:00
parent 27285f1f0f
commit fe33ee426a

View File

@ -702,6 +702,92 @@ create_query_path (GtkStyleContext *context,
return path;
}
static gboolean
may_use_global_parent_cache (GtkStyleContext *context)
{
GtkStyleContextPrivate *priv = context->priv;
if (priv->cascade != _gtk_settings_get_style_cascade (gtk_settings_get_for_screen (priv->screen)))
return FALSE;
return TRUE;
}
static GtkCssStyle *
lookup_in_global_parent_cache (GtkStyleContext *context,
GtkCssStyle *parent,
const GtkCssNodeDeclaration *decl)
{
GHashTable *cache;
GtkCssStyle *style;
if (parent == NULL ||
!may_use_global_parent_cache (context))
return NULL;
cache = g_object_get_data (G_OBJECT (parent), "gtk-global-cache");
if (cache == NULL)
return NULL;
style = g_hash_table_lookup (cache, decl);
return style;
}
static gboolean
may_be_stored_in_parent_cache (GtkCssStyle *style)
{
GtkCssChange change;
change = gtk_css_static_style_get_change (GTK_CSS_STATIC_STYLE (style));
/* The cache is shared between all children of the parent, so if a
* style depends on a sibling it is not independant of the child.
*/
if (change & GTK_CSS_CHANGE_ANY_SIBLING)
return FALSE;
/* Again, the cache is shared between all children of the parent.
* If the position is relevant, no child has the same style.
*/
if (change & GTK_CSS_CHANGE_POSITION)
return FALSE;
return TRUE;
}
static void
store_in_global_parent_cache (GtkStyleContext *context,
GtkCssStyle *parent,
const GtkCssNodeDeclaration *decl,
GtkCssStyle *style)
{
GHashTable *cache;
g_assert (GTK_IS_CSS_STATIC_STYLE (style));
if (parent == NULL ||
!may_use_global_parent_cache (context))
return;
if (!may_be_stored_in_parent_cache (style))
return;
cache = g_object_get_data (G_OBJECT (parent), "gtk-global-cache");
if (cache == NULL)
{
cache = g_hash_table_new_full (gtk_css_node_declaration_hash,
gtk_css_node_declaration_equal,
(GDestroyNotify) gtk_css_node_declaration_unref,
g_object_unref);
g_object_set_data_full (G_OBJECT (parent), "gtk-global-cache", cache, (GDestroyNotify) g_hash_table_destroy);
}
g_hash_table_insert (cache,
gtk_css_node_declaration_ref ((GtkCssNodeDeclaration *) decl),
g_object_ref (style));
}
static GtkCssStyle *
update_properties (GtkStyleContext *context,
GtkCssStyle *style,
@ -716,6 +802,10 @@ update_properties (GtkStyleContext *context,
priv = context->priv;
result = lookup_in_global_parent_cache (context, parent, decl);
if (result)
return g_object_ref (result);
path = create_query_path (context, decl);
if (!_gtk_css_matcher_init (&matcher, path))
@ -732,6 +822,8 @@ update_properties (GtkStyleContext *context,
gtk_widget_path_free (path);
store_in_global_parent_cache (context, parent, decl, style);
return result;
}
@ -747,6 +839,10 @@ build_properties (GtkStyleContext *context,
priv = context->priv;
style = lookup_in_global_parent_cache (context, parent, decl);
if (style)
return g_object_ref (style);
path = create_query_path (context, decl);
if (_gtk_css_matcher_init (&matcher, path))
@ -762,6 +858,8 @@ build_properties (GtkStyleContext *context,
gtk_widget_path_free (path);
store_in_global_parent_cache (context, parent, decl, style);
return style;
}