[gtk+] cssnode: Implement the style cache



commit 024429f76fc605e834fef3ca654a0d0cdaac1dfa
Author: Benjamin Otte <otte redhat com>
Date:   Sat Jan 16 04:48:58 2016 +0100

    cssnode: Implement the style cache
    
    This essentially copies the previous cache implementation. With one
    caveat: It is now attached to and maintained by the CssNode, not by the
    CssStyle.
    
    And this is important because styles may be reused in incompatible
    situations which would cause cache collisions and lead to broken CSS in
    weird situations.

 gtk/gtkcssnodestylecache.c        |   97 ++++++++++++++++++++++++++++++++++++-
 gtk/gtkcssnodestylecacheprivate.h |    2 +
 2 files changed, 97 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkcssnodestylecache.c b/gtk/gtkcssnodestylecache.c
index 5c4e61d..8c250bc 100644
--- a/gtk/gtkcssnodestylecache.c
+++ b/gtk/gtkcssnodestylecache.c
@@ -19,12 +19,18 @@
 
 #include "gtkcssnodestylecacheprivate.h"
 
+#include "gtkcssstaticstyleprivate.h"
+
 struct _GtkCssNodeStyleCache {
   guint        ref_count;
   GtkCssStyle *style;
   GHashTable  *children;
 };
 
+#define UNPACK_DECLARATION(packed) ((GtkCssNodeDeclaration *) (GPOINTER_TO_SIZE (packed) & ~0x3))
+#define UNPACK_FLAGS(packed) (GPOINTER_TO_SIZE (packed) & 0x3)
+#define PACK(decl, first_child, last_child) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (decl) | ((first_child) ? 0x2 
: 0) | ((last_child) ? 0x1 : 0))
+
 GtkCssNodeStyleCache *
 gtk_css_node_style_cache_new (GtkCssStyle *style)
 {
@@ -38,6 +44,14 @@ gtk_css_node_style_cache_new (GtkCssStyle *style)
   return result;
 }
 
+GtkCssNodeStyleCache *
+gtk_css_node_style_cache_ref (GtkCssNodeStyleCache *cache)
+{
+  cache->ref_count++; 
+
+  return cache;
+}
+
 void
 gtk_css_node_style_cache_unref (GtkCssNodeStyleCache *cache)
 {
@@ -47,6 +61,10 @@ gtk_css_node_style_cache_unref (GtkCssNodeStyleCache *cache)
     return;
 
   g_object_unref (cache->style);
+  if (cache->children)
+    g_hash_table_unref (cache->children);
+
+  g_slice_free (GtkCssNodeStyleCache, cache);
 }
 
 GtkCssStyle *
@@ -55,6 +73,55 @@ gtk_css_node_style_cache_get_style (GtkCssNodeStyleCache *cache)
   return cache->style;
 }
 
+static gboolean
+may_be_stored_in_cache (GtkCssStyle *style)
+{
+  GtkCssChange change;
+
+  if (!GTK_IS_CSS_STATIC_STYLE (style))
+    return FALSE;
+
+  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_NTH_CHILD | GTK_CSS_CHANGE_NTH_LAST_CHILD))
+    return FALSE;
+
+  return TRUE;
+}
+
+static guint
+gtk_css_node_style_cache_decl_hash (gconstpointer item)
+{
+  return gtk_css_node_declaration_hash (UNPACK_DECLARATION (item)) << 2
+    | UNPACK_FLAGS (item);
+}
+
+static gboolean
+gtk_css_node_style_cache_decl_equal (gconstpointer item1,
+                                     gconstpointer item2)
+{
+  if (UNPACK_FLAGS (item1) != UNPACK_FLAGS (item2))
+    return FALSE;
+
+  return gtk_css_node_declaration_equal (UNPACK_DECLARATION (item1),
+                                         UNPACK_DECLARATION (item2));
+}
+
+static void
+gtk_css_node_style_cache_decl_free (gpointer item)
+{
+  gtk_css_node_declaration_unref (UNPACK_DECLARATION (item));
+}
+
 GtkCssNodeStyleCache *
 gtk_css_node_style_cache_insert (GtkCssNodeStyleCache   *parent,
                                  GtkCssNodeDeclaration  *decl,
@@ -62,7 +129,24 @@ gtk_css_node_style_cache_insert (GtkCssNodeStyleCache   *parent,
                                  gboolean                is_last,
                                  GtkCssStyle            *style)
 {
-  return gtk_css_node_style_cache_new (style);
+  GtkCssNodeStyleCache *result;
+
+  if (!may_be_stored_in_cache (style))
+    return NULL;
+
+  if (parent->children == NULL)
+    parent->children = g_hash_table_new_full (gtk_css_node_style_cache_decl_hash,
+                                              gtk_css_node_style_cache_decl_equal,
+                                              gtk_css_node_style_cache_decl_free,
+                                              (GDestroyNotify) gtk_css_node_style_cache_unref);
+
+  result = gtk_css_node_style_cache_new (style);
+
+  g_hash_table_insert (parent->children,
+                       PACK (gtk_css_node_declaration_ref (decl), is_first, is_last),
+                       gtk_css_node_style_cache_ref (result));
+
+  return result;
 }
 
 GtkCssNodeStyleCache *
@@ -71,6 +155,15 @@ gtk_css_node_style_cache_lookup (GtkCssNodeStyleCache   *parent,
                                  gboolean                is_first,
                                  gboolean                is_last)
 {
-  return NULL;
+  GtkCssNodeStyleCache *result;
+
+  if (parent->children == NULL)
+    return NULL;
+
+  result = g_hash_table_lookup (parent->children, PACK (decl, is_first, is_last));
+  if (result == NULL)
+    return NULL;
+
+  return gtk_css_node_style_cache_ref (result);
 }
 
diff --git a/gtk/gtkcssnodestylecacheprivate.h b/gtk/gtkcssnodestylecacheprivate.h
index c406fbf..cef1ec2 100644
--- a/gtk/gtkcssnodestylecacheprivate.h
+++ b/gtk/gtkcssnodestylecacheprivate.h
@@ -18,6 +18,7 @@
 #ifndef __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__
 #define __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__
 
+#include "gtkcssnodedeclarationprivate.h"
 #include "gtkcssstyleprivate.h"
 
 G_BEGIN_DECLS
@@ -25,6 +26,7 @@ G_BEGIN_DECLS
 typedef struct _GtkCssNodeStyleCache GtkCssNodeStyleCache;
 
 GtkCssNodeStyleCache *  gtk_css_node_style_cache_new            (GtkCssStyle            *style);
+GtkCssNodeStyleCache *  gtk_css_node_style_cache_ref            (GtkCssNodeStyleCache   *cache);
 void                    gtk_css_node_style_cache_unref          (GtkCssNodeStyleCache   *cache);
 
 GtkCssStyle *           gtk_css_node_style_cache_get_style      (GtkCssNodeStyleCache   *cache);


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