diff options
author | Benjamin Otte <otte@redhat.com> | 2014-11-25 19:15:36 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2014-11-25 19:31:13 +0100 |
commit | 8a3a617475cbccbd3da934a2861d1400a8597076 (patch) | |
tree | ec2eea3a35955bfa5d4653039b32a0c3920229cd | |
parent | fd1eb92508c7d48b1ca150bfbbaa91fcf22b3d87 (diff) | |
download | gtk+-8a3a617475cbccbd3da934a2861d1400a8597076.tar.gz |
cssselector: Add initial support for :not()
:not() works for names, ids, classes and pseudoclasses based on states.
It does not yet work for positional pseudoclasses (like :last-child or
:even) as there is region madness going on with those.
-rw-r--r-- | gtk/gtkcssselector.c | 135 |
1 files changed, 123 insertions, 12 deletions
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c index f513ac9c1b..5704aa781f 100644 --- a/gtk/gtkcssselector.c +++ b/gtk/gtkcssselector.c @@ -595,6 +595,15 @@ gtk_css_selector_ ## n ## _print (const GtkCssSelector *selector, \ print_func (selector, string); \ } \ \ +static void \ +gtk_css_selector_not_ ## n ## _print (const GtkCssSelector *selector, \ + GString *string) \ +{ \ + g_string_append (string, ":not("); \ + print_func (selector, string); \ + g_string_append (string, ")"); \ +} \ +\ static gboolean \ gtk_css_selector_ ## n ## _match (const GtkCssSelector *selector, \ const GtkCssMatcher *matcher) \ @@ -605,6 +614,16 @@ gtk_css_selector_ ## n ## _match (const GtkCssSelector *selector, \ return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher); \ } \ \ +static gboolean \ +gtk_css_selector_not_ ## n ## _match (const GtkCssSelector *selector, \ + const GtkCssMatcher *matcher) \ +{ \ + if (match_func (selector, matcher)) \ + return FALSE; \ +\ + return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher); \ +} \ +\ static void \ gtk_css_selector_ ## n ## _tree_match (const GtkCssSelectorTree *tree, \ const GtkCssMatcher *matcher, \ @@ -618,6 +637,19 @@ gtk_css_selector_ ## n ## _tree_match (const GtkCssSelectorTree *tree, \ gtk_css_selector_tree_match_previous (tree, matcher, res); \ } \ \ +static void \ +gtk_css_selector_not_ ## n ## _tree_match (const GtkCssSelectorTree *tree, \ + const GtkCssMatcher *matcher, \ + GHashTable *res) \ +{ \ + if (match_func (&tree->selector, matcher)) \ + return; \ +\ + gtk_css_selector_tree_found_match (tree, res); \ +\ + gtk_css_selector_tree_match_previous (tree, matcher, res); \ +} \ +\ static GtkCssChange \ gtk_css_selector_ ## n ##_tree_get_change (const GtkCssSelectorTree *tree, \ const GtkCssMatcher *matcher) \ @@ -656,6 +688,18 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ ## c = { \ comp_func, \ increase_id_specificity, increase_class_specificity, increase_element_specificity, \ TRUE, FALSE \ +};\ +\ +static const GtkCssSelectorClass GTK_CSS_SELECTOR_NOT_ ## c = { \ + "not_" G_STRINGIFY(n), \ + gtk_css_selector_not_ ## n ## _print, \ + gtk_css_selector_not_ ## n ## _match, \ + gtk_css_selector_not_ ## n ## _tree_match, \ + gtk_css_selector_ ## n ## _get_change, \ + gtk_css_selector_ ## n ## _tree_get_change, \ + comp_func, \ + increase_id_specificity, increase_class_specificity, increase_element_specificity, \ + TRUE, FALSE \ }; /* ANY */ @@ -1505,7 +1549,9 @@ gtk_css_selector_new (const GtkCssSelectorClass *class, } static GtkCssSelector * -parse_selector_class (GtkCssParser *parser, GtkCssSelector *selector) +parse_selector_class (GtkCssParser *parser, + GtkCssSelector *selector, + gboolean negate) { char *name; @@ -1519,7 +1565,8 @@ parse_selector_class (GtkCssParser *parser, GtkCssSelector *selector) return NULL; } - selector = gtk_css_selector_new (>K_CSS_SELECTOR_CLASS, + selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_CLASS + : >K_CSS_SELECTOR_CLASS, selector, GUINT_TO_POINTER (g_quark_from_string (name))); @@ -1529,7 +1576,9 @@ parse_selector_class (GtkCssParser *parser, GtkCssSelector *selector) } static GtkCssSelector * -parse_selector_id (GtkCssParser *parser, GtkCssSelector *selector) +parse_selector_id (GtkCssParser *parser, + GtkCssSelector *selector, + gboolean negate) { char *name; @@ -1543,7 +1592,8 @@ parse_selector_id (GtkCssParser *parser, GtkCssSelector *selector) return NULL; } - selector = gtk_css_selector_new (>K_CSS_SELECTOR_ID, + selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_ID + : >K_CSS_SELECTOR_ID, selector, g_intern_string (name)); @@ -1555,10 +1605,19 @@ parse_selector_id (GtkCssParser *parser, GtkCssSelector *selector) static GtkCssSelector * parse_selector_pseudo_class_nth_child (GtkCssParser *parser, GtkCssSelector *selector, - PositionType type) + PositionType type, + gboolean negate) { int a, b; + if (negate) + { + _gtk_css_parser_error (parser, "position pseudoclases not yet supported for :not()"); + if (selector) + _gtk_css_selector_free (selector); + return NULL; + } + if (!_gtk_css_parser_try (parser, "(", TRUE)) { _gtk_css_parser_error (parser, "Missing opening bracket for pseudo-class"); @@ -1672,7 +1731,8 @@ parse_selector_pseudo_class_nth_child (GtkCssParser *parser, static GtkCssSelector * parse_selector_pseudo_class (GtkCssParser *parser, - GtkCssSelector *selector) + GtkCssSelector *selector, + gboolean negate) { static const struct { const char *name; @@ -1703,18 +1763,26 @@ parse_selector_pseudo_class (GtkCssParser *parser, guint i; if (_gtk_css_parser_try (parser, "nth-child", FALSE)) - return parse_selector_pseudo_class_nth_child (parser, selector, POSITION_FORWARD); + return parse_selector_pseudo_class_nth_child (parser, selector, POSITION_FORWARD, negate); else if (_gtk_css_parser_try (parser, "nth-last-child", FALSE)) - return parse_selector_pseudo_class_nth_child (parser, selector, POSITION_BACKWARD); + return parse_selector_pseudo_class_nth_child (parser, selector, POSITION_BACKWARD, negate); for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++) { 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 = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE + : >K_CSS_SELECTOR_PSEUDOCLASS_STATE, selector, GUINT_TO_POINTER (pseudo_classes[i].state_flag)); + else if (negate) + { + _gtk_css_parser_error (parser, "position pseudoclases not yet supported for :not()"); + if (selector) + _gtk_css_selector_free (selector); + return NULL; + } else selector = gtk_css_selector_new (>K_CSS_SELECTOR_PSEUDOCLASS_POSITION, selector, @@ -1757,6 +1825,47 @@ try_parse_name (GtkCssParser *parser, } static GtkCssSelector * +parse_selector_negation (GtkCssParser *parser, + GtkCssSelector *selector) +{ + char *name; + + name = _gtk_css_parser_try_ident (parser, FALSE); + if (name) + { + selector = gtk_css_selector_new (>K_CSS_SELECTOR_NOT_NAME, + selector, + get_type_reference (name)); + g_free (name); + } + else if (_gtk_css_parser_try (parser, "#", FALSE)) + selector = parse_selector_id (parser, selector, TRUE); + else if (_gtk_css_parser_try (parser, ".", FALSE)) + selector = parse_selector_class (parser, selector, TRUE); + else if (_gtk_css_parser_try (parser, ":", FALSE)) + selector = parse_selector_pseudo_class (parser, selector, TRUE); + else + { + _gtk_css_parser_error (parser, "Not a valid selector for :not()"); + if (selector) + _gtk_css_selector_free (selector); + return NULL; + } + + _gtk_css_parser_skip_whitespace (parser); + + if (!_gtk_css_parser_try (parser, ")", FALSE)) + { + _gtk_css_parser_error (parser, "Missing closing bracket for :not()"); + if (selector) + _gtk_css_selector_free (selector); + return NULL; + } + + return selector; +} + +static GtkCssSelector * parse_simple_selector (GtkCssParser *parser, GtkCssSelector *selector) { @@ -1766,11 +1875,13 @@ parse_simple_selector (GtkCssParser *parser, do { if (_gtk_css_parser_try (parser, "#", FALSE)) - selector = parse_selector_id (parser, selector); + selector = parse_selector_id (parser, selector, FALSE); else if (_gtk_css_parser_try (parser, ".", FALSE)) - selector = parse_selector_class (parser, selector); + selector = parse_selector_class (parser, selector, FALSE); + else if (_gtk_css_parser_try (parser, ":not(", TRUE)) + selector = parse_selector_negation (parser, selector); else if (_gtk_css_parser_try (parser, ":", FALSE)) - selector = parse_selector_pseudo_class (parser, selector); + selector = parse_selector_pseudo_class (parser, selector, FALSE); else if (gtk_css_selector_size (selector) == size) { _gtk_css_parser_error (parser, "Expected a valid selector"); |