[gtk/wip/matthiasc/css-values: 14/14] css: Faster matching for simple selectors
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/matthiasc/css-values: 14/14] css: Faster matching for simple selectors
- Date: Sun, 12 Jan 2020 20:04:59 +0000 (UTC)
commit 212c6b575b855be39bfeb00bd2124e41370d951c
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Jan 12 13:12:07 2020 -0500
css: Faster matching for simple selectors
Inline simple selectors for node matchers.
A bit ugly, but works.
gtk/gtkcssmatcher.c | 17 ++---
gtk/gtkcssmatcherprivate.h | 10 ++-
gtk/gtkcssselector.c | 163 ++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 172 insertions(+), 18 deletions(-)
---
diff --git a/gtk/gtkcssmatcher.c b/gtk/gtkcssmatcher.c
index 0fee1ea6c3..5424e0964b 100644
--- a/gtk/gtkcssmatcher.c
+++ b/gtk/gtkcssmatcher.c
@@ -160,14 +160,14 @@ gtk_css_matcher_widget_path_has_position (const GtkCssMatcher *matcher,
}
static const GtkCssMatcherClass GTK_CSS_MATCHER_WIDGET_PATH = {
+ GTK_CSS_MATCHER_TYPE_WIDGET_PATH,
gtk_css_matcher_widget_path_get_parent,
gtk_css_matcher_widget_path_get_previous,
gtk_css_matcher_widget_path_get_state,
gtk_css_matcher_widget_path_has_name,
gtk_css_matcher_widget_path_has_class,
gtk_css_matcher_widget_path_has_id,
- gtk_css_matcher_widget_path_has_position,
- FALSE
+ gtk_css_matcher_widget_path_has_position
};
gboolean
@@ -336,14 +336,14 @@ gtk_css_matcher_node_has_position (const GtkCssMatcher *matcher,
}
static const GtkCssMatcherClass GTK_CSS_MATCHER_NODE = {
+ GTK_CSS_MATCHER_TYPE_NODE,
gtk_css_matcher_node_get_parent,
gtk_css_matcher_node_get_previous,
gtk_css_matcher_node_get_state,
gtk_css_matcher_node_has_name,
gtk_css_matcher_node_has_class,
gtk_css_matcher_node_has_id,
- gtk_css_matcher_node_has_position,
- FALSE
+ gtk_css_matcher_node_has_position
};
void
@@ -421,14 +421,14 @@ gtk_css_matcher_any_has_position (const GtkCssMatcher *matcher,
}
static const GtkCssMatcherClass GTK_CSS_MATCHER_ANY = {
+ GTK_CSS_MATCHER_TYPE_ANY,
gtk_css_matcher_any_get_parent,
gtk_css_matcher_any_get_previous,
gtk_css_matcher_any_get_state,
gtk_css_matcher_any_has_name,
gtk_css_matcher_any_has_class,
gtk_css_matcher_any_has_id,
- gtk_css_matcher_any_has_position,
- TRUE
+ gtk_css_matcher_any_has_position
};
void
@@ -497,14 +497,14 @@ gtk_css_matcher_superset_has_position (const GtkCssMatcher *matcher,
}
static const GtkCssMatcherClass GTK_CSS_MATCHER_SUPERSET2 = {
+ 0,
gtk_css_matcher_superset_get_parent,
gtk_css_matcher_superset_get_previous,
gtk_css_matcher_superset_get_state,
gtk_css_matcher_superset_has_name,
gtk_css_matcher_superset_has_class,
gtk_css_matcher_superset_has_id,
- gtk_css_matcher_superset_has_position,
- FALSE
+ gtk_css_matcher_superset_has_position
};
void
@@ -517,6 +517,7 @@ _gtk_css_matcher_superset_init (GtkCssMatcher *matcher,
g_return_if_fail ((relevant & ~(GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_POSITION |
GTK_CSS_CHANGE_STATE)) == 0);
*klass = GTK_CSS_MATCHER_SUPERSET2;
+ klass->matcher_type = subset->klass->matcher_type;
if (relevant & GTK_CSS_CHANGE_CLASS)
klass->has_class = subset->klass->has_class;
diff --git a/gtk/gtkcssmatcherprivate.h b/gtk/gtkcssmatcherprivate.h
index 6f5e9d195c..0530d672c7 100644
--- a/gtk/gtkcssmatcherprivate.h
+++ b/gtk/gtkcssmatcherprivate.h
@@ -29,7 +29,14 @@ typedef struct _GtkCssMatcherSuperset GtkCssMatcherSuperset;
typedef struct _GtkCssMatcherWidgetPath GtkCssMatcherWidgetPath;
typedef struct _GtkCssMatcherClass GtkCssMatcherClass;
+typedef enum {
+ GTK_CSS_MATCHER_TYPE_WIDGET_PATH,
+ GTK_CSS_MATCHER_TYPE_NODE,
+ GTK_CSS_MATCHER_TYPE_ANY
+} GtkCssMatcherType;
+
struct _GtkCssMatcherClass {
+ GtkCssMatcherType matcher_type;
gboolean (* get_parent) (GtkCssMatcher *matcher,
const GtkCssMatcher *child);
gboolean (* get_previous) (GtkCssMatcher *matcher,
@@ -46,7 +53,6 @@ struct _GtkCssMatcherClass {
gboolean forward,
int a,
int b);
- gboolean is_any;
};
struct _GtkCssMatcherWidgetPath {
@@ -145,7 +151,7 @@ _gtk_css_matcher_has_position (const GtkCssMatcher *matcher,
static inline gboolean
_gtk_css_matcher_matches_any (const GtkCssMatcher *matcher)
{
- return matcher->klass->is_any;
+ return matcher->klass->matcher_type == GTK_CSS_MATCHER_TYPE_ANY;
}
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c
index 4e237c6af2..bacedf276f 100644
--- a/gtk/gtkcssselector.c
+++ b/gtk/gtkcssselector.c
@@ -1800,6 +1800,91 @@ gtk_css_selectors_skip_initial_selector (GtkCssSelector *selector, const GtkCssS
return (GtkCssSelector *)gtk_css_selector_previous (selector);
}
+static inline gboolean
+match_node_name (const GtkCssMatcher *matcher,
+ const char *name)
+{
+ return matcher->node.node_name == name;
+}
+
+static inline gboolean
+match_node_id (const GtkCssMatcher *matcher,
+ const char *id)
+{
+ return matcher->node.node_id == id;
+}
+
+static inline gboolean
+match_node_class (const GtkCssMatcher *matcher,
+ GQuark class_name)
+{
+ const GQuark *classes = matcher->node.classes;
+
+ switch (matcher->node.n_classes)
+ {
+ case 3:
+ if (classes[2] == class_name)
+ return TRUE;
+ G_GNUC_FALLTHROUGH;
+
+ case 2:
+ if (classes[1] == class_name)
+ return TRUE;
+ G_GNUC_FALLTHROUGH;
+
+ case 1:
+ if (classes[0] == class_name)
+ return TRUE;
+ G_GNUC_FALLTHROUGH;
+
+ case 0:
+ return FALSE;
+
+ default:
+ return gtk_css_node_has_class (matcher->node.node, class_name);
+ }
+
+ return FALSE;
+}
+
+static inline gboolean
+match_node_state (const GtkCssMatcher *matcher,
+ GtkStateFlags state)
+{
+ return (matcher->node.node_state & state) == state;
+}
+
+static inline gboolean
+gtk_css_selector_match_node (const GtkCssSelector *selector,
+ const GtkCssMatcher *matcher)
+{
+ if (selector->class == >K_CSS_SELECTOR_NAME)
+ return match_node_name (matcher, selector->name.name);
+
+ if (selector->class == >K_CSS_SELECTOR_CLASS)
+ return match_node_class (matcher, selector->style_class.style_class);
+
+ if (selector->class == >K_CSS_SELECTOR_PSEUDOCLASS_STATE)
+ return match_node_state (matcher, selector->state.state);
+
+ if (selector->class == >K_CSS_SELECTOR_ID)
+ return match_node_id (matcher, selector->id.name);
+
+ if (selector->class == >K_CSS_SELECTOR_NOT_NAME)
+ return !match_node_name (matcher, selector->name.name);
+
+ if (selector->class == >K_CSS_SELECTOR_NOT_CLASS)
+ return !match_node_class (matcher, selector->style_class.style_class);
+
+ if (selector->class == >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE)
+ return !match_node_state (matcher, selector->state.state);
+
+ if (selector->class == >K_CSS_SELECTOR_NOT_ID)
+ return !match_node_id (matcher, selector->id.name);
+
+ return gtk_css_selector_match (selector, matcher);
+}
+
static gboolean
gtk_css_selector_tree_match_foreach (const GtkCssSelector *selector,
const GtkCssMatcher *matcher,
@@ -1821,15 +1906,42 @@ gtk_css_selector_tree_match_foreach (const GtkCssSelector *selector,
return FALSE;
}
+static gboolean
+gtk_css_selector_tree_match_node_foreach (const GtkCssSelector *selector,
+ const GtkCssMatcher *matcher,
+ gpointer res)
+{
+ const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
+ const GtkCssSelectorTree *prev;
+
+ if (!gtk_css_selector_match_node (selector, matcher))
+ return FALSE;
+
+ 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))
+ gtk_css_selector_foreach (&prev->selector, matcher, gtk_css_selector_tree_match_node_foreach, res);
+
+ return FALSE;
+}
+
GPtrArray *
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
GPtrArray *array = NULL;
+ GtkCssSelectorForeachFunc func;
+
+ if (matcher->klass->matcher_type == GTK_CSS_MATCHER_TYPE_NODE)
+ func = gtk_css_selector_tree_match_node_foreach;
+ else
+ func = gtk_css_selector_tree_match_foreach;
for (; tree != NULL;
- tree = gtk_css_selector_tree_get_sibling (tree))
- gtk_css_selector_foreach (&tree->selector, matcher, gtk_css_selector_tree_match_foreach, &array);
+ tree = gtk_css_selector_tree_get_sibling (tree))
+ gtk_css_selector_foreach (&tree->selector, matcher, func, &array);
return array;
}
@@ -1865,13 +1977,14 @@ static GtkCssChange
gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
+ const GtkCssSelector *selector = &tree->selector;
GtkCssChange change = 0;
const GtkCssSelectorTree *prev;
- if (!gtk_css_selector_match (&tree->selector, matcher))
+ if (!gtk_css_selector_match (selector, matcher))
return 0;
- if (!tree->selector.class->is_simple)
+ if (!selector->class->is_simple)
return tree->change | GTK_CSS_CHANGE_GOT_MATCH;
for (prev = gtk_css_selector_tree_get_previous (tree);
@@ -1880,7 +1993,32 @@ gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
change |= gtk_css_selector_tree_get_change (prev, matcher);
if (change || gtk_css_selector_tree_get_matches (tree))
- change = tree->selector.class->get_change (&tree->selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) |
GTK_CSS_CHANGE_GOT_MATCH;
+ change = tree->selector.class->get_change (selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) |
GTK_CSS_CHANGE_GOT_MATCH;
+
+ return change;
+}
+
+static GtkCssChange
+gtk_css_selector_tree_get_change_node (const GtkCssSelectorTree *tree,
+ const GtkCssMatcher *matcher)
+{
+ const GtkCssSelector *selector = &tree->selector;
+ GtkCssChange change = 0;
+ const GtkCssSelectorTree *prev;
+
+ if (!gtk_css_selector_match_node (selector, matcher))
+ return 0;
+
+ if (!selector->class->is_simple)
+ return tree->change | GTK_CSS_CHANGE_GOT_MATCH;
+
+ for (prev = gtk_css_selector_tree_get_previous (tree);
+ prev != NULL;
+ prev = gtk_css_selector_tree_get_sibling (prev))
+ change |= gtk_css_selector_tree_get_change_node (prev, matcher);
+
+ if (change || gtk_css_selector_tree_get_matches (tree))
+ change = tree->selector.class->get_change (selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) |
GTK_CSS_CHANGE_GOT_MATCH;
return change;
}
@@ -1900,9 +2038,18 @@ _gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
change = 0;
/* no need to foreach here because we abort for non-simple selectors */
- for (; tree != NULL;
- tree = gtk_css_selector_tree_get_sibling (tree))
- change |= gtk_css_selector_tree_get_change (tree, matcher);
+ if (matcher->klass->matcher_type == GTK_CSS_MATCHER_TYPE_NODE)
+ {
+ for (; tree != NULL;
+ tree = gtk_css_selector_tree_get_sibling (tree))
+ change |= gtk_css_selector_tree_get_change_node (tree, matcher);
+ }
+ else
+ {
+ for (; tree != NULL;
+ tree = gtk_css_selector_tree_get_sibling (tree))
+ change |= gtk_css_selector_tree_get_change (tree, matcher);
+ }
/* Never return reserved bit set */
return change & ~GTK_CSS_CHANGE_RESERVED_BIT;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]