cssnode: Split out the style cache

For now, the split out style cache doesn't cache anything. This is
mostly to make sure that bisections of wrong caching behavior will
bisect down to the commit that actually adds caching.
This commit is contained in:
Benjamin Otte 2016-01-15 23:27:51 +01:00
parent 93f8fa7576
commit 5d562b6a2a
5 changed files with 151 additions and 96 deletions

View File

@ -416,6 +416,7 @@ gtk_private_h_sources = \
gtkcssmatcherprivate.h \ gtkcssmatcherprivate.h \
gtkcssnodeprivate.h \ gtkcssnodeprivate.h \
gtkcssnodedeclarationprivate.h \ gtkcssnodedeclarationprivate.h \
gtkcssnodestylecacheprivate.h \
gtkcssnumbervalueprivate.h \ gtkcssnumbervalueprivate.h \
gtkcsspalettevalueprivate.h \ gtkcsspalettevalueprivate.h \
gtkcssparserprivate.h \ gtkcssparserprivate.h \
@ -676,6 +677,7 @@ gtk_base_c_sources = \
gtkcssmatcher.c \ gtkcssmatcher.c \
gtkcssnode.c \ gtkcssnode.c \
gtkcssnodedeclaration.c \ gtkcssnodedeclaration.c \
gtkcssnodestylecache.c \
gtkcssnumbervalue.c \ gtkcssnumbervalue.c \
gtkcsspalettevalue.c \ gtkcsspalettevalue.c \
gtkcssparser.c \ gtkcssparser.c \

View File

@ -20,13 +20,13 @@
#include "gtkcssnodeprivate.h" #include "gtkcssnodeprivate.h"
#include "gtkcssanimatedstyleprivate.h" #include "gtkcssanimatedstyleprivate.h"
#include "gtkcsssectionprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkdebug.h" #include "gtkdebug.h"
#include "gtkintl.h" #include "gtkintl.h"
#include "gtkmarshalers.h" #include "gtkmarshalers.h"
#include "gtksettingsprivate.h" #include "gtksettingsprivate.h"
#include "gtktypebuiltins.h" #include "gtktypebuiltins.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsssectionprivate.h"
/* /*
* CSS nodes are the backbone of the GtkStyleContext implementation and * CSS nodes are the backbone of the GtkStyleContext implementation and
@ -116,8 +116,6 @@ struct _GtkCssNodeStyleChange {
static guint cssnode_signals[LAST_SIGNAL] = { 0 }; static guint cssnode_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *cssnode_properties[NUM_PROPERTIES]; static GParamSpec *cssnode_properties[NUM_PROPERTIES];
static GQuark quark_global_cache;
static GtkStyleProviderPrivate * static GtkStyleProviderPrivate *
gtk_css_node_get_style_provider_or_null (GtkCssNode *cssnode) gtk_css_node_get_style_provider_or_null (GtkCssNode *cssnode)
{ {
@ -285,10 +283,6 @@ gtk_css_node_is_last_child (GtkCssNode *node)
return TRUE; return TRUE;
} }
#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))
static gboolean static gboolean
may_use_global_parent_cache (GtkCssNode *node) may_use_global_parent_cache (GtkCssNode *node)
{ {
@ -308,109 +302,52 @@ may_use_global_parent_cache (GtkCssNode *node)
static GtkCssStyle * static GtkCssStyle *
lookup_in_global_parent_cache (GtkCssNode *node, lookup_in_global_parent_cache (GtkCssNode *node,
GtkCssStyle *parent,
const GtkCssNodeDeclaration *decl) const GtkCssNodeDeclaration *decl)
{ {
GHashTable *cache; GtkCssNode *parent;
GtkCssStyle *style;
parent = node->parent;
if (parent == NULL || if (parent == NULL ||
!may_use_global_parent_cache (node)) !may_use_global_parent_cache (node))
return NULL; return NULL;
cache = g_object_get_qdata (G_OBJECT (parent), quark_global_cache); if (parent->cache == NULL)
if (cache == NULL)
return NULL; return NULL;
style = g_hash_table_lookup (cache, node->cache = gtk_css_node_style_cache_lookup (parent->cache,
PACK (decl, (GtkCssNodeDeclaration *) decl,
gtk_css_node_is_first_child (node), gtk_css_node_is_first_child (node),
gtk_css_node_is_last_child (node))); gtk_css_node_is_last_child (node));
if (node->cache == NULL)
return NULL;
return style; return gtk_css_node_style_cache_get_style (node->cache);
}
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_NTH_CHILD | GTK_CSS_CHANGE_NTH_LAST_CHILD))
return FALSE;
return TRUE;
}
static guint
gtk_global_parent_cache_hash (gconstpointer item)
{
return gtk_css_node_declaration_hash (UNPACK_DECLARATION (item)) << 2
| UNPACK_FLAGS (item);
}
static gboolean
gtk_global_parent_cache_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_global_parent_cache_free (gpointer item)
{
gtk_css_node_declaration_unref (UNPACK_DECLARATION (item));
} }
static void static void
store_in_global_parent_cache (GtkCssNode *node, store_in_global_parent_cache (GtkCssNode *node,
GtkCssStyle *parent,
const GtkCssNodeDeclaration *decl, const GtkCssNodeDeclaration *decl,
GtkCssStyle *style) GtkCssStyle *style)
{ {
GHashTable *cache; GtkCssNode *parent;
g_assert (GTK_IS_CSS_STATIC_STYLE (style)); g_assert (GTK_IS_CSS_STATIC_STYLE (style));
parent = node->parent;
if (parent == NULL || if (parent == NULL ||
!may_use_global_parent_cache (node)) !may_use_global_parent_cache (node))
return; return;
if (!may_be_stored_in_parent_cache (style)) if (parent->cache == NULL)
return; parent->cache = gtk_css_node_style_cache_new (parent->style);
cache = g_object_get_qdata (G_OBJECT (parent), quark_global_cache); node->cache = gtk_css_node_style_cache_insert (parent->cache,
if (cache == NULL) (GtkCssNodeDeclaration *) decl,
{
cache = g_hash_table_new_full (gtk_global_parent_cache_hash,
gtk_global_parent_cache_equal,
gtk_global_parent_cache_free,
g_object_unref);
g_object_set_qdata_full (G_OBJECT (parent),
quark_global_cache,
cache,
(GDestroyNotify) g_hash_table_destroy);
}
g_hash_table_insert (cache,
PACK (gtk_css_node_declaration_ref ((GtkCssNodeDeclaration *) decl),
gtk_css_node_is_first_child (node), gtk_css_node_is_first_child (node),
gtk_css_node_is_last_child (node)), gtk_css_node_is_last_child (node),
g_object_ref (style)); style);
} }
static GtkCssStyle * static GtkCssStyle *
@ -424,7 +361,7 @@ gtk_css_node_create_style (GtkCssNode *cssnode)
decl = gtk_css_node_get_declaration (cssnode); decl = gtk_css_node_get_declaration (cssnode);
parent = cssnode->parent ? cssnode->parent->style : NULL; parent = cssnode->parent ? cssnode->parent->style : NULL;
style = lookup_in_global_parent_cache (cssnode, parent, decl); style = lookup_in_global_parent_cache (cssnode, decl);
if (style) if (style)
return g_object_ref (style); return g_object_ref (style);
@ -437,7 +374,7 @@ gtk_css_node_create_style (GtkCssNode *cssnode)
NULL, NULL,
parent); parent);
store_in_global_parent_cache (cssnode, parent, decl, style); store_in_global_parent_cache (cssnode, decl, style);
return style; return style;
} }
@ -625,8 +562,6 @@ gtk_css_node_class_init (GtkCssNodeClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
quark_global_cache = g_quark_from_static_string ("gtk-global-cache");
object_class->get_property = gtk_css_node_get_property; object_class->get_property = gtk_css_node_get_property;
object_class->set_property = gtk_css_node_set_property; object_class->set_property = gtk_css_node_set_property;
object_class->dispose = gtk_css_node_dispose; object_class->dispose = gtk_css_node_dispose;
@ -1059,6 +994,8 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
if (cssnode->previous_sibling) if (cssnode->previous_sibling)
gtk_css_node_ensure_style (cssnode->previous_sibling, current_time); gtk_css_node_ensure_style (cssnode->previous_sibling, current_time);
g_clear_pointer (&cssnode->cache, gtk_css_node_style_cache_unref);
new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode, new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
cssnode->pending_changes, cssnode->pending_changes,
current_time, current_time,
@ -1066,12 +1003,6 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
style_changed = gtk_css_node_set_style (cssnode, new_style); style_changed = gtk_css_node_set_style (cssnode, new_style);
g_object_unref (new_style); g_object_unref (new_style);
if (!style_changed && (cssnode->pending_changes & GTK_CSS_CHANGE_SOURCE))
{
/* clear the global cache if we reuse the same style after the CSS changed */
g_object_set_qdata (G_OBJECT (cssnode->style), quark_global_cache, NULL);
}
} }
else else
{ {

View File

@ -19,6 +19,7 @@
#define __GTK_CSS_NODE_PRIVATE_H__ #define __GTK_CSS_NODE_PRIVATE_H__
#include "gtkcssnodedeclarationprivate.h" #include "gtkcssnodedeclarationprivate.h"
#include "gtkcssnodestylecacheprivate.h"
#include "gtkcssstylechangeprivate.h" #include "gtkcssstylechangeprivate.h"
#include "gtkbitmaskprivate.h" #include "gtkbitmaskprivate.h"
#include "gtkcsstypesprivate.h" #include "gtkcsstypesprivate.h"
@ -46,6 +47,7 @@ struct _GtkCssNode
GtkCssNodeDeclaration *decl; GtkCssNodeDeclaration *decl;
GtkCssStyle *style; GtkCssStyle *style;
GtkCssNodeStyleCache *cache; /* cache for children to look up styles */
GtkCssChange pending_changes; /* changes that accumulated since the style was last computed */ GtkCssChange pending_changes; /* changes that accumulated since the style was last computed */

View File

@ -0,0 +1,76 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2015 Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtkcssnodestylecacheprivate.h"
struct _GtkCssNodeStyleCache {
guint ref_count;
GtkCssStyle *style;
GHashTable *children;
};
GtkCssNodeStyleCache *
gtk_css_node_style_cache_new (GtkCssStyle *style)
{
GtkCssNodeStyleCache *result;
result = g_slice_new0 (GtkCssNodeStyleCache);
result->ref_count = 1;
result->style = g_object_ref (style);
return result;
}
void
gtk_css_node_style_cache_unref (GtkCssNodeStyleCache *cache)
{
cache->ref_count--;
if (cache->ref_count > 0)
return;
g_object_unref (cache->style);
}
GtkCssStyle *
gtk_css_node_style_cache_get_style (GtkCssNodeStyleCache *cache)
{
return cache->style;
}
GtkCssNodeStyleCache *
gtk_css_node_style_cache_insert (GtkCssNodeStyleCache *parent,
GtkCssNodeDeclaration *decl,
gboolean is_first,
gboolean is_last,
GtkCssStyle *style)
{
return gtk_css_node_style_cache_new (style);
}
GtkCssNodeStyleCache *
gtk_css_node_style_cache_lookup (GtkCssNodeStyleCache *parent,
GtkCssNodeDeclaration *decl,
gboolean is_first,
gboolean is_last)
{
return NULL;
}

View File

@ -0,0 +1,44 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2016 Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__
#define __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__
#include "gtkcssstyleprivate.h"
G_BEGIN_DECLS
typedef struct _GtkCssNodeStyleCache GtkCssNodeStyleCache;
GtkCssNodeStyleCache * gtk_css_node_style_cache_new (GtkCssStyle *style);
void gtk_css_node_style_cache_unref (GtkCssNodeStyleCache *cache);
GtkCssStyle * gtk_css_node_style_cache_get_style (GtkCssNodeStyleCache *cache);
GtkCssNodeStyleCache * gtk_css_node_style_cache_insert (GtkCssNodeStyleCache *parent,
GtkCssNodeDeclaration *decl,
gboolean is_first,
gboolean is_last,
GtkCssStyle *style);
GtkCssNodeStyleCache * gtk_css_node_style_cache_lookup (GtkCssNodeStyleCache *parent,
GtkCssNodeDeclaration *decl,
gboolean is_first,
gboolean is_last);
G_END_DECLS
#endif /* __GTK_CSS_NODE_STYLE_CACHE_PRIVATE_H__ */