cssprovider: Refactor handling of rulesets

Keep rulesets as an on-stack/heap structure instead of allocating all
instances separately.
Also, pass a ruleset to the ruleset parser, so we can make the ruleset
parser do lots of fancy things that might be useful for performance.
This commit is contained in:
Benjamin Otte 2011-05-18 04:20:05 +02:00
parent 151294576d
commit 0318ab2ce1

View File

@ -764,7 +764,7 @@ struct _GtkCssProviderPrivate
GHashTable *symbolic_colors; GHashTable *symbolic_colors;
GPtrArray *rulesets; GArray *rulesets;
}; };
enum ParserScope { enum ParserScope {
@ -908,19 +908,20 @@ gtk_css_provider_take_error_full (GtkCssProvider *provider,
g_error_free (error); g_error_free (error);
} }
static GtkCssRuleset * static void
gtk_css_ruleset_new (GtkCssSelector *selector) gtk_css_ruleset_init_copy (GtkCssRuleset *new,
const GtkCssRuleset *ruleset,
GtkCssSelector *selector)
{ {
GtkCssRuleset *ruleset; memcpy (new, ruleset, sizeof (GtkCssRuleset));
ruleset = g_slice_new0 (GtkCssRuleset); new->selector = selector;
ruleset->selector = selector; if (new->style)
g_hash_table_ref (new->style);
return ruleset;
} }
static void static void
gtk_css_ruleset_free (GtkCssRuleset *ruleset) gtk_css_ruleset_clear (GtkCssRuleset *ruleset)
{ {
if (ruleset->style) if (ruleset->style)
g_hash_table_unref (ruleset->style); g_hash_table_unref (ruleset->style);
@ -928,28 +929,7 @@ gtk_css_ruleset_free (GtkCssRuleset *ruleset)
if (ruleset->selector) if (ruleset->selector)
_gtk_css_selector_free (ruleset->selector); _gtk_css_selector_free (ruleset->selector);
g_slice_free (GtkCssRuleset, ruleset); memset (ruleset, 0, sizeof (GtkCssRuleset));
}
static void
gtk_css_ruleset_set_style (GtkCssRuleset *ruleset,
GHashTable *style)
{
if (ruleset->style)
g_hash_table_unref (ruleset->style);
if (style)
ruleset->style = g_hash_table_ref (style);
else
ruleset->style = NULL;
}
static gboolean
gtk_css_ruleset_matches (GtkCssRuleset *ruleset,
GtkWidgetPath *path,
guint length)
{
return _gtk_css_selector_matches (ruleset->selector, path, length);
} }
static void static void
@ -961,6 +941,28 @@ property_value_free (GValue *value)
g_slice_free (GValue, value); g_slice_free (GValue, value);
} }
static void
gtk_css_ruleset_add_style (GtkCssRuleset *ruleset,
char *name,
GValue *value)
{
if (ruleset->style == NULL)
ruleset->style = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) property_value_free);
g_hash_table_insert (ruleset->style, name, value);
}
static gboolean
gtk_css_ruleset_matches (GtkCssRuleset *ruleset,
GtkWidgetPath *path,
guint length)
{
return _gtk_css_selector_matches (ruleset->selector, path, length);
}
static void static void
gtk_css_scanner_reset (GtkCssScanner *scanner) gtk_css_scanner_reset (GtkCssScanner *scanner)
{ {
@ -1079,7 +1081,7 @@ gtk_css_provider_init (GtkCssProvider *css_provider)
GTK_TYPE_CSS_PROVIDER, GTK_TYPE_CSS_PROVIDER,
GtkCssProviderPrivate); GtkCssProviderPrivate);
priv->rulesets = g_ptr_array_new_with_free_func ((GDestroyNotify) gtk_css_ruleset_free); priv->rulesets = g_array_new (FALSE, FALSE, sizeof (GtkCssRuleset));
priv->symbolic_colors = g_hash_table_new_full (g_str_hash, g_str_equal, priv->symbolic_colors = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free, (GDestroyNotify) g_free,
@ -1133,7 +1135,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
GHashTableIter iter; GHashTableIter iter;
gpointer key, value; gpointer key, value;
ruleset = g_ptr_array_index (priv->rulesets, i); ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
if (l < length && _gtk_css_selector_get_state_flags (ruleset->selector)) if (l < length && _gtk_css_selector_get_state_flags (ruleset->selector))
continue; continue;
@ -1187,7 +1189,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
GtkCssRuleset *ruleset; GtkCssRuleset *ruleset;
GtkStateFlags selector_state; GtkStateFlags selector_state;
ruleset = g_ptr_array_index (priv->rulesets, i); ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
if (!gtk_css_ruleset_matches (ruleset, path, gtk_widget_path_length (path))) if (!gtk_css_ruleset_matches (ruleset, path, gtk_widget_path_length (path)))
continue; continue;
@ -1240,7 +1242,7 @@ gtk_css_provider_finalize (GObject *object)
css_provider = GTK_CSS_PROVIDER (object); css_provider = GTK_CSS_PROVIDER (object);
priv = css_provider->priv; priv = css_provider->priv;
g_ptr_array_free (priv->rulesets, TRUE); g_array_free (priv->rulesets, TRUE);
if (priv->symbolic_colors) if (priv->symbolic_colors)
g_hash_table_destroy (priv->symbolic_colors); g_hash_table_destroy (priv->symbolic_colors);
@ -1325,32 +1327,29 @@ gtk_css_provider_invalid_token (GtkCssProvider *provider,
static void static void
css_provider_commit (GtkCssProvider *css_provider, css_provider_commit (GtkCssProvider *css_provider,
GSList *selectors, GSList *selectors,
GHashTable *properties) GtkCssRuleset *ruleset)
{ {
GtkCssProviderPrivate *priv; GtkCssProviderPrivate *priv;
GSList *l; GSList *l;
priv = css_provider->priv; priv = css_provider->priv;
if (g_hash_table_size (properties) == 0) if (ruleset->style == NULL)
{ {
g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free); g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
g_hash_table_unref (properties);
return; return;
} }
for (l = selectors; l; l = l->next) for (l = selectors; l; l = l->next)
{ {
GtkCssSelector *selector = l->data; GtkCssRuleset new;
GtkCssRuleset *ruleset;
ruleset = gtk_css_ruleset_new (selector); gtk_css_ruleset_init_copy (&new, ruleset, l->data);
gtk_css_ruleset_set_style (ruleset, properties);
g_ptr_array_add (priv->rulesets, ruleset); g_array_append_val (priv->rulesets, new);
} }
g_hash_table_unref (properties); g_slist_free (selectors);
} }
static void static void
@ -1383,11 +1382,13 @@ static void
gtk_css_provider_reset (GtkCssProvider *css_provider) gtk_css_provider_reset (GtkCssProvider *css_provider)
{ {
GtkCssProviderPrivate *priv; GtkCssProviderPrivate *priv;
guint i;
priv = css_provider->priv; priv = css_provider->priv;
if (priv->rulesets->len > 0) for (i = 0; i < priv->rulesets->len; i++)
g_ptr_array_remove_range (priv->rulesets, 0, priv->rulesets->len); gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
g_array_set_size (priv->rulesets, 0);
} }
static void static void
@ -1898,7 +1899,8 @@ parse_selector_list (GtkCssScanner *scanner)
} }
static void static void
parse_declaration (GtkCssScanner *scanner, GHashTable *properties) parse_declaration (GtkCssScanner *scanner,
GtkCssRuleset *ruleset)
{ {
GtkStylePropertyParser parse_func = NULL; GtkStylePropertyParser parse_func = NULL;
GParamSpec *pspec = NULL; GParamSpec *pspec = NULL;
@ -1951,20 +1953,20 @@ parse_declaration (GtkCssScanner *scanner, GHashTable *properties)
* to override other style providers when merged * to override other style providers when merged
*/ */
g_param_value_set_default (pspec, val); g_param_value_set_default (pspec, val);
g_hash_table_insert (properties, name, val); gtk_css_ruleset_add_style (ruleset, name, val);
} }
else if (strcmp (name, "gtk-key-bindings") == 0) else if (strcmp (name, "gtk-key-bindings") == 0)
{ {
/* Private property holding the binding sets */ /* Private property holding the binding sets */
resolve_binding_sets (value_str, val); resolve_binding_sets (value_str, val);
g_hash_table_insert (properties, name, val); gtk_css_ruleset_add_style (ruleset, name, val);
} }
else if (parse_func) else if (parse_func)
{ {
GError *error = NULL; GError *error = NULL;
if ((*parse_func) (value_str, val, &error)) if ((*parse_func) (value_str, val, &error))
g_hash_table_insert (properties, name, val); gtk_css_ruleset_add_style (ruleset, name, val);
else else
gtk_css_provider_take_error (scanner->provider, scanner, error); gtk_css_provider_take_error (scanner->provider, scanner, error);
} }
@ -1977,7 +1979,7 @@ parse_declaration (GtkCssScanner *scanner, GHashTable *properties)
value_str, value_str,
&error)) &error))
{ {
g_hash_table_insert (properties, name, val); gtk_css_ruleset_add_style (ruleset, name, val);
} }
else else
{ {
@ -1997,7 +1999,7 @@ parse_declaration (GtkCssScanner *scanner, GHashTable *properties)
g_value_init (val, G_TYPE_STRING); g_value_init (val, G_TYPE_STRING);
g_value_set_string (val, value_str); g_value_set_string (val, value_str);
g_hash_table_insert (properties, name, val); gtk_css_ruleset_add_style (ruleset, name, val);
} }
else else
g_free (name); g_free (name);
@ -2020,30 +2022,22 @@ check_for_semicolon:
} }
} }
static GHashTable * static void
parse_declarations (GtkCssScanner *scanner) parse_declarations (GtkCssScanner *scanner,
GtkCssRuleset *ruleset)
{ {
GHashTable *properties;
properties = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) property_value_free);
while (!_gtk_css_parser_is_eof (scanner->parser) && while (!_gtk_css_parser_is_eof (scanner->parser) &&
!_gtk_css_parser_begins_with (scanner->parser, '}')) !_gtk_css_parser_begins_with (scanner->parser, '}'))
{ {
parse_declaration (scanner, properties); parse_declaration (scanner, ruleset);
} }
return properties;
} }
static void static void
parse_ruleset (GtkCssScanner *scanner) parse_ruleset (GtkCssScanner *scanner)
{ {
GSList *selectors; GSList *selectors;
GHashTable *properties; GtkCssRuleset ruleset = { 0, };
selectors = parse_selector_list (scanner); selectors = parse_selector_list (scanner);
if (selectors == NULL) if (selectors == NULL)
@ -2061,7 +2055,7 @@ parse_ruleset (GtkCssScanner *scanner)
return; return;
} }
properties = parse_declarations (scanner); parse_declarations (scanner, &ruleset);
if (!_gtk_css_parser_try (scanner->parser, "}", TRUE)) if (!_gtk_css_parser_try (scanner->parser, "}", TRUE))
{ {
@ -2074,16 +2068,13 @@ parse_ruleset (GtkCssScanner *scanner)
{ {
_gtk_css_parser_resync (scanner->parser, FALSE, 0); _gtk_css_parser_resync (scanner->parser, FALSE, 0);
g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free); g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
if (properties) gtk_css_ruleset_clear (&ruleset);
g_hash_table_unref (properties);
return; return;
} }
} }
if (properties) css_provider_commit (scanner->provider, selectors, &ruleset);
css_provider_commit (scanner->provider, selectors, properties); gtk_css_ruleset_clear (&ruleset);
else
g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
} }
static void static void
@ -2114,8 +2105,8 @@ static int
gtk_css_provider_compare_rule (gconstpointer a_, gtk_css_provider_compare_rule (gconstpointer a_,
gconstpointer b_) gconstpointer b_)
{ {
const GtkCssRuleset *a = *(const GtkCssRuleset **) a_; const GtkCssRuleset *a = (const GtkCssRuleset *) a_;
const GtkCssRuleset *b = *(const GtkCssRuleset **) b_; const GtkCssRuleset *b = (const GtkCssRuleset *) b_;
int compare; int compare;
compare = _gtk_css_selector_compare (a->selector, b->selector); compare = _gtk_css_selector_compare (a->selector, b->selector);
@ -2137,7 +2128,7 @@ gtk_css_provider_postprocess (GtkCssProvider *css_provider)
{ {
GtkCssProviderPrivate *priv = css_provider->priv; GtkCssProviderPrivate *priv = css_provider->priv;
g_ptr_array_sort (priv->rulesets, gtk_css_provider_compare_rule); g_array_sort (priv->rulesets, gtk_css_provider_compare_rule);
} }
static gboolean static gboolean
@ -2903,7 +2894,7 @@ gtk_css_provider_to_string (GtkCssProvider *provider)
{ {
if (i > 0) if (i > 0)
g_string_append (str, "\n"); g_string_append (str, "\n");
gtk_css_ruleset_print (g_ptr_array_index (priv->rulesets, i), str); gtk_css_ruleset_print (&g_array_index (priv->rulesets, GtkCssRuleset, i), str);
} }
return g_string_free (str, FALSE); return g_string_free (str, FALSE);