cssselector: Make specificity handling a vfunc

The new region selector tracks more than just one soimple selector, so
it requires some more advanced specificity tracking.

Technically, this is still not correct, because it will report the same
specificity for
  tab:sorted
and
  tab:sorted:sorted
(and the second selector will be printed as the first) but this is
regions, so meh.
This commit is contained in:
Benjamin Otte 2014-12-08 06:46:38 +01:00
parent 371a601858
commit 06b0b47d04

View File

@ -52,13 +52,14 @@ struct _GtkCssSelectorClass {
GtkCssChange previous_change); GtkCssChange previous_change);
GtkCssChange (* tree_get_change) (const GtkCssSelectorTree *tree, GtkCssChange (* tree_get_change) (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher); const GtkCssMatcher *matcher);
void (* add_specificity) (const GtkCssSelector *selector,
guint *ids,
guint *classes,
guint *elements);
guint (* hash_one) (const GtkCssSelector *selector); guint (* hash_one) (const GtkCssSelector *selector);
int (* compare_one) (const GtkCssSelector *a, int (* compare_one) (const GtkCssSelector *a,
const GtkCssSelector *b); const GtkCssSelector *b);
guint increase_id_specificity :1;
guint increase_class_specificity :1;
guint increase_element_specificity :1;
guint is_simple :1; guint is_simple :1;
}; };
@ -261,6 +262,17 @@ gtk_css_selector_tree_get_previous_change (const GtkCssSelectorTree *tree,
return previous_change; return previous_change;
} }
/* DEFAULTS */
static void
gtk_css_selector_default_add_specificity (const GtkCssSelector *selector,
guint *ids,
guint *classes,
guint *elements)
{
/* no specificity changes */
}
/* DESCENDANT */ /* DESCENDANT */
static void static void
@ -360,9 +372,10 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
gtk_css_selector_descendant_tree_match, gtk_css_selector_descendant_tree_match,
gtk_css_selector_descendant_get_change, gtk_css_selector_descendant_get_change,
gtk_css_selector_descendant_tree_get_change, gtk_css_selector_descendant_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_descendant_hash_one, gtk_css_selector_descendant_hash_one,
gtk_css_selector_descendant_compare_one, gtk_css_selector_descendant_compare_one,
FALSE, FALSE, FALSE, FALSE FALSE
}; };
/* DESCENDANT FOR REGION */ /* DESCENDANT FOR REGION */
@ -475,9 +488,10 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT_FOR_REGION = {
gtk_css_selector_descendant_for_region_tree_match, gtk_css_selector_descendant_for_region_tree_match,
gtk_css_selector_descendant_for_region_get_change, gtk_css_selector_descendant_for_region_get_change,
gtk_css_selector_descendant_for_region_tree_get_change, gtk_css_selector_descendant_for_region_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_descendant_for_region_hash_one, gtk_css_selector_descendant_for_region_hash_one,
gtk_css_selector_descendant_for_region_compare_one, gtk_css_selector_descendant_for_region_compare_one,
FALSE, FALSE, FALSE, FALSE FALSE
}; };
/* CHILD */ /* CHILD */
@ -561,9 +575,10 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = {
gtk_css_selector_child_tree_match, gtk_css_selector_child_tree_match,
gtk_css_selector_child_get_change, gtk_css_selector_child_get_change,
gtk_css_selector_child_tree_get_change, gtk_css_selector_child_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_child_hash_one, gtk_css_selector_child_hash_one,
gtk_css_selector_child_compare_one, gtk_css_selector_child_compare_one,
FALSE, FALSE, FALSE, FALSE FALSE
}; };
/* SIBLING */ /* SIBLING */
@ -667,9 +682,10 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = {
gtk_css_selector_sibling_tree_match, gtk_css_selector_sibling_tree_match,
gtk_css_selector_sibling_get_change, gtk_css_selector_sibling_get_change,
gtk_css_selector_sibling_tree_get_change, gtk_css_selector_sibling_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_sibling_hash_one, gtk_css_selector_sibling_hash_one,
gtk_css_selector_sibling_compare_one, gtk_css_selector_sibling_compare_one,
FALSE, FALSE, FALSE, FALSE FALSE
}; };
/* ADJACENT */ /* ADJACENT */
@ -754,9 +770,10 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = {
gtk_css_selector_adjacent_tree_match, gtk_css_selector_adjacent_tree_match,
gtk_css_selector_adjacent_get_change, gtk_css_selector_adjacent_get_change,
gtk_css_selector_adjacent_tree_get_change, gtk_css_selector_adjacent_tree_get_change,
gtk_css_selector_default_add_specificity,
gtk_css_selector_adjacent_hash_one, gtk_css_selector_adjacent_hash_one,
gtk_css_selector_adjacent_compare_one, gtk_css_selector_adjacent_compare_one,
FALSE, FALSE, FALSE, FALSE FALSE
}; };
/* SIMPLE SELECTOR DEFINE */ /* SIMPLE SELECTOR DEFINE */
@ -860,6 +877,20 @@ gtk_css_selector_ ## n ## _get_change (const GtkCssSelector *selector, GtkCssCha
return previous_change | GTK_CSS_CHANGE_ ## c; \ return previous_change | GTK_CSS_CHANGE_ ## c; \
} \ } \
\ \
static void \
gtk_css_selector_ ## n ## _add_specificity (const GtkCssSelector *selector, \
guint *ids, \
guint *classes, \
guint *elements) \
{ \
if (increase_id_specificity) \
(*ids)++; \
if (increase_class_specificity) \
(*classes)++; \
if (increase_element_specificity) \
(*elements)++; \
} \
\
static const GtkCssSelectorClass GTK_CSS_SELECTOR_ ## c = { \ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ ## c = { \
G_STRINGIFY(n), \ G_STRINGIFY(n), \
gtk_css_selector_ ## n ## _print, \ gtk_css_selector_ ## n ## _print, \
@ -867,9 +898,9 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ ## c = { \
gtk_css_selector_ ## n ## _tree_match, \ gtk_css_selector_ ## n ## _tree_match, \
gtk_css_selector_ ## n ## _get_change, \ gtk_css_selector_ ## n ## _get_change, \
gtk_css_selector_ ## n ## _tree_get_change, \ gtk_css_selector_ ## n ## _tree_get_change, \
gtk_css_selector_ ## n ## _add_specificity, \
hash_func, \ hash_func, \
comp_func, \ comp_func, \
increase_id_specificity, increase_class_specificity, increase_element_specificity, \
TRUE \ TRUE \
};\ };\
\ \
@ -880,9 +911,9 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_NOT_ ## c = { \
gtk_css_selector_not_ ## n ## _tree_match, \ gtk_css_selector_not_ ## n ## _tree_match, \
gtk_css_selector_ ## n ## _get_change, \ gtk_css_selector_ ## n ## _get_change, \
gtk_css_selector_ ## n ## _tree_get_change, \ gtk_css_selector_ ## n ## _tree_get_change, \
gtk_css_selector_ ## n ## _add_specificity, \
hash_func, \ hash_func, \
comp_func, \ comp_func, \
increase_id_specificity, increase_class_specificity, increase_element_specificity, \
TRUE \ TRUE \
}; };
@ -1085,6 +1116,28 @@ gtk_css_selector_region_get_change (const GtkCssSelector *selector, GtkCssChange
return previous_change | GTK_CSS_CHANGE_REGION; return previous_change | GTK_CSS_CHANGE_REGION;
} }
static guint
count_bits (guint n)
{
guint result = 0;
for (result = 0; n != 0; result++)
n &= n - 1;
return result;
}
static void
gtk_css_selector_region_add_specificity (const GtkCssSelector *selector,
guint *ids,
guint *classes,
guint *elements)
{
(*elements)++;
(*classes) += count_bits (selector->region.flags);
}
static guint static guint
gtk_css_selector_region_hash_one (const GtkCssSelector *a) gtk_css_selector_region_hash_one (const GtkCssSelector *a)
{ {
@ -1111,9 +1164,10 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_REGION = {
gtk_css_selector_region_tree_match, gtk_css_selector_region_tree_match,
gtk_css_selector_region_get_change, gtk_css_selector_region_get_change,
gtk_css_selector_region_tree_get_change, gtk_css_selector_region_tree_get_change,
gtk_css_selector_region_add_specificity,
gtk_css_selector_region_hash_one, gtk_css_selector_region_hash_one,
gtk_css_selector_region_compare_one, gtk_css_selector_region_compare_one,
FALSE, FALSE, TRUE, TRUE TRUE
}; };
/* CLASS */ /* CLASS */
@ -1922,14 +1976,7 @@ _gtk_css_selector_get_specificity (const GtkCssSelector *selector,
{ {
for (; selector; selector = gtk_css_selector_previous (selector)) for (; selector; selector = gtk_css_selector_previous (selector))
{ {
const GtkCssSelectorClass *klass = selector->class; selector->class->add_specificity (selector, ids, classes, elements);
if (klass->increase_id_specificity)
(*ids)++;
if (klass->increase_class_specificity)
(*classes)++;
if (klass->increase_element_specificity)
(*elements)++;
} }
} }