Compare commits

...

4 Commits

Author SHA1 Message Date
Alexander Larsson
281aa2a6a7 Don't keep the GtkCSSSections around unless GTK_CSS_DEBUG env var set
This was using ~110Kb of memory showing gtk3-demo, which is to much
for a pure debugging feature.
2012-02-15 20:30:48 +01:00
Alexander Larsson
94876a23ec Don't use hashtables for storing css rule properties
This saves a lot of memory
2012-02-15 17:06:30 +01:00
Alexander Larsson
b2e36bb85b Internalize computed css values to save memory 2012-02-15 17:06:19 +01:00
Alexander Larsson
cd189e515e Add _gtk_css_number_hash 2012-02-15 13:35:34 +01:00
5 changed files with 630 additions and 126 deletions

View File

@@ -20,14 +20,88 @@
#include "config.h" #include "config.h"
#include <string.h>
#include <cairo-gobject.h>
#include "gtkcsscomputedvaluesprivate.h" #include "gtkcsscomputedvaluesprivate.h"
#include "gtkcssstylepropertyprivate.h" #include "gtkcssstylepropertyprivate.h"
#include "gtkcsstypesprivate.h" #include "gtkcsstypesprivate.h"
#include "gtkprivatetypebuiltins.h" #include "gtkprivatetypebuiltins.h"
#include "gtkshadowprivate.h"
#include "gtkanimationdescription.h"
#include "gtkcssimageprivate.h"
G_DEFINE_TYPE (GtkCssComputedValues, _gtk_css_computed_values, G_TYPE_OBJECT) 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 static void
gtk_css_computed_values_dispose (GObject *object) gtk_css_computed_values_dispose (GObject *object)
{ {
@@ -35,7 +109,7 @@ gtk_css_computed_values_dispose (GObject *object)
if (values->values) if (values->values)
{ {
g_array_free (values->values, TRUE); g_ptr_array_unref (values->values);
values->values = NULL; values->values = NULL;
} }
if (values->sections) 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); 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 static void
_gtk_css_computed_values_class_init (GtkCssComputedValuesClass *klass) _gtk_css_computed_values_class_init (GtkCssComputedValuesClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_css_computed_values_dispose; 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 static void
_gtk_css_computed_values_init (GtkCssComputedValues *computed_values) _gtk_css_computed_values_init (GtkCssComputedValues *computed_values)
{ {
} }
GtkCssComputedValues * GtkCssComputedValues *
@@ -92,12 +430,9 @@ _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
parent = gtk_style_context_get_parent (context); parent = gtk_style_context_get_parent (context);
if (values->values == NULL) if (values->values == NULL)
{ values->values = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_css_value_unref);
values->values = g_array_new (FALSE, TRUE, sizeof (GValue));
g_array_set_clear_func (values->values, (GDestroyNotify) g_value_unset);
}
if (id <= values->values->len) 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 /* http://www.w3.org/TR/css3-cascade/#cascade
* Then, for every element, the value for each property can be found * 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); 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) if (specified)
{ {
GValue value = G_VALUE_INIT;
_gtk_css_style_property_compute_value (prop, _gtk_css_style_property_compute_value (prop,
&g_array_index (values->values, GValue, id), &value,
context, context,
specified); specified);
g_ptr_array_index (values->values, id) = gtk_css_value_dup_value (&value);
g_value_unset (&value);
} }
else else
{ {
const GValue *parent_value; 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, parent_value = _gtk_style_context_peek_property (parent,
_gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop))); _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
g_value_init (value, G_VALUE_TYPE (parent_value)); g_ptr_array_index (values->values, id) = gtk_css_value_ref_value ((GValue *)parent_value);
g_value_copy (parent_value, value);
} }
if (section) if (section)
@@ -193,23 +533,19 @@ _gtk_css_computed_values_set_value (GtkCssComputedValues *values,
const GValue *value, const GValue *value,
GtkCssSection *section) GtkCssSection *section)
{ {
GValue *set;
g_return_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values)); g_return_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values));
g_return_if_fail (value == NULL || G_IS_VALUE (value)); g_return_if_fail (value == NULL || G_IS_VALUE (value));
if (values->values == NULL) if (values->values == NULL)
{ values->values = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_css_value_unref);
values->values = g_array_new (FALSE, TRUE, sizeof (GValue));
g_array_set_clear_func (values->values, (GDestroyNotify) g_value_unset);
}
if (id <= values->values->len) 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_ptr_array_index (values->values, id) = gtk_css_value_ref_value ((GValue *)value);
g_value_init (set, G_VALUE_TYPE (value));
g_value_copy (value, set);
if (section) if (section)
{ {
@@ -226,19 +562,13 @@ const GValue *
_gtk_css_computed_values_get_value (GtkCssComputedValues *values, _gtk_css_computed_values_get_value (GtkCssComputedValues *values,
guint id) guint id)
{ {
const GValue *v;
g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL); g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL);
if (values->values == NULL || if (values->values == NULL ||
id >= values->values->len) id >= values->values->len)
return NULL; return NULL;
v = &g_array_index (values->values, GValue, id); return gtk_css_value_peek (g_ptr_array_index (values->values, id));
if (!G_IS_VALUE (v))
return NULL;
return v;
} }
const GValue * const GValue *

View File

@@ -42,7 +42,7 @@ struct _GtkCssComputedValues
{ {
GObject parent; GObject parent;
GArray *values; GPtrArray *values;
GPtrArray *sections; GPtrArray *sections;
}; };

View File

@@ -964,15 +964,19 @@
typedef struct GtkCssRuleset GtkCssRuleset; typedef struct GtkCssRuleset GtkCssRuleset;
typedef struct _GtkCssScanner GtkCssScanner; typedef struct _GtkCssScanner GtkCssScanner;
typedef struct _PropertyValue PropertyValue;
typedef struct _WidgetPropertyValue WidgetPropertyValue;
typedef enum ParserScope ParserScope; typedef enum ParserScope ParserScope;
typedef enum ParserSymbol ParserSymbol; typedef enum ParserSymbol ParserSymbol;
struct GtkCssRuleset struct GtkCssRuleset
{ {
GtkCssSelector *selector; GtkCssSelector *selector;
GHashTable *widget_style; WidgetPropertyValue *widget_style;
GHashTable *style; PropertyValue *style;
GtkBitmask *set_styles; GtkBitmask *set_styles;
guint owns_style : 1;
guint owns_widget_style : 1;
}; };
struct _GtkCssScanner struct _GtkCssScanner
@@ -1001,11 +1005,15 @@ enum {
LAST_SIGNAL LAST_SIGNAL
}; };
static gboolean gtk_keep_css_sections = FALSE;
static guint css_provider_signals[LAST_SIGNAL] = { 0 }; static guint css_provider_signals[LAST_SIGNAL] = { 0 };
static void gtk_css_provider_finalize (GObject *object); static void gtk_css_provider_finalize (GObject *object);
static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface); static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface);
static void gtk_css_style_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface); static void gtk_css_style_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface);
static void property_value_list_free (PropertyValue *head);
static void widget_property_value_list_free (WidgetPropertyValue *head);
static gboolean static gboolean
gtk_css_provider_load_internal (GtkCssProvider *css_provider, gtk_css_provider_load_internal (GtkCssProvider *css_provider,
@@ -1078,6 +1086,9 @@ gtk_css_provider_class_init (GtkCssProviderClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
if (g_getenv ("GTK_CSS_DEBUG"))
gtk_keep_css_sections = TRUE;
/** /**
* GtkCssProvider::parsing-error: * GtkCssProvider::parsing-error:
* @provider: the provider that had a parsing error * @provider: the provider that had a parsing error
@@ -1114,16 +1125,17 @@ gtk_css_provider_class_init (GtkCssProviderClass *klass)
static void static void
gtk_css_ruleset_init_copy (GtkCssRuleset *new, gtk_css_ruleset_init_copy (GtkCssRuleset *new,
const GtkCssRuleset *ruleset, GtkCssRuleset *ruleset,
GtkCssSelector *selector) GtkCssSelector *selector)
{ {
memcpy (new, ruleset, sizeof (GtkCssRuleset)); memcpy (new, ruleset, sizeof (GtkCssRuleset));
new->selector = selector; new->selector = selector;
if (new->widget_style) /* First copy takes over ownership */
g_hash_table_ref (new->widget_style); if (ruleset->owns_style)
if (new->style) ruleset->owns_style = FALSE;
g_hash_table_ref (new->style); if (ruleset->owns_widget_style)
ruleset->owns_widget_style = FALSE;
if (new->set_styles) if (new->set_styles)
new->set_styles = _gtk_bitmask_copy (new->set_styles); new->set_styles = _gtk_bitmask_copy (new->set_styles);
} }
@@ -1131,59 +1143,200 @@ gtk_css_ruleset_init_copy (GtkCssRuleset *new,
static void static void
gtk_css_ruleset_clear (GtkCssRuleset *ruleset) gtk_css_ruleset_clear (GtkCssRuleset *ruleset)
{ {
if (ruleset->style) if (ruleset->owns_style)
g_hash_table_unref (ruleset->style); property_value_list_free (ruleset->style);
if (ruleset->set_styles) if (ruleset->set_styles)
_gtk_bitmask_free (ruleset->set_styles); _gtk_bitmask_free (ruleset->set_styles);
if (ruleset->widget_style) if (ruleset->owns_widget_style)
g_hash_table_unref (ruleset->widget_style); widget_property_value_list_free (ruleset->widget_style);
if (ruleset->selector) if (ruleset->selector)
_gtk_css_selector_free (ruleset->selector); _gtk_css_selector_free (ruleset->selector);
memset (ruleset, 0, sizeof (GtkCssRuleset)); memset (ruleset, 0, sizeof (GtkCssRuleset));
} }
typedef struct _PropertyValue PropertyValue;
struct _PropertyValue { struct _PropertyValue {
GtkCssSection *section; GtkStyleProperty *property;
PropertyValue *next;
GValue value; GValue value;
}; };
typedef struct _PropertyValueWithSection PropertyValueWithSection;
struct _PropertyValueWithSection {
PropertyValue base;
GtkCssSection *section;
};
static PropertyValue * static PropertyValue *
property_value_new (GtkCssSection *section) property_value_new (GtkStyleProperty *property, GtkCssSection *section)
{ {
PropertyValue *value; PropertyValue *value;
value = g_slice_new0 (PropertyValue); if (gtk_keep_css_sections)
value = (PropertyValue *)g_slice_new0 (PropertyValueWithSection);
else
value = g_slice_new0 (PropertyValue);
value->section = gtk_css_section_ref (section); value->property = property;
if (gtk_keep_css_sections)
((PropertyValueWithSection *)value)->section = gtk_css_section_ref (section);
return value; return value;
} }
static GtkCssSection *
property_value_get_section (PropertyValue *value)
{
if (gtk_keep_css_sections)
return ((PropertyValueWithSection *)value)->section;
return NULL;
}
static void static void
property_value_free (PropertyValue *value) property_value_free (PropertyValue *value)
{ {
GtkCssSection *section;
if (G_IS_VALUE (&value->value)) if (G_IS_VALUE (&value->value))
g_value_unset (&value->value); g_value_unset (&value->value);
gtk_css_section_unref (value->section); section = property_value_get_section (value);
if (section != NULL)
gtk_css_section_unref (section);
g_slice_free (PropertyValue, value); g_slice_free (PropertyValue, value);
} }
static void
property_value_list_free (PropertyValue *head)
{
PropertyValue *l, *next;
for (l = head; l != NULL; l = next)
{
next = l->next;
property_value_free (l);
}
}
static PropertyValue *
property_value_list_remove_property (PropertyValue *head, GtkStyleProperty *property)
{
PropertyValue *l, **last;
last = &head;
for (l = head; l != NULL; l = l->next)
{
if (l->property == property)
{
*last = l->next;
property_value_free (l);
break;
}
last = &l->next;
}
return head;
}
struct _WidgetPropertyValue {
char *name;
WidgetPropertyValue *next;
GValue value;
};
typedef struct _WidgetPropertyValueWithSection WidgetPropertyValueWithSection;
struct _WidgetPropertyValueWithSection {
WidgetPropertyValue base;
GtkCssSection *section;
};
static WidgetPropertyValue *
widget_property_value_new (char *name, GtkCssSection *section)
{
WidgetPropertyValue *value;
if (gtk_keep_css_sections)
value = (WidgetPropertyValue *)g_slice_new0 (WidgetPropertyValueWithSection);
else
value = g_slice_new0 (WidgetPropertyValue);
value->name = name;
if (gtk_keep_css_sections)
((WidgetPropertyValueWithSection *)value)->section = gtk_css_section_ref (section);
return value;
}
static GtkCssSection *
widget_property_value_get_section (WidgetPropertyValue *value)
{
if (gtk_keep_css_sections)
return ((WidgetPropertyValueWithSection *)value)->section;
return NULL;
}
static void
widget_property_value_free (WidgetPropertyValue *value)
{
GtkCssSection *section;
if (G_IS_VALUE (&value->value))
g_value_unset (&value->value);
g_free (value->name);
section = widget_property_value_get_section (value);
if (section != NULL)
gtk_css_section_unref (section);
g_slice_free (WidgetPropertyValue, value);
}
static void
widget_property_value_list_free (WidgetPropertyValue *head)
{
WidgetPropertyValue *l, *next;
for (l = head; l != NULL; l = next)
{
next = l->next;
widget_property_value_free (l);
}
}
static WidgetPropertyValue *
widget_property_value_list_remove_name (WidgetPropertyValue *head, const char *name)
{
WidgetPropertyValue *l, **last;
last = &head;
for (l = head; l != NULL; l = l->next)
{
if (strcmp (l->name, name) == 0)
{
*last = l->next;
widget_property_value_free (l);
break;
}
last = &l->next;
}
return head;
}
static void static void
gtk_css_ruleset_add_style (GtkCssRuleset *ruleset, gtk_css_ruleset_add_style (GtkCssRuleset *ruleset,
char *name, char *name,
PropertyValue *value) WidgetPropertyValue *value)
{ {
if (ruleset->widget_style == NULL) value->next = widget_property_value_list_remove_name (ruleset->widget_style, name);
ruleset->widget_style = g_hash_table_new_full (g_str_hash, ruleset->widget_style = value;
g_str_equal, ruleset->owns_widget_style = TRUE;
(GDestroyNotify) g_free,
(GDestroyNotify) property_value_free);
g_hash_table_insert (ruleset->widget_style, name, value);
} }
static void static void
@@ -1191,14 +1344,8 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
GtkStyleProperty *prop, GtkStyleProperty *prop,
PropertyValue *value) PropertyValue *value)
{ {
if (ruleset->style == NULL) if (ruleset->set_styles == NULL)
{ ruleset->set_styles = _gtk_bitmask_new ();
ruleset->style = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify) property_value_free);
ruleset->set_styles = _gtk_bitmask_new ();
}
if (GTK_IS_CSS_SHORTHAND_PROPERTY (prop)) if (GTK_IS_CSS_SHORTHAND_PROPERTY (prop))
{ {
@@ -1212,7 +1359,8 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
const GValue *sub = &g_array_index (array, GValue, i); const GValue *sub = &g_array_index (array, GValue, i);
PropertyValue *val; PropertyValue *val;
val = property_value_new (value->section); val = property_value_new (GTK_STYLE_PROPERTY (child),
property_value_get_section (value));
g_value_init (&val->value, G_VALUE_TYPE (sub)); g_value_init (&val->value, G_VALUE_TYPE (sub));
g_value_copy (sub, &val->value); g_value_copy (sub, &val->value);
gtk_css_ruleset_add (ruleset, GTK_STYLE_PROPERTY (child), val); gtk_css_ruleset_add (ruleset, GTK_STYLE_PROPERTY (child), val);
@@ -1227,7 +1375,10 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
_gtk_bitmask_set (ruleset->set_styles, _gtk_bitmask_set (ruleset->set_styles,
_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)), _gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)),
TRUE); TRUE);
g_hash_table_insert (ruleset->style, prop, value);
value->next = property_value_list_remove_property (ruleset->style, prop);
ruleset->style = value;
ruleset->owns_style = TRUE;
} }
else else
{ {
@@ -1426,8 +1577,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
for (i = 0; i < priv->rulesets->len; i++) for (i = 0; i < priv->rulesets->len; i++)
{ {
GtkCssRuleset *ruleset; GtkCssRuleset *ruleset;
GHashTableIter iter; PropertyValue *value;
gpointer key, val;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i); ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
@@ -1437,18 +1587,11 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
if (!gtk_css_ruleset_matches (ruleset, path, 0)) if (!gtk_css_ruleset_matches (ruleset, path, 0))
continue; continue;
g_hash_table_iter_init (&iter, ruleset->style); for (value = ruleset->style; value != NULL; value = value->next)
_gtk_style_properties_set_property_by_property (props,
while (g_hash_table_iter_next (&iter, &key, &val)) GTK_CSS_STYLE_PROPERTY (value->property),
{ _gtk_css_selector_get_state_flags (ruleset->selector),
GtkCssStyleProperty *prop = key; &value->value);
PropertyValue *value = val;
_gtk_style_properties_set_property_by_property (props,
prop,
_gtk_css_selector_get_state_flags (ruleset->selector),
&value->value);
}
} }
return props; return props;
@@ -1463,7 +1606,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
{ {
GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider); GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
GtkCssProviderPrivate *priv = css_provider->priv; GtkCssProviderPrivate *priv = css_provider->priv;
PropertyValue *val; WidgetPropertyValue *val;
gboolean found = FALSE; gboolean found = FALSE;
gchar *prop_name; gchar *prop_name;
gint i; gint i;
@@ -1484,27 +1627,32 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
if (!gtk_css_ruleset_matches (ruleset, path, state)) if (!gtk_css_ruleset_matches (ruleset, path, state))
continue; continue;
val = g_hash_table_lookup (ruleset->widget_style, prop_name); for (val = ruleset->widget_style; val != NULL; val = val->next)
{
if (strcmp (val->name, prop_name) == 0)
{
GtkCssScanner *scanner;
GtkCssSection *section;
if (val) section = widget_property_value_get_section (val);
{ scanner = gtk_css_scanner_new (css_provider,
GtkCssScanner *scanner; NULL,
section,
section ? gtk_css_section_get_file (section) : NULL,
g_value_get_string (&val->value));
scanner = gtk_css_scanner_new (css_provider, found = _gtk_css_style_parse_value (value,
NULL, scanner->parser,
val->section, NULL);
gtk_css_section_get_file (val->section),
g_value_get_string (&val->value));
found = _gtk_css_style_parse_value (value, gtk_css_scanner_destroy (scanner);
scanner->parser,
NULL);
gtk_css_scanner_destroy (scanner); break;
}
}
if (found) if (found)
break; break;
}
} }
g_free (prop_name); g_free (prop_name);
@@ -1544,8 +1692,7 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
for (i = priv->rulesets->len - 1; i >= 0; i--) for (i = priv->rulesets->len - 1; i >= 0; i--)
{ {
GtkCssRuleset *ruleset; GtkCssRuleset *ruleset;
GHashTableIter iter; PropertyValue *value;
gpointer key, val;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i); ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
@@ -1559,18 +1706,17 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
if (!gtk_css_ruleset_matches (ruleset, path, state)) if (!gtk_css_ruleset_matches (ruleset, path, state))
continue; continue;
g_hash_table_iter_init (&iter, ruleset->style); for (value = ruleset->style; value != NULL; value = value->next)
while (g_hash_table_iter_next (&iter, &key, &val))
{ {
GtkCssStyleProperty *prop = key; GtkCssStyleProperty *prop = GTK_CSS_STYLE_PROPERTY (value->property);
PropertyValue *value = val;
guint id = _gtk_css_style_property_get_id (prop); guint id = _gtk_css_style_property_get_id (prop);
if (!_gtk_css_lookup_is_missing (lookup, id)) if (!_gtk_css_lookup_is_missing (lookup, id))
continue; continue;
_gtk_css_lookup_set (lookup, id, value->section, &value->value); _gtk_css_lookup_set (lookup, id,
property_value_get_section (value),
&value->value);
} }
} }
} }
@@ -2385,7 +2531,7 @@ parse_declaration (GtkCssScanner *scanner,
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_VALUE); gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_VALUE);
val = property_value_new (scanner->section); val = property_value_new (property, scanner->section);
if (_gtk_style_property_parse_value (property, if (_gtk_style_property_parse_value (property,
&val->value, &val->value,
@@ -2431,9 +2577,9 @@ parse_declaration (GtkCssScanner *scanner,
value_str = _gtk_css_parser_read_value (scanner->parser); value_str = _gtk_css_parser_read_value (scanner->parser);
if (value_str) if (value_str)
{ {
PropertyValue *val; WidgetPropertyValue *val;
val = property_value_new (scanner->section); val = widget_property_value_new (name, scanner->section);
g_value_init (&val->value, G_TYPE_STRING); g_value_init (&val->value, G_TYPE_STRING);
g_value_take_string (&val->value, value_str); g_value_take_string (&val->value, value_str);
@@ -2972,15 +3118,27 @@ gtk_css_provider_get_named (const gchar *name,
static int static int
compare_properties (gconstpointer a, gconstpointer b) compare_properties (gconstpointer a, gconstpointer b)
{ {
return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *) a), const PropertyValue *aa = a;
_gtk_style_property_get_name ((GtkStyleProperty *) b)); const PropertyValue *bb = b;
return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *)aa->property),
_gtk_style_property_get_name ((GtkStyleProperty *)bb->property));
}
static int
compare_names (gconstpointer a, gconstpointer b)
{
const WidgetPropertyValue *aa = a;
const WidgetPropertyValue *bb = b;
return strcmp (aa->name, bb->name);
} }
static void static void
gtk_css_ruleset_print (const GtkCssRuleset *ruleset, gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
GString *str) GString *str)
{ {
GList *keys, *walk; GList *values, *walk;
PropertyValue *value;
WidgetPropertyValue *widget_value;
_gtk_css_selector_print (ruleset->selector, str); _gtk_css_selector_print (ruleset->selector, str);
@@ -2988,14 +3146,18 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
if (ruleset->style) if (ruleset->style)
{ {
keys = g_hash_table_get_keys (ruleset->style); values = NULL;
/* so the output is identical for identical selector styles */ for (value = ruleset->style; value != NULL; value = value->next)
keys = g_list_sort (keys, compare_properties); values = g_list_prepend (values, value);
for (walk = keys; walk; walk = walk->next) /* so the output is identical for identical selector styles */
values = g_list_sort (values, compare_properties);
for (walk = values; walk; walk = walk->next)
{ {
GtkCssStyleProperty *prop = walk->data; GtkCssStyleProperty *prop;
const PropertyValue *value = g_hash_table_lookup (ruleset->style, prop); value = walk->data;
prop = GTK_CSS_STYLE_PROPERTY (value->property);
g_string_append (str, " "); g_string_append (str, " ");
g_string_append (str, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop))); g_string_append (str, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
@@ -3004,28 +3166,30 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
g_string_append (str, ";\n"); g_string_append (str, ";\n");
} }
g_list_free (keys); g_list_free (values);
} }
if (ruleset->widget_style) if (ruleset->widget_style)
{ {
keys = g_hash_table_get_keys (ruleset->widget_style); values = NULL;
/* so the output is identical for identical selector styles */ for (widget_value = ruleset->widget_style; widget_value != NULL; widget_value = widget_value->next)
keys = g_list_sort (keys, (GCompareFunc) strcmp); values = g_list_prepend (values, widget_value);
for (walk = keys; walk; walk = walk->next) /* so the output is identical for identical selector styles */
values = g_list_sort (values, compare_names);
for (walk = values; walk; walk = walk->next)
{ {
const char *name = walk->data; widget_value = walk->data;
const PropertyValue *value = g_hash_table_lookup (ruleset->widget_style, (gpointer) name);
g_string_append (str, " "); g_string_append (str, " ");
g_string_append (str, name); g_string_append (str, widget_value->name);
g_string_append (str, ": "); g_string_append (str, ": ");
g_string_append (str, g_value_get_string (&value->value)); g_string_append (str, g_value_get_string (&widget_value->value));
g_string_append (str, ";\n"); g_string_append (str, ";\n");
} }
g_list_free (keys); g_list_free (values);
} }
g_string_append (str, "}\n"); g_string_append (str, "}\n");

View File

@@ -54,6 +54,15 @@ _gtk_css_number_equal (const GtkCssNumber *one,
one->value == two->value; one->value == two->value;
} }
guint
_gtk_css_number_hash (const GtkCssNumber *number)
{
guint hash;
hash = (guint)number->value;
hash ^= (guint)number->unit;
}
double double
_gtk_css_number_get (const GtkCssNumber *number, _gtk_css_number_get (const GtkCssNumber *number,
double one_hundred_percent) double one_hundred_percent)

View File

@@ -142,6 +142,7 @@ void _gtk_css_number_init (GtkCssNumber
GtkCssUnit unit); GtkCssUnit unit);
gboolean _gtk_css_number_equal (const GtkCssNumber *one, gboolean _gtk_css_number_equal (const GtkCssNumber *one,
const GtkCssNumber *two); const GtkCssNumber *two);
guint _gtk_css_number_hash (const GtkCssNumber *number);
double _gtk_css_number_get (const GtkCssNumber *number, double _gtk_css_number_get (const GtkCssNumber *number,
double one_hundred_percent); double one_hundred_percent);
void _gtk_css_number_compute (GtkCssNumber *dest, void _gtk_css_number_compute (GtkCssNumber *dest,