Compare commits

...

22 Commits

Author SHA1 Message Date
Alexander Larsson
0542d5461f css: Make test pass
The new css tree may change the order of selectors (keeping the
same semantics). This affects how the selectors are printed later,
which causes some css parsing tests to not match the references.

Fortunately the order is consistent between runs given the same
css, so we just have to switch around the order in some of the
.ref.css files.
2012-11-30 14:18:39 +01:00
Alexander Larsson
28033a25dd css: Allocate the css tree in a single chunk
This gives us several advantages:

* Smaller struct on 64bit (32bit indexes vs 64bit pointers)
* Less overhead for allocation
* Less fragmentation
2012-11-29 22:21:23 +01:00
Alexander Larsson
536e38aef6 css: Fix leak of lists while building tree 2012-11-29 22:21:23 +01:00
Alexander Larsson
867f70586c css: Add accessor functions for traversing css tree
This will let us later change how the tree is stored
2012-11-29 22:21:23 +01:00
Alexander Larsson
8e461c2ecd css: Add const to _gtk_css_selector_tree_match_all arg 2012-11-29 22:21:23 +01:00
Alexander Larsson
e3930f2342 css: Don't keep around linear selectors
Now we use the selector tree everywhere, so there is no need to
keep around the linear selectors unless we're using them to
verify the tree correctness, so free them.
2012-11-29 22:21:23 +01:00
Alexander Larsson
24f5412b3d css: Remove gtk_css_ruleset_matches
This is only not needed anymore, and only the VERIFY_TREE code
should access ->selector.
2012-11-29 22:21:23 +01:00
Alexander Larsson
36200036db css: Use tree for gtk_css_provider_get_style_property 2012-11-29 22:21:23 +01:00
Alexander Larsson
67c62fff13 css: Implement ruleset_get_change() with the tree
We traverse the tree on the matches instead of using
the linear selectors.
2012-11-29 22:21:23 +01:00
Alexander Larsson
55f8bb5279 css: Ensure the tree built is always the same
We add some "artificial" ordering to the otherwise unordered
tree nodes. This means the tree will be the same every time for the
same input. This is good because e.g. tree order affects the
reordering of the simple selectors, which may affect how
css providers are printed, which need to be consistent for
the css tests to work.
2012-11-29 22:21:23 +01:00
Alexander Larsson
736d1bccf6 css: Use the tree to print css selectors 2012-11-29 22:21:23 +01:00
Alexander Larsson
ef1dbc7c36 css: Track the tree selector matches 2012-11-29 22:21:23 +01:00
Alexander Larsson
f11013e80a css: Fix type of GtkCssSelectorRuleSetInfo match
The old type was a leftover from a previous version.
2012-11-29 22:21:23 +01:00
Alexander Larsson
d40d532067 css: Track parent in the css tree nodes
This way we can reconstruct matched css rules
2012-11-29 22:21:22 +01:00
Alexander Larsson
64d8034164 css: Better tree match verification 2012-11-29 22:21:22 +01:00
Alexander Larsson
d9357402ed css: Fix up position with region tree matching
This was using the wrong result in case of a match (results from
the position, not the region. Also, the descendant checks were
wrong.
2012-11-29 22:21:22 +01:00
Alexander Larsson
6702974e32 css: Don't reorder some selectors when building selector tree
When building the tree we generally reorder the selectors inside
the same simple selector in order to pick a good first selector
to balance the tree better. However, some kinds of selectors
can't really be reordered, even thought they are simple.

This is since the matching code for some types handle
the existance of a directly preceeding selector differently:

 REGION and ANY selectors look for a DESCENDANT previous
 POSITION selector look for a REGION previous
2012-11-29 22:21:22 +01:00
Alexander Larsson
18536fc044 css: Fixed typo in PRINT_TREE debug code 2012-11-28 12:13:09 +01:00
Alexander Larsson
fa2f5eee64 css: Create and use a tree for css selector matching 2012-11-28 11:21:06 +01:00
Alexander Larsson
b70bac8b76 css: Add GtkCssSelectorTree creation and matching
From a set of GtkCssSelectors and the rulesets they match to
we create a large decision tree that lets us efficitently match
against all the rules and return the set of matched rulesets.

The tree is created such that at each level we pick the initial rule[1]
in all the considered selectors for that level and use put the
one that is in most selectors in the node. All selectors matching that
are put in the previous part of the tree.
2012-11-28 11:15:53 +01:00
Alexander Larsson
b786ccc6d9 css: Add _gtk_css_matcher_matches_any()
This returns true if the matcher matches *anything*. We need
to check this later, because such matchers are dangerous in loops
that iterate over all parents/siblings since such loops would not
terminate.
2012-11-28 11:07:52 +01:00
Alexander Larsson
af7c38c60c css: Track which selectors are "simple" 2012-11-27 10:50:59 +01:00
6 changed files with 1116 additions and 88 deletions

View File

@@ -185,6 +185,7 @@ static const GtkCssMatcherClass GTK_CSS_MATCHER_WIDGET_PATH = {
gtk_css_matcher_widget_path_has_regions,
gtk_css_matcher_widget_path_has_region,
gtk_css_matcher_widget_path_has_position,
FALSE
};
gboolean
@@ -288,6 +289,7 @@ static const GtkCssMatcherClass GTK_CSS_MATCHER_ANY = {
gtk_css_matcher_any_has_regions,
gtk_css_matcher_any_has_region,
gtk_css_matcher_any_has_position,
TRUE
};
void
@@ -406,6 +408,7 @@ static const GtkCssMatcherClass GTK_CSS_MATCHER_SUPERSET = {
gtk_css_matcher_superset_has_regions,
gtk_css_matcher_superset_has_region,
gtk_css_matcher_superset_has_position,
FALSE
};
void

View File

@@ -50,6 +50,7 @@ struct _GtkCssMatcherClass {
gboolean forward,
int a,
int b);
gboolean is_any;
};
struct _GtkCssMatcherWidgetPath {
@@ -146,6 +147,12 @@ _gtk_css_matcher_has_position (const GtkCssMatcher *matcher,
return matcher->klass->has_position (matcher, forward, a, b);
}
static inline gboolean
_gtk_css_matcher_matches_any (const GtkCssMatcher *matcher)
{
return matcher->klass->is_any;
}
G_END_DECLS

View File

@@ -986,6 +986,7 @@ struct _WidgetPropertyValue {
struct GtkCssRuleset
{
GtkCssSelector *selector;
GtkCssSelectorTree *selector_match;
WidgetPropertyValue *widget_style;
PropertyValue *styles;
GtkBitmask *set_styles;
@@ -1011,6 +1012,7 @@ struct _GtkCssProviderPrivate
GHashTable *keyframes;
GArray *rulesets;
GtkCssSelectorTree *tree;
GResource *resource;
};
@@ -1271,17 +1273,10 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
ruleset->styles[i].section = NULL;
}
static gboolean
gtk_css_ruleset_matches (GtkCssRuleset *ruleset,
const GtkCssMatcher *matcher)
{
return _gtk_css_selector_matches (ruleset->selector, matcher);
}
static GtkCssChange
gtk_css_ruleset_get_change (GtkCssRuleset *ruleset)
{
return _gtk_css_selector_get_change (ruleset->selector);
return _gtk_css_selector_tree_match_get_change (ruleset->selector_match);
}
static void
@@ -1409,6 +1404,43 @@ gtk_css_provider_init (GtkCssProvider *css_provider)
(GDestroyNotify) _gtk_css_value_unref);
}
static void
verify_tree_match_results (GtkCssProvider *provider,
const GtkCssMatcher *matcher,
GPtrArray *tree_rules)
{
#ifdef VERIFY_TREE
GtkCssProviderPrivate *priv = provider->priv;
GtkCssRuleset *ruleset;
gboolean should_match;
int i, j;
for (i = 0; i < priv->rulesets->len; i++)
{
gboolean found = FALSE;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
for (j = 0; j < tree_rules->len; j++)
{
if (ruleset == tree_rules->pdata[j])
{
found = TRUE;
break;
}
}
should_match = _gtk_css_selector_matches (ruleset->selector, matcher);
if (found != !!should_match)
{
g_error ("expected rule '%s' to %s, but it %s\n",
_gtk_css_selector_to_string (ruleset->selector),
should_match ? "match" : "not match",
found ? "matched" : "didn't match");
}
}
#endif
}
static gboolean
gtk_css_provider_get_style_property (GtkStyleProvider *provider,
GtkWidgetPath *path,
@@ -1419,6 +1451,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
GtkCssProviderPrivate *priv = css_provider->priv;
WidgetPropertyValue *val;
GPtrArray *tree_rules;
GtkCssMatcher matcher;
gboolean found = FALSE;
gchar *prop_name;
@@ -1427,22 +1460,20 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
if (!_gtk_css_matcher_init (&matcher, path, state))
return FALSE;
tree_rules = _gtk_css_selector_tree_match_all (priv->tree, &matcher);
verify_tree_match_results (css_provider, &matcher, tree_rules);
prop_name = g_strdup_printf ("-%s-%s",
g_type_name (pspec->owner_type),
pspec->name);
for (i = priv->rulesets->len - 1; i >= 0; i--)
for (i = tree_rules->len - 1; i >= 0; i--)
{
GtkCssRuleset *ruleset;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
GtkCssRuleset *ruleset = tree_rules->pdata[i];
if (ruleset->widget_style == NULL)
continue;
if (!gtk_css_ruleset_matches (ruleset, &matcher))
continue;
for (val = ruleset->widget_style; val != NULL; val = val->next)
{
if (strcmp (val->name, prop_name) == 0)
@@ -1469,6 +1500,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
}
g_free (prop_name);
g_ptr_array_free (tree_rules, TRUE);
return found;
}
@@ -1506,17 +1538,19 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
GtkCssProviderPrivate *priv;
GtkCssRuleset *ruleset;
guint j;
int i;
GPtrArray *tree_rules;
css_provider = GTK_CSS_PROVIDER (provider);
priv = css_provider->priv;
if (priv->rulesets->len == 0)
return;
tree_rules = _gtk_css_selector_tree_match_all (priv->tree, matcher);
verify_tree_match_results (css_provider, matcher, tree_rules);
for (ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, priv->rulesets->len - 1);
ruleset >= &g_array_index (priv->rulesets, GtkCssRuleset, 0);
ruleset--)
for (i = tree_rules->len - 1; i >= 0; i--)
{
ruleset = tree_rules->pdata[i];
if (ruleset->styles == NULL)
continue;
@@ -1524,9 +1558,6 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
ruleset->set_styles))
continue;
if (!gtk_css_ruleset_matches (ruleset, matcher))
continue;
for (j = 0; j < ruleset->n_styles; j++)
{
GtkCssStyleProperty *prop = ruleset->styles[j].property;
@@ -1544,6 +1575,8 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
if (_gtk_bitmask_is_empty (_gtk_css_lookup_get_missing (lookup)))
break;
}
g_ptr_array_free (tree_rules, TRUE);
}
static GtkCssChange
@@ -1553,26 +1586,29 @@ gtk_css_style_provider_get_change (GtkStyleProviderPrivate *provider,
GtkCssProvider *css_provider;
GtkCssProviderPrivate *priv;
GtkCssChange change = 0;
GPtrArray *tree_rules;
int i;
css_provider = GTK_CSS_PROVIDER (provider);
priv = css_provider->priv;
for (i = priv->rulesets->len - 1; i >= 0; i--)
tree_rules = _gtk_css_selector_tree_match_all (priv->tree, matcher);
verify_tree_match_results (css_provider, matcher, tree_rules);
for (i = tree_rules->len - 1; i >= 0; i--)
{
GtkCssRuleset *ruleset;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
ruleset = tree_rules->pdata[i];
if (ruleset->styles == NULL)
continue;
if (!gtk_css_ruleset_matches (ruleset, matcher))
continue;
change |= gtk_css_ruleset_get_change (ruleset);
}
g_ptr_array_free (tree_rules, TRUE);
return change;
}
@@ -1599,6 +1635,7 @@ gtk_css_provider_finalize (GObject *object)
gtk_css_ruleset_clear (&g_array_index (priv->rulesets, GtkCssRuleset, i));
g_array_free (priv->rulesets, TRUE);
_gtk_css_selector_tree_free (priv->tree);
g_hash_table_destroy (priv->symbolic_colors);
g_hash_table_destroy (priv->keyframes);
@@ -1736,6 +1773,9 @@ gtk_css_provider_reset (GtkCssProvider *css_provider)
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);
_gtk_css_selector_tree_free (priv->tree);
priv->tree = NULL;
}
static void
@@ -2370,8 +2410,38 @@ static void
gtk_css_provider_postprocess (GtkCssProvider *css_provider)
{
GtkCssProviderPrivate *priv = css_provider->priv;
GtkCssSelectorTreeBuilder *builder;
guint i;
g_array_sort (priv->rulesets, gtk_css_provider_compare_rule);
builder = _gtk_css_selector_tree_builder_new ();
for (i = 0; i < priv->rulesets->len; i++)
{
GtkCssRuleset *ruleset;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
_gtk_css_selector_tree_builder_add (builder,
ruleset->selector,
&ruleset->selector_match,
ruleset);
}
priv->tree = _gtk_css_selector_tree_builder_build (builder);
_gtk_css_selector_tree_builder_free (builder);
#ifndef VERIFY_TREE
for (i = 0; i < priv->rulesets->len; i++)
{
GtkCssRuleset *ruleset;
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
_gtk_css_selector_free (ruleset->selector);
ruleset->selector = NULL;
}
#endif
}
static gboolean
@@ -2820,7 +2890,7 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
WidgetPropertyValue *widget_value;
guint i;
_gtk_css_selector_print (ruleset->selector, str);
_gtk_css_selector_tree_match_print (ruleset->selector_match, str);
g_string_append (str, " {\n");

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,8 @@
G_BEGIN_DECLS
typedef struct _GtkCssSelector GtkCssSelector;
typedef struct _GtkCssSelectorTree GtkCssSelectorTree;
typedef struct _GtkCssSelectorTreeBuilder GtkCssSelectorTreeBuilder;
GtkCssSelector * _gtk_css_selector_parse (GtkCssParser *parser);
void _gtk_css_selector_free (GtkCssSelector *selector);
@@ -32,12 +34,27 @@ char * _gtk_css_selector_to_string (const GtkCssSelector *sel
void _gtk_css_selector_print (const GtkCssSelector *selector,
GString *str);
GtkCssChange _gtk_css_selector_get_change (const GtkCssSelector *selector);
gboolean _gtk_css_selector_matches (const GtkCssSelector *selector,
const GtkCssMatcher *matcher);
int _gtk_css_selector_compare (const GtkCssSelector *a,
const GtkCssSelector *b);
void _gtk_css_selector_tree_free (GtkCssSelectorTree *tree);
GPtrArray * _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher);
void _gtk_css_selector_tree_match_print (const GtkCssSelectorTree *tree,
GString *str);
GtkCssChange _gtk_css_selector_tree_match_get_change (const GtkCssSelectorTree *tree);
GtkCssSelectorTreeBuilder *_gtk_css_selector_tree_builder_new (void);
void _gtk_css_selector_tree_builder_add (GtkCssSelectorTreeBuilder *builder,
GtkCssSelector *selectors,
GtkCssSelectorTree **selector_match,
gpointer match);
GtkCssSelectorTree * _gtk_css_selector_tree_builder_build (GtkCssSelectorTreeBuilder *builder);
void _gtk_css_selector_tree_builder_free (GtkCssSelectorTreeBuilder *builder);
G_END_DECLS
#endif /* __GTK_CSS_SELECTOR_PRIVATE_H__ */

View File

@@ -262,7 +262,7 @@ a ~ :hover {
int-property: 42;
}
:hover.b {
.b:hover {
int-property: 42;
}
@@ -398,7 +398,7 @@ a ~ #b {
int-property: 42;
}
:hover#b {
#b:hover {
int-property: 42;
}