[gtk+/wip/css-memuse: 2/3] Internalize computed css values to save memory
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/css-memuse: 2/3] Internalize computed css values to save memory
- Date: Wed, 15 Feb 2012 16:08:44 +0000 (UTC)
commit b2e36bb85b8d30c0c6d048e89688a099b4d1f861
Author: Alexander Larsson <alexl redhat com>
Date: Wed Feb 15 13:36:15 2012 +0100
Internalize computed css values to save memory
gtk/gtkcsscomputedvalues.c | 388 ++++++++++++++++++++++++++++++++++---
gtk/gtkcsscomputedvaluesprivate.h | 2 +-
2 files changed, 360 insertions(+), 30 deletions(-)
---
diff --git a/gtk/gtkcsscomputedvalues.c b/gtk/gtkcsscomputedvalues.c
index c5b6038..d41b240 100644
--- a/gtk/gtkcsscomputedvalues.c
+++ b/gtk/gtkcsscomputedvalues.c
@@ -20,14 +20,88 @@
#include "config.h"
+#include <string.h>
+#include <cairo-gobject.h>
+
#include "gtkcsscomputedvaluesprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsstypesprivate.h"
#include "gtkprivatetypebuiltins.h"
+#include "gtkshadowprivate.h"
+#include "gtkanimationdescription.h"
+#include "gtkcssimageprivate.h"
G_DEFINE_TYPE (GtkCssComputedValues, _gtk_css_computed_values, G_TYPE_OBJECT)
+
+typedef GValue GtkCssValue;
+
+static GHashTable *gtk_css_values;
+
+static guint gtk_css_value_hash (GtkCssValue *css_value);
+static gboolean gtk_css_value_equal (GtkCssValue *css_value_a, GtkCssValue *css_value_b);
+
+static GtkCssValue *
+gtk_css_value_ref (GtkCssValue *v)
+{
+ v->data[1].v_int++;
+ return v;
+}
+
+static void
+gtk_css_value_unref (GtkCssValue *v)
+{
+ if (--v->data[1].v_int == 0)
+ {
+ g_hash_table_remove (gtk_css_values, v);
+ g_value_unset ((GValue *)v);
+ }
+}
+
+static GtkCssValue *
+gtk_css_value_dup_value (const GValue *v)
+{
+ GtkCssValue *new;
+
+ if (v == NULL || !G_IS_VALUE (v))
+ return NULL;
+
+ new = g_hash_table_lookup (gtk_css_values, v);
+ if (new)
+ return gtk_css_value_ref (new);
+
+ new = g_new0 (GtkCssValue, 1);
+ g_value_init ((GValue *)new, G_VALUE_TYPE (v));
+ g_value_copy (v, (GValue *)new);
+ new->data[1].v_int = 1;
+
+ g_hash_table_insert (gtk_css_values, new, new);
+
+ return new;
+}
+
+
+static GtkCssValue *
+gtk_css_value_ref_value (GValue *v)
+{
+
+ if (v == NULL || !G_IS_VALUE (v))
+ return NULL;
+
+ /* Some magic to detect if the GValue is already a GtkCssValue so we can just ref it */
+ if (v->data[1].v_int > 0)
+ return gtk_css_value_ref ((GtkCssValue *)v);
+
+ return gtk_css_value_dup_value (v);
+}
+
+const GValue *
+gtk_css_value_peek (GtkCssValue *v)
+{
+ return (const GValue *)v;
+}
+
static void
gtk_css_computed_values_dispose (GObject *object)
{
@@ -35,7 +109,7 @@ gtk_css_computed_values_dispose (GObject *object)
if (values->values)
{
- g_array_free (values->values, TRUE);
+ g_ptr_array_unref (values->values);
values->values = NULL;
}
if (values->sections)
@@ -47,18 +121,282 @@ gtk_css_computed_values_dispose (GObject *object)
G_OBJECT_CLASS (_gtk_css_computed_values_parent_class)->dispose (object);
}
+static gboolean
+strv_equal (char **a, char **b)
+{
+ int i;
+
+ if (a == b)
+ return TRUE;
+
+ if (a == NULL || b == NULL)
+ return FALSE;
+
+ for (i = 0; a[i] != NULL && b[i] != NULL; i++)
+ {
+ if (strcmp (a[i], b[i]) != 0)
+ return FALSE;
+ }
+ return a[i] == NULL && b[i] == NULL;
+}
+
+static guint
+strv_hash (char **v)
+{
+ int i;
+ guint hash;
+
+ if (v == NULL)
+ return 0;
+
+ hash = 0;
+ for (i = 0; v[i] != NULL; i++)
+ hash ^= g_str_hash (v[i]);
+ return hash;
+}
+
+static gboolean
+gtk_css_value_equal (GtkCssValue *css_value_a, GtkCssValue *css_value_b)
+{
+ GType type;
+ const GValue *a = gtk_css_value_peek (css_value_a);
+ const GValue *b = gtk_css_value_peek (css_value_b);
+
+ if (a == b)
+ return TRUE;
+
+ if (a == NULL || b == NULL)
+ return FALSE;
+
+ if (a->g_type != b->g_type)
+ return FALSE;
+
+ type = a->g_type;
+ if (type == G_TYPE_INT || type == G_TYPE_BOOLEAN)
+ {
+ return a->data[0].v_int == b->data[0].v_int;
+ }
+ else if (type == G_TYPE_DOUBLE)
+ {
+ return a->data[0].v_double == b->data[0].v_double;
+ }
+ else if (type == G_TYPE_LONG ||
+ G_TYPE_IS_ENUM (type) ||
+ G_TYPE_IS_FLAGS (type))
+ {
+ return a->data[0].v_long == b->data[0].v_long;
+ }
+ else if (type == GDK_TYPE_RGBA)
+ {
+ return gdk_rgba_equal (a->data[0].v_pointer,
+ b->data[0].v_pointer);
+ }
+ else if (type == G_TYPE_STRV)
+ {
+ return strv_equal (a->data[0].v_pointer,
+ b->data[0].v_pointer);
+ }
+ else if (type == GTK_TYPE_CSS_NUMBER)
+ {
+ return _gtk_css_number_equal (a->data[0].v_pointer,
+ b->data[0].v_pointer);
+ }
+ else if (type == GTK_TYPE_CSS_BORDER_IMAGE_REPEAT)
+ {
+ GtkCssBorderImageRepeat *aa = a->data[0].v_pointer;
+ GtkCssBorderImageRepeat *bb = b->data[0].v_pointer;
+
+ if (aa == bb)
+ return TRUE;
+ if (aa == NULL || bb == NULL)
+ return FALSE;
+
+ return
+ aa->vrepeat == bb->vrepeat &&
+ aa->hrepeat == bb->hrepeat;
+ }
+ else if (type == GTK_TYPE_CSS_BORDER_CORNER_RADIUS)
+ {
+ GtkCssBorderCornerRadius *aa = a->data[0].v_pointer;
+ GtkCssBorderCornerRadius *bb = b->data[0].v_pointer;
+
+ if (aa == bb)
+ return TRUE;
+ if (aa == NULL || bb == NULL)
+ return FALSE;
+
+ return
+ _gtk_css_number_equal (&aa->horizontal, &bb->horizontal) &&
+ _gtk_css_number_equal (&aa->vertical, &bb->vertical);
+ }
+ else if (type == GTK_TYPE_BORDER)
+ {
+ GtkBorder *aa = a->data[0].v_pointer;
+ GtkBorder *bb = b->data[0].v_pointer;
+
+ if (aa == bb)
+ return TRUE;
+ if (aa == NULL || bb == NULL)
+ return FALSE;
+
+ return
+ aa->left == bb->left &&
+ aa->right == bb->right &&
+ aa->top == bb->top &&
+ aa->bottom == bb->bottom;
+ }
+ else if (type == GTK_TYPE_CSS_BACKGROUND_SIZE)
+ {
+ GtkCssBackgroundSize *aa = a->data[0].v_pointer;
+ GtkCssBackgroundSize *bb = b->data[0].v_pointer;
+
+ if (aa == bb)
+ return TRUE;
+ if (aa == NULL || bb == NULL)
+ return FALSE;
+
+ return
+ _gtk_css_number_equal (&aa->width, &bb->width) &&
+ _gtk_css_number_equal (&aa->height, &bb->height) &&
+ aa->cover == bb->cover &&
+ aa->contain == bb->contain;
+ }
+ else if (type == GTK_TYPE_SHADOW ||
+ type == G_TYPE_PTR_ARRAY ||
+ type == CAIRO_GOBJECT_TYPE_PATTERN ||
+ type == GTK_TYPE_THEMING_ENGINE ||
+ type == GTK_TYPE_ANIMATION_DESCRIPTION||
+ type == GTK_TYPE_CSS_IMAGE)
+ {
+ /* These are refcounted, compare by pointer */
+ return a->data[0].v_pointer == b->data[0].v_pointer;
+ }
+ else
+ {
+ g_error ("Can't handle CSS type %s\n", g_type_name (type));
+ }
+
+ return FALSE;
+}
+
+
+static guint
+gtk_css_value_hash (GtkCssValue *css_value)
+{
+ GType type;
+ const GValue *v = gtk_css_value_peek (css_value);
+
+ if (v == NULL)
+ return 0;
+
+ if (v->g_type == 0)
+ return 0;
+
+ type = v->g_type;
+
+ if (type == G_TYPE_INT || type == G_TYPE_BOOLEAN)
+ {
+ return (guint)v->data[0].v_int;
+ }
+ else if (type == G_TYPE_DOUBLE)
+ {
+ return (guint)v->data[0].v_double;
+ }
+ else if (type == G_TYPE_LONG ||
+ G_TYPE_IS_ENUM (type) ||
+ G_TYPE_IS_FLAGS (type))
+ {
+ return (guint)v->data[0].v_long;
+ }
+ else if (type == GDK_TYPE_RGBA)
+ {
+ return gdk_rgba_hash (v->data[0].v_pointer);
+ }
+ else if (type == G_TYPE_STRV)
+ {
+ return strv_hash (v->data[0].v_pointer);
+ }
+ else if (type == GTK_TYPE_CSS_NUMBER)
+ {
+ return _gtk_css_number_hash (v->data[0].v_pointer);
+ }
+ else if (type == GTK_TYPE_CSS_BORDER_IMAGE_REPEAT)
+ {
+ GtkCssBorderImageRepeat *vv = v->data[0].v_pointer;
+
+ if (vv == NULL)
+ return 0;
+
+ return ((guint)vv->vrepeat) ^ ((guint)vv->hrepeat);
+ }
+ else if (type == GTK_TYPE_CSS_BORDER_CORNER_RADIUS)
+ {
+ GtkCssBorderCornerRadius *vv = v->data[0].v_pointer;
+
+ if (vv == NULL)
+ return 0;
+
+ return
+ _gtk_css_number_hash (&vv->horizontal) ^
+ _gtk_css_number_hash (&vv->vertical);
+ }
+ else if (type == GTK_TYPE_BORDER)
+ {
+ GtkBorder *vv = v->data[0].v_pointer;
+
+ if (vv == NULL)
+ return 0;
+
+ return
+ ((guint)vv->left) ^
+ (((guint)vv->right) << 16) ^
+ ((guint)vv->top) ^
+ (((guint)vv->bottom) << 16);
+ }
+ else if (type == GTK_TYPE_CSS_BACKGROUND_SIZE)
+ {
+ GtkCssBackgroundSize *vv = v->data[0].v_pointer;
+
+ if (vv == NULL)
+ return 0;
+
+ return
+ _gtk_css_number_hash (&vv->width) ^
+ _gtk_css_number_hash (&vv->height) ^
+ (((guint)vv->cover) << 9) ^
+ (((guint)vv->contain) << 9);
+ }
+ else if (type == GTK_TYPE_SHADOW ||
+ type == G_TYPE_PTR_ARRAY ||
+ type == CAIRO_GOBJECT_TYPE_PATTERN ||
+ type == GTK_TYPE_THEMING_ENGINE ||
+ type == GTK_TYPE_ANIMATION_DESCRIPTION||
+ type == GTK_TYPE_CSS_IMAGE)
+ {
+ /* These are refcounted, compare by pointer */
+ return GPOINTER_TO_INT (v->data[0].v_pointer);
+ }
+ else
+ {
+ g_error ("Can't handle CSS type %s\n", g_type_name (type));
+ }
+
+ return FALSE;
+}
+
static void
_gtk_css_computed_values_class_init (GtkCssComputedValuesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_css_computed_values_dispose;
+
+ gtk_css_values = g_hash_table_new ((GHashFunc)gtk_css_value_hash, (GEqualFunc)gtk_css_value_equal);
}
static void
_gtk_css_computed_values_init (GtkCssComputedValues *computed_values)
{
-
}
GtkCssComputedValues *
@@ -92,12 +430,9 @@ _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
parent = gtk_style_context_get_parent (context);
if (values->values == NULL)
- {
- values->values = g_array_new (FALSE, TRUE, sizeof (GValue));
- g_array_set_clear_func (values->values, (GDestroyNotify) g_value_unset);
- }
+ values->values = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_css_value_unref);
if (id <= values->values->len)
- g_array_set_size (values->values, id + 1);
+ g_ptr_array_set_size (values->values, id + 1);
/* http://www.w3.org/TR/css3-cascade/#cascade
* Then, for every element, the value for each property can be found
@@ -158,22 +493,27 @@ _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
specified = _gtk_css_style_property_get_initial_value (prop);
}
+
+ /* Clear existing value, can't reuse as it may be shared */
+ if (g_ptr_array_index (values->values, id) != NULL)
+ gtk_css_value_unref (g_ptr_array_index (values->values, id));
+
if (specified)
{
+ GValue value = G_VALUE_INIT;
_gtk_css_style_property_compute_value (prop,
- &g_array_index (values->values, GValue, id),
+ &value,
context,
specified);
+ g_ptr_array_index (values->values, id) = gtk_css_value_dup_value (&value);
+ g_value_unset (&value);
}
else
{
const GValue *parent_value;
- GValue *value = &g_array_index (values->values, GValue, id);
- /* Set NULL here and do the inheritance upon lookup? */
parent_value = _gtk_style_context_peek_property (parent,
_gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
- g_value_init (value, G_VALUE_TYPE (parent_value));
- g_value_copy (parent_value, value);
+ g_ptr_array_index (values->values, id) = gtk_css_value_ref_value ((GValue *)parent_value);
}
if (section)
@@ -193,23 +533,19 @@ _gtk_css_computed_values_set_value (GtkCssComputedValues *values,
const GValue *value,
GtkCssSection *section)
{
- GValue *set;
-
g_return_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values));
g_return_if_fail (value == NULL || G_IS_VALUE (value));
if (values->values == NULL)
- {
- values->values = g_array_new (FALSE, TRUE, sizeof (GValue));
- g_array_set_clear_func (values->values, (GDestroyNotify) g_value_unset);
- }
+ values->values = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_css_value_unref);
if (id <= values->values->len)
- g_array_set_size (values->values, id + 1);
+ g_ptr_array_set_size (values->values, id + 1);
+ /* Clear existing value, can't reuse as it may be shared */
+ if (g_ptr_array_index (values->values, id) != NULL)
+ gtk_css_value_unref (g_ptr_array_index (values->values, id));
- set = &g_array_index (values->values, GValue, id);
- g_value_init (set, G_VALUE_TYPE (value));
- g_value_copy (value, set);
+ g_ptr_array_index (values->values, id) = gtk_css_value_ref_value ((GValue *)value);
if (section)
{
@@ -226,19 +562,13 @@ const GValue *
_gtk_css_computed_values_get_value (GtkCssComputedValues *values,
guint id)
{
- const GValue *v;
-
g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL);
if (values->values == NULL ||
id >= values->values->len)
return NULL;
- v = &g_array_index (values->values, GValue, id);
- if (!G_IS_VALUE (v))
- return NULL;
-
- return v;
+ return gtk_css_value_peek (g_ptr_array_index (values->values, id));
}
const GValue *
diff --git a/gtk/gtkcsscomputedvaluesprivate.h b/gtk/gtkcsscomputedvaluesprivate.h
index 74a15ec..dff18ae 100644
--- a/gtk/gtkcsscomputedvaluesprivate.h
+++ b/gtk/gtkcsscomputedvaluesprivate.h
@@ -42,7 +42,7 @@ struct _GtkCssComputedValues
{
GObject parent;
- GArray *values;
+ GPtrArray *values;
GPtrArray *sections;
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]