[gtk+/wip/cssstyle: 30/30] stylecontext: Add a parent style cache



commit e72038af18fc6d34b06b02341037796209339950
Author: Benjamin Otte <otte redhat com>
Date:   Tue Jan 6 00:38:54 2015 +0100

    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

 gtk/gtkstylecontext.c |   98 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 98 insertions(+), 0 deletions(-)
---
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index d7c4fd0..45f53bf 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -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;
 }
 


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