From 67d0b8195d3659e1080b52457826c105b8200939 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 15 Feb 2012 15:42:00 +0100 Subject: [PATCH] css: Move selector parsing code into a custom function --- gtk/gtkcssprovider.c | 279 +----------------------------------- gtk/gtkcssselector.c | 269 ++++++++++++++++++++++++++++++++-- gtk/gtkcssselectorprivate.h | 14 +- 3 files changed, 264 insertions(+), 298 deletions(-) diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index 4811c01d9f..2da4073437 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -2075,283 +2075,6 @@ parse_at_keyword (GtkCssScanner *scanner) } } -static gboolean -parse_selector_class (GtkCssScanner *scanner, GArray *classes) -{ - GQuark qname; - char *name; - - name = _gtk_css_parser_try_name (scanner->parser, FALSE); - - if (name == NULL) - { - gtk_css_provider_error_literal (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Expected a valid name for class"); - return FALSE; - } - - qname = g_quark_from_string (name); - g_array_append_val (classes, qname); - g_free (name); - return TRUE; -} - -static gboolean -parse_selector_name (GtkCssScanner *scanner, GArray *names) -{ - GQuark qname; - char *name; - - name = _gtk_css_parser_try_name (scanner->parser, FALSE); - - if (name == NULL) - { - gtk_css_provider_error_literal (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Expected a valid name for id"); - return FALSE; - } - - qname = g_quark_from_string (name); - g_array_append_val (names, qname); - g_free (name); - return TRUE; -} - -static gboolean -parse_selector_pseudo_class (GtkCssScanner *scanner, - GtkRegionFlags *region_to_modify, - GtkStateFlags *state_to_modify) -{ - struct { - const char *name; - GtkRegionFlags region_flag; - GtkStateFlags state_flag; - } pseudo_classes[] = { - { "first-child", GTK_REGION_FIRST, 0 }, - { "last-child", GTK_REGION_LAST, 0 }, - { "only-child", GTK_REGION_ONLY, 0 }, - { "sorted", GTK_REGION_SORTED, 0 }, - { "active", 0, GTK_STATE_FLAG_ACTIVE }, - { "prelight", 0, GTK_STATE_FLAG_PRELIGHT }, - { "hover", 0, GTK_STATE_FLAG_PRELIGHT }, - { "selected", 0, GTK_STATE_FLAG_SELECTED }, - { "insensitive", 0, GTK_STATE_FLAG_INSENSITIVE }, - { "inconsistent", 0, GTK_STATE_FLAG_INCONSISTENT }, - { "focused", 0, GTK_STATE_FLAG_FOCUSED }, - { "focus", 0, GTK_STATE_FLAG_FOCUSED }, - { "backdrop", 0, GTK_STATE_FLAG_BACKDROP }, - { NULL, } - }, nth_child_classes[] = { - { "first", GTK_REGION_FIRST, 0 }, - { "last", GTK_REGION_LAST, 0 }, - { "even", GTK_REGION_EVEN, 0 }, - { "odd", GTK_REGION_ODD, 0 }, - { NULL, } - }, *classes; - guint i; - char *name; - - name = _gtk_css_parser_try_ident (scanner->parser, FALSE); - if (name == NULL) - { - gtk_css_provider_error_literal (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Missing name of pseudo-class"); - return FALSE; - } - - if (_gtk_css_parser_try (scanner->parser, "(", TRUE)) - { - char *function = name; - - name = _gtk_css_parser_try_ident (scanner->parser, TRUE); - if (!_gtk_css_parser_try (scanner->parser, ")", FALSE)) - { - gtk_css_provider_error_literal (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Missing closing bracket for pseudo-class"); - return FALSE; - } - - if (g_ascii_strcasecmp (function, "nth-child") != 0) - { - gtk_css_provider_error (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, - "Unknown pseudo-class '%s(%s)'", function, name ? name : ""); - g_free (function); - g_free (name); - return FALSE; - } - - g_free (function); - - if (name == NULL) - { - gtk_css_provider_error (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, - "nth-child() requires an argument"); - return FALSE; - } - - classes = nth_child_classes; - } - else - classes = pseudo_classes; - - for (i = 0; classes[i].name != NULL; i++) - { - if (g_ascii_strcasecmp (name, classes[i].name) == 0) - { - if ((*region_to_modify & classes[i].region_flag) || - (*state_to_modify & classes[i].state_flag)) - { - if (classes == nth_child_classes) - gtk_css_provider_error (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Duplicate pseudo-class 'nth-child(%s)'", name); - else - gtk_css_provider_error (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Duplicate pseudo-class '%s'", name); - } - *region_to_modify |= classes[i].region_flag; - *state_to_modify |= classes[i].state_flag; - - g_free (name); - return TRUE; - } - } - - if (classes == nth_child_classes) - gtk_css_provider_error (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, - "Unknown pseudo-class 'nth-child(%s)'", name); - else - gtk_css_provider_error (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, - "Unknown pseudo-class '%s'", name); - g_free (name); - return FALSE; -} - -static gboolean -parse_simple_selector (GtkCssScanner *scanner, - char **name, - GArray *ids, - GArray *classes, - GtkRegionFlags *pseudo_classes, - GtkStateFlags *state) -{ - gboolean parsed_something; - - *name = _gtk_css_parser_try_ident (scanner->parser, FALSE); - if (*name) - parsed_something = TRUE; - else - parsed_something = _gtk_css_parser_try (scanner->parser, "*", FALSE); - - do { - if (_gtk_css_parser_try (scanner->parser, "#", FALSE)) - { - if (!parse_selector_name (scanner, ids)) - return FALSE; - } - else if (_gtk_css_parser_try (scanner->parser, ".", FALSE)) - { - if (!parse_selector_class (scanner, classes)) - return FALSE; - } - else if (_gtk_css_parser_try (scanner->parser, ":", FALSE)) - { - if (!parse_selector_pseudo_class (scanner, pseudo_classes, state)) - return FALSE; - } - else if (!parsed_something) - { - gtk_css_provider_error_literal (scanner->provider, - scanner, - GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_SYNTAX, - "Expected a valid selector"); - return FALSE; - } - else - break; - - parsed_something = TRUE; - } - while (!_gtk_css_parser_is_eof (scanner->parser)); - - _gtk_css_parser_skip_whitespace (scanner->parser); - return TRUE; -} - -static GtkCssSelector * -parse_selector (GtkCssScanner *scanner) -{ - GtkCssSelector *selector = NULL; - - do { - char *name = NULL; - GArray *ids = g_array_new (TRUE, FALSE, sizeof (GQuark)); - GArray *classes = g_array_new (TRUE, FALSE, sizeof (GQuark)); - GtkRegionFlags pseudo_classes = 0; - GtkStateFlags state = 0; - GtkCssCombinator combine = GTK_CSS_COMBINE_DESCANDANT; - - if (selector) - { - if (_gtk_css_parser_try (scanner->parser, ">", TRUE)) - combine = GTK_CSS_COMBINE_CHILD; - } - - if (!parse_simple_selector (scanner, &name, ids, classes, &pseudo_classes, &state)) - { - g_array_free (ids, TRUE); - g_array_free (classes, TRUE); - if (selector) - _gtk_css_selector_free (selector); - return NULL; - } - - selector = _gtk_css_selector_new (selector, - combine, - name, - (GQuark *) g_array_free (ids, ids->len == 0), - (GQuark *) g_array_free (classes, classes->len == 0), - pseudo_classes, - state); - g_free (name); - } - while (!_gtk_css_parser_is_eof (scanner->parser) && - !_gtk_css_parser_begins_with (scanner->parser, ',') && - !_gtk_css_parser_begins_with (scanner->parser, '{')); - - return selector; -} - static GSList * parse_selector_list (GtkCssScanner *scanner) { @@ -2360,7 +2083,7 @@ parse_selector_list (GtkCssScanner *scanner) gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_SELECTOR); do { - GtkCssSelector *select = parse_selector (scanner); + GtkCssSelector *select = _gtk_css_selector_parse (scanner->parser); if (select == NULL) { diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c index d67880f500..71247c0cc3 100644 --- a/gtk/gtkcssselector.c +++ b/gtk/gtkcssselector.c @@ -19,8 +19,14 @@ #include "gtkcssselectorprivate.h" +#include "gtkcssprovider.h" #include "gtkstylecontextprivate.h" +typedef enum { + GTK_CSS_COMBINE_DESCANDANT, + GTK_CSS_COMBINE_CHILD +} GtkCssCombinator; + struct _GtkCssSelector { GtkCssSelector * previous; /* link to next element in selector or NULL if last */ @@ -33,14 +39,14 @@ struct _GtkCssSelector GtkStateFlags state; /* required state flags (currently not checked when matching) */ }; -GtkCssSelector * -_gtk_css_selector_new (GtkCssSelector *previous, - GtkCssCombinator combine, - const char * name, - GQuark * ids, - GQuark * classes, - GtkRegionFlags pseudo_classes, - GtkStateFlags state) +static GtkCssSelector * +gtk_css_selector_new (GtkCssSelector *previous, + GtkCssCombinator combine, + const char * name, + GQuark * ids, + GQuark * classes, + GtkRegionFlags pseudo_classes, + GtkStateFlags state) { GtkCssSelector *selector; @@ -57,6 +63,253 @@ _gtk_css_selector_new (GtkCssSelector *previous, return selector; } +static gboolean +parse_selector_class (GtkCssParser *parser, GArray *classes) +{ + GQuark qname; + char *name; + + name = _gtk_css_parser_try_name (parser, FALSE); + + if (name == NULL) + { + _gtk_css_parser_error (parser, "Expected a valid name for class"); + return FALSE; + } + + qname = g_quark_from_string (name); + g_array_append_val (classes, qname); + g_free (name); + return TRUE; +} + +static gboolean +parse_selector_name (GtkCssParser *parser, GArray *names) +{ + GQuark qname; + char *name; + + name = _gtk_css_parser_try_name (parser, FALSE); + + if (name == NULL) + { + _gtk_css_parser_error (parser, "Expected a valid name for id"); + return FALSE; + } + + qname = g_quark_from_string (name); + g_array_append_val (names, qname); + g_free (name); + return TRUE; +} + +static gboolean +parse_selector_pseudo_class (GtkCssParser *parser, + GtkRegionFlags *region_to_modify, + GtkStateFlags *state_to_modify) +{ + struct { + const char *name; + GtkRegionFlags region_flag; + GtkStateFlags state_flag; + } pseudo_classes[] = { + { "first-child", GTK_REGION_FIRST, 0 }, + { "last-child", GTK_REGION_LAST, 0 }, + { "only-child", GTK_REGION_ONLY, 0 }, + { "sorted", GTK_REGION_SORTED, 0 }, + { "active", 0, GTK_STATE_FLAG_ACTIVE }, + { "prelight", 0, GTK_STATE_FLAG_PRELIGHT }, + { "hover", 0, GTK_STATE_FLAG_PRELIGHT }, + { "selected", 0, GTK_STATE_FLAG_SELECTED }, + { "insensitive", 0, GTK_STATE_FLAG_INSENSITIVE }, + { "inconsistent", 0, GTK_STATE_FLAG_INCONSISTENT }, + { "focused", 0, GTK_STATE_FLAG_FOCUSED }, + { "focus", 0, GTK_STATE_FLAG_FOCUSED }, + { "backdrop", 0, GTK_STATE_FLAG_BACKDROP }, + { NULL, } + }, nth_child_classes[] = { + { "first", GTK_REGION_FIRST, 0 }, + { "last", GTK_REGION_LAST, 0 }, + { "even", GTK_REGION_EVEN, 0 }, + { "odd", GTK_REGION_ODD, 0 }, + { NULL, } + }, *classes; + guint i; + char *name; + GError *error; + + name = _gtk_css_parser_try_ident (parser, FALSE); + if (name == NULL) + { + _gtk_css_parser_error (parser, "Missing name of pseudo-class"); + return FALSE; + } + + if (_gtk_css_parser_try (parser, "(", TRUE)) + { + char *function = name; + + name = _gtk_css_parser_try_ident (parser, TRUE); + if (!_gtk_css_parser_try (parser, ")", FALSE)) + { + _gtk_css_parser_error (parser, "Missing closing bracket for pseudo-class"); + return FALSE; + } + + if (g_ascii_strcasecmp (function, "nth-child") != 0) + { + error = g_error_new (GTK_CSS_PROVIDER_ERROR, + GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, + "Unknown pseudo-class '%s(%s)'", function, name ? name : ""); + _gtk_css_parser_take_error (parser, error); + g_free (function); + g_free (name); + return FALSE; + } + + g_free (function); + + if (name == NULL) + { + error = g_error_new (GTK_CSS_PROVIDER_ERROR, + GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, + "Unknown pseudo-class 'nth-child(%s)'", name); + _gtk_css_parser_take_error (parser, error); + return FALSE; + } + + classes = nth_child_classes; + } + else + classes = pseudo_classes; + + for (i = 0; classes[i].name != NULL; i++) + { + if (g_ascii_strcasecmp (name, classes[i].name) == 0) + { + if ((*region_to_modify & classes[i].region_flag) || + (*state_to_modify & classes[i].state_flag)) + { + if (classes == nth_child_classes) + _gtk_css_parser_error (parser, "Duplicate pseudo-class 'nth-child(%s)'", name); + else + _gtk_css_parser_error (parser, "Duplicate pseudo-class '%s'", name); + } + *region_to_modify |= classes[i].region_flag; + *state_to_modify |= classes[i].state_flag; + + g_free (name); + return TRUE; + } + } + + if (classes == nth_child_classes) + error = g_error_new (GTK_CSS_PROVIDER_ERROR, + GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, + "Unknown pseudo-class 'nth-child(%s)'", name); + else + error = g_error_new (GTK_CSS_PROVIDER_ERROR, + GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE, + "Unknown pseudo-class '%s'", name); + + g_free (name); + _gtk_css_parser_take_error (parser, error); + + return FALSE; +} + +static gboolean +parse_simple_selector (GtkCssParser *parser, + char **name, + GArray *ids, + GArray *classes, + GtkRegionFlags *pseudo_classes, + GtkStateFlags *state) +{ + gboolean parsed_something; + + *name = _gtk_css_parser_try_ident (parser, FALSE); + if (*name) + parsed_something = TRUE; + else + parsed_something = _gtk_css_parser_try (parser, "*", FALSE); + + do { + if (_gtk_css_parser_try (parser, "#", FALSE)) + { + if (!parse_selector_name (parser, ids)) + return FALSE; + } + else if (_gtk_css_parser_try (parser, ".", FALSE)) + { + if (!parse_selector_class (parser, classes)) + return FALSE; + } + else if (_gtk_css_parser_try (parser, ":", FALSE)) + { + if (!parse_selector_pseudo_class (parser, pseudo_classes, state)) + return FALSE; + } + else if (!parsed_something) + { + _gtk_css_parser_error (parser, "Expected a valid selector"); + return FALSE; + } + else + break; + + parsed_something = TRUE; + } + while (!_gtk_css_parser_is_eof (parser)); + + _gtk_css_parser_skip_whitespace (parser); + return TRUE; +} + +GtkCssSelector * +_gtk_css_selector_parse (GtkCssParser *parser) +{ + GtkCssSelector *selector = NULL; + + do { + char *name = NULL; + GArray *ids = g_array_new (TRUE, FALSE, sizeof (GQuark)); + GArray *classes = g_array_new (TRUE, FALSE, sizeof (GQuark)); + GtkRegionFlags pseudo_classes = 0; + GtkStateFlags state = 0; + GtkCssCombinator combine = GTK_CSS_COMBINE_DESCANDANT; + + if (selector) + { + if (_gtk_css_parser_try (parser, ">", TRUE)) + combine = GTK_CSS_COMBINE_CHILD; + } + + if (!parse_simple_selector (parser, &name, ids, classes, &pseudo_classes, &state)) + { + g_array_free (ids, TRUE); + g_array_free (classes, TRUE); + if (selector) + _gtk_css_selector_free (selector); + return NULL; + } + + selector = gtk_css_selector_new (selector, + combine, + name, + (GQuark *) g_array_free (ids, ids->len == 0), + (GQuark *) g_array_free (classes, classes->len == 0), + pseudo_classes, + state); + g_free (name); + } + while (!_gtk_css_parser_is_eof (parser) && + !_gtk_css_parser_begins_with (parser, ',') && + !_gtk_css_parser_begins_with (parser, '{')); + + return selector; +} + void _gtk_css_selector_free (GtkCssSelector *selector) { diff --git a/gtk/gtkcssselectorprivate.h b/gtk/gtkcssselectorprivate.h index 860138132c..b74dfc5404 100644 --- a/gtk/gtkcssselectorprivate.h +++ b/gtk/gtkcssselectorprivate.h @@ -20,23 +20,13 @@ #include #include +#include "gtk/gtkcssparserprivate.h" G_BEGIN_DECLS -typedef enum { - GTK_CSS_COMBINE_DESCANDANT, - GTK_CSS_COMBINE_CHILD -} GtkCssCombinator; - typedef struct _GtkCssSelector GtkCssSelector; -GtkCssSelector * _gtk_css_selector_new (GtkCssSelector *previous, - GtkCssCombinator combine, - const char * name, - GQuark * ids, - GQuark * classes, - GtkRegionFlags pseudo_classes, - GtkStateFlags state); +GtkCssSelector * _gtk_css_selector_parse (GtkCssParser *parser); void _gtk_css_selector_free (GtkCssSelector *selector); char * _gtk_css_selector_to_string (const GtkCssSelector *selector);