Compare commits
6 Commits
3.11.5
...
wip/css-op
Author | SHA1 | Date | |
---|---|---|---|
|
90bcb52293 | ||
|
3b48e562dd | ||
|
fc12246758 | ||
|
ae194d14d1 | ||
|
c55a492ad3 | ||
|
b70d8c477d |
@@ -994,6 +994,37 @@ struct GtkCssRuleset
|
|||||||
guint owns_widget_style : 1;
|
guint owns_widget_style : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RulesetsTreeType {
|
||||||
|
RULESETS_TREE_TYPE_STATE,
|
||||||
|
RULESETS_TREE_TYPE_CLASS,
|
||||||
|
RULESETS_TREE_TYPE_RULES
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _GtkCssRulesetList GtkCssRulesetList;
|
||||||
|
typedef struct _GtkCssRulesetsTree GtkCssRulesetsTree;
|
||||||
|
|
||||||
|
struct _GtkCssRulesetList {
|
||||||
|
guint *rules;
|
||||||
|
guint num_rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GtkCssRulesetsTree
|
||||||
|
{
|
||||||
|
enum RulesetsTreeType type;
|
||||||
|
union {
|
||||||
|
GtkCssRulesetList rules;
|
||||||
|
struct {
|
||||||
|
GtkCssRulesetsTree *matched;
|
||||||
|
GtkStateFlags state;
|
||||||
|
} state;
|
||||||
|
struct {
|
||||||
|
GtkCssRulesetsTree *matched;
|
||||||
|
GQuark class;
|
||||||
|
} class;
|
||||||
|
} u;
|
||||||
|
GtkCssRulesetsTree *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct _GtkCssScanner
|
struct _GtkCssScanner
|
||||||
{
|
{
|
||||||
GtkCssProvider *provider;
|
GtkCssProvider *provider;
|
||||||
@@ -1011,6 +1042,8 @@ struct _GtkCssProviderPrivate
|
|||||||
GHashTable *keyframes;
|
GHashTable *keyframes;
|
||||||
|
|
||||||
GArray *rulesets;
|
GArray *rulesets;
|
||||||
|
guint *rulesets_refs;
|
||||||
|
GtkCssRulesetsTree *rulesets_tree;
|
||||||
GResource *resource;
|
GResource *resource;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1027,6 +1060,7 @@ 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 widget_property_value_list_free (WidgetPropertyValue *head);
|
static void widget_property_value_list_free (WidgetPropertyValue *head);
|
||||||
|
static void gtk_css_rulesets_tree_free (GtkCssRulesetsTree *tree);
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_css_provider_load_internal (GtkCssProvider *css_provider,
|
gtk_css_provider_load_internal (GtkCssProvider *css_provider,
|
||||||
@@ -1561,6 +1595,117 @@ gtk_css_style_provider_get_keyframes (GtkStyleProviderPrivate *provider,
|
|||||||
return g_hash_table_lookup (css_provider->priv->keyframes, name);
|
return g_hash_table_lookup (css_provider->priv->keyframes, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
collect_possible_rules (GPtrArray *rules_lists,
|
||||||
|
GtkCssRulesetsTree *tree,
|
||||||
|
const GtkCssMatcher *matcher)
|
||||||
|
{
|
||||||
|
if (tree == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (tree->type)
|
||||||
|
{
|
||||||
|
case RULESETS_TREE_TYPE_RULES:
|
||||||
|
g_ptr_array_add (rules_lists, &tree->u.rules);
|
||||||
|
break;
|
||||||
|
case RULESETS_TREE_TYPE_STATE:
|
||||||
|
if ((_gtk_css_matcher_get_state (matcher) & tree->u.state.state) == tree->u.state.state)
|
||||||
|
collect_possible_rules (rules_lists,
|
||||||
|
tree->u.state.matched,
|
||||||
|
matcher);
|
||||||
|
break;
|
||||||
|
case RULESETS_TREE_TYPE_CLASS:
|
||||||
|
if (_gtk_css_matcher_has_class (matcher, tree->u.class.class))
|
||||||
|
collect_possible_rules (rules_lists,
|
||||||
|
tree->u.class.matched,
|
||||||
|
matcher);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
collect_possible_rules (rules_lists,
|
||||||
|
tree->next,
|
||||||
|
matcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Merged two pre-sorted arrays of uints, assumes enough space in destination to fit a_len + b_len */
|
||||||
|
static void
|
||||||
|
merge_uints (guint *dest, const guint *a, int a_len, const guint* b, int b_len)
|
||||||
|
{
|
||||||
|
const guint *a_end = a + a_len;
|
||||||
|
const guint *b_end = b + b_len;
|
||||||
|
|
||||||
|
while (a != a_end ||
|
||||||
|
b != b_end)
|
||||||
|
{
|
||||||
|
if (a == a_end)
|
||||||
|
{
|
||||||
|
memcpy (dest, b, sizeof (guint) * (b_end - b));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (b == b_end)
|
||||||
|
{
|
||||||
|
memcpy (dest, a, sizeof (guint) * (a_end - a));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (*a <= *b)
|
||||||
|
*dest++ = *a++;
|
||||||
|
else
|
||||||
|
*dest++ = *b++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint *
|
||||||
|
find_possible_rules (GtkCssRulesetsTree *tree,
|
||||||
|
const GtkCssMatcher *matcher,
|
||||||
|
guint *num_refs_out)
|
||||||
|
{
|
||||||
|
GPtrArray *rules_lists;
|
||||||
|
gint i;
|
||||||
|
guint *merged, *tmp_refs, *swap_ptr;
|
||||||
|
guint merged_size;
|
||||||
|
guint num_refs;
|
||||||
|
|
||||||
|
/* Collect all possible rules from the tree */
|
||||||
|
rules_lists = g_ptr_array_new ();
|
||||||
|
collect_possible_rules (rules_lists, tree, matcher);
|
||||||
|
|
||||||
|
/* Merge the separate sorted lists into one list */
|
||||||
|
num_refs = 0;
|
||||||
|
for (i = 0; i < rules_lists->len; i++)
|
||||||
|
{
|
||||||
|
GtkCssRulesetList *list = (GtkCssRulesetList *)rules_lists->pdata[i];
|
||||||
|
num_refs += list->num_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
merged = g_new (guint, num_refs);
|
||||||
|
merged_size = 0;
|
||||||
|
tmp_refs = g_new (guint, num_refs);
|
||||||
|
|
||||||
|
/* Merge the already sorted refs list */
|
||||||
|
for (i = 0; i < rules_lists->len; i++)
|
||||||
|
{
|
||||||
|
GtkCssRulesetList *list = (GtkCssRulesetList *)rules_lists->pdata[i];
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
memcpy (merged, list->rules, sizeof (*list->rules) * list->num_rules);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
merge_uints (tmp_refs, merged, merged_size, list->rules, list->num_rules);
|
||||||
|
swap_ptr = merged;
|
||||||
|
merged = tmp_refs;
|
||||||
|
tmp_refs = swap_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
merged_size += list->num_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (tmp_refs);
|
||||||
|
g_ptr_array_free (rules_lists, TRUE);
|
||||||
|
|
||||||
|
*num_refs_out = num_refs;
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||||
const GtkCssMatcher *matcher,
|
const GtkCssMatcher *matcher,
|
||||||
@@ -1570,6 +1715,9 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
|||||||
GtkCssProviderPrivate *priv;
|
GtkCssProviderPrivate *priv;
|
||||||
GtkCssRuleset *ruleset;
|
GtkCssRuleset *ruleset;
|
||||||
guint j;
|
guint j;
|
||||||
|
gint i;
|
||||||
|
guint *refs;
|
||||||
|
guint num_refs;
|
||||||
|
|
||||||
css_provider = GTK_CSS_PROVIDER (provider);
|
css_provider = GTK_CSS_PROVIDER (provider);
|
||||||
priv = css_provider->priv;
|
priv = css_provider->priv;
|
||||||
@@ -1577,10 +1725,14 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
|||||||
if (priv->rulesets->len == 0)
|
if (priv->rulesets->len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, priv->rulesets->len - 1);
|
refs = find_possible_rules (priv->rulesets_tree, matcher, &num_refs);
|
||||||
ruleset >= &g_array_index (priv->rulesets, GtkCssRuleset, 0);
|
if (num_refs == 0)
|
||||||
ruleset--)
|
return;
|
||||||
|
|
||||||
|
for (i = num_refs - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, refs[i]);
|
||||||
|
|
||||||
if (ruleset->styles == NULL)
|
if (ruleset->styles == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1608,6 +1760,8 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
|||||||
if (_gtk_bitmask_is_empty (_gtk_css_lookup_get_missing (lookup)))
|
if (_gtk_bitmask_is_empty (_gtk_css_lookup_get_missing (lookup)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (refs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkCssChange
|
static GtkCssChange
|
||||||
@@ -1618,15 +1772,21 @@ gtk_css_style_provider_get_change (GtkStyleProviderPrivate *provider,
|
|||||||
GtkCssProviderPrivate *priv;
|
GtkCssProviderPrivate *priv;
|
||||||
GtkCssChange change = 0;
|
GtkCssChange change = 0;
|
||||||
int i;
|
int i;
|
||||||
|
guint *refs;
|
||||||
|
guint num_refs;
|
||||||
|
|
||||||
css_provider = GTK_CSS_PROVIDER (provider);
|
css_provider = GTK_CSS_PROVIDER (provider);
|
||||||
priv = css_provider->priv;
|
priv = css_provider->priv;
|
||||||
|
|
||||||
for (i = priv->rulesets->len - 1; i >= 0; i--)
|
refs = find_possible_rules (priv->rulesets_tree, matcher, &num_refs);
|
||||||
|
if (num_refs == 0)
|
||||||
|
return change;
|
||||||
|
|
||||||
|
for (i = num_refs - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
GtkCssRuleset *ruleset;
|
GtkCssRuleset *ruleset;
|
||||||
|
|
||||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
|
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, refs[i]);
|
||||||
|
|
||||||
if (ruleset->styles == NULL)
|
if (ruleset->styles == NULL)
|
||||||
continue;
|
continue;
|
||||||
@@ -1637,6 +1797,8 @@ gtk_css_style_provider_get_change (GtkStyleProviderPrivate *provider,
|
|||||||
change |= gtk_css_ruleset_get_change (ruleset);
|
change |= gtk_css_ruleset_get_change (ruleset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (refs);
|
||||||
|
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1663,6 +1825,8 @@ gtk_css_provider_finalize (GObject *object)
|
|||||||
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
|
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
|
||||||
|
|
||||||
g_array_free (priv->rulesets, TRUE);
|
g_array_free (priv->rulesets, TRUE);
|
||||||
|
g_free (priv->rulesets_refs);
|
||||||
|
gtk_css_rulesets_tree_free (priv->rulesets_tree);
|
||||||
|
|
||||||
g_hash_table_destroy (priv->symbolic_colors);
|
g_hash_table_destroy (priv->symbolic_colors);
|
||||||
g_hash_table_destroy (priv->keyframes);
|
g_hash_table_destroy (priv->keyframes);
|
||||||
@@ -1797,6 +1961,11 @@ gtk_css_provider_reset (GtkCssProvider *css_provider)
|
|||||||
g_hash_table_remove_all (priv->symbolic_colors);
|
g_hash_table_remove_all (priv->symbolic_colors);
|
||||||
g_hash_table_remove_all (priv->keyframes);
|
g_hash_table_remove_all (priv->keyframes);
|
||||||
|
|
||||||
|
g_free (priv->rulesets_refs);
|
||||||
|
priv->rulesets_refs = NULL;
|
||||||
|
gtk_css_rulesets_tree_free (priv->rulesets_tree);
|
||||||
|
priv->rulesets_tree = NULL;
|
||||||
|
|
||||||
for (i = 0; i < priv->rulesets->len; i++)
|
for (i = 0; i < priv->rulesets->len; i++)
|
||||||
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
|
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
|
||||||
g_array_set_size (priv->rulesets, 0);
|
g_array_set_size (priv->rulesets, 0);
|
||||||
@@ -2430,12 +2599,274 @@ gtk_css_provider_compare_rule (gconstpointer a_,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_css_rulesets_tree_free (GtkCssRulesetsTree *tree)
|
||||||
|
{
|
||||||
|
if (tree == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (tree->type)
|
||||||
|
{
|
||||||
|
case RULESETS_TREE_TYPE_RULES:
|
||||||
|
break;
|
||||||
|
case RULESETS_TREE_TYPE_STATE:
|
||||||
|
gtk_css_rulesets_tree_free (tree->u.state.matched);
|
||||||
|
break;
|
||||||
|
case RULESETS_TREE_TYPE_CLASS:
|
||||||
|
gtk_css_rulesets_tree_free (tree->u.class.matched);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_css_rulesets_tree_free (tree->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_refs_by_val (gconstpointer pa,
|
||||||
|
gconstpointer pb,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
guint a = *(guint *)pa;
|
||||||
|
guint b = *(guint *)pb;
|
||||||
|
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkCssRulesetsTree *
|
||||||
|
subdivide_by_none (GtkCssProviderPrivate *priv, guint *refs, guint start, guint end)
|
||||||
|
{
|
||||||
|
GtkCssRulesetsTree *tree;
|
||||||
|
|
||||||
|
tree = g_new0 (GtkCssRulesetsTree, 1);
|
||||||
|
tree->type = RULESETS_TREE_TYPE_RULES;
|
||||||
|
tree->u.rules.rules = refs + start;
|
||||||
|
tree->u.rules.num_rules = end - start;
|
||||||
|
tree->next = NULL;
|
||||||
|
|
||||||
|
/* Sort by rule index (i.e. css prio order) */
|
||||||
|
g_qsort_with_data (tree->u.rules.rules,
|
||||||
|
tree->u.rules.num_rules,
|
||||||
|
sizeof (guint),
|
||||||
|
compare_refs_by_val,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GQuark class;
|
||||||
|
guint count;
|
||||||
|
} GtkCssPseudoClassCount;
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_class_count (gconstpointer pa,
|
||||||
|
gconstpointer pb,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkCssPseudoClassCount *a = (GtkCssPseudoClassCount *)pa;
|
||||||
|
GtkCssPseudoClassCount *b = (GtkCssPseudoClassCount *)pb;
|
||||||
|
|
||||||
|
return b->count - a->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkCssRulesetsTree *
|
||||||
|
subdivide_by_class (GtkCssProviderPrivate *priv, guint *refs, guint start, guint end)
|
||||||
|
{
|
||||||
|
GHashTable *count_ht;
|
||||||
|
GHashTableIter iter;
|
||||||
|
guint i, j, n_classes;
|
||||||
|
gpointer key, value;
|
||||||
|
GtkCssPseudoClassCount *class_count;
|
||||||
|
GtkCssRulesetsTree *tree;
|
||||||
|
GtkCssRulesetsTree *trees = NULL;
|
||||||
|
|
||||||
|
count_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
|
|
||||||
|
for (i = start; i < end; i++)
|
||||||
|
{
|
||||||
|
GtkCssSelector *selector = g_array_index (priv->rulesets, GtkCssRuleset, refs[i]).selector;
|
||||||
|
GQuark *classes = _gtk_css_selector_get_primary_classes (selector);
|
||||||
|
|
||||||
|
for (j = 0; classes[j] != 0; j++)
|
||||||
|
{
|
||||||
|
guint count = GPOINTER_TO_INT (g_hash_table_lookup (count_ht, GUINT_TO_POINTER (classes[j])));
|
||||||
|
g_hash_table_replace (count_ht, GUINT_TO_POINTER (classes[j]), GUINT_TO_POINTER (count + 1));
|
||||||
|
}
|
||||||
|
g_free (classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
n_classes = 0;
|
||||||
|
class_count = g_new (GtkCssPseudoClassCount, g_hash_table_size (count_ht));
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, count_ht);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
guint count = GPOINTER_TO_UINT (value);
|
||||||
|
/* Random cuttoff point here. Obviously if any given class has only one item
|
||||||
|
with it, then adding a check doesn't help, and it uses memory. Where
|
||||||
|
is the inflexion point? Lets make it 3... */
|
||||||
|
if (count >= 3)
|
||||||
|
{
|
||||||
|
class_count[n_classes].class = GPOINTER_TO_UINT (key);
|
||||||
|
class_count[n_classes].count = count;
|
||||||
|
n_classes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_destroy (count_ht);
|
||||||
|
|
||||||
|
/* Sort largest class counts first */
|
||||||
|
g_qsort_with_data (class_count,
|
||||||
|
n_classes,
|
||||||
|
sizeof (*class_count),
|
||||||
|
compare_class_count,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < n_classes; i++)
|
||||||
|
{
|
||||||
|
guint split = start;
|
||||||
|
for (j = start; j < end; j++)
|
||||||
|
{
|
||||||
|
GtkCssSelector *selector = g_array_index (priv->rulesets, GtkCssRuleset, refs[j]).selector;
|
||||||
|
|
||||||
|
if (_gtk_css_selector_has_primary_class (selector, class_count[i].class))
|
||||||
|
{
|
||||||
|
guint tmp = refs[split];
|
||||||
|
refs[split] = refs[j];
|
||||||
|
refs[j] = tmp;
|
||||||
|
split++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check size again sice nodes may have been used in other trees */
|
||||||
|
if (split - start > 3)
|
||||||
|
{
|
||||||
|
tree = g_new (GtkCssRulesetsTree, 1);
|
||||||
|
tree->type = RULESETS_TREE_TYPE_CLASS;
|
||||||
|
tree->u.class.matched = subdivide_by_none (priv, refs, start, split);
|
||||||
|
tree->u.class.class = class_count[i].class;
|
||||||
|
|
||||||
|
tree->next = trees;
|
||||||
|
trees = tree;
|
||||||
|
start = split;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (class_count);
|
||||||
|
|
||||||
|
if (start != end)
|
||||||
|
{
|
||||||
|
tree = subdivide_by_none (priv, refs, start, end);
|
||||||
|
tree->next = trees;
|
||||||
|
trees = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trees;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GtkCssRulesetsTree *
|
||||||
|
subdivide_by_state (GtkCssProviderPrivate *priv, guint *refs, guint start, guint end, guint state)
|
||||||
|
{
|
||||||
|
GtkCssRulesetsTree *tree;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (end == start)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (state == 0)
|
||||||
|
return subdivide_by_class (priv, refs, start, end);
|
||||||
|
|
||||||
|
// Find first non-set flag
|
||||||
|
for (i = start; i < end; i++)
|
||||||
|
{
|
||||||
|
GtkCssSelector *selector = g_array_index (priv->rulesets, GtkCssRuleset, refs[i]).selector;
|
||||||
|
if ((_gtk_css_selector_get_primary_state_flags (selector) & state) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == start || i == end) /* All or none set, no use subdividing by this */
|
||||||
|
return subdivide_by_state (priv, refs, start, end, state >> 1);
|
||||||
|
|
||||||
|
tree = g_new (GtkCssRulesetsTree, 1);
|
||||||
|
tree->type = RULESETS_TREE_TYPE_STATE;
|
||||||
|
tree->u.state.matched = subdivide_by_state (priv, refs, start, i, state >> 1);
|
||||||
|
tree->u.state.state = state;
|
||||||
|
|
||||||
|
tree->next = subdivide_by_state (priv, refs, i, end, state >> 1);
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_refs_by_flags (gconstpointer pa,
|
||||||
|
gconstpointer pb,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
guint a = *(guint *)pa;
|
||||||
|
guint b = *(guint *)pb;
|
||||||
|
GArray *rulesets = user_data;
|
||||||
|
GtkCssSelector *selector_a, *selector_b;
|
||||||
|
guint32 flags_a, flags_b;
|
||||||
|
|
||||||
|
selector_a = g_array_index (rulesets, GtkCssRuleset, a).selector;
|
||||||
|
selector_b = g_array_index (rulesets, GtkCssRuleset, b).selector;
|
||||||
|
|
||||||
|
flags_a = _gtk_css_selector_get_primary_state_flags (selector_a);
|
||||||
|
flags_b = _gtk_css_selector_get_primary_state_flags (selector_b);
|
||||||
|
|
||||||
|
return flags_b - flags_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_tree (GtkCssRulesetsTree *tree, int indent)
|
||||||
|
{
|
||||||
|
if (tree == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (tree->type)
|
||||||
|
{
|
||||||
|
case RULESETS_TREE_TYPE_RULES:
|
||||||
|
printf ("%*sCheck rules %p len %d\n", indent, "", tree->u.rules.rules, tree->u.rules.num_rules);
|
||||||
|
break;
|
||||||
|
case RULESETS_TREE_TYPE_STATE:
|
||||||
|
printf ("%*sMatch state 0x%x ->\n", indent, "", tree->u.state.state);
|
||||||
|
print_tree (tree->u.state.matched, indent + 4);
|
||||||
|
break;
|
||||||
|
case RULESETS_TREE_TYPE_CLASS:
|
||||||
|
printf ("%*sMatch class %s ->\n", indent, "", g_quark_to_string (tree->u.class.class));
|
||||||
|
print_tree (tree->u.class.matched, indent + 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_tree (tree->next, indent);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_css_provider_postprocess (GtkCssProvider *css_provider)
|
gtk_css_provider_postprocess (GtkCssProvider *css_provider)
|
||||||
{
|
{
|
||||||
GtkCssProviderPrivate *priv = css_provider->priv;
|
GtkCssProviderPrivate *priv = css_provider->priv;
|
||||||
|
guint *refs, i;
|
||||||
|
|
||||||
g_array_sort (priv->rulesets, gtk_css_provider_compare_rule);
|
g_array_sort (priv->rulesets, gtk_css_provider_compare_rule);
|
||||||
|
|
||||||
|
refs = g_new (guint, priv->rulesets->len);
|
||||||
|
priv->rulesets_refs = refs;
|
||||||
|
|
||||||
|
for (i = 0; i < priv->rulesets->len; i++)
|
||||||
|
refs[i] = i;
|
||||||
|
|
||||||
|
/* Sort by flags, so that high bits set is sorted first at each level */
|
||||||
|
g_qsort_with_data (refs,
|
||||||
|
priv->rulesets->len,
|
||||||
|
sizeof (guint),
|
||||||
|
compare_refs_by_flags,
|
||||||
|
priv->rulesets);
|
||||||
|
|
||||||
|
priv->rulesets_tree = subdivide_by_state (priv, refs, 0, priv->rulesets->len, GTK_STATE_FLAG_BACKDROP);
|
||||||
|
if (g_getenv ("GTK_CSS_DEBUG_TREE"))
|
||||||
|
{
|
||||||
|
g_print ("Rulesets tree for proviced %p (%d rules)\n", css_provider, priv->rulesets->len);
|
||||||
|
print_tree (priv->rulesets_tree, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@@ -38,6 +38,7 @@ struct _GtkCssSelectorClass {
|
|||||||
guint increase_id_specificity :1;
|
guint increase_id_specificity :1;
|
||||||
guint increase_class_specificity :1;
|
guint increase_class_specificity :1;
|
||||||
guint increase_element_specificity :1;
|
guint increase_element_specificity :1;
|
||||||
|
guint is_simple :1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GtkCssSelector
|
struct _GtkCssSelector
|
||||||
@@ -112,7 +113,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
|
|||||||
gtk_css_selector_descendant_print,
|
gtk_css_selector_descendant_print,
|
||||||
gtk_css_selector_descendant_match,
|
gtk_css_selector_descendant_match,
|
||||||
gtk_css_selector_descendant_get_change,
|
gtk_css_selector_descendant_get_change,
|
||||||
FALSE, FALSE, FALSE
|
FALSE, FALSE, FALSE, FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* CHILD */
|
/* CHILD */
|
||||||
@@ -147,7 +148,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = {
|
|||||||
gtk_css_selector_child_print,
|
gtk_css_selector_child_print,
|
||||||
gtk_css_selector_child_match,
|
gtk_css_selector_child_match,
|
||||||
gtk_css_selector_child_get_change,
|
gtk_css_selector_child_get_change,
|
||||||
FALSE, FALSE, FALSE
|
FALSE, FALSE, FALSE, FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* SIBLING */
|
/* SIBLING */
|
||||||
@@ -187,7 +188,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = {
|
|||||||
gtk_css_selector_sibling_print,
|
gtk_css_selector_sibling_print,
|
||||||
gtk_css_selector_sibling_match,
|
gtk_css_selector_sibling_match,
|
||||||
gtk_css_selector_sibling_get_change,
|
gtk_css_selector_sibling_get_change,
|
||||||
FALSE, FALSE, FALSE
|
FALSE, FALSE, FALSE, FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ADJACENT */
|
/* ADJACENT */
|
||||||
@@ -222,7 +223,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = {
|
|||||||
gtk_css_selector_adjacent_print,
|
gtk_css_selector_adjacent_print,
|
||||||
gtk_css_selector_adjacent_match,
|
gtk_css_selector_adjacent_match,
|
||||||
gtk_css_selector_adjacent_get_change,
|
gtk_css_selector_adjacent_get_change,
|
||||||
FALSE, FALSE, FALSE
|
FALSE, FALSE, FALSE, FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ANY */
|
/* ANY */
|
||||||
@@ -262,7 +263,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ANY = {
|
|||||||
gtk_css_selector_any_print,
|
gtk_css_selector_any_print,
|
||||||
gtk_css_selector_any_match,
|
gtk_css_selector_any_match,
|
||||||
gtk_css_selector_any_get_change,
|
gtk_css_selector_any_get_change,
|
||||||
FALSE, FALSE, FALSE
|
FALSE, FALSE, FALSE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NAME */
|
/* NAME */
|
||||||
@@ -295,7 +296,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_NAME = {
|
|||||||
gtk_css_selector_name_print,
|
gtk_css_selector_name_print,
|
||||||
gtk_css_selector_name_match,
|
gtk_css_selector_name_match,
|
||||||
gtk_css_selector_name_get_change,
|
gtk_css_selector_name_get_change,
|
||||||
FALSE, FALSE, TRUE
|
FALSE, FALSE, TRUE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* REGION */
|
/* REGION */
|
||||||
@@ -341,7 +342,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_REGION = {
|
|||||||
gtk_css_selector_region_print,
|
gtk_css_selector_region_print,
|
||||||
gtk_css_selector_region_match,
|
gtk_css_selector_region_match,
|
||||||
gtk_css_selector_region_get_change,
|
gtk_css_selector_region_get_change,
|
||||||
FALSE, FALSE, TRUE
|
FALSE, FALSE, TRUE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* CLASS */
|
/* CLASS */
|
||||||
@@ -375,7 +376,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CLASS = {
|
|||||||
gtk_css_selector_class_print,
|
gtk_css_selector_class_print,
|
||||||
gtk_css_selector_class_match,
|
gtk_css_selector_class_match,
|
||||||
gtk_css_selector_class_get_change,
|
gtk_css_selector_class_get_change,
|
||||||
FALSE, TRUE, FALSE
|
FALSE, TRUE, FALSE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ID */
|
/* ID */
|
||||||
@@ -409,7 +410,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ID = {
|
|||||||
gtk_css_selector_id_print,
|
gtk_css_selector_id_print,
|
||||||
gtk_css_selector_id_match,
|
gtk_css_selector_id_match,
|
||||||
gtk_css_selector_id_get_change,
|
gtk_css_selector_id_get_change,
|
||||||
TRUE, FALSE, FALSE
|
TRUE, FALSE, FALSE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PSEUDOCLASS FOR STATE */
|
/* PSEUDOCLASS FOR STATE */
|
||||||
@@ -430,18 +431,15 @@ gtk_css_selector_pseudoclass_state_print (const GtkCssSelector *selector,
|
|||||||
guint i, state;
|
guint i, state;
|
||||||
|
|
||||||
state = GPOINTER_TO_UINT (selector->data);
|
state = GPOINTER_TO_UINT (selector->data);
|
||||||
g_string_append_c (string, ':');
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (state_names); i++)
|
for (i = 0; i < G_N_ELEMENTS (state_names); i++)
|
||||||
{
|
{
|
||||||
if (state == (1 << i))
|
if (state == (1 << i))
|
||||||
{
|
{
|
||||||
|
g_string_append_c (string, ':');
|
||||||
g_string_append (string, state_names[i]);
|
g_string_append (string, state_names[i]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -467,7 +465,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_PSEUDOCLASS_STATE = {
|
|||||||
gtk_css_selector_pseudoclass_state_print,
|
gtk_css_selector_pseudoclass_state_print,
|
||||||
gtk_css_selector_pseudoclass_state_match,
|
gtk_css_selector_pseudoclass_state_match,
|
||||||
gtk_css_selector_pseudoclass_state_get_change,
|
gtk_css_selector_pseudoclass_state_get_change,
|
||||||
FALSE, TRUE, FALSE
|
FALSE, TRUE, FALSE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PSEUDOCLASS FOR POSITION */
|
/* PSEUDOCLASS FOR POSITION */
|
||||||
@@ -708,7 +706,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION = {
|
|||||||
gtk_css_selector_pseudoclass_position_print,
|
gtk_css_selector_pseudoclass_position_print,
|
||||||
gtk_css_selector_pseudoclass_position_match,
|
gtk_css_selector_pseudoclass_position_match,
|
||||||
gtk_css_selector_pseudoclass_position_get_change,
|
gtk_css_selector_pseudoclass_position_get_change,
|
||||||
FALSE, TRUE, FALSE
|
FALSE, TRUE, FALSE, TRUE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* API */
|
/* API */
|
||||||
@@ -950,9 +948,16 @@ parse_selector_pseudo_class (GtkCssParser *parser,
|
|||||||
if (_gtk_css_parser_try (parser, pseudo_classes[i].name, FALSE))
|
if (_gtk_css_parser_try (parser, pseudo_classes[i].name, FALSE))
|
||||||
{
|
{
|
||||||
if (pseudo_classes[i].state_flag)
|
if (pseudo_classes[i].state_flag)
|
||||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_STATE,
|
{
|
||||||
selector,
|
/* Piggy back on previous pseudoclass if any */
|
||||||
GUINT_TO_POINTER (pseudo_classes[i].state_flag));
|
if (selector && selector->class == >K_CSS_SELECTOR_PSEUDOCLASS_STATE)
|
||||||
|
selector->data = GUINT_TO_POINTER (GPOINTER_TO_UINT (selector->data) |
|
||||||
|
pseudo_classes[i].state_flag);
|
||||||
|
else
|
||||||
|
selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_STATE,
|
||||||
|
selector,
|
||||||
|
GUINT_TO_POINTER (pseudo_classes[i].state_flag));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_POSITION,
|
selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_POSITION,
|
||||||
selector,
|
selector,
|
||||||
@@ -1172,3 +1177,49 @@ _gtk_css_selector_get_state_flags (const GtkCssSelector *selector)
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GtkStateFlags
|
||||||
|
_gtk_css_selector_get_primary_state_flags (const GtkCssSelector *selector)
|
||||||
|
{
|
||||||
|
GtkStateFlags state = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (selector != NULL, 0);
|
||||||
|
|
||||||
|
for (; selector && selector->class->is_simple; selector = gtk_css_selector_previous (selector))
|
||||||
|
{
|
||||||
|
if (selector->class == >K_CSS_SELECTOR_PSEUDOCLASS_STATE)
|
||||||
|
state |= GPOINTER_TO_UINT (selector->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark *
|
||||||
|
_gtk_css_selector_get_primary_classes (const GtkCssSelector *selector)
|
||||||
|
{
|
||||||
|
GArray *array = g_array_new (TRUE, FALSE, sizeof (GQuark));
|
||||||
|
|
||||||
|
g_return_val_if_fail (selector != NULL, 0);
|
||||||
|
|
||||||
|
for (; selector && selector->class->is_simple; selector = gtk_css_selector_previous (selector))
|
||||||
|
{
|
||||||
|
if (selector->class == >K_CSS_SELECTOR_CLASS)
|
||||||
|
g_array_append_val (array, selector->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GQuark *)g_array_free (array, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_gtk_css_selector_has_primary_class (const GtkCssSelector *selector, GQuark class)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (selector != NULL, 0);
|
||||||
|
|
||||||
|
for (; selector && selector->class->is_simple; selector = gtk_css_selector_previous (selector))
|
||||||
|
{
|
||||||
|
if (selector->class == >K_CSS_SELECTOR_CLASS)
|
||||||
|
if (GPOINTER_TO_UINT (selector->data) == class)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
@@ -40,6 +40,11 @@ gboolean _gtk_css_selector_matches (const GtkCssSelector *sel
|
|||||||
int _gtk_css_selector_compare (const GtkCssSelector *a,
|
int _gtk_css_selector_compare (const GtkCssSelector *a,
|
||||||
const GtkCssSelector *b);
|
const GtkCssSelector *b);
|
||||||
|
|
||||||
|
GtkStateFlags _gtk_css_selector_get_primary_state_flags (const GtkCssSelector *selector);
|
||||||
|
GQuark * _gtk_css_selector_get_primary_classes (const GtkCssSelector *selector);
|
||||||
|
gboolean _gtk_css_selector_has_primary_class (const GtkCssSelector *selector,
|
||||||
|
GQuark class);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GTK_CSS_SELECTOR_PRIVATE_H__ */
|
#endif /* __GTK_CSS_SELECTOR_PRIVATE_H__ */
|
||||||
|
Reference in New Issue
Block a user