summaryrefslogtreecommitdiff
path: root/gtk/gtkcssselector.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2014-12-08 05:55:36 +0100
committerBenjamin Otte <otte@redhat.com>2014-12-10 03:49:40 +0100
commit528691f5b323c342c7075c335b1b2a7cfc410b63 (patch)
treecb3db35af38141537fa8508cf597813f66ff62e1 /gtk/gtkcssselector.c
parent8b3f25ab963c8b3b4af3dacea0a54455bbb07865 (diff)
downloadgtk+-528691f5b323c342c7075c335b1b2a7cfc410b63.tar.gz
cssselector: Introduce descendant matcher for regions
This is just a way to handle regions more conveniently. What this does is to change the descendant matcher into a maybe-descendant matcher whenever the current object we're parsing might be a region. Because "*" might also refer to a region and not just a new element. See testsuite/reftests/css-match-region-matches-star.ui for a testcase.
Diffstat (limited to 'gtk/gtkcssselector.c')
-rw-r--r--gtk/gtkcssselector.c165
1 files changed, 127 insertions, 38 deletions
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c
index c3d8afba63..3ae16c1792 100644
--- a/gtk/gtkcssselector.c
+++ b/gtk/gtkcssselector.c
@@ -366,6 +366,121 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
FALSE, FALSE, FALSE, FALSE, FALSE
};
+/* DESCENDANT FOR REGION */
+
+static void
+gtk_css_selector_descendant_for_region_print (const GtkCssSelector *selector,
+ GString *string)
+{
+ g_string_append_c (string, ' ');
+}
+
+static gboolean
+gtk_css_selector_descendant_for_region_match (const GtkCssSelector *selector,
+ const GtkCssMatcher *matcher)
+{
+ GtkCssMatcher ancestor;
+
+ if (_gtk_css_matcher_has_regions (matcher))
+ {
+ if (gtk_css_selector_match (gtk_css_selector_previous (selector), matcher))
+ return TRUE;
+ }
+
+ while (_gtk_css_matcher_get_parent (&ancestor, matcher))
+ {
+ matcher = &ancestor;
+
+ if (gtk_css_selector_match (gtk_css_selector_previous (selector), matcher))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_css_selector_descendant_for_region_tree_match (const GtkCssSelectorTree *tree,
+ const GtkCssMatcher *matcher,
+ GHashTable *res)
+{
+ GtkCssMatcher ancestor;
+
+ if (_gtk_css_matcher_has_regions (matcher))
+ gtk_css_selector_tree_match_previous (tree, matcher, res);
+
+ while (_gtk_css_matcher_get_parent (&ancestor, matcher))
+ {
+ matcher = &ancestor;
+
+ gtk_css_selector_tree_match_previous (tree, matcher, res);
+
+ /* any matchers are dangerous here, as we may loop forever, but
+ we can terminate now as all possible matches have already been added */
+ if (_gtk_css_matcher_matches_any (matcher))
+ break;
+ }
+}
+
+static GtkCssChange
+gtk_css_selector_descendant_for_region_tree_get_change (const GtkCssSelectorTree *tree,
+ const GtkCssMatcher *matcher)
+{
+ GtkCssMatcher ancestor;
+ GtkCssChange change, previous_change;
+
+ previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher);
+
+ change = 0;
+
+ while (_gtk_css_matcher_get_parent (&ancestor, matcher))
+ {
+ matcher = &ancestor;
+
+ previous_change |= _gtk_css_change_for_child (gtk_css_selector_tree_get_previous_change (tree, matcher));
+
+ /* any matchers are dangerous here, as we may loop forever, but
+ we can terminate now as all possible matches have already been added */
+ if (_gtk_css_matcher_matches_any (matcher))
+ break;
+ }
+
+ if (previous_change != 0)
+ change |= previous_change | GTK_CSS_CHANGE_GOT_MATCH;
+
+ return change;
+}
+
+static guint
+gtk_css_selector_descendant_for_region_hash_one (const GtkCssSelector *a)
+{
+ return 0;
+}
+
+static int
+gtk_css_selector_descendant_for_region_compare_one (const GtkCssSelector *a,
+ const GtkCssSelector *b)
+{
+ return 0;
+}
+
+static GtkCssChange
+gtk_css_selector_descendant_for_region_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
+{
+ return previous_change | _gtk_css_change_for_child (previous_change);
+}
+
+static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT_FOR_REGION = {
+ "descendant_for_region",
+ gtk_css_selector_descendant_for_region_print,
+ gtk_css_selector_descendant_for_region_match,
+ gtk_css_selector_descendant_for_region_tree_match,
+ gtk_css_selector_descendant_for_region_get_change,
+ gtk_css_selector_descendant_for_region_tree_get_change,
+ gtk_css_selector_descendant_for_region_hash_one,
+ gtk_css_selector_descendant_for_region_compare_one,
+ FALSE, FALSE, FALSE, FALSE, FALSE
+};
+
/* CHILD */
static void
@@ -785,17 +900,7 @@ static gboolean
gtk_css_selector_any_match (const GtkCssSelector *selector,
const GtkCssMatcher *matcher)
{
- const GtkCssSelector *previous = gtk_css_selector_previous (selector);
-
- if (previous &&
- previous->class == &GTK_CSS_SELECTOR_DESCENDANT &&
- _gtk_css_matcher_has_regions (matcher))
- {
- if (gtk_css_selector_match (gtk_css_selector_previous (previous), matcher))
- return TRUE;
- }
-
- return gtk_css_selector_match (previous, matcher);
+ return gtk_css_selector_match (gtk_css_selector_previous (selector), matcher);
}
static void
@@ -803,27 +908,15 @@ gtk_css_selector_any_tree_match (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher,
GHashTable *res)
{
- const GtkCssSelectorTree *prev;
-
gtk_css_selector_tree_found_match (tree, res);
- for (prev = gtk_css_selector_tree_get_previous (tree);
- prev != NULL;
- prev = gtk_css_selector_tree_get_sibling (prev))
- {
- if (prev->selector.class == &GTK_CSS_SELECTOR_DESCENDANT &&
- _gtk_css_matcher_has_regions (matcher))
- gtk_css_selector_tree_match_previous (prev, matcher, res);
-
- gtk_css_selector_tree_match (prev, matcher, res);
- }
+ gtk_css_selector_tree_match_previous (tree, matcher, res);
}
static GtkCssChange
gtk_css_selector_any_tree_get_change (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
- const GtkCssSelectorTree *prev;
GtkCssChange change, previous_change;
change = 0;
@@ -831,17 +924,7 @@ gtk_css_selector_any_tree_get_change (const GtkCssSelectorTree *tree,
if (tree->matches_offset != GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET)
change |= GTK_CSS_CHANGE_GOT_MATCH;
- previous_change = 0;
- for (prev = gtk_css_selector_tree_get_previous (tree);
- prev != NULL;
- prev = gtk_css_selector_tree_get_sibling (prev))
- {
- if (prev->selector.class == &GTK_CSS_SELECTOR_DESCENDANT &&
- _gtk_css_matcher_has_regions (matcher))
- previous_change |= gtk_css_selector_tree_get_previous_change (prev, matcher);
-
- previous_change |= gtk_css_selector_tree_get_change (prev, matcher);
- }
+ previous_change = gtk_css_selector_tree_get_previous_change (tree, matcher);
if (previous_change != 0)
change |= previous_change | GTK_CSS_CHANGE_GOT_MATCH;
@@ -849,7 +932,6 @@ gtk_css_selector_any_tree_get_change (const GtkCssSelectorTree *tree,
return change;
}
-
static GtkCssChange
gtk_css_selector_any_get_change (const GtkCssSelector *selector, GtkCssChange previous_change)
{
@@ -878,7 +960,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ANY = {
gtk_css_selector_any_tree_get_change,
gtk_css_selector_any_hash_one,
gtk_css_selector_any_compare_one,
- FALSE, FALSE, FALSE, TRUE, TRUE
+ FALSE, FALSE, FALSE, TRUE, FALSE
};
/* NONE */
@@ -940,7 +1022,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_NONE = {
gtk_css_selector_none_tree_get_change,
gtk_css_selector_none_hash_one,
gtk_css_selector_none_compare_one,
- FALSE, FALSE, FALSE, TRUE, TRUE
+ FALSE, FALSE, FALSE, TRUE, FALSE
};
/* NAME */
@@ -1855,6 +1937,13 @@ parse_simple_selector (GtkCssParser *parser,
_gtk_css_parser_skip_whitespace (parser);
+ /* This is the big region hack where we change the descendant matcher
+ * to a version that respects regions.
+ */
+ if (selector &&
+ selector[0].class == &GTK_CSS_SELECTOR_ANY && selector[1].class == &GTK_CSS_SELECTOR_DESCENDANT)
+ selector[1].class = &GTK_CSS_SELECTOR_DESCENDANT_FOR_REGION;
+
return selector;
}