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 <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 *

View File

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

View File

@@ -964,15 +964,19 @@
typedef struct GtkCssRuleset GtkCssRuleset;
typedef struct _GtkCssScanner GtkCssScanner;
typedef struct _PropertyValue PropertyValue;
typedef struct _WidgetPropertyValue WidgetPropertyValue;
typedef enum ParserScope ParserScope;
typedef enum ParserSymbol ParserSymbol;
struct GtkCssRuleset
{
GtkCssSelector *selector;
GHashTable *widget_style;
GHashTable *style;
WidgetPropertyValue *widget_style;
PropertyValue *style;
GtkBitmask *set_styles;
guint owns_style : 1;
guint owns_widget_style : 1;
};
struct _GtkCssScanner
@@ -1001,11 +1005,15 @@ enum {
LAST_SIGNAL
};
static gboolean gtk_keep_css_sections = FALSE;
static guint css_provider_signals[LAST_SIGNAL] = { 0 };
static void gtk_css_provider_finalize (GObject *object);
static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *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
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);
if (g_getenv ("GTK_CSS_DEBUG"))
gtk_keep_css_sections = TRUE;
/**
* GtkCssProvider::parsing-error:
* @provider: the provider that had a parsing error
@@ -1114,16 +1125,17 @@ gtk_css_provider_class_init (GtkCssProviderClass *klass)
static void
gtk_css_ruleset_init_copy (GtkCssRuleset *new,
const GtkCssRuleset *ruleset,
GtkCssRuleset *ruleset,
GtkCssSelector *selector)
{
memcpy (new, ruleset, sizeof (GtkCssRuleset));
new->selector = selector;
if (new->widget_style)
g_hash_table_ref (new->widget_style);
if (new->style)
g_hash_table_ref (new->style);
/* First copy takes over ownership */
if (ruleset->owns_style)
ruleset->owns_style = FALSE;
if (ruleset->owns_widget_style)
ruleset->owns_widget_style = FALSE;
if (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
gtk_css_ruleset_clear (GtkCssRuleset *ruleset)
{
if (ruleset->style)
g_hash_table_unref (ruleset->style);
if (ruleset->owns_style)
property_value_list_free (ruleset->style);
if (ruleset->set_styles)
_gtk_bitmask_free (ruleset->set_styles);
if (ruleset->widget_style)
g_hash_table_unref (ruleset->widget_style);
if (ruleset->owns_widget_style)
widget_property_value_list_free (ruleset->widget_style);
if (ruleset->selector)
_gtk_css_selector_free (ruleset->selector);
memset (ruleset, 0, sizeof (GtkCssRuleset));
}
typedef struct _PropertyValue PropertyValue;
struct _PropertyValue {
GtkCssSection *section;
GtkStyleProperty *property;
PropertyValue *next;
GValue value;
};
typedef struct _PropertyValueWithSection PropertyValueWithSection;
struct _PropertyValueWithSection {
PropertyValue base;
GtkCssSection *section;
};
static PropertyValue *
property_value_new (GtkCssSection *section)
property_value_new (GtkStyleProperty *property, GtkCssSection *section)
{
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;
}
static GtkCssSection *
property_value_get_section (PropertyValue *value)
{
if (gtk_keep_css_sections)
return ((PropertyValueWithSection *)value)->section;
return NULL;
}
static void
property_value_free (PropertyValue *value)
{
GtkCssSection *section;
if (G_IS_VALUE (&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);
}
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
gtk_css_ruleset_add_style (GtkCssRuleset *ruleset,
char *name,
PropertyValue *value)
WidgetPropertyValue *value)
{
if (ruleset->widget_style == NULL)
ruleset->widget_style = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) property_value_free);
g_hash_table_insert (ruleset->widget_style, name, value);
value->next = widget_property_value_list_remove_name (ruleset->widget_style, name);
ruleset->widget_style = value;
ruleset->owns_widget_style = TRUE;
}
static void
@@ -1191,14 +1344,8 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
GtkStyleProperty *prop,
PropertyValue *value)
{
if (ruleset->style == NULL)
{
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 (ruleset->set_styles == NULL)
ruleset->set_styles = _gtk_bitmask_new ();
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);
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_copy (sub, &val->value);
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_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)),
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
{
@@ -1426,8 +1577,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
for (i = 0; i < priv->rulesets->len; i++)
{
GtkCssRuleset *ruleset;
GHashTableIter iter;
gpointer key, val;
PropertyValue *value;
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))
continue;
g_hash_table_iter_init (&iter, ruleset->style);
while (g_hash_table_iter_next (&iter, &key, &val))
{
GtkCssStyleProperty *prop = key;
PropertyValue *value = val;
_gtk_style_properties_set_property_by_property (props,
prop,
_gtk_css_selector_get_state_flags (ruleset->selector),
&value->value);
}
for (value = ruleset->style; value != NULL; value = value->next)
_gtk_style_properties_set_property_by_property (props,
GTK_CSS_STYLE_PROPERTY (value->property),
_gtk_css_selector_get_state_flags (ruleset->selector),
&value->value);
}
return props;
@@ -1463,7 +1606,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
{
GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
GtkCssProviderPrivate *priv = css_provider->priv;
PropertyValue *val;
WidgetPropertyValue *val;
gboolean found = FALSE;
gchar *prop_name;
gint i;
@@ -1484,27 +1627,32 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
if (!gtk_css_ruleset_matches (ruleset, path, state))
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)
{
GtkCssScanner *scanner;
section = widget_property_value_get_section (val);
scanner = gtk_css_scanner_new (css_provider,
NULL,
section,
section ? gtk_css_section_get_file (section) : NULL,
g_value_get_string (&val->value));
scanner = gtk_css_scanner_new (css_provider,
NULL,
val->section,
gtk_css_section_get_file (val->section),
g_value_get_string (&val->value));
found = _gtk_css_style_parse_value (value,
scanner->parser,
NULL);
found = _gtk_css_style_parse_value (value,
scanner->parser,
NULL);
gtk_css_scanner_destroy (scanner);
gtk_css_scanner_destroy (scanner);
break;
}
}
if (found)
break;
}
if (found)
break;
}
g_free (prop_name);
@@ -1544,8 +1692,7 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
for (i = priv->rulesets->len - 1; i >= 0; i--)
{
GtkCssRuleset *ruleset;
GHashTableIter iter;
gpointer key, val;
PropertyValue *value;
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))
continue;
g_hash_table_iter_init (&iter, ruleset->style);
while (g_hash_table_iter_next (&iter, &key, &val))
for (value = ruleset->style; value != NULL; value = value->next)
{
GtkCssStyleProperty *prop = key;
PropertyValue *value = val;
GtkCssStyleProperty *prop = GTK_CSS_STYLE_PROPERTY (value->property);
guint id = _gtk_css_style_property_get_id (prop);
if (!_gtk_css_lookup_is_missing (lookup, id))
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);
val = property_value_new (scanner->section);
val = property_value_new (property, scanner->section);
if (_gtk_style_property_parse_value (property,
&val->value,
@@ -2431,9 +2577,9 @@ parse_declaration (GtkCssScanner *scanner,
value_str = _gtk_css_parser_read_value (scanner->parser);
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_take_string (&val->value, value_str);
@@ -2972,15 +3118,27 @@ gtk_css_provider_get_named (const gchar *name,
static int
compare_properties (gconstpointer a, gconstpointer b)
{
return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *) a),
_gtk_style_property_get_name ((GtkStyleProperty *) b));
const PropertyValue *aa = a;
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
gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
GString *str)
{
GList *keys, *walk;
GList *values, *walk;
PropertyValue *value;
WidgetPropertyValue *widget_value;
_gtk_css_selector_print (ruleset->selector, str);
@@ -2988,14 +3146,18 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
if (ruleset->style)
{
keys = g_hash_table_get_keys (ruleset->style);
/* so the output is identical for identical selector styles */
keys = g_list_sort (keys, compare_properties);
values = NULL;
for (value = ruleset->style; value != NULL; value = value->next)
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;
const PropertyValue *value = g_hash_table_lookup (ruleset->style, prop);
GtkCssStyleProperty *prop;
value = walk->data;
prop = GTK_CSS_STYLE_PROPERTY (value->property);
g_string_append (str, " ");
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_list_free (keys);
g_list_free (values);
}
if (ruleset->widget_style)
{
keys = g_hash_table_get_keys (ruleset->widget_style);
/* so the output is identical for identical selector styles */
keys = g_list_sort (keys, (GCompareFunc) strcmp);
values = NULL;
for (widget_value = ruleset->widget_style; widget_value != NULL; widget_value = widget_value->next)
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;
const PropertyValue *value = g_hash_table_lookup (ruleset->widget_style, (gpointer) name);
widget_value = walk->data;
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_value_get_string (&value->value));
g_string_append (str, g_value_get_string (&widget_value->value));
g_string_append (str, ";\n");
}
g_list_free (keys);
g_list_free (values);
}
g_string_append (str, "}\n");

View File

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

View File

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