summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-04-09 04:47:00 +0200
committerBenjamin Otte <otte@redhat.com>2019-04-12 19:34:28 +0200
commite0a01ba1743cd147ee29ad11944f8204768dd5c1 (patch)
tree85b615330d4050cff811d2be9d2c0a6bb6a9059a
parent98e076b51ea05fae38d75514f0144b68ff4aabfd (diff)
downloadgtk+-e0a01ba1743cd147ee29ad11944f8204768dd5c1.tar.gz
css: Redo for new parser
This commit is still way too big, but I couldn't make it smaller. It transitions the old CSS parser to the new parser. CSS parsing is now tokenized, everything else is probably still buggy.
-rw-r--r--gtk/css/gtkcssparser.c44
-rw-r--r--gtk/css/gtkcssparserprivate.h2
-rw-r--r--gtk/gtkcsscalcvalue.c58
-rw-r--r--gtk/gtkcsscolorvalue.c298
-rw-r--r--gtk/gtkcssdimensionvalue.c113
-rw-r--r--gtk/gtkcssfontfeaturesvalue.c1
-rw-r--r--gtk/gtkcssfontvariationsvalue.c1
-rw-r--r--gtk/gtkcssimage.c3
-rw-r--r--gtk/gtkcsskeyframes.c58
-rw-r--r--gtk/gtkcssnumbervalue.c9
-rw-r--r--gtk/gtkcssparser.c1244
-rw-r--r--gtk/gtkcssparserprivate.h92
-rw-r--r--gtk/gtkcssprovider.c255
-rw-r--r--gtk/gtkcsssection.c33
-rw-r--r--gtk/gtkcssselector.c816
-rw-r--r--gtk/gtkcssshadowvalue.c3
16 files changed, 1011 insertions, 2019 deletions
diff --git a/gtk/css/gtkcssparser.c b/gtk/css/gtkcssparser.c
index e0bb5f8a8a..6f63393931 100644
--- a/gtk/css/gtkcssparser.c
+++ b/gtk/css/gtkcssparser.c
@@ -352,21 +352,13 @@ gtk_css_parser_end_block (GtkCssParser *self)
if (gtk_css_token_is (&self->token, GTK_CSS_TOKEN_EOF))
{
- gtk_css_parser_warn (self,
- GTK_CSS_PARSER_WARNING_SYNTAX,
- gtk_css_parser_get_block_location (self),
- gtk_css_parser_get_start_location (self),
- "Unterminated block at end of document");
+ gtk_css_parser_warn_syntax (self, "Unterminated block at end of document");
g_array_set_size (self->blocks, self->blocks->len - 1);
}
else if (gtk_css_token_is (&self->token, block->inherited_end_token))
{
g_assert (block->end_token == GTK_CSS_TOKEN_SEMICOLON);
- gtk_css_parser_warn (self,
- GTK_CSS_PARSER_WARNING_SYNTAX,
- gtk_css_parser_get_block_location (self),
- gtk_css_parser_get_start_location (self),
- "Expected ';' at end of block");
+ gtk_css_parser_warn_syntax (self, "Expected ';' at end of block");
g_array_set_size (self->blocks, self->blocks->len - 1);
}
else
@@ -434,15 +426,13 @@ gtk_css_parser_skip_until (GtkCssParser *self,
}
void
-gtk_css_parser_emit_error (GtkCssParser *self,
- const GError *error)
+gtk_css_parser_emit_error (GtkCssParser *self,
+ const GtkCssLocation *start,
+ const GtkCssLocation *end,
+ const GError *error)
{
if (self->error_func)
- self->error_func (self,
- &self->location,
- &self->location,
- error,
- self->user_data);
+ self->error_func (self, start, end, error, self->user_data);
}
void
@@ -457,7 +447,10 @@ gtk_css_parser_error_syntax (GtkCssParser *self,
error = g_error_new_valist (GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
format, args);
- gtk_css_parser_emit_error (self, error);
+ gtk_css_parser_emit_error (self,
+ &self->location,
+ gtk_css_tokenizer_get_location (self->tokenizer),
+ error);
g_error_free (error);
va_end (args);
}
@@ -474,7 +467,10 @@ gtk_css_parser_error_value (GtkCssParser *self,
error = g_error_new_valist (GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE,
format, args);
- gtk_css_parser_emit_error (self, error);
+ gtk_css_parser_emit_error (self,
+ &self->location,
+ gtk_css_tokenizer_get_location (self->tokenizer),
+ error);
g_error_free (error);
va_end (args);
}
@@ -491,7 +487,10 @@ gtk_css_parser_warn_syntax (GtkCssParser *self,
error = g_error_new_valist (GTK_CSS_PARSER_WARNING,
GTK_CSS_PARSER_WARNING_SYNTAX,
format, args);
- gtk_css_parser_emit_error (self, error);
+ gtk_css_parser_emit_error (self,
+ &self->location,
+ gtk_css_tokenizer_get_location (self->tokenizer),
+ error);
g_error_free (error);
va_end (args);
}
@@ -864,7 +863,10 @@ gtk_css_parser_consume_url (GtkCssParser *self)
GError *error = g_error_new (GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_IMPORT,
"Could not resolve \"%s\" to a valid URL", url);
- gtk_css_parser_emit_error (self, error);
+ gtk_css_parser_emit_error (self,
+ &self->location,
+ gtk_css_tokenizer_get_location (self->tokenizer),
+ error);
g_free (url);
g_error_free (error);
return NULL;
diff --git a/gtk/css/gtkcssparserprivate.h b/gtk/css/gtkcssparserprivate.h
index 9ae77e2e7e..f39d0025a3 100644
--- a/gtk/css/gtkcssparserprivate.h
+++ b/gtk/css/gtkcssparserprivate.h
@@ -82,6 +82,8 @@ void gtk_css_parser_skip_until (GtkCssParser
GtkCssTokenType token_type);
void gtk_css_parser_emit_error (GtkCssParser *self,
+ const GtkCssLocation *start,
+ const GtkCssLocation *end,
const GError *error);
void gtk_css_parser_error_syntax (GtkCssParser *self,
const char *format,
diff --git a/gtk/gtkcsscalcvalue.c b/gtk/gtkcsscalcvalue.c
index 129dd93c52..aed0326fb6 100644
--- a/gtk/gtkcsscalcvalue.c
+++ b/gtk/gtkcsscalcvalue.c
@@ -322,19 +322,24 @@ gtk_css_calc_value_parse_value (GtkCssParser *parser,
return NULL;
}
- if (_gtk_css_parser_try (parser, "(", TRUE))
+ if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_OPEN_PARENS))
{
- GtkCssValue *result = gtk_css_calc_value_parse_sum (parser, flags);
- if (result == NULL)
- return NULL;
+ GtkCssValue *result;
+
+ gtk_css_parser_start_block (parser);
- if (!_gtk_css_parser_try (parser, ")", TRUE))
+ result = gtk_css_calc_value_parse_sum (parser, flags);
+ if (result == NULL)
{
- _gtk_css_parser_error (parser, "Missing closing ')' in calc() subterm");
- _gtk_css_value_unref (result);
+ gtk_css_parser_end_block (parser);
return NULL;
}
+ if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ _gtk_css_parser_error (parser, "Expected closing ')' in calc() subterm");
+
+ gtk_css_parser_end_block (parser);
+
return result;
}
@@ -454,32 +459,45 @@ fail:
return NULL;
}
+typedef struct
+{
+ GtkCssNumberParseFlags flags;
+ GtkCssValue *value;
+} ParseCalcData;
+
+static guint
+gtk_css_calc_value_parse_arg (GtkCssParser *parser,
+ guint arg,
+ gpointer data_)
+{
+ ParseCalcData *data = data_;
+
+ data->value = gtk_css_calc_value_parse_sum (parser, data->flags);
+ if (data->value == NULL)
+ return 0;
+
+ return 1;
+}
+
GtkCssValue *
gtk_css_calc_value_parse (GtkCssParser *parser,
GtkCssNumberParseFlags flags)
{
- GtkCssValue *value;
+ ParseCalcData data;
/* This can only be handled at compute time, we allow '-' after all */
- flags &= ~GTK_CSS_POSITIVE_ONLY;
+ data.flags = flags & ~GTK_CSS_POSITIVE_ONLY;
+ data.value = NULL;
- if (!_gtk_css_parser_try (parser, "calc(", TRUE))
+ if (!gtk_css_parser_has_function (parser, "calc"))
{
_gtk_css_parser_error (parser, "Expected 'calc('");
return NULL;
}
- value = gtk_css_calc_value_parse_sum (parser, flags);
- if (value == NULL)
+ if (!gtk_css_parser_consume_function (parser, 1, 1, gtk_css_calc_value_parse_arg, &data))
return NULL;
- if (!_gtk_css_parser_try (parser, ")", TRUE))
- {
- _gtk_css_value_unref (value);
- _gtk_css_parser_error (parser, "Expected ')' after calc() statement");
- return NULL;
- }
-
- return value;
+ return data.value;
}
diff --git a/gtk/gtkcsscolorvalue.c b/gtk/gtkcsscolorvalue.c
index 0735d1e9f4..40b3159666 100644
--- a/gtk/gtkcsscolorvalue.c
+++ b/gtk/gtkcsscolorvalue.c
@@ -22,9 +22,10 @@
#include "gtkcssrgbavalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkhslaprivate.h"
+#include "gtkprivate.h"
#include "gtkstylepropertyprivate.h"
-#include "gtkprivate.h"
+#include "gdk/gdkrgbaprivate.h"
typedef enum {
COLOR_TYPE_LITERAL,
@@ -510,227 +511,144 @@ _gtk_css_color_value_new_current_color (void)
return _gtk_css_value_ref (&current_color);
}
-typedef enum {
- COLOR_RGBA,
- COLOR_RGB,
- COLOR_LIGHTER,
- COLOR_DARKER,
- COLOR_SHADE,
- COLOR_ALPHA,
- COLOR_MIX
-} ColorParseType;
-
-static GtkCssValue *
-_gtk_css_color_value_parse_function (GtkCssParser *parser,
- ColorParseType color)
+typedef struct
{
- GtkCssValue *value;
- GtkCssValue *child1, *child2;
- double d;
-
- if (!_gtk_css_parser_try (parser, "(", TRUE))
- {
- _gtk_css_parser_error (parser, "Missing opening bracket in color definition");
- return NULL;
- }
-
- if (color == COLOR_RGB || color == COLOR_RGBA)
- {
- GdkRGBA rgba;
- double tmp;
- guint i;
+ GtkCssValue *color;
+ GtkCssValue *color2;
+ double value;
+} ColorFunctionData;
+
+static guint
+parse_color_mix (GtkCssParser *parser,
+ guint arg,
+ gpointer data_)
+{
+ ColorFunctionData *data = data_;
- for (i = 0; i < 3; i++)
- {
- if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
- {
- _gtk_css_parser_error (parser, "Expected ',' in color definition");
- return NULL;
- }
-
- if (!gtk_css_parser_consume_number (parser, &tmp))
- return NULL;
-
- if (_gtk_css_parser_try (parser, "%", TRUE))
- tmp /= 100.0;
- else
- tmp /= 255.0;
- if (i == 0)
- rgba.red = tmp;
- else if (i == 1)
- rgba.green = tmp;
- else if (i == 2)
- rgba.blue = tmp;
- else
- g_assert_not_reached ();
- }
+ switch (arg)
+ {
+ case 0:
+ data->color = _gtk_css_color_value_parse (parser);
+ if (data->color == NULL)
+ return 0;
+ return 1;
+
+ case 1:
+ data->color2 = _gtk_css_color_value_parse (parser);
+ if (data->color2 == NULL)
+ return 0;
+ return 1;
+
+ case 2:
+ if (!gtk_css_parser_consume_number (parser, &data->value))
+ return 0;
+ return 1;
- if (color == COLOR_RGBA)
- {
- if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
- {
- _gtk_css_parser_error (parser, "Expected ',' in color definition");
- return NULL;
- }
-
- if (!gtk_css_parser_consume_number (parser, &rgba.alpha))
- return NULL;
- }
- else
- rgba.alpha = 1.0;
-
- value = _gtk_css_color_value_new_literal (&rgba);
- }
- else
- {
- child1 = _gtk_css_color_value_parse (parser);
- if (child1 == NULL)
- return NULL;
+ default:
+ g_return_val_if_reached (0);
+ }
+}
- if (color == COLOR_MIX)
- {
- if (!_gtk_css_parser_try (parser, ",", TRUE))
- {
- _gtk_css_parser_error (parser, "Expected ',' in color definition");
- _gtk_css_value_unref (child1);
- return NULL;
- }
-
- child2 = _gtk_css_color_value_parse (parser);
- if (child2 == NULL)
- {
- _gtk_css_value_unref (child1);
- return NULL;
- }
- }
- else
- child2 = NULL;
+static guint
+parse_color_number (GtkCssParser *parser,
+ guint arg,
+ gpointer data_)
+{
+ ColorFunctionData *data = data_;
- if (color == COLOR_LIGHTER)
- d = 1.3;
- else if (color == COLOR_DARKER)
- d = 0.7;
- else
- {
- if (!_gtk_css_parser_try (parser, ",", TRUE))
- {
- _gtk_css_parser_error (parser, "Expected ',' in color definition");
- _gtk_css_value_unref (child1);
- if (child2)
- _gtk_css_value_unref (child2);
- return NULL;
- }
-
- if (!gtk_css_parser_consume_number (parser, &d))
- {
- _gtk_css_value_unref (child1);
- if (child2)
- _gtk_css_value_unref (child2);
- return NULL;
- }
- }
-
- switch (color)
- {
- case COLOR_LIGHTER:
- case COLOR_DARKER:
- case COLOR_SHADE:
- value = _gtk_css_color_value_new_shade (child1, d);
- break;
- case COLOR_ALPHA:
- value = _gtk_css_color_value_new_alpha (child1, d);
- break;
- case COLOR_MIX:
- value = _gtk_css_color_value_new_mix (child1, child2, d);
- break;
- case COLOR_RGB:
- case COLOR_RGBA:
- default:
- g_assert_not_reached ();
- value = NULL;
- }
+ switch (arg)
+ {
+ case 0:
+ data->color = _gtk_css_color_value_parse (parser);
+ if (data->color == NULL)
+ return 0;
+ return 1;
- _gtk_css_value_unref (child1);
- if (child2)
- _gtk_css_value_unref (child2);
- }
+ case 1:
+ if (!gtk_css_parser_consume_number (parser, &data->value))
+ return 0;
+ return 1;
- if (!_gtk_css_parser_try (parser, ")", TRUE))
- {
- _gtk_css_parser_error (parser, "Expected ')' in color definition");
- _gtk_css_value_unref (value);
- return NULL;
- }
-
- return value;
+ default:
+ g_return_val_if_reached (0);
+ }
}
GtkCssValue *
_gtk_css_color_value_parse (GtkCssParser *parser)
{
+ ColorFunctionData data = { NULL, };
GtkCssValue *value;
GdkRGBA rgba;
- guint color;
- const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix"};
- char *name;
if (gtk_css_parser_try_ident (parser, "currentColor"))
- return _gtk_css_color_value_new_current_color ();
-
- if (gtk_css_parser_try_ident (parser, "transparent"))
{
- GdkRGBA transparent = { 0, 0, 0, 0 };
-
- return _gtk_css_color_value_new_literal (&transparent);
+ return _gtk_css_color_value_new_current_color ();
}
-
- if (_gtk_css_parser_try (parser, "@", FALSE))
+ else if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_AT_KEYWORD))
{
- name = _gtk_css_parser_try_name (parser, TRUE);
+ const GtkCssToken *token = gtk_css_parser_get_token (parser);
- if (name)
- {
- value = _gtk_css_color_value_new_name (name);
- }
- else
- {
- _gtk_css_parser_error (parser, "'%s' is not a valid color color name", name);
- value = NULL;
- }
+ value = _gtk_css_color_value_new_name (token->string.string);
+ gtk_css_parser_consume_token (parser);
- g_free (name);
return value;
}
-
- for (color = 0; color < G_N_ELEMENTS (names); color++)
+ else if (gtk_css_parser_has_function (parser, "lighter"))
{
- if (_gtk_css_parser_try (parser, names[color], TRUE))
- break;
+ if (gtk_css_parser_consume_function (parser, 1, 1, parse_color_number, &data))
+ value = _gtk_css_color_value_new_shade (data.color, 1.3);
+ else
+ value = NULL;
+
+ g_clear_pointer (&data.color, gtk_css_value_unref);
+ return value;
}
+ else if (gtk_css_parser_has_function (parser, "darker"))
+ {
+ if (gtk_css_parser_consume_function (parser, 1, 1, parse_color_number, &data))
+ value = _gtk_css_color_value_new_shade (data.color, 0.7);
+ else
+ value = NULL;
- if (color < G_N_ELEMENTS (names))
- return _gtk_css_color_value_parse_function (parser, color);
+ g_clear_pointer (&data.color, gtk_css_value_unref);
+ return value;
+ }
+ else if (gtk_css_parser_has_function (parser, "shade"))
+ {
+ if (gtk_css_parser_consume_function (parser, 2, 2, parse_color_number, &data))
+ value = _gtk_css_color_value_new_shade (data.color, data.value);
+ else
+ value = NULL;
- if (_gtk_css_parser_try_hash_color (parser, &rgba))
- return _gtk_css_color_value_new_literal (&rgba);
+ g_clear_pointer (&data.color, gtk_css_value_unref);
+ return value;
+ }
+ else if (gtk_css_parser_has_function (parser, "alpha"))
+ {
+ if (gtk_css_parser_consume_function (parser, 2, 2, parse_color_number, &data))
+ value = _gtk_css_color_value_new_alpha (data.color, data.value);
+ else
+ value = NULL;
- name = _gtk_css_parser_try_name (parser, TRUE);
- if (name)
+ g_clear_pointer (&data.color, gtk_css_value_unref);
+ return value;
+ }
+ else if (gtk_css_parser_has_function (parser, "mix"))
{
- if (gdk_rgba_parse (&rgba, name))
- {
- value = _gtk_css_color_value_new_literal (&rgba);
- }
+ if (gtk_css_parser_consume_function (parser, 3, 3, parse_color_mix, &data))
+ value = _gtk_css_color_value_new_mix (data.color, data.color2, data.value);
else
- {
- _gtk_css_parser_error (parser, "'%s' is not a valid color name", name);
- value = NULL;
- }
- g_free (name);
+ value = NULL;
+
+ g_clear_pointer (&data.color, gtk_css_value_unref);
+ g_clear_pointer (&data.color2, gtk_css_value_unref);
return value;
}
- _gtk_css_parser_error (parser, "Not a color definition");
- return NULL;
+ if (gdk_rgba_parser_parse (parser, &rgba))
+ return _gtk_css_color_value_new_literal (&rgba);
+ else
+ return NULL;
}
diff --git a/gtk/gtkcssdimensionvalue.c b/gtk/gtkcssdimensionvalue.c
index c9c378e0cf..feaaf9a991 100644
--- a/gtk/gtkcssdimensionvalue.c
+++ b/gtk/gtkcssdimensionvalue.c
@@ -325,3 +325,116 @@ gtk_css_dimension_value_new (double value,
return result;
}
+GtkCssValue *
+gtk_css_dimension_value_parse (GtkCssParser *parser,
+ GtkCssNumberParseFlags flags)
+{
+ static const struct {
+ const char *name;
+ GtkCssUnit unit;
+ GtkCssNumberParseFlags required_flags;
+ } units[] = {
+ { "px", GTK_CSS_PX, GTK_CSS_PARSE_LENGTH },
+ { "pt", GTK_CSS_PT, GTK_CSS_PARSE_LENGTH },
+ { "em", GTK_CSS_EM, GTK_CSS_PARSE_LENGTH },
+ { "ex", GTK_CSS_EX, GTK_CSS_PARSE_LENGTH },
+ { "rem", GTK_CSS_REM, GTK_CSS_PARSE_LENGTH },
+ { "pc", GTK_CSS_PC, GTK_CSS_PARSE_LENGTH },
+ { "in", GTK_CSS_IN, GTK_CSS_PARSE_LENGTH },
+ { "cm", GTK_CSS_CM, GTK_CSS_PARSE_LENGTH },
+ { "mm", GTK_CSS_MM, GTK_CSS_PARSE_LENGTH },
+ { "rad", GTK_CSS_RAD, GTK_CSS_PARSE_ANGLE },
+ { "deg", GTK_CSS_DEG, GTK_CSS_PARSE_ANGLE },
+ { "grad", GTK_CSS_GRAD, GTK_CSS_PARSE_ANGLE },
+ { "turn", GTK_CSS_TURN, GTK_CSS_PARSE_ANGLE },
+ { "s", GTK_CSS_S, GTK_CSS_PARSE_TIME },
+ { "ms", GTK_CSS_MS, GTK_CSS_PARSE_TIME }
+ };
+ const GtkCssToken *token;
+ GtkCssValue *result;
+ GtkCssUnit unit;
+ double number;
+
+ token = gtk_css_parser_get_token (parser);
+
+ /* Handle percentages first */
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
+ {
+ if (!(flags & GTK_CSS_PARSE_PERCENT))
+ {
+ gtk_css_parser_error_value (parser, "Percentages are not allowed here");
+ return NULL;
+ }
+ number = token->number.number;
+ unit = GTK_CSS_PERCENT;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER))
+ {
+ number = token->number.number;
+ if (number == 0.0)
+ {
+ if (flags & GTK_CSS_PARSE_NUMBER)
+ unit = GTK_CSS_NUMBER;
+ else if (flags & GTK_CSS_PARSE_LENGTH)
+ unit = GTK_CSS_PX;
+ else if (flags & GTK_CSS_PARSE_ANGLE)
+ unit = GTK_CSS_DEG;
+ else if (flags & GTK_CSS_PARSE_TIME)
+ unit = GTK_CSS_S;
+ else
+ unit = GTK_CSS_PERCENT;
+ }
+ else if (flags & GTK_CSS_PARSE_NUMBER)
+ {
+ unit = GTK_CSS_NUMBER;
+ }
+ else
+ {
+ gtk_css_parser_error_syntax (parser, "Unit is missing.");
+ return NULL;
+ }
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_DIMENSION))
+ {
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (units); i++)
+ {
+ if (flags & units[i].required_flags &&
+ g_ascii_strcasecmp (token->dimension.dimension, units[i].name) == 0)
+ break;
+ }
+
+ if (i >= G_N_ELEMENTS (units))
+ {
+ gtk_css_parser_error_syntax (parser, "'%s' is not a valid unit.", token->dimension.dimension);
+ return NULL;
+ }
+
+ unit = units[i].unit;
+ number = token->dimension.value;
+ }
+ else
+ {
+ gtk_css_parser_error_syntax (parser, "Expected a number");
+ return NULL;
+ }
+
+ if (flags & GTK_CSS_POSITIVE_ONLY &&
+ number < 0)
+ {
+ gtk_css_parser_error_value (parser, "negative values are not allowed.");
+ return NULL;
+ }
+
+ result = gtk_css_dimension_value_new (number, unit);
+ gtk_css_parser_consume_token (parser);
+
+ return result;
+}
+
diff --git a/gtk/gtkcssfontfeaturesvalue.c b/gtk/gtkcssfontfeaturesvalue.c
index 6f7c2894f0..5f7dce764b 100644
--- a/gtk/gtkcssfontfeaturesvalue.c
+++ b/gtk/gtkcssfontfeaturesvalue.c
@@ -236,7 +236,6 @@ gtk_css_font_features_value_parse (GtkCssParser *parser)
result = gtk_css_font_features_value_new_empty ();
do {
- _gtk_css_parser_skip_whitespace (parser);
name = gtk_css_parser_consume_string (parser);
if (name == NULL)
{
diff --git a/gtk/gtkcssfontvariationsvalue.c b/gtk/gtkcssfontvariationsvalue.c
index be3ab90e72..537ebb1d6e 100644
--- a/gtk/gtkcssfontvariationsvalue.c
+++ b/gtk/gtkcssfontvariationsvalue.c
@@ -234,7 +234,6 @@ gtk_css_font_variations_value_parse (GtkCssParser *parser)
result = gtk_css_font_variations_value_new_empty ();
do {
- _gtk_css_parser_skip_whitespace (parser);
name = gtk_css_parser_consume_string (parser);
if (name == NULL)
{
diff --git a/gtk/gtkcssimage.c b/gtk/gtkcssimage.c
index ac0eab182a..b1e6d3b6e0 100644
--- a/gtk/gtkcssimage.c
+++ b/gtk/gtkcssimage.c
@@ -513,6 +513,9 @@ gtk_css_image_get_parser_type (GtkCssParser *parser)
return image_types[i].type_func ();
}
+ if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_URL))
+ return _gtk_css_image_url_get_type ();
+
return G_TYPE_INVALID;
}
diff --git a/gtk/gtkcsskeyframes.c b/gtk/gtkcsskeyframes.c
index 891da2ea59..16d0e5efda 100644
--- a/gtk/gtkcsskeyframes.c
+++ b/gtk/gtkcsskeyframes.c
@@ -215,23 +215,19 @@ keyframes_set_value (GtkCssKeyframes *keyframes,
}
static gboolean
-parse_declaration (GtkCssKeyframes *keyframes,
- guint k,
- GtkCssParser *parser)
+gtk_css_keyframes_parse_declaration (GtkCssKeyframes *keyframes,
+ guint k,
+ GtkCssParser *parser)
{
GtkStyleProperty *property;
GtkCssValue *value;
char *name;
- while (_gtk_css_parser_try (parser, ";", TRUE))
- {
- /* SKIP ALL THE THINGS! */
- }
-
- name = _gtk_css_parser_try_ident (parser, TRUE);
+ name = gtk_css_parser_consume_ident (parser);
if (name == NULL)
{
- _gtk_css_parser_error (parser, "No property name given");
+ if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ gtk_css_parser_error_syntax (parser, "Expected a property name");
return FALSE;
}
@@ -246,7 +242,7 @@ parse_declaration (GtkCssKeyframes *keyframes,
g_free (name);
- if (!_gtk_css_parser_try (parser, ":", TRUE))
+ if (!gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COLON))
{
_gtk_css_parser_error (parser, "Expected a ':'");
return FALSE;
@@ -256,8 +252,7 @@ parse_declaration (GtkCssKeyframes *keyframes,
if (value == NULL)
return FALSE;
- if (!_gtk_css_parser_try (parser, ";", TRUE) &&
- !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_CLOSE_CURLY))
+ if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
{
_gtk_css_parser_error (parser, "Junk at end of value");
_gtk_css_value_unref (value);
@@ -297,28 +292,27 @@ parse_declaration (GtkCssKeyframes *keyframes,
}
static gboolean
-parse_block (GtkCssKeyframes *keyframes,
- guint k,
- GtkCssParser *parser)
+gtk_css_keyframes_parse_block (GtkCssKeyframes *keyframes,
+ guint k,
+ GtkCssParser *parser)
{
- if (!_gtk_css_parser_try (parser, "{", TRUE))
+ if (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_OPEN_CURLY))
{
- _gtk_css_parser_error (parser, "Expected closing bracket after keyframes block");
+ gtk_css_parser_error_syntax (parser, "Expected '{'");
return FALSE;
}
- while (!_gtk_css_parser_try (parser, "}", TRUE))
- {
- if (!parse_declaration (keyframes, k, parser))
- _gtk_css_parser_resync (parser, TRUE, '}');
+ gtk_css_parser_start_block (parser);
- if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
- {
- _gtk_css_parser_error (parser, "Expected closing '}' after keyframes block");
- return FALSE;
- }
+ while (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
+ {
+ gtk_css_parser_start_semicolon_block (parser, GTK_CSS_TOKEN_EOF);
+ gtk_css_keyframes_parse_declaration (keyframes, k, parser);
+ gtk_css_parser_end_block (parser);
}
+ gtk_css_parser_end_block (parser);
+
return TRUE;
}
@@ -333,19 +327,18 @@ _gtk_css_keyframes_parse (GtkCssParser *parser)
keyframes = gtk_css_keyframes_new ();
- while (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_CLOSE_CURLY))
+ while (!gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF))
{
if (gtk_css_parser_try_ident (parser, "from"))
progress = 0;
else if (gtk_css_parser_try_ident (parser, "to"))
progress = 1;
- else if (gtk_css_parser_consume_number (parser, &progress) &&
- _gtk_css_parser_try (parser, "%", TRUE))
+ else if (gtk_css_parser_consume_percentage (parser, &progress))
{
if (progress < 0 || progress > 100)
{
/* XXX: should we skip over the block here? */
- _gtk_css_parser_error (parser, "percentages must be between 0%% and 100%%");
+ gtk_css_parser_error_value (parser, "percentages must be between 0%% and 100%%");
_gtk_css_keyframes_unref (keyframes);
return NULL;
}
@@ -353,14 +346,13 @@ _gtk_css_keyframes_parse (GtkCssParser *parser)
}
else
{
- _gtk_css_parser_error (parser, "expected a percentage");
_gtk_css_keyframes_unref (keyframes);
return NULL;
}
k = gtk_css_keyframes_add_keyframe (keyframes, progress);
- if (!parse_block (keyframes, k, parser))
+ if (!gtk_css_keyframes_parse_block (keyframes, k, parser))
{
_gtk_css_keyframes_unref (keyframes);
return NULL;
diff --git a/gtk/gtkcssnumbervalue.c b/gtk/gtkcssnumbervalue.c
index 6b742c42e1..e8543bea28 100644
--- a/gtk/gtkcssnumbervalue.c
+++ b/gtk/gtkcssnumbervalue.c
@@ -129,7 +129,14 @@ gtk_css_number_value_transition (GtkCssValue *start,
gboolean
gtk_css_number_value_can_parse (GtkCssParser *parser)
{
- return _gtk_css_parser_has_number (parser)
+ return gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNED_NUMBER)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNLESS_NUMBER)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNED_INTEGER)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNLESS_INTEGER)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_PERCENTAGE)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)
+ || gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_DIMENSION)
|| gtk_css_parser_has_function (parser, "calc");
}
diff --git a/gtk/gtkcssparser.c b/gtk/gtkcssparser.c
index 502f2ec794..46b8a9786b 100644
--- a/gtk/gtkcssparser.c
+++ b/gtk/gtkcssparser.c
@@ -19,1159 +19,23 @@
#include "gtkcssparserprivate.h"
-#include "gtkcssdimensionvalueprivate.h"
-
-#include <errno.h>
-#include <string.h>
-
-/* just for the errors, yay! */
-#include "gtkcssprovider.h"
-
-#define NEWLINE_CHARS "\r\n"
-#define WHITESPACE_CHARS "\f \t"
-#define NMSTART "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-#define NMCHAR NMSTART "01234567890-_"
-#define URLCHAR NMCHAR "!#$%&*~"
-
-#define GTK_IS_CSS_PARSER(parser) ((parser) != NULL)
-
-struct _GtkCssParser
-{
- const char *data;
- GFile *file;
- GtkCssParserErrorFunc error_func;
- gpointer user_data;
-
- const char *line_start;
- guint line;
-
- /* Use this for parsing identifiers, names and strings. */
- GString *ident_str;
-};
-
-GtkCssParser *
-_gtk_css_parser_new (const char *data,
- GFile *file,
- GtkCssParserErrorFunc error_func,
- gpointer user_data)
-{
- GtkCssParser *parser;
-
- g_return_val_if_fail (data != NULL, NULL);
- g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
-
- parser = g_slice_new0 (GtkCssParser);
-
- parser->data = data;
- if (file)
- parser->file = g_object_ref (file);
- parser->error_func = error_func;
- parser->user_data = user_data;
-
- parser->line_start = data;
- parser->line = 0;
-
- parser->ident_str = NULL;
-
- return parser;
-}
-
-void
-_gtk_css_parser_free (GtkCssParser *parser)
-{
- g_return_if_fail (GTK_IS_CSS_PARSER (parser));
-
- if (parser->file)
- g_object_unref (parser->file);
-
- if (parser->ident_str)
- g_string_free (parser->ident_str, TRUE);
-
- g_slice_free (GtkCssParser, parser);
-}
-
-guint
-_gtk_css_parser_get_line (GtkCssParser *parser)
-{
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), 1);
-
- return parser->line;
-}
-
-guint
-_gtk_css_parser_get_position (GtkCssParser *parser)
-{
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), 1);
-
- return parser->data - parser->line_start;
-}
-
-static GFile *
-gtk_css_parser_get_base_file (GtkCssParser *parser)
-{
- GFile *base;
-
- if (parser->file)
- {
- base = g_file_get_parent (parser->file);
- }
- else
- {
- char *dir = g_get_current_dir ();
- base = g_file_new_for_path (dir);
- g_free (dir);
- }
-
- return base;
-}
-
-GFile *
-gtk_css_parser_resolve_url (GtkCssParser *parser,
- const char *url)
-{
- GFile *base, *file;
- char *scheme;
-
- g_return_val_if_fail (parser != NULL, NULL);
- g_return_val_if_fail (url != NULL, NULL);
-
- scheme = g_uri_parse_scheme (url);
- if (scheme != NULL)
- {
- file = g_file_new_for_uri (url);
- g_free (scheme);
- return file;
- }
- g_free (scheme);
-
- base = gtk_css_parser_get_base_file (parser);
- file = g_file_resolve_relative_path (base, url);
- g_object_unref (base);
-
- return file;
-}
-
-GFile *
-_gtk_css_parser_get_file (GtkCssParser *parser)
-{
- g_return_val_if_fail (parser != NULL, NULL);
-
- return parser->file;
-}
-
-void
-_gtk_css_parser_take_error (GtkCssParser *parser,
- GError *error)
-{
- parser->error_func (parser, error, parser->user_data);
-
- g_error_free (error);
-}
-
void
_gtk_css_parser_error (GtkCssParser *parser,
const char *format,
...)
{
- GError *error;
-
+ GtkCssLocation location;
va_list args;
+ GError *error;
+ gtk_css_parser_get_location (parser, &location);
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PARSER_ERROR,
- GTK_CSS_PARSER_ERROR_SYNTAX,
+ GTK_CSS_PARSER_ERROR_FAILED,
format, args);
+ gtk_css_parser_emit_error (parser, &location, &location, error);
+ g_error_free (error);
va_end (args);
-
- _gtk_css_parser_take_error (parser, error);
-}
-
-static gboolean
-gtk_css_parser_new_line (GtkCssParser *parser)
-{
- gboolean result = FALSE;
-
- if (*parser->data == '\r')
- {
- result = TRUE;
- parser->data++;
- }
- if (*parser->data == '\n')
- {
- result = TRUE;
- parser->data++;
- }
-
- if (result)
- {
- parser->line++;
- parser->line_start = parser->data;
- }
-
- return result;
-}
-
-static gboolean
-gtk_css_parser_skip_comment (GtkCssParser *parser)
-{
- if (parser->data[0] != '/' ||
- parser->data[1] != '*')
- return FALSE;
-
- parser->data += 2;
-
- while (*parser->data)
- {
- gsize len = strcspn (parser->data, NEWLINE_CHARS "/");
-
- parser->data += len;
-
- if (gtk_css_parser_new_line (parser))
- continue;
-
- parser->data++;
-
- if (len > 0 && parser->data[-2] == '*')
- return TRUE;
- if (parser->data[0] == '*')
- _gtk_css_parser_error (parser, "'/*' in comment block");
- }
-
- /* FIXME: position */
- _gtk_css_parser_error (parser, "Unterminated comment");
- return TRUE;
-}
-
-void
-_gtk_css_parser_skip_whitespace (GtkCssParser *parser)
-{
- size_t len;
-
- while (*parser->data)
- {
- if (gtk_css_parser_new_line (parser))
- continue;
-
- len = strspn (parser->data, WHITESPACE_CHARS);
- if (len)
- {
- parser->data += len;
- continue;
- }
-
- if (!gtk_css_parser_skip_comment (parser))
- break;
- }
-}
-
-gboolean
-_gtk_css_parser_try (GtkCssParser *parser,
- const char *string,
- gboolean skip_whitespace)
-{
- gsize string_len;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
- g_return_val_if_fail (string != NULL, FALSE);
-
- string_len = strlen (string);
-
- if (g_ascii_strncasecmp (parser->data, string, string_len) != 0)
- return FALSE;
-
- parser->data += string_len;
-
- if (skip_whitespace)
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-}
-
-gboolean
-gtk_css_parser_try_at_keyword (GtkCssParser *parser,
- const char *keyword)
-{
- gsize len;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
- g_return_val_if_fail (keyword != NULL, FALSE);
-
- len = strlen (keyword);
-
- if (parser->data[0] != '@' ||
- g_ascii_strncasecmp (&parser->data[1], keyword, len) != 0)
- return FALSE;
-
- parser->data += len + 1;
-
- _gtk_css_parser_skip_whitespace (parser);
-
- return TRUE;
-}
-
-gboolean
-gtk_css_parser_try_ident (GtkCssParser *parser,
- const char *ident)
-{
- gsize len;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
- g_return_val_if_fail (ident != NULL, FALSE);
-
- len = strlen (ident);
-
- if (g_ascii_strncasecmp (parser->data, ident, len) != 0 ||
- parser->data[len] == '(')
- return FALSE;
-
- parser->data += len;
-
- _gtk_css_parser_skip_whitespace (parser);
-
- return TRUE;
-}
-
-gboolean
-gtk_css_parser_try_delim (GtkCssParser *parser,
- gunichar delim)
-{
- if (*parser->data != delim)
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-}
-
-gboolean
-gtk_css_parser_try_token (GtkCssParser *parser,
- GtkCssTokenType type)
-{
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
-
- switch (type)
- {
- case GTK_CSS_TOKEN_OPEN_CURLY:
- if (*parser->data != '{')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- case GTK_CSS_TOKEN_CLOSE_CURLY:
- if (*parser->data != '}')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- case GTK_CSS_TOKEN_OPEN_PARENS:
- if (*parser->data != '(')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- case GTK_CSS_TOKEN_CLOSE_PARENS:
- if (*parser->data != ')')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- case GTK_CSS_TOKEN_COMMA:
- if (*parser->data != ',')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- case GTK_CSS_TOKEN_COLON:
- if (*parser->data != ':')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- case GTK_CSS_TOKEN_SEMICOLON:
- if (*parser->data != ';')
- return FALSE;
- parser->data += 1;
- _gtk_css_parser_skip_whitespace (parser);
- return TRUE;
-
- default:
- case GTK_CSS_TOKEN_STRING:
- case GTK_CSS_TOKEN_AT_KEYWORD:
- case GTK_CSS_TOKEN_IDENT:
- case GTK_CSS_TOKEN_FUNCTION:
- case GTK_CSS_TOKEN_HASH_UNRESTRICTED:
- case GTK_CSS_TOKEN_HASH_ID:
- case GTK_CSS_TOKEN_URL:
- case GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION:
- case GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION:
- case GTK_CSS_TOKEN_DIMENSION:
- case GTK_CSS_TOKEN_EOF:
- case GTK_CSS_TOKEN_WHITESPACE:
- case GTK_CSS_TOKEN_OPEN_SQUARE:
- case GTK_CSS_TOKEN_CLOSE_SQUARE:
- case GTK_CSS_TOKEN_CDC:
- case GTK_CSS_TOKEN_CDO:
- case GTK_CSS_TOKEN_DELIM:
- case GTK_CSS_TOKEN_SIGNED_INTEGER:
- case GTK_CSS_TOKEN_SIGNLESS_INTEGER:
- case GTK_CSS_TOKEN_SIGNED_NUMBER:
- case GTK_CSS_TOKEN_SIGNLESS_NUMBER:
- case GTK_CSS_TOKEN_PERCENTAGE:
- case GTK_CSS_TOKEN_INCLUDE_MATCH:
- case GTK_CSS_TOKEN_DASH_MATCH:
- case GTK_CSS_TOKEN_PREFIX_MATCH:
- case GTK_CSS_TOKEN_SUFFIX_MATCH:
- case GTK_CSS_TOKEN_SUBSTRING_MATCH:
- case GTK_CSS_TOKEN_COLUMN:
- case GTK_CSS_TOKEN_BAD_STRING:
- case GTK_CSS_TOKEN_BAD_URL:
- case GTK_CSS_TOKEN_COMMENT:
- g_assert_not_reached ();
- return FALSE;
- }
-}
-
-static guint
-get_xdigit (char c)
-{
- if (c >= 'a')
- return c - 'a' + 10;
- else if (c >= 'A')
- return c - 'A' + 10;
- else
- return c - '0';
-}
-
-static void
-_gtk_css_parser_unescape (GtkCssParser *parser,
- GString *str)
-{
- guint i;
- gunichar result = 0;
-
- g_assert (*parser->data == '\\');
-
- parser->data++;
-
- for (i = 0; i < 6; i++)
- {
- if (!g_ascii_isxdigit (parser->data[i]))
- break;
-
- result = (result << 4) + get_xdigit (parser->data[i]);
- }
-
- if (i != 0)
- {
- g_string_append_unichar (str, result);
- parser->data += i;
-
- /* NB: gtk_css_parser_new_line() forward data pointer itself */
- if (!gtk_css_parser_new_line (parser) &&
- *parser->data &&
- strchr (WHITESPACE_CHARS, *parser->data))
- parser->data++;
- return;
- }
-
- if (gtk_css_parser_new_line (parser))
- return;
-
- g_string_append_c (str, *parser->data);
- parser->data++;
-
- return;
-}
-
-static gboolean
-_gtk_css_parser_read_char (GtkCssParser *parser,
- GString * str,
- const char * allowed)
-{
- if (*parser->data == 0)
- return FALSE;
-
- if (strchr (allowed, *parser->data))
- {
- g_string_append_c (str, *parser->data);
- parser->data++;
- return TRUE;
- }
- if (*parser->data >= 127)
- {
- gsize len = g_utf8_skip[(guint) *(guchar *) parser->data];
-
- g_string_append_len (str, parser->data, len);
- parser->data += len;
- return TRUE;
- }
- if (*parser->data == '\\')
- {
- _gtk_css_parser_unescape (parser, str);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static char *
-_gtk_css_parser_get_ident (GtkCssParser *parser)
-{
- char *result;
- gsize len;
-
- len = parser->ident_str->len;
-
- result = g_new (char, len + 1);
- memcpy (result, parser->ident_str->str, len + 1);
- g_string_set_size (parser->ident_str, 0);
-
- return result;
-}
-
-char *
-_gtk_css_parser_try_name (GtkCssParser *parser,
- gboolean skip_whitespace)
-{
- GString *name;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
-
- if (parser->ident_str == NULL)
- parser->ident_str = g_string_new (NULL);
-
- name = parser->ident_str;
-
- while (_gtk_css_parser_read_char (parser, name, NMCHAR))
- ;
-
- if (skip_whitespace)
- _gtk_css_parser_skip_whitespace (parser);
-
- return _gtk_css_parser_get_ident (parser);
-}
-
-char *
-_gtk_css_parser_try_ident (GtkCssParser *parser,
- gboolean skip_whitespace)
-{
- const char *start;
- GString *ident;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
-
- start = parser->data;
-
- if (parser->ident_str == NULL)
- parser->ident_str = g_string_new (NULL);
-
- ident = parser->ident_str;
-
- if (*parser->data == '-')
- {
- g_string_append_c (ident, '-');
- parser->data++;
- }
-
- if (!_gtk_css_parser_read_char (parser, ident, NMSTART))
- {
- parser->data = start;
- g_string_set_size (ident, 0);
- return NULL;
- }
-
- while (_gtk_css_parser_read_char (parser, ident, NMCHAR))
- ;
-
- if (skip_whitespace)
- _gtk_css_parser_skip_whitespace (parser);
-
- return _gtk_css_parser_get_ident (parser);
-}
-
-gboolean
-gtk_css_parser_has_token (GtkCssParser *parser,
- GtkCssTokenType type)
-{
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
-
- switch (type)
- {
- case GTK_CSS_TOKEN_STRING:
- return *parser->data == '"' || *parser->data == '\'';
-
- case GTK_CSS_TOKEN_OPEN_CURLY:
- return *parser->data == '{';
-
- case GTK_CSS_TOKEN_CLOSE_CURLY:
- return *parser->data == '}';
-
- case GTK_CSS_TOKEN_OPEN_PARENS:
- return *parser->data == '(';
-
- case GTK_CSS_TOKEN_CLOSE_PARENS:
- return *parser->data == ')';
-
- case GTK_CSS_TOKEN_COMMA:
- return *parser->data == ',';
-
- case GTK_CSS_TOKEN_COLON:
- return *parser->data == ':';
-
- case GTK_CSS_TOKEN_SEMICOLON:
- return *parser->data == ';';
-
- case GTK_CSS_TOKEN_AT_KEYWORD:
- return *parser->data == '@';
-
- case GTK_CSS_TOKEN_EOF:
- return *parser->data == 0;
-
- case GTK_CSS_TOKEN_IDENT:
- return *parser->data != 0 &&
- strchr (NMSTART "-", *parser->data) != NULL;
-
- default:
- case GTK_CSS_TOKEN_FUNCTION:
- case GTK_CSS_TOKEN_HASH_UNRESTRICTED:
- case GTK_CSS_TOKEN_HASH_ID:
- case GTK_CSS_TOKEN_URL:
- case GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION:
- case GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION:
- case GTK_CSS_TOKEN_DIMENSION:
- case GTK_CSS_TOKEN_WHITESPACE:
- case GTK_CSS_TOKEN_OPEN_SQUARE:
- case GTK_CSS_TOKEN_CLOSE_SQUARE:
- case GTK_CSS_TOKEN_CDC:
- case GTK_CSS_TOKEN_CDO:
- case GTK_CSS_TOKEN_DELIM:
- case GTK_CSS_TOKEN_SIGNED_INTEGER:
- case GTK_CSS_TOKEN_SIGNLESS_INTEGER:
- case GTK_CSS_TOKEN_SIGNED_NUMBER:
- case GTK_CSS_TOKEN_SIGNLESS_NUMBER:
- case GTK_CSS_TOKEN_PERCENTAGE:
- case GTK_CSS_TOKEN_INCLUDE_MATCH:
- case GTK_CSS_TOKEN_DASH_MATCH:
- case GTK_CSS_TOKEN_PREFIX_MATCH:
- case GTK_CSS_TOKEN_SUFFIX_MATCH:
- case GTK_CSS_TOKEN_SUBSTRING_MATCH:
- case GTK_CSS_TOKEN_COLUMN:
- case GTK_CSS_TOKEN_BAD_STRING:
- case GTK_CSS_TOKEN_BAD_URL:
- case GTK_CSS_TOKEN_COMMENT:
- g_assert_not_reached ();
- return FALSE;
- }
-}
-
-gboolean
-gtk_css_parser_has_ident (GtkCssParser *parser,
- const char *ident)
-{
- gsize len;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
- g_return_val_if_fail (ident != NULL, FALSE);
-
- len = strlen (ident);
-
- return g_ascii_strncasecmp (parser->data, ident, len) == 0 &&
- parser->data[len] != '(';
-}
-
-gboolean
-gtk_css_parser_has_integer (GtkCssParser *parser)
-{
- guint i;
-
- i = 0;
- if (parser->data[0] == '-')
- i++;
-
- if (parser->data[i] >= '0' && parser->data[i] <= '9')
- return TRUE;
-
- return FALSE;
-}
-
-gboolean
-gtk_css_parser_has_function (GtkCssParser *parser,
- const char *name)
-{
- gsize len;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
- g_return_val_if_fail (name != NULL, FALSE);
-
- len = strlen (name);
-
- return g_ascii_strncasecmp (parser->data, name, len) == 0 &&
- parser->data[len] == '(';
-}
-
-char *
-gtk_css_parser_consume_string (GtkCssParser *parser)
-{
- GString *str;
- char quote;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
-
- quote = *parser->data;
-
- if (quote != '"' && quote != '\'')
- {
- _gtk_css_parser_error (parser, "Expected a string.");
- return NULL;
- }
-
- parser->data++;
-
- if (parser->ident_str == NULL)
- parser->ident_str = g_string_new (NULL);
-
- str = parser->ident_str;
- g_assert (str->len == 0);
-
- while (TRUE)
- {
- gsize len = strcspn (parser->data, "\\'\"\n\r\f");
-
- g_string_append_len (str, parser->data, len);
-
- parser->data += len;
-
- switch (*parser->data)
- {
- case '\\':
- _gtk_css_parser_unescape (parser, str);
- break;
- case '"':
- case '\'':
- if (*parser->data == quote)
- {
- parser->data++;
- _gtk_css_parser_skip_whitespace (parser);
- return _gtk_css_parser_get_ident (parser);
- }
-
- g_string_append_c (str, *parser->data);
- parser->data++;
- break;
- case '\0':
- /* FIXME: position */
- _gtk_css_parser_error (parser, "Missing end quote in string.");
- g_string_set_size (str, 0);
- return NULL;
- default:
- _gtk_css_parser_error (parser,
- "Invalid character in string. Must be escaped.");
- g_string_set_size (str, 0);
- return NULL;
- }
- }
-
- g_assert_not_reached ();
- return NULL;
-}
-
-gboolean
-gtk_css_parser_consume_integer (GtkCssParser *parser,
- int *value)
-{
- gint64 result;
- char *end;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
- g_return_val_if_fail (value != NULL, FALSE);
-
- /* strtoll parses a plus, but we are not allowed to */
- if (*parser->data == '+')
- goto fail;
-
- errno = 0;
- result = g_ascii_strtoll (parser->data, &end, 10);
- if (errno)
- goto fail;
- if (result > G_MAXINT || result < G_MININT)
- goto fail;
- if (parser->data == end)
- goto fail;
-
- parser->data = end;
- *value = result;
-
- _gtk_css_parser_skip_whitespace (parser);
-
- return TRUE;
-
-fail:
- _gtk_css_parser_error (parser, "Expected an integer");
- return FALSE;
-}
-
-gboolean
-gtk_css_parser_consume_number (GtkCssParser *self,
- double *number)
-{
- gdouble result;
- char *end;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (self), FALSE);
- g_return_val_if_fail (number != NULL, FALSE);
-
- errno = 0;
- result = g_ascii_strtod (self->data, &end);
- if (errno ||
- self->data == end)
- {
- _gtk_css_parser_error (self, "Expected a number");
- return FALSE;
- }
-
- self->data = end;
- *number = result;
-
- _gtk_css_parser_skip_whitespace (self);
-
- return TRUE;
-}
-
-char *
-gtk_css_parser_consume_ident (GtkCssParser *self)
-{
- char *result;
-
- result = _gtk_css_parser_try_ident (self, TRUE);
- if (result == NULL)
- _gtk_css_parser_error (self, "Expected an identifier");
-
- return result;
-}
-
-gboolean
-_gtk_css_parser_has_number (GtkCssParser *parser)
-{
- char c;
-
- if (parser->data[0] == '-' || parser->data[0] == '+')
- c = parser->data[1];
- else
- c = parser->data[0];
-
- /* ahem */
- return g_ascii_isdigit (c) || c == '.';
-}
-
-GtkCssValue *
-gtk_css_dimension_value_parse (GtkCssParser *parser,
- GtkCssNumberParseFlags flags)
-{
- static const struct {
- const char *name;
- GtkCssUnit unit;
- GtkCssNumberParseFlags required_flags;
- } units[] = {
- { "px", GTK_CSS_PX, GTK_CSS_PARSE_LENGTH },
- { "pt", GTK_CSS_PT, GTK_CSS_PARSE_LENGTH },
- { "em", GTK_CSS_EM, GTK_CSS_PARSE_LENGTH },
- { "ex", GTK_CSS_EX, GTK_CSS_PARSE_LENGTH },
- { "rem", GTK_CSS_REM, GTK_CSS_PARSE_LENGTH },
- { "pc", GTK_CSS_PC, GTK_CSS_PARSE_LENGTH },
- { "in", GTK_CSS_IN, GTK_CSS_PARSE_LENGTH },
- { "cm", GTK_CSS_CM, GTK_CSS_PARSE_LENGTH },
- { "mm", GTK_CSS_MM, GTK_CSS_PARSE_LENGTH },
- { "rad", GTK_CSS_RAD, GTK_CSS_PARSE_ANGLE },
- { "deg", GTK_CSS_DEG, GTK_CSS_PARSE_ANGLE },
- { "grad", GTK_CSS_GRAD, GTK_CSS_PARSE_ANGLE },
- { "turn", GTK_CSS_TURN, GTK_CSS_PARSE_ANGLE },
- { "s", GTK_CSS_S, GTK_CSS_PARSE_TIME },
- { "ms", GTK_CSS_MS, GTK_CSS_PARSE_TIME }
- };
- char *end, *unit_name;
- double value;
- GtkCssUnit unit;
-
- g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
-
- errno = 0;
- value = g_ascii_strtod (parser->data, &end);
- if (errno)
- {
- _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno));
- return NULL;
- }
- if (parser->data == end)
- {
- _gtk_css_parser_error (parser, "not a number");
- return NULL;
- }
-
- parser->data = end;
-
- if (flags & GTK_CSS_POSITIVE_ONLY &&
- value < 0)
- {
- _gtk_css_parser_error (parser, "negative values are not allowed.");
- return NULL;
- }
-
- unit_name = _gtk_css_parser_try_ident (parser, FALSE);
-
- if (unit_name)
- {
- guint i;
-
- for (i = 0; i < G_N_ELEMENTS (units); i++)
- {
- if (flags & units[i].required_flags &&
- g_ascii_strcasecmp (unit_name, units[i].name) == 0)
- break;
- }
-
- if (i >= G_N_ELEMENTS (units))
- {
- _gtk_css_parser_error (parser, "'%s' is not a valid unit.", unit_name);
- g_free (unit_name);
- return NULL;
- }
-
- unit = units[i].unit;
-
- g_free (unit_name);
- }
- else
- {
- if ((flags & GTK_CSS_PARSE_PERCENT) &&
- _gtk_css_parser_try (parser, "%", FALSE))
- {
- unit = GTK_CSS_PERCENT;
- }
- else if (value == 0.0)
- {
- if (flags & GTK_CSS_PARSE_NUMBER)
- unit = GTK_CSS_NUMBER;
- else if (flags & GTK_CSS_PARSE_LENGTH)
- unit = GTK_CSS_PX;
- else if (flags & GTK_CSS_PARSE_ANGLE)
- unit = GTK_CSS_DEG;
- else if (flags & GTK_CSS_PARSE_TIME)
- unit = GTK_CSS_S;
- else
- unit = GTK_CSS_PERCENT;
- }
- else if (flags & GTK_CSS_PARSE_NUMBER)
- {
- unit = GTK_CSS_NUMBER;
- }
- else
- {
- _gtk_css_parser_error (parser, "Unit is missing.");
- return NULL;
- }
- }
-
- _gtk_css_parser_skip_whitespace (parser);
-
- return gtk_css_dimension_value_new (value, unit);
-}
-
-gboolean
-_gtk_css_parser_try_hash_color (GtkCssParser *parser,
- GdkRGBA *rgba)
-{
- if (parser->data[0] == '#' &&
- g_ascii_isxdigit (parser->data[1]) &&
- g_ascii_isxdigit (parser->data[2]) &&
- g_ascii_isxdigit (parser->data[3]))
- {
- if (g_ascii_isxdigit (parser->data[4]))
- {
- if (g_ascii_isxdigit (parser->data[5]) &&
- g_ascii_isxdigit (parser->data[6]))
- {
- rgba->red = ((get_xdigit (parser->data[1]) << 4) + get_xdigit (parser->data[2])) / 255.0;
- rgba->green = ((get_xdigit (parser->data[3]) << 4) + get_xdigit (parser->data[4])) / 255.0;
- rgba->blue = ((get_xdigit (parser->data[5]) << 4) + get_xdigit (parser->data[6])) / 255.0;
- if (g_ascii_isxdigit (parser->data[7]) &&
- g_ascii_isxdigit (parser->data[8]))
- {
- rgba->alpha = ((get_xdigit (parser->data[7]) << 4) + get_xdigit (parser->data[8])) / 255.0;
- parser->data += 9;
- }
- else
- {
- rgba->alpha = 1.0;
- parser->data += 7;
- }
- }
- else
- {
- rgba->red = get_xdigit (parser->data[1]) / 15.0;
- rgba->green = get_xdigit (parser->data[2]) / 15.0;
- rgba->blue = get_xdigit (parser->data[3]) / 15.0;
- rgba->alpha = get_xdigit (parser->data[4]) / 15.0;
- parser->data += 5;
- }
- }
- else
- {
- rgba->red = get_xdigit (parser->data[1]) / 15.0;
- rgba->green = get_xdigit (parser->data[2]) / 15.0;
- rgba->blue = get_xdigit (parser->data[3]) / 15.0;
- rgba->alpha = 1.0;
- parser->data += 4;
- }
-
- _gtk_css_parser_skip_whitespace (parser);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-GFile *
-gtk_css_parser_consume_url (GtkCssParser *parser)
-{
- gchar *path;
- GFile *file;
-
- if (_gtk_css_parser_try (parser, "url", FALSE))
- {
- if (!_gtk_css_parser_try (parser, "(", TRUE))
- {
- _gtk_css_parser_error (parser, "Expected '(' after 'url'");
- return NULL;
- }
-
- path = gtk_css_parser_consume_string (parser);
- if (path == NULL)
- return NULL;
-
- if (!_gtk_css_parser_try (parser, ")", TRUE))
- {
- _gtk_css_parser_error (parser, "No closing ')' found for 'url'");
- g_free (path);
- return NULL;
- }
- }
- else
- {
- path = _gtk_css_parser_try_name (parser, TRUE);
- if (path == NULL)
- {
- _gtk_css_parser_error (parser, "Not a valid url");
- return NULL;
- }
- }
-
- file = gtk_css_parser_resolve_url (parser, path);
- g_free (path);
-
- return file;
-}
-
-static void
-gtk_css_parser_resync_internal (GtkCssParser *parser,
- gboolean sync_at_semicolon,
- gboolean read_sync_token,
- char terminator)
-{
- gsize len;
-
- do {
- len = strcspn (parser->data, "\\\"'/()[]{};" NEWLINE_CHARS);
- parser->data += len;
-
- if (gtk_css_parser_new_line (parser))
- continue;
-
- if (gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_STRING))
- {
- /* Hrm, this emits errors, and i suspect it shouldn't... */
- char *free_me = gtk_css_parser_consume_string (parser);
- g_free (free_me);
- continue;
- }
-
- if (gtk_css_parser_skip_comment (parser))
- continue;
-
- switch (*parser->data)
- {
- case '\\':
- {
- GString *ignore = g_string_new (NULL);
- _gtk_css_parser_unescape (parser, ignore);
- g_string_free (ignore, TRUE);
- }
- break;
- case ';':
- if (sync_at_semicolon && !read_sync_token)
- return;
- parser->data++;
- if (sync_at_semicolon)
- {
- _gtk_css_parser_skip_whitespace (parser);
- return;
- }
- break;
- case '(':
- parser->data++;
- _gtk_css_parser_resync (parser, FALSE, ')');
- if (*parser->data)
- parser->data++;
- break;
- case '[':
- parser->data++;
- _gtk_css_parser_resync (parser, FALSE, ']');
- if (*parser->data)
- parser->data++;
- break;
- case '{':
- parser->data++;
- _gtk_css_parser_resync (parser, FALSE, '}');
- if (*parser->data)
- parser->data++;
- if (sync_at_semicolon || !terminator)
- {
- _gtk_css_parser_skip_whitespace (parser);
- return;
- }
- break;
- case '}':
- case ')':
- case ']':
- if (terminator == *parser->data)
- {
- _gtk_css_parser_skip_whitespace (parser);
- return;
- }
- parser->data++;
- continue;
- case '\0':
- break;
- case '/':
- default:
- parser->data++;
- break;
- }
- } while (*parser->data);
-}
-
-void
-_gtk_css_parser_resync (GtkCssParser *parser,
- gboolean sync_at_semicolon,
- char terminator)
-{
- g_return_if_fail (GTK_IS_CSS_PARSER (parser));
-
- gtk_css_parser_resync_internal (parser, sync_at_semicolon, TRUE, terminator);
}
void
@@ -1219,99 +83,3 @@ out:
g_string_append_c (str, '"');
}
-gboolean
-gtk_css_parser_consume_function (GtkCssParser *self,
- guint min_args,
- guint max_args,
- guint (* parse_func) (GtkCssParser *, guint, gpointer),
- gpointer data)
-{
- gboolean result = FALSE;
- char *function_name;
- guint arg;
-
- function_name = _gtk_css_parser_try_ident (self, FALSE);
- g_return_val_if_fail (function_name != NULL, FALSE);
- g_return_val_if_fail (_gtk_css_parser_try (self, "(", TRUE), FALSE);
-
- arg = 0;
- while (TRUE)
- {
- guint parse_args = parse_func (self, arg, data);
- if (parse_args == 0)
- break;
- arg += parse_args;
- if (gtk_css_parser_try_token (self, GTK_CSS_TOKEN_CLOSE_PARENS))
- {
- if (arg < min_args)
- {
- _gtk_css_parser_error (self, "%s() requires at least %u arguments", function_name, min_args);
- break;
- }
- else
- {
- result = TRUE;
- break;
- }
- }
- else if (gtk_css_parser_try_token (self, GTK_CSS_TOKEN_COMMA))
- {
- if (arg >= max_args)
- {
- _gtk_css_parser_error (self, "Expected ')' at end of %s()", function_name);
- break;
- }
-
- continue;
- }
- else
- {
- _gtk_css_parser_error (self, "Unexpected data at end of %s() argument", function_name);
- break;
- }
- }
-
- g_free (function_name);
-
- return result;
-}
-
-gsize
-gtk_css_parser_consume_any (GtkCssParser *parser,
- const GtkCssParseOption *options,
- gsize n_options,
- gpointer user_data)
-{
- gsize result;
- gsize i;
-
- g_return_val_if_fail (parser != NULL, 0);
- g_return_val_if_fail (options != NULL, 0);
- g_return_val_if_fail (n_options < sizeof (gsize) * 8 - 1, 0);
-
- result = 0;
- while (result != (1 << n_options) - 1)
- {
- for (i = 0; i < n_options; i++)
- {
- if (result & (1 << i))
- continue;
- if (options[i].can_parse && !options[i].can_parse (parser, options[i].data, user_data))
- continue;
- if (!options[i].parse (parser, options[i].data, user_data))
- return 0;
- result |= 1 << i;
- break;
- }
- if (i == n_options)
- break;
- }
- if (result == 0)
- {
- _gtk_css_parser_error (parser, "No valid value given");
- return result;
- }
-
- return result;
-}
-
diff --git a/gtk/gtkcssparserprivate.h b/gtk/gtkcssparserprivate.h
index fec25fceff..68de9ea207 100644
--- a/gtk/gtkcssparserprivate.h
+++ b/gtk/gtkcssparserprivate.h
@@ -22,104 +22,14 @@
#include <gtk/css/gtkcss.h>
#include "gtk/css/gtkcsstokenizerprivate.h"
+#include "gtk/css/gtkcssparserprivate.h"
G_BEGIN_DECLS
-typedef struct _GtkCssParser GtkCssParser;
-
-typedef void (* GtkCssParserErrorFunc) (GtkCssParser *parser,
- const GError *error,
- gpointer user_data);
-
-typedef struct _GtkCssParseOption GtkCssParseOption;
-
-struct _GtkCssParseOption
-{
- gboolean (* can_parse) (GtkCssParser *parser,
- gpointer option_data,
- gpointer user_data);
- gboolean (* parse) (GtkCssParser *parser,
- gpointer option_data,
- gpointer user_data);
- gpointer data;
-};
-
-GtkCssParser * _gtk_css_parser_new (const char *data,
- GFile *file,
- GtkCssParserErrorFunc error_func,
- gpointer user_data);
-void _gtk_css_parser_free (GtkCssParser *parser);
-
-void _gtk_css_parser_take_error (GtkCssParser *parser,
- GError *error);
void _gtk_css_parser_error (GtkCssParser *parser,
const char *format,
...) G_GNUC_PRINTF (2, 3);
-guint _gtk_css_parser_get_line (GtkCssParser *parser);
-guint _gtk_css_parser_get_position (GtkCssParser *parser);
-GFile * _gtk_css_parser_get_file (GtkCssParser *parser);
-GFile * gtk_css_parser_resolve_url (GtkCssParser *parser,
- const char *url);
-
-gboolean gtk_css_parser_has_token (GtkCssParser *parser,
- GtkCssTokenType token_type);
-gboolean gtk_css_parser_has_ident (GtkCssParser *parser,
- const char *name);
-gboolean gtk_css_parser_has_integer (GtkCssParser *parser);
-gboolean gtk_css_parser_has_function (GtkCssParser *parser,
- const char *name);
-
-/* IMPORTANT:
- * _try_foo() functions do not modify the data pointer if they fail, nor do they
- * signal an error. _read_foo() will modify the data pointer and position it at
- * the first token that is broken and emit an error about the failure.
- * So only call _read_foo() when you know that you are reading a foo. _try_foo()
- * however is fine to call if you don’t know yet if the token is a foo or a bar,
- * you can _try_bar() if try_foo() failed.
- */
-gboolean gtk_css_parser_try_ident (GtkCssParser *parser,
- const char *ident);
-gboolean gtk_css_parser_try_delim (GtkCssParser *parser,
- gunichar delim);
-gboolean gtk_css_parser_try_at_keyword (GtkCssParser *parser,
- const char *keyword);
-gboolean gtk_css_parser_try_token (GtkCssParser *parser,
- GtkCssTokenType token_type);
-gboolean _gtk_css_parser_try (GtkCssParser *parser,
- const char *string,
- gboolean skip_whitespace);
-char * _gtk_css_parser_try_ident (GtkCssParser *parser,
- gboolean skip_whitespace);
-char * _gtk_css_parser_try_name (GtkCssParser *parser,
- gboolean skip_whitespace);
-gboolean _gtk_css_parser_try_hash_color (GtkCssParser *parser,
- GdkRGBA *rgba);
-
-char * gtk_css_parser_consume_ident (GtkCssParser *self);
-char * gtk_css_parser_consume_string (GtkCssParser *self);
-GFile * gtk_css_parser_consume_url (GtkCssParser *self);
-gboolean gtk_css_parser_consume_number (GtkCssParser *self,
- double *number);
-gboolean gtk_css_parser_consume_integer (GtkCssParser *parser,
- int *value);
-gboolean gtk_css_parser_consume_function (GtkCssParser *self,
- guint min_args,
- guint max_args,
- guint (* parse_func) (GtkCssParser *, guint, gpointer),
- gpointer data);
-gsize gtk_css_parser_consume_any (GtkCssParser *parser,
- const GtkCssParseOption *options,
- gsize n_options,
- gpointer user_data);
-
-gboolean _gtk_css_parser_has_number (GtkCssParser *parser);
-
-void _gtk_css_parser_skip_whitespace (GtkCssParser *parser);
-void _gtk_css_parser_resync (GtkCssParser *parser,
- gboolean sync_at_semicolon,
- char terminator);
-
/* XXX: Find better place to put it? */
void _gtk_css_print_string (GString *str,
const char *string);
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 1abcaa8472..8f99c79579 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -140,7 +140,7 @@ static void
gtk_css_provider_load_internal (GtkCssProvider *css_provider,
GtkCssScanner *scanner,
GFile *file,
- const char *data);
+ GBytes *bytes);
G_DEFINE_TYPE_EXTENDED (GtkCssProvider, gtk_css_provider, G_TYPE_OBJECT, 0,
G_ADD_PRIVATE (GtkCssProvider)
@@ -312,7 +312,7 @@ gtk_css_scanner_destroy (GtkCssScanner *scanner)
if (scanner->section)
gtk_css_section_unref (scanner->section);
g_object_unref (scanner->provider);
- _gtk_css_parser_free (scanner->parser);
+ gtk_css_parser_unref (scanner->parser);
g_slice_free (GtkCssScanner, scanner);
}
@@ -336,9 +336,11 @@ gtk_css_provider_emit_error (GtkCssProvider *provider,
}
static void
-gtk_css_scanner_parser_error (GtkCssParser *parser,
- const GError *error,
- gpointer user_data)
+gtk_css_scanner_parser_error (GtkCssParser *parser,
+ const GtkCssLocation *start,
+ const GtkCssLocation *end,
+ const GError *error,
+ gpointer user_data)
{
GtkCssScanner *scanner = user_data;
@@ -350,7 +352,7 @@ gtk_css_scanner_new (GtkCssProvider *provider,
GtkCssScanner *parent,
GtkCssSection *section,
GFile *file,
- const gchar *text)
+ GBytes *bytes)
{
GtkCssScanner *scanner;
@@ -362,10 +364,12 @@ gtk_css_scanner_new (GtkCssProvider *provider,
if (section)
scanner->section = gtk_css_section_ref (section);
- scanner->parser = _gtk_css_parser_new (text,
- file,
- gtk_css_scanner_parser_error,
- scanner);
+ scanner->parser = gtk_css_parser_new_for_bytes (bytes,
+ file,
+ NULL,
+ gtk_css_scanner_parser_error,
+ scanner,
+ NULL);
return scanner;
}
@@ -376,7 +380,7 @@ gtk_css_scanner_would_recurse (GtkCssScanner *scanner,
{
while (scanner)
{
- GFile *parser_file = _gtk_css_parser_get_file (scanner->parser);
+ GFile *parser_file = gtk_css_parser_get_file (scanner->parser);
if (parser_file && g_file_equal (parser_file, file))
return TRUE;
@@ -766,7 +770,6 @@ gtk_css_provider_reset (GtkCssProvider *css_provider)
g_array_set_size (priv->rulesets, 0);
_gtk_css_selector_tree_free (priv->tree);
priv->tree = NULL;
-
}
static gboolean
@@ -790,6 +793,15 @@ parse_import (GtkCssScanner *scanner)
if (url)
{
file = gtk_css_parser_resolve_url (scanner->parser, url);
+ if (file == NULL)
+ {
+ gtk_css_provider_error (scanner->provider,
+ scanner,
+ GTK_CSS_PARSER_ERROR,
+ GTK_CSS_PARSER_ERROR_IMPORT,
+ "Could not resolve \"%s\" to a valid URL",
+ url);
+ }
g_free (url);
}
else
@@ -802,15 +814,11 @@ parse_import (GtkCssScanner *scanner)
if (file == NULL)
{
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
- gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_IMPORT);
- return TRUE;
+ /* nothing to do */
}
-
- if (!_gtk_css_parser_try (scanner->parser, ";", FALSE))
+ else if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
gtk_css_provider_invalid_token (scanner->provider, scanner, "semicolon");
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
}
else if (gtk_css_scanner_would_recurse (scanner, file))
{
@@ -831,10 +839,9 @@ parse_import (GtkCssScanner *scanner)
NULL);
}
- g_object_unref (file);
+ g_clear_object (&file);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_IMPORT);
- _gtk_css_parser_skip_whitespace (scanner->parser);
return TRUE;
}
@@ -854,15 +861,9 @@ parse_color_definition (GtkCssScanner *scanner)
return FALSE;
}
- name = _gtk_css_parser_try_name (scanner->parser, TRUE);
+ name = gtk_css_parser_consume_ident (scanner->parser);
if (name == NULL)
{
- gtk_css_provider_error_literal (scanner->provider,
- scanner,
- GTK_CSS_PARSER_ERROR,
- GTK_CSS_PARSER_ERROR_SYNTAX,
- "Not a valid color name");
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_COLOR_DEFINITION);
return TRUE;
}
@@ -871,12 +872,11 @@ parse_color_definition (GtkCssScanner *scanner)
if (color == NULL)
{
g_free (name);
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_COLOR_DEFINITION);
return TRUE;
}
- if (!_gtk_css_parser_try (scanner->parser, ";", TRUE))
+ if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
g_free (name);
_gtk_css_value_unref (color);
@@ -885,7 +885,6 @@ parse_color_definition (GtkCssScanner *scanner)
GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
"Missing semicolon at end of color definition");
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_COLOR_DEFINITION);
return TRUE;
@@ -912,52 +911,39 @@ parse_keyframes (GtkCssScanner *scanner)
return FALSE;
}
- name = _gtk_css_parser_try_ident (scanner->parser, TRUE);
+ name = gtk_css_parser_consume_ident (scanner->parser);
if (name == NULL)
{
- gtk_css_provider_error_literal (scanner->provider,
- scanner,
- GTK_CSS_PARSER_ERROR,
- GTK_CSS_PARSER_ERROR_SYNTAX,
- "Expected name for keyframes");
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
- goto exit;
+ gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_KEYFRAMES);
+ return FALSE;
}
- if (!_gtk_css_parser_try (scanner->parser, "{", TRUE))
+ if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
gtk_css_provider_error_literal (scanner->provider,
scanner,
GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
"Expected '{' for keyframes");
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
- g_free (name);
- goto exit;
+ gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_KEYFRAMES);
+ return FALSE;
}
- keyframes = _gtk_css_keyframes_parse (scanner->parser);
- if (keyframes == NULL)
- {
- _gtk_css_parser_resync (scanner->parser, TRUE, '}');
- g_free (name);
- goto exit;
- }
+ gtk_css_parser_end_block_prelude (scanner->parser);
- g_hash_table_insert (priv->keyframes, name, keyframes);
+ keyframes = _gtk_css_keyframes_parse (scanner->parser);
+ if (keyframes != NULL)
+ g_hash_table_insert (priv->keyframes, name, keyframes);
- if (!_gtk_css_parser_try (scanner->parser, "}", TRUE))
+ if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
gtk_css_provider_error_literal (scanner->provider,
scanner,
GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
"expected '}' after declarations");
- if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
- _gtk_css_parser_resync (scanner->parser, FALSE, 0);
}
-exit:
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_KEYFRAMES);
return TRUE;
@@ -966,22 +952,20 @@ exit:
static void
parse_at_keyword (GtkCssScanner *scanner)
{
- if (parse_import (scanner))
- return;
- if (parse_color_definition (scanner))
- return;
- if (parse_keyframes (scanner))
- return;
+ gtk_css_parser_start_semicolon_block (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY);
- else
+ if (!parse_import (scanner) &&
+ !parse_color_definition (scanner) &&
+ !parse_keyframes (scanner))
{
gtk_css_provider_error_literal (scanner->provider,
scanner,
GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
"unknown @ rule");
- _gtk_css_parser_resync (scanner->parser, TRUE, 0);
}
+
+ gtk_css_parser_end_block (scanner->parser);
}
static GSList *
@@ -996,15 +980,13 @@ parse_selector_list (GtkCssScanner *scanner)
if (select == NULL)
{
- g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
- _gtk_css_parser_resync (scanner->parser, FALSE, 0);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_SELECTOR);
return NULL;
}
selectors = g_slist_prepend (selectors, select);
}
- while (_gtk_css_parser_try (scanner->parser, ",", TRUE));
+ while (gtk_css_parser_try_token (scanner->parser, GTK_CSS_TOKEN_COMMA));
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_SELECTOR);
@@ -1019,27 +1001,37 @@ parse_declaration (GtkCssScanner *scanner,
char *name;
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_DECLARATION);
+ gtk_css_parser_start_semicolon_block (scanner->parser, GTK_CSS_TOKEN_EOF);
- name = _gtk_css_parser_try_ident (scanner->parser, TRUE);
- if (name == NULL)
- goto check_for_semicolon;
-
- property = _gtk_style_property_lookup (name);
+ if (gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
+ {
+ gtk_css_parser_warn_syntax (scanner->parser, "Empty declaration");
+ gtk_css_parser_end_block (scanner->parser);
+ return;
+ }
- if (!gtk_css_parser_try_token (scanner->parser, GTK_CSS_TOKEN_COLON))
+ name = gtk_css_parser_consume_ident (scanner->parser);
+ if (name == NULL)
{
- gtk_css_provider_invalid_token (scanner->provider, scanner, "':'");
- _gtk_css_parser_resync (scanner->parser, TRUE, '}');
- g_free (name);
+ gtk_css_parser_end_block (scanner->parser);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
return;
}
+ property = _gtk_style_property_lookup (name);
+
if (property)
{
GtkCssValue *value;
- g_free (name);
+ if (!gtk_css_parser_try_token (scanner->parser, GTK_CSS_TOKEN_COLON))
+ {
+ gtk_css_parser_error_syntax (scanner->parser, "Expected ':'");
+ g_free (name);
+ gtk_css_parser_end_block (scanner->parser);
+ gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
+ return;
+ }
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_VALUE);
@@ -1048,22 +1040,20 @@ parse_declaration (GtkCssScanner *scanner,
if (value == NULL)
{
- _gtk_css_parser_resync (scanner->parser, TRUE, '}');
+ gtk_css_parser_end_block (scanner->parser);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
return;
}
- if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_SEMICOLON) &&
- !gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_CLOSE_CURLY) &&
- !gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
+ if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
gtk_css_provider_error (scanner->provider,
scanner,
GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
"Junk at end of value for %s", property->name);
- _gtk_css_parser_resync (scanner->parser, TRUE, '}');
+ gtk_css_parser_end_block (scanner->parser);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
return;
@@ -1098,32 +1088,21 @@ parse_declaration (GtkCssScanner *scanner,
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_VALUE);
}
else
- g_free (name);
-
-check_for_semicolon:
- gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
-
- if (!_gtk_css_parser_try (scanner->parser, ";", TRUE))
{
- if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_CLOSE_CURLY) &&
- !gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
- {
- gtk_css_provider_error_literal (scanner->provider,
- scanner,
- GTK_CSS_PARSER_ERROR,
- GTK_CSS_PARSER_ERROR_SYNTAX,
- "Expected semicolon");
- _gtk_css_parser_resync (scanner->parser, TRUE, '}');
- }
+ gtk_css_parser_error_value (scanner->parser, "No property named \"%s\"", name);
}
+
+ g_free (name);
+
+ gtk_css_parser_end_block (scanner->parser);
+ gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_DECLARATION);
}
static void
parse_declarations (GtkCssScanner *scanner,
GtkCssRuleset *ruleset)
{
- while (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF) &&
- !gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_CLOSE_CURLY))
+ while (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
parse_declaration (scanner, ruleset);
}
@@ -1140,40 +1119,31 @@ parse_ruleset (GtkCssScanner *scanner)
selectors = parse_selector_list (scanner);
if (selectors == NULL)
{
+ gtk_css_parser_skip_until (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY);
+ gtk_css_parser_skip (scanner->parser);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_RULESET);
return;
}
- if (!_gtk_css_parser_try (scanner->parser, "{", TRUE))
+ if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY))
{
gtk_css_provider_error_literal (scanner->provider,
scanner,
GTK_CSS_PARSER_ERROR,
GTK_CSS_PARSER_ERROR_SYNTAX,
"expected '{' after selectors");
- _gtk_css_parser_resync (scanner->parser, FALSE, 0);
g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
+ gtk_css_parser_skip_until (scanner->parser, GTK_CSS_TOKEN_OPEN_CURLY);
+ gtk_css_parser_skip (scanner->parser);
gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_RULESET);
return;
}
+ gtk_css_parser_start_block (scanner->parser);
+
parse_declarations (scanner, &ruleset);
- if (!_gtk_css_parser_try (scanner->parser, "}", TRUE))
- {
- gtk_css_provider_error_literal (scanner->provider,
- scanner,
- GTK_CSS_PARSER_ERROR,
- GTK_CSS_PARSER_ERROR_SYNTAX,
- "expected '}' after declarations");
- if (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
- {
- _gtk_css_parser_resync (scanner->parser, FALSE, 0);
- g_slist_free_full (selectors, (GDestroyNotify) _gtk_css_selector_free);
- gtk_css_ruleset_clear (&ruleset);
- gtk_css_scanner_pop_section (scanner, GTK_CSS_SECTION_RULESET);
- }
- }
+ gtk_css_parser_end_block (scanner->parser);
css_provider_commit (scanner->provider, selectors, &ruleset);
gtk_css_ruleset_clear (&ruleset);
@@ -1194,13 +1164,14 @@ parse_stylesheet (GtkCssScanner *scanner)
{
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_DOCUMENT);
- _gtk_css_parser_skip_whitespace (scanner->parser);
-
while (!gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
{
- if (_gtk_css_parser_try (scanner->parser, "<!--", TRUE) ||
- _gtk_css_parser_try (scanner->parser, "-->", TRUE))
- continue;
+ if (gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_CDO) ||
+ gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_CDC))
+ {
+ gtk_css_parser_consume_token (scanner->parser);
+ continue;
+ }
parse_statement (scanner);
}
@@ -1265,30 +1236,27 @@ static void
gtk_css_provider_load_internal (GtkCssProvider *css_provider,
GtkCssScanner *parent,
GFile *file,
- const char *text)
+ GBytes *bytes)
{
GtkCssScanner *scanner;
- GBytes *bytes;
- if (text == NULL)
+ if (bytes == NULL)
{
GError *load_error = NULL;
bytes = g_file_load_bytes (file, NULL, NULL, &load_error);
- if (bytes)
- {
- text = g_bytes_get_data (bytes, NULL);
- }
- else
+ if (bytes == NULL)
{
if (parent == NULL)
{
+ GBytes *tmp_bytes = g_bytes_new_static ("", 0);
scanner = gtk_css_scanner_new (css_provider,
NULL,
NULL,
file,
- "");
+ tmp_bytes);
+ g_bytes_unref (tmp_bytes);
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_DOCUMENT);
}
@@ -1310,18 +1278,14 @@ gtk_css_provider_load_internal (GtkCssProvider *css_provider,
}
}
}
- else
- {
- bytes = NULL;
- }
- if (text)
+ if (bytes)
{
scanner = gtk_css_scanner_new (css_provider,
parent,
parent ? parent->section : NULL,
file,
- text);
+ bytes);
parse_stylesheet (scanner);
@@ -1330,9 +1294,6 @@ gtk_css_provider_load_internal (GtkCssProvider *css_provider,
if (parent == NULL)
gtk_css_provider_postprocess (css_provider);
}
-
- if (bytes)
- g_bytes_unref (bytes);
}
/**
@@ -1351,27 +1312,21 @@ gtk_css_provider_load_from_data (GtkCssProvider *css_provider,
const gchar *data,
gssize length)
{
- char *free_data;
+ GBytes *bytes;
g_return_if_fail (GTK_IS_CSS_PROVIDER (css_provider));
g_return_if_fail (data != NULL);
if (length < 0)
- {
- length = strlen (data);
- free_data = NULL;
- }
- else
- {
- free_data = g_strndup (data, length);
- data = free_data;
- }
+ length = strlen (data);
+
+ bytes = g_bytes_new_static (data, length);
gtk_css_provider_reset (css_provider);
- gtk_css_provider_load_internal (css_provider, NULL, NULL, data);
+ gtk_css_provider_load_internal (css_provider, NULL, NULL, bytes);
- g_free (free_data);
+ g_bytes_unref (bytes);
gtk_style_provider_changed (GTK_STYLE_PROVIDER (css_provider));
}
diff --git a/gtk/gtkcsssection.c b/gtk/gtkcsssection.c
index b8e15f2c98..747069212a 100644
--- a/gtk/gtkcsssection.c
+++ b/gtk/gtkcsssection.c
@@ -43,6 +43,7 @@ _gtk_css_section_new (GtkCssSection *parent,
GtkCssParser *parser)
{
GtkCssSection *section;
+ GtkCssLocation location;
gtk_internal_return_val_if_fail (parser != NULL, NULL);
@@ -52,12 +53,13 @@ _gtk_css_section_new (GtkCssSection *parent,
section->section_type = type;
if (parent)
section->parent = gtk_css_section_ref (parent);
- section->file = _gtk_css_parser_get_file (parser);
+ section->file = gtk_css_parser_get_file (parser);
if (section->file)
g_object_ref (section->file);
- section->start_line = _gtk_css_parser_get_line (parser);
- section->start_position = _gtk_css_parser_get_position (parser);
section->parser = parser;
+ gtk_css_parser_get_location (section->parser, &location);
+ section->start_line = location.lines;
+ section->start_position = location.line_chars;
return section;
}
@@ -82,11 +84,14 @@ _gtk_css_section_new_for_file (GtkCssSectionType type,
void
_gtk_css_section_end (GtkCssSection *section)
{
+ GtkCssLocation location;
+
gtk_internal_return_if_fail (section != NULL);
gtk_internal_return_if_fail (section->parser != NULL);
- section->end_line = _gtk_css_parser_get_line (section->parser);
- section->end_position = _gtk_css_parser_get_position (section->parser);
+ gtk_css_parser_get_location (section->parser, &location);
+ section->end_line = location.lines;
+ section->end_position = location.line_chars;
section->parser = NULL;
}
@@ -243,12 +248,15 @@ gtk_css_section_get_start_position (const GtkCssSection *section)
guint
gtk_css_section_get_end_line (const GtkCssSection *section)
{
+ GtkCssLocation location;
+
gtk_internal_return_val_if_fail (section != NULL, 0);
- if (section->parser)
- return _gtk_css_parser_get_line (section->parser);
- else
+ if (!section->parser)
return section->end_line;
+
+ gtk_css_parser_get_location (section->parser, &location);
+ return location.lines;
}
/**
@@ -269,12 +277,15 @@ gtk_css_section_get_end_line (const GtkCssSection *section)
guint
gtk_css_section_get_end_position (const GtkCssSection *section)
{
+ GtkCssLocation location;
+
gtk_internal_return_val_if_fail (section != NULL, 0);
- if (section->parser)
- return _gtk_css_parser_get_position (section->parser);
- else
+ if (!section->parser)
return section->end_position;
+
+ gtk_css_parser_get_location (section->parser, &location);
+ return location.line_chars;
}
void
diff --git a/gtk/gtkcssselector.c b/gtk/gtkcssselector.c
index 30de213cc7..bd1b1523f2 100644
--- a/gtk/gtkcssselector.c
+++ b/gtk/gtkcssselector.c
@@ -25,6 +25,7 @@
#include "gtkcssprovider.h"
#include "gtkstylecontextprivate.h"
+#include <errno.h>
#if defined(_MSC_VER) && _MSC_VER >= 1500
# include <intrin.h>
#endif
@@ -922,296 +923,544 @@ gtk_css_selector_new (const GtkCssSelectorClass *class,
}
static GtkCssSelector *
-parse_selector_class (GtkCssParser *parser,
- GtkCssSelector *selector,
- gboolean negate)
+gtk_css_selector_parse_selector_class (GtkCssParser *parser,
+ GtkCssSelector *selector,
+ gboolean negate)
{
- char *name;
-
- name = _gtk_css_parser_try_name (parser, FALSE);
+ const GtkCssToken *token;
+
+ gtk_css_parser_consume_token (parser);
+ for (token = gtk_css_parser_peek_token (parser);
+ gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT);
+ token = gtk_css_parser_peek_token (parser))
+ {
+ gtk_css_parser_consume_token (parser);
+ }
- if (name == NULL)
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_CLASS
+ : &GTK_CSS_SELECTOR_CLASS,
+ selector);
+ selector->style_class.style_class = g_quark_from_string (token->string.string);
+ gtk_css_parser_consume_token (parser);
+ return selector;
+ }
+ else
{
- _gtk_css_parser_error (parser, "Expected a valid name for class");
+ gtk_css_parser_error_syntax (parser, "No class name after '.' in selector");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
+}
- selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_CLASS
- : &GTK_CSS_SELECTOR_CLASS,
- selector);
- selector->style_class.style_class = g_quark_from_string (name);
+static gboolean
+string_has_number (const char *string,
+ const char *prefix,
+ int *number)
+{
+ gsize len = strlen (prefix);
+ char *end;
- g_free (name);
+ if (g_ascii_strncasecmp (string, prefix, len) != 0)
+ return FALSE;
- return selector;
+ errno = 0;
+ *number = strtoul (string + len, &end, 10);
+ if (*end != '\0' || errno != 0)
+ return FALSE;
+
+ return TRUE;
}
-static GtkCssSelector *
-parse_selector_id (GtkCssParser *parser,
- GtkCssSelector *selector,
- gboolean negate)
+static gboolean
+parse_plus_b (GtkCssParser *parser,
+ gboolean negate,
+ gint *b)
{
- char *name;
-
- name = _gtk_css_parser_try_name (parser, FALSE);
+ const GtkCssToken *token;
+ gboolean has_seen_sign;
+
+ token = gtk_css_parser_get_token (parser);
- if (name == NULL)
+ if (negate)
{
- _gtk_css_parser_error (parser, "Expected a valid name for id");
- if (selector)
- _gtk_css_selector_free (selector);
- return NULL;
+ has_seen_sign = TRUE;
+ }
+ else
+ {
+ if (gtk_css_token_is_delim (token, '+'))
+ {
+ gtk_css_parser_consume_token (parser);
+ has_seen_sign = TRUE;
+ }
+ else if (gtk_css_token_is_delim (token, '-'))
+ {
+ gtk_css_parser_consume_token (parser);
+ negate = TRUE;
+ has_seen_sign = TRUE;
+ }
+ else
+ {
+ has_seen_sign = FALSE;
+ }
}
- selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_ID
- : &GTK_CSS_SELECTOR_ID,
- selector);
- selector->id.name = g_intern_string (name);
+ token = gtk_css_parser_get_token (parser);
+ if (!has_seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER))
+ {
+ *b = token->number.number;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else if (has_seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
+ {
+ *b = token->number.number;
+ if (negate)
+ *b = - *b;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else if (!has_seen_sign)
+ {
+ *b = 0;
+ return TRUE;
+ }
+
+ gtk_css_parser_error_syntax (parser, "Not a valid an+b type");
+ return FALSE;
+}
- g_free (name);
+static gboolean
+parse_n_plus_b (GtkCssParser *parser,
+ gint before,
+ gint *a,
+ gint *b)
+{
+ const GtkCssToken *token;
- return selector;
-}
+ token = gtk_css_parser_get_token (parser);
-static GtkCssSelector *
-parse_selector_pseudo_class_nth_child (GtkCssParser *parser,
- GtkCssSelector *selector,
- PositionType type,
- gboolean negate)
+ if (gtk_css_token_is_ident (token, "n"))
+ {
+ *a = before;
+ gtk_css_parser_consume_token (parser);
+ return parse_plus_b (parser, FALSE, b);
+ }
+ else if (gtk_css_token_is_ident (token, "n-"))
+ {
+ *a = before;
+ gtk_css_parser_consume_token (parser);
+ return parse_plus_b (parser, TRUE, b);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
+ string_has_number (token->string.string, "n-", b))
+ {
+ *a = before;
+ *b = -*b;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else
+ {
+ *b = before;
+ *a = 0;
+ return TRUE;
+ }
+
+ gtk_css_parser_error_syntax (parser, "Not a valid an+b type");
+ return FALSE;
+}
+
+static gboolean
+parse_a_n_plus_b (GtkCssParser *parser,
+ gint seen_sign,
+ gint *a,
+ gint *b)
{
- int a, b;
+ const GtkCssToken *token;
+
+ token = gtk_css_parser_get_token (parser);
- if (!_gtk_css_parser_try (parser, "(", TRUE))
+ if (!seen_sign && gtk_css_token_is_ident (token, "even"))
{
- _gtk_css_parser_error (parser, "Missing opening bracket for pseudo-class");
- if (selector)
- _gtk_css_selector_free (selector);
- return NULL;
+ *a = 2;
+ *b = 0;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else if (!seen_sign && gtk_css_token_is_ident (token, "odd"))
+ {
+ *a = 2;
+ *b = 1;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
}
+ else if (!seen_sign && gtk_css_token_is_delim (token, '+'))
+ {
+ gtk_css_parser_consume_token (parser);
+ return parse_a_n_plus_b (parser, 1, a, b);
+ }
+ else if (!seen_sign && gtk_css_token_is_delim (token, '-'))
+ {
+ gtk_css_parser_consume_token (parser);
+ return parse_a_n_plus_b (parser, -1, a, b);
+ }
+ else if ((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER)) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
+ {
+ int x = token->number.number * (seen_sign ? seen_sign : 1);
+ gtk_css_parser_consume_token (parser);
- if (_gtk_css_parser_try (parser, "even", TRUE))
+ return parse_n_plus_b (parser, x , a, b);
+ }
+ else if (((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)) &&
+ g_ascii_strcasecmp (token->dimension.dimension, "n") == 0)
+ {
+ *a = token->dimension.value * (seen_sign ? seen_sign : 1);
+ gtk_css_parser_consume_token (parser);
+ return parse_plus_b (parser, FALSE, b);
+ }
+ else if (((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)) &&
+ g_ascii_strcasecmp (token->dimension.dimension, "n-") == 0)
+ {
+ *a = token->dimension.value * (seen_sign ? seen_sign : 1);
+ gtk_css_parser_consume_token (parser);
+ return parse_plus_b (parser, TRUE, b);
+ }
+ else if (((!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER_DIMENSION)) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER_DIMENSION)) &&
+ string_has_number (token->dimension.dimension, "n-", b))
+ {
+ *a = token->dimension.value * (seen_sign ? seen_sign : 1);
+ *b = -*b;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else if (!seen_sign && gtk_css_token_is_ident (token, "-n"))
+ {
+ *a = -1;
+ gtk_css_parser_consume_token (parser);
+ return parse_plus_b (parser, FALSE, b);
+ }
+ else if (!seen_sign && gtk_css_token_is_ident (token, "-n-"))
+ {
+ *a = -1;
+ gtk_css_parser_consume_token (parser);
+ return parse_plus_b (parser, TRUE, b);
+ }
+ else if (!seen_sign &&
+ gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
+ string_has_number (token->string.string, "-n-", b))
+ {
+ *a = -1;
+ *b = -*b;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else if (gtk_css_token_is_ident (token, "n") ||
+ gtk_css_token_is_ident (token, "n-"))
{
- a = 2;
- b = 0;
+ return parse_n_plus_b (parser, seen_sign ? seen_sign : 1, a, b);
}
- else if (_gtk_css_parser_try (parser, "odd", TRUE))
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
+ string_has_number (token->string.string, "n-", b))
{
- a = 2;
- b = 1;
+ *a = seen_sign ? seen_sign : 1;
+ *b = -*b;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
}
- else if (type == POSITION_FORWARD &&
- _gtk_css_parser_try (parser, "first", TRUE))
+ else if (!seen_sign && gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
+ string_has_number (token->string.string, "-n-", b))
{
- a = 0;
- b = 1;
+ *a = -1;
+ *b = -*b;
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
}
- else if (type == POSITION_FORWARD &&
- _gtk_css_parser_try (parser, "last", TRUE))
+
+ gtk_css_parser_error_syntax (parser, "Not a valid an+b type");
+ return FALSE;
+}
+
+static guint
+parse_a_n_plus_b_arg (GtkCssParser *parser,
+ guint arg,
+ gpointer data)
+{
+ gint *ab = data;
+
+ if (!parse_a_n_plus_b (parser, FALSE, &ab[0], &ab[1]))
+ return 0;
+
+ return 1;
+}
+
+static guint
+parse_dir_arg (GtkCssParser *parser,
+ guint arg,
+ gpointer data)
+{
+ GtkStateFlags *flag = data;
+
+ if (gtk_css_parser_try_ident (parser, "ltr"))
+ {
+ *flag = GTK_STATE_FLAG_DIR_LTR;
+ return 1;
+ }
+ else if (gtk_css_parser_try_ident (parser, "rtl"))
{
- a = 0;
- b = 1;
- type = POSITION_BACKWARD;
+ *flag = GTK_STATE_FLAG_DIR_RTL;
+ return 1;
}
else
{
- int multiplier;
+ gtk_css_parser_error_value (parser, "Expected \"ltr\" or \"rtl\"");
+ return 0;
+ }
+}
+
+static guint
+parse_identifier_arg (GtkCssParser *parser,
+ guint arg,
+ gpointer data)
+{
+ const char *ident = data;
+
+ if (!gtk_css_parser_try_ident (parser, ident))
+ {
+ gtk_css_parser_error_value (parser, "Expected \"%s\"", ident);
+ return 0;
+ }
- if (_gtk_css_parser_try (parser, "+", TRUE))
- multiplier = 1;
- else if (_gtk_css_parser_try (parser, "-", TRUE))
- multiplier = -1;
- else
- multiplier = 1;
+ return 1;
+}
+
+static GtkCssSelector *
+gtk_css_selector_parse_selector_pseudo_class (GtkCssParser *parser,
+ GtkCssSelector *selector,
+ gboolean negate)
+{
+ const GtkCssToken *token;
+
+ gtk_css_parser_consume_token (parser);
+ for (token = gtk_css_parser_peek_token (parser);
+ gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT);
+ token = gtk_css_parser_peek_token (parser))
+ {
+ gtk_css_parser_consume_token (parser);
+ }
- if (gtk_css_parser_has_integer (parser))
+ if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ static const struct {
+ const char *name;
+ GtkStateFlags state_flag;
+ PositionType position_type;
+ int position_a;
+ int position_b;
+ } pseudo_classes[] = {
+ { "first-child", 0, POSITION_FORWARD, 0, 1 },
+ { "last-child", 0, POSITION_BACKWARD, 0, 1 },
+ { "only-child", 0, POSITION_ONLY, 0, 0 },
+ { "active", GTK_STATE_FLAG_ACTIVE, },
+ { "hover", GTK_STATE_FLAG_PRELIGHT, },
+ { "selected", GTK_STATE_FLAG_SELECTED, },
+ { "disabled", GTK_STATE_FLAG_INSENSITIVE, },
+ { "indeterminate", GTK_STATE_FLAG_INCONSISTENT, },
+ { "focus", GTK_STATE_FLAG_FOCUSED, },
+ { "backdrop", GTK_STATE_FLAG_BACKDROP, },
+ { "link", GTK_STATE_FLAG_LINK, },
+ { "visited", GTK_STATE_FLAG_VISITED, },
+ { "checked", GTK_STATE_FLAG_CHECKED, },
+ };
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
{
- if (!gtk_css_parser_consume_integer (parser, &a))
+ if (g_ascii_strcasecmp (pseudo_classes[i].name, token->string.string) == 0)
+ {
+ if (pseudo_classes[i].state_flag)
+ {
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = pseudo_classes[i].state_flag;
+ }
+ else
+ {
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
+ selector);
+ selector->position.type = pseudo_classes[i].position_type;
+ selector->position.a = pseudo_classes[i].position_a;
+ selector->position.b = pseudo_classes[i].position_b;
+ }
+ gtk_css_parser_consume_token (parser);
+ return selector;
+ }
+ }
+
+ gtk_css_parser_error_value (parser, "Unknown name of pseudo-class");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_FUNCTION))
+ {
+ if (gtk_css_token_is_function (token, "nth-child"))
+ {
+ gint ab[2];
+
+ if (!gtk_css_parser_consume_function (parser, 1, 1, parse_a_n_plus_b_arg, ab))
{
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
- if (a < 0)
+
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
+ selector);
+ selector->position.type = POSITION_FORWARD;
+ selector->position.a = ab[0];
+ selector->position.b = ab[1];
+ }
+ else if (gtk_css_token_is_function (token, "nth-last-child"))
+ {
+ gint ab[2];
+
+ if (!gtk_css_parser_consume_function (parser, 1, 1, parse_a_n_plus_b_arg, ab))
{
- _gtk_css_parser_error (parser, "Expected an integer");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
}
- a *= multiplier;
- }
- else if (gtk_css_parser_has_ident (parser, "n"))
- {
- a = multiplier;
- }
- else
- {
- _gtk_css_parser_error (parser, "Expected an integer");
- if (selector)
- _gtk_css_selector_free (selector);
- return NULL;
- }
- if (_gtk_css_parser_try (parser, "n", TRUE))
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
+ selector);
+ selector->position.type = POSITION_BACKWARD;
+ selector->position.a = ab[0];
+ selector->position.b = ab[1];
+ }
+ else if (gtk_css_token_is_function (token, "not"))
{
- if (_gtk_css_parser_try (parser, "+", TRUE))
- multiplier = 1;
- else if (_gtk_css_parser_try (parser, "-", TRUE))
- multiplier = -1;
+ if (negate)
+ {
+ gtk_css_parser_error_syntax (parser, "Nesting of :not() not allowed");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
else
- multiplier = 1;
-
- if (gtk_css_parser_has_integer (parser))
{
- if (!gtk_css_parser_consume_integer (parser, &b))
+ gtk_css_parser_start_block (parser);
+ token = gtk_css_parser_get_token (parser);
+
+ if (gtk_css_token_is_delim (token, '*'))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_ANY, selector);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_NAME, selector);
+ selector->name.name = g_intern_string (token->string.string);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_ID, selector);
+ selector->id.name = g_intern_string (token->string.string);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is_delim (token, '.'))
+ {
+ selector = gtk_css_selector_parse_selector_class (parser, selector, TRUE);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
{
+ selector = gtk_css_selector_parse_selector_pseudo_class (parser, selector, TRUE);
+ }
+ else
+ {
+ gtk_css_parser_error_syntax (parser, "Invalid contents of :not() selector");
if (selector)
_gtk_css_selector_free (selector);
+ selector = NULL;
return NULL;
}
- if (b < 0)
+
+ token = gtk_css_parser_get_token (parser);
+ if (!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
- _gtk_css_parser_error (parser, "Expected an integer");
+ gtk_css_parser_error_syntax (parser, "Invalid contents of :not() selector");
if (selector)
_gtk_css_selector_free (selector);
+ selector = NULL;
return NULL;
}
+ gtk_css_parser_end_block (parser);
}
- else
- b = 0;
-
- b *= multiplier;
}
- else
+ else if (gtk_css_token_is_function (token, "dir"))
{
- b = a;
- a = 0;
- }
- }
+ GtkStateFlags flag;
- if (!_gtk_css_parser_try (parser, ")", FALSE))
- {
- _gtk_css_parser_error (parser, "Missing closing bracket for pseudo-class");
- if (selector)
- _gtk_css_selector_free (selector);
- return NULL;
- }
-
- selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
- : &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
- selector);
- selector->position.type = type;
- selector->position.a = a;
- selector->position.b = b;
-
- return selector;
-}
-
-static GtkCssSelector *
-parse_selector_pseudo_class (GtkCssParser *parser,
- GtkCssSelector *selector,
- gboolean negate)
-{
- static const struct {
- const char *name;
- GtkStateFlags state_flag;
- PositionType position_type;
- int position_a;
- int position_b;
- } pseudo_classes[] = {
- { "first-child", 0, POSITION_FORWARD, 0, 1 },
- { "last-child", 0, POSITION_BACKWARD, 0, 1 },
- { "only-child", 0, POSITION_ONLY, 0, 0 },
- { "active", GTK_STATE_FLAG_ACTIVE, },
- { "hover", GTK_STATE_FLAG_PRELIGHT, },
- { "selected", GTK_STATE_FLAG_SELECTED, },
- { "disabled", GTK_STATE_FLAG_INSENSITIVE, },
- { "indeterminate", GTK_STATE_FLAG_INCONSISTENT, },
- { "focus(visible)", GTK_STATE_FLAG_FOCUS_VISIBLE, },
- { "focus", GTK_STATE_FLAG_FOCUSED, },
- { "backdrop", GTK_STATE_FLAG_BACKDROP, },
- { "dir(ltr)", GTK_STATE_FLAG_DIR_LTR, },
- { "dir(rtl)", GTK_STATE_FLAG_DIR_RTL, },
- { "link", GTK_STATE_FLAG_LINK, },
- { "visited", GTK_STATE_FLAG_VISITED, },
- { "checked", GTK_STATE_FLAG_CHECKED, },
- { "drop(active)", GTK_STATE_FLAG_DROP_ACTIVE, }
- };
-
- guint i;
-
- if (_gtk_css_parser_try (parser, "nth-child", FALSE))
- 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, negate);
+ if (!gtk_css_parser_consume_function (parser, 1, 1, parse_dir_arg, &flag))
+ {
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
- for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
- {
- if (_gtk_css_parser_try (parser, pseudo_classes[i].name, FALSE))
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = flag;
+ }
+ else if (gtk_css_token_is_function (token, "drop"))
{
- if (pseudo_classes[i].state_flag)
+ if (!gtk_css_parser_consume_function (parser, 1, 1, parse_identifier_arg, (gpointer) "active"))
{
- selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
- : &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
- selector);
- selector->state.state = pseudo_classes[i].state_flag;
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
}
- else
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = GTK_STATE_FLAG_DROP_ACTIVE;
+ }
+ else if (gtk_css_token_is_function (token, "focus"))
+ {
+ if (!gtk_css_parser_consume_function (parser, 1, 1, parse_identifier_arg, (gpointer) "visible"))
{
- selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
- : &GTK_CSS_SELECTOR_PSEUDOCLASS_POSITION,
- selector);
- selector->position.type = pseudo_classes[i].position_type;
- selector->position.a = pseudo_classes[i].position_a;
- selector->position.b = pseudo_classes[i].position_b;
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
}
- return selector;
+ selector = gtk_css_selector_new (negate ? &GTK_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
+ : &GTK_CSS_SELECTOR_PSEUDOCLASS_STATE,
+ selector);
+ selector->state.state = GTK_STATE_FLAG_FOCUS_VISIBLE;
+ }
+ else
+ {
+ gtk_css_parser_error_value (parser, "Unknown pseudoclass");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ return NULL;
}
}
-
- _gtk_css_parser_error (parser, "Invalid name of pseudo-class");
- if (selector)
- _gtk_css_selector_free (selector);
- return NULL;
-}
-
-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 (&GTK_CSS_SELECTOR_NOT_NAME,
- selector);
- selector->name.name = g_intern_string (name);
- g_free (name);
- }
- else if (_gtk_css_parser_try (parser, "*", FALSE))
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NOT_ANY, selector);
- 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()");
+ gtk_css_parser_error_value (parser, "Unknown pseudoclass");
if (selector)
_gtk_css_selector_free (selector);
return NULL;
@@ -1221,50 +1470,60 @@ parse_selector_negation (GtkCssParser *parser,
}
static GtkCssSelector *
-parse_simple_selector (GtkCssParser *parser,
- GtkCssSelector *selector)
+gtk_css_selector_parse_simple_selector (GtkCssParser *parser,
+ GtkCssSelector *selector)
{
gboolean parsed_something = FALSE;
- char *name;
-
- name = _gtk_css_parser_try_ident (parser, FALSE);
- if (name)
- {
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NAME, selector);
- selector->name.name = g_intern_string (name);
- g_free (name);
- parsed_something = TRUE;
- }
- else if (_gtk_css_parser_try (parser, "*", FALSE))
- {
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ANY, selector);
- parsed_something = TRUE;
- }
+ const GtkCssToken *token;
do {
- if (_gtk_css_parser_try (parser, "#", FALSE))
- selector = parse_selector_id (parser, selector, FALSE);
- else if (_gtk_css_parser_try (parser, ".", FALSE))
- 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, FALSE);
- else if (!parsed_something)
+ for (token = gtk_css_parser_peek_token (parser);
+ gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT);
+ token = gtk_css_parser_peek_token (parser))
{
- _gtk_css_parser_error (parser, "Expected a valid selector");
- if (selector)
- _gtk_css_selector_free (selector);
- return NULL;
+ gtk_css_parser_consume_token (parser);
+ }
+
+ if (!parsed_something && gtk_css_token_is_delim (token, '*'))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ANY, selector);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (!parsed_something && gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_NAME, selector);
+ selector->name.name = g_intern_string (token->string.string);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ID, selector);
+ selector->id.name = g_intern_string (token->string.string);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is_delim (token, '.'))
+ {
+ selector = gtk_css_selector_parse_selector_class (parser, selector, FALSE);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_COLON))
+ {
+ selector = gtk_css_selector_parse_selector_pseudo_class (parser, selector, FALSE);
}
else
- break;
+ {
+ if (!parsed_something)
+ {
+ gtk_css_parser_error_syntax (parser, "Expected a valid selector");
+ if (selector)
+ _gtk_css_selector_free (selector);
+ selector = NULL;
+ }
+ break;
+ }
parsed_something = TRUE;
}
- while (selector && !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF));
-
- _gtk_css_parser_skip_whitespace (parser);
+ while (TRUE);
return selector;
}
@@ -1273,20 +1532,59 @@ GtkCssSelector *
_gtk_css_selector_parse (GtkCssParser *parser)
{
GtkCssSelector *selector = NULL;
+ const GtkCssToken *token;
- while ((selector = parse_simple_selector (parser, selector)) &&
- !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF) &&
- !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_COMMA) &&
- !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_OPEN_CURLY))
+ while (TRUE)
{
- if (_gtk_css_parser_try (parser, "+", TRUE))
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ADJACENT, selector);
- else if (_gtk_css_parser_try (parser, "~", TRUE))
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_SIBLING, selector);
- else if (_gtk_css_parser_try (parser, ">", TRUE))
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_CHILD, selector);
+ gboolean seen_whitespace = FALSE;
+
+ /* skip all whitespace and comments */
+ gtk_css_parser_get_token (parser);
+
+ selector = gtk_css_selector_parse_simple_selector (parser, selector);
+ if (selector == NULL)
+ return NULL;
+
+ for (token = gtk_css_parser_peek_token (parser);
+ gtk_css_token_is (token, GTK_CSS_TOKEN_COMMENT) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
+ token = gtk_css_parser_peek_token (parser))
+ {
+ seen_whitespace |= gtk_css_token_is (token, GTK_CSS_TOKEN_WHITESPACE);
+ gtk_css_parser_consume_token (parser);
+ }
+
+ if (gtk_css_token_is_delim (token, '+'))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_ADJACENT, selector);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is_delim (token, '~'))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_SIBLING, selector);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is_delim (token, '>'))
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_CHILD, selector);
+ gtk_css_parser_consume_token (parser);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_COMMA) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_OPEN_CURLY))
+ {
+ break;
+ }
+ else if (seen_whitespace)
+ {
+ selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_DESCENDANT, selector);
+ }
else
- selector = gtk_css_selector_new (&GTK_CSS_SELECTOR_DESCENDANT, selector);
+ {
+ gtk_css_parser_error_syntax (parser, "Expected a valid selector");
+ _gtk_css_selector_free (selector);
+ return NULL;
+ }
}
return selector;
diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c
index bd8746ab13..072396f6c9 100644
--- a/gtk/gtkcssshadowvalue.c
+++ b/gtk/gtkcssshadowvalue.c
@@ -266,10 +266,7 @@ _gtk_css_shadow_value_parse (GtkCssParser *parser,
}
else if (!inset && box_shadow_mode && gtk_css_parser_try_ident (parser, "inset"))
{
- if (values[HOFFSET] == NULL)
- goto fail;
inset = TRUE;
- break;
}
else if (values[COLOR] == NULL)
{