Compare commits
6 Commits
textview-b
...
wip/css-op
Author | SHA1 | Date | |
---|---|---|---|
|
90bcb52293 | ||
|
3b48e562dd | ||
|
fc12246758 | ||
|
ae194d14d1 | ||
|
c55a492ad3 | ||
|
b70d8c477d |
@@ -994,6 +994,37 @@ struct GtkCssRuleset
|
||||
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
|
||||
{
|
||||
GtkCssProvider *provider;
|
||||
@@ -1011,6 +1042,8 @@ struct _GtkCssProviderPrivate
|
||||
GHashTable *keyframes;
|
||||
|
||||
GArray *rulesets;
|
||||
guint *rulesets_refs;
|
||||
GtkCssRulesetsTree *rulesets_tree;
|
||||
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_private_iface_init (GtkStyleProviderPrivateInterface *iface);
|
||||
static void widget_property_value_list_free (WidgetPropertyValue *head);
|
||||
static void gtk_css_rulesets_tree_free (GtkCssRulesetsTree *tree);
|
||||
|
||||
static gboolean
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||
const GtkCssMatcher *matcher,
|
||||
@@ -1570,6 +1715,9 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||
GtkCssProviderPrivate *priv;
|
||||
GtkCssRuleset *ruleset;
|
||||
guint j;
|
||||
gint i;
|
||||
guint *refs;
|
||||
guint num_refs;
|
||||
|
||||
css_provider = GTK_CSS_PROVIDER (provider);
|
||||
priv = css_provider->priv;
|
||||
@@ -1577,10 +1725,14 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||
if (priv->rulesets->len == 0)
|
||||
return;
|
||||
|
||||
for (ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, priv->rulesets->len - 1);
|
||||
ruleset >= &g_array_index (priv->rulesets, GtkCssRuleset, 0);
|
||||
ruleset--)
|
||||
refs = find_possible_rules (priv->rulesets_tree, matcher, &num_refs);
|
||||
if (num_refs == 0)
|
||||
return;
|
||||
|
||||
for (i = num_refs - 1; i >= 0; i--)
|
||||
{
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, refs[i]);
|
||||
|
||||
if (ruleset->styles == NULL)
|
||||
continue;
|
||||
|
||||
@@ -1608,6 +1760,8 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||
if (_gtk_bitmask_is_empty (_gtk_css_lookup_get_missing (lookup)))
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (refs);
|
||||
}
|
||||
|
||||
static GtkCssChange
|
||||
@@ -1618,15 +1772,21 @@ gtk_css_style_provider_get_change (GtkStyleProviderPrivate *provider,
|
||||
GtkCssProviderPrivate *priv;
|
||||
GtkCssChange change = 0;
|
||||
int i;
|
||||
guint *refs;
|
||||
guint num_refs;
|
||||
|
||||
css_provider = GTK_CSS_PROVIDER (provider);
|
||||
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;
|
||||
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, refs[i]);
|
||||
|
||||
if (ruleset->styles == NULL)
|
||||
continue;
|
||||
@@ -1637,6 +1797,8 @@ gtk_css_style_provider_get_change (GtkStyleProviderPrivate *provider,
|
||||
change |= gtk_css_ruleset_get_change (ruleset);
|
||||
}
|
||||
|
||||
g_free (refs);
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
@@ -1663,6 +1825,8 @@ gtk_css_provider_finalize (GObject *object)
|
||||
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
|
||||
|
||||
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->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->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++)
|
||||
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
|
||||
g_array_set_size (priv->rulesets, 0);
|
||||
@@ -2430,12 +2599,274 @@ gtk_css_provider_compare_rule (gconstpointer a_,
|
||||
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
|
||||
gtk_css_provider_postprocess (GtkCssProvider *css_provider)
|
||||
{
|
||||
GtkCssProviderPrivate *priv = css_provider->priv;
|
||||
guint *refs, i;
|
||||
|
||||
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
|
||||
|
@@ -38,6 +38,7 @@ struct _GtkCssSelectorClass {
|
||||
guint increase_id_specificity :1;
|
||||
guint increase_class_specificity :1;
|
||||
guint increase_element_specificity :1;
|
||||
guint is_simple :1;
|
||||
};
|
||||
|
||||
struct _GtkCssSelector
|
||||
@@ -112,7 +113,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
|
||||
gtk_css_selector_descendant_print,
|
||||
gtk_css_selector_descendant_match,
|
||||
gtk_css_selector_descendant_get_change,
|
||||
FALSE, FALSE, FALSE
|
||||
FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
/* CHILD */
|
||||
@@ -147,7 +148,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = {
|
||||
gtk_css_selector_child_print,
|
||||
gtk_css_selector_child_match,
|
||||
gtk_css_selector_child_get_change,
|
||||
FALSE, FALSE, FALSE
|
||||
FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
/* SIBLING */
|
||||
@@ -187,7 +188,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = {
|
||||
gtk_css_selector_sibling_print,
|
||||
gtk_css_selector_sibling_match,
|
||||
gtk_css_selector_sibling_get_change,
|
||||
FALSE, FALSE, FALSE
|
||||
FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
/* ADJACENT */
|
||||
@@ -222,7 +223,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = {
|
||||
gtk_css_selector_adjacent_print,
|
||||
gtk_css_selector_adjacent_match,
|
||||
gtk_css_selector_adjacent_get_change,
|
||||
FALSE, FALSE, FALSE
|
||||
FALSE, FALSE, FALSE, FALSE
|
||||
};
|
||||
|
||||
/* ANY */
|
||||
@@ -262,7 +263,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ANY = {
|
||||
gtk_css_selector_any_print,
|
||||
gtk_css_selector_any_match,
|
||||
gtk_css_selector_any_get_change,
|
||||
FALSE, FALSE, FALSE
|
||||
FALSE, FALSE, FALSE, TRUE
|
||||
};
|
||||
|
||||
/* NAME */
|
||||
@@ -295,7 +296,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_NAME = {
|
||||
gtk_css_selector_name_print,
|
||||
gtk_css_selector_name_match,
|
||||
gtk_css_selector_name_get_change,
|
||||
FALSE, FALSE, TRUE
|
||||
FALSE, FALSE, TRUE, TRUE
|
||||
};
|
||||
|
||||
/* REGION */
|
||||
@@ -341,7 +342,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_REGION = {
|
||||
gtk_css_selector_region_print,
|
||||
gtk_css_selector_region_match,
|
||||
gtk_css_selector_region_get_change,
|
||||
FALSE, FALSE, TRUE
|
||||
FALSE, FALSE, TRUE, TRUE
|
||||
};
|
||||
|
||||
/* CLASS */
|
||||
@@ -375,7 +376,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CLASS = {
|
||||
gtk_css_selector_class_print,
|
||||
gtk_css_selector_class_match,
|
||||
gtk_css_selector_class_get_change,
|
||||
FALSE, TRUE, FALSE
|
||||
FALSE, TRUE, FALSE, TRUE
|
||||
};
|
||||
|
||||
/* ID */
|
||||
@@ -409,7 +410,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ID = {
|
||||
gtk_css_selector_id_print,
|
||||
gtk_css_selector_id_match,
|
||||
gtk_css_selector_id_get_change,
|
||||
TRUE, FALSE, FALSE
|
||||
TRUE, FALSE, FALSE, TRUE
|
||||
};
|
||||
|
||||
/* PSEUDOCLASS FOR STATE */
|
||||
@@ -430,18 +431,15 @@ gtk_css_selector_pseudoclass_state_print (const GtkCssSelector *selector,
|
||||
guint i, state;
|
||||
|
||||
state = GPOINTER_TO_UINT (selector->data);
|
||||
g_string_append_c (string, ':');
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (state_names); i++)
|
||||
{
|
||||
if (state == (1 << i))
|
||||
{
|
||||
g_string_append_c (string, ':');
|
||||
g_string_append (string, state_names[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
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_match,
|
||||
gtk_css_selector_pseudoclass_state_get_change,
|
||||
FALSE, TRUE, FALSE
|
||||
FALSE, TRUE, FALSE, TRUE
|
||||
};
|
||||
|
||||
/* 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_match,
|
||||
gtk_css_selector_pseudoclass_position_get_change,
|
||||
FALSE, TRUE, FALSE
|
||||
FALSE, TRUE, FALSE, TRUE
|
||||
};
|
||||
|
||||
/* API */
|
||||
@@ -950,9 +948,16 @@ parse_selector_pseudo_class (GtkCssParser *parser,
|
||||
if (_gtk_css_parser_try (parser, pseudo_classes[i].name, FALSE))
|
||||
{
|
||||
if (pseudo_classes[i].state_flag)
|
||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_STATE,
|
||||
selector,
|
||||
GUINT_TO_POINTER (pseudo_classes[i].state_flag));
|
||||
{
|
||||
/* Piggy back on previous pseudoclass if any */
|
||||
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
|
||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_POSITION,
|
||||
selector,
|
||||
@@ -1172,3 +1177,49 @@ _gtk_css_selector_get_state_flags (const GtkCssSelector *selector)
|
||||
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,
|
||||
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
|
||||
|
||||
#endif /* __GTK_CSS_SELECTOR_PRIVATE_H__ */
|
||||
|
Reference in New Issue
Block a user