diff --git a/gtk/gtkcssnodestylecache.c b/gtk/gtkcssnodestylecache.c index 5c4e61de1f..8c250bcac6 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 c406fbf0ee..cef1ec2bff 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);