mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
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.
This commit is contained in:
parent
98e076b51e
commit
e0a01ba174
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
||||
gtk_css_parser_start_block (parser);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 (¤t_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;
|
||||
GtkCssValue *color;
|
||||
GtkCssValue *color2;
|
||||
double value;
|
||||
} ColorFunctionData;
|
||||
|
||||
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Missing opening bracket in color definition");
|
||||
return NULL;
|
||||
}
|
||||
static guint
|
||||
parse_color_mix (GtkCssParser *parser,
|
||||
guint arg,
|
||||
gpointer data_)
|
||||
{
|
||||
ColorFunctionData *data = data_;
|
||||
|
||||
if (color == COLOR_RGB || color == COLOR_RGBA)
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
double tmp;
|
||||
guint i;
|
||||
switch (arg)
|
||||
{
|
||||
case 0:
|
||||
data->color = _gtk_css_color_value_parse (parser);
|
||||
if (data->color == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
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;
|
||||
}
|
||||
case 1:
|
||||
data->color2 = _gtk_css_color_value_parse (parser);
|
||||
if (data->color2 == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
if (!gtk_css_parser_consume_number (parser, &tmp))
|
||||
return NULL;
|
||||
case 2:
|
||||
if (!gtk_css_parser_consume_number (parser, &data->value))
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
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 ();
|
||||
}
|
||||
default:
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (color == COLOR_RGBA)
|
||||
{
|
||||
if (i > 0 && !_gtk_css_parser_try (parser, ",", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected ',' in color definition");
|
||||
return NULL;
|
||||
}
|
||||
static guint
|
||||
parse_color_number (GtkCssParser *parser,
|
||||
guint arg,
|
||||
gpointer data_)
|
||||
{
|
||||
ColorFunctionData *data = data_;
|
||||
|
||||
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;
|
||||
switch (arg)
|
||||
{
|
||||
case 0:
|
||||
data->color = _gtk_css_color_value_parse (parser);
|
||||
if (data->color == NULL)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
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;
|
||||
}
|
||||
case 1:
|
||||
if (!gtk_css_parser_consume_number (parser, &data->value))
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
child2 = _gtk_css_color_value_parse (parser);
|
||||
if (child2 == NULL)
|
||||
{
|
||||
_gtk_css_value_unref (child1);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
child2 = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
_gtk_css_value_unref (child1);
|
||||
if (child2)
|
||||
_gtk_css_value_unref (child2);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
value = _gtk_css_color_value_new_name (token->string.string);
|
||||
gtk_css_parser_consume_token (parser);
|
||||
|
||||
return value;
|
||||
}
|
||||
else if (gtk_css_parser_has_function (parser, "lighter"))
|
||||
{
|
||||
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
|
||||
{
|
||||
_gtk_css_parser_error (parser, "'%s' is not a valid color color name", name);
|
||||
value = NULL;
|
||||
}
|
||||
value = NULL;
|
||||
|
||||
g_free (name);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
g_clear_pointer (&data.color, gtk_css_value_unref);
|
||||
return value;
|
||||
}
|
||||
else if (gtk_css_parser_has_function (parser, "mix"))
|
||||
{
|
||||
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
|
||||
value = NULL;
|
||||
|
||||
g_clear_pointer (&data.color, gtk_css_value_unref);
|
||||
g_clear_pointer (&data.color2, gtk_css_value_unref);
|
||||
return value;
|
||||
}
|
||||
|
||||
for (color = 0; color < G_N_ELEMENTS (names); color++)
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, names[color], TRUE))
|
||||
break;
|
||||
}
|
||||
|
||||
if (color < G_N_ELEMENTS (names))
|
||||
return _gtk_css_color_value_parse_function (parser, color);
|
||||
|
||||
if (_gtk_css_parser_try_hash_color (parser, &rgba))
|
||||
if (gdk_rgba_parser_parse (parser, &rgba))
|
||||
return _gtk_css_color_value_new_literal (&rgba);
|
||||
|
||||
name = _gtk_css_parser_try_name (parser, TRUE);
|
||||
if (name)
|
||||
{
|
||||
if (gdk_rgba_parse (&rgba, name))
|
||||
{
|
||||
value = _gtk_css_color_value_new_literal (&rgba);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gtk_css_parser_error (parser, "'%s' is not a valid color name", name);
|
||||
value = NULL;
|
||||
}
|
||||
g_free (name);
|
||||
return value;
|
||||
}
|
||||
|
||||
_gtk_css_parser_error (parser, "Not a color definition");
|
||||
return NULL;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
1244
gtk/gtkcssparser.c
1244
gtk/gtkcssparser.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
gtk_css_parser_end_block_prelude (scanner->parser);
|
||||
|
||||
keyframes = _gtk_css_keyframes_parse (scanner->parser);
|
||||
if (keyframes == NULL)
|
||||
{
|
||||
_gtk_css_parser_resync (scanner->parser, TRUE, '}');
|
||||
g_free (name);
|
||||
goto exit;
|
||||
}
|
||||
if (keyframes != NULL)
|
||||
g_hash_table_insert (priv->keyframes, name, keyframes);
|
||||
|
||||
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_try_token (scanner->parser, GTK_CSS_TOKEN_COLON))
|
||||
if (gtk_css_parser_has_token (scanner->parser, GTK_CSS_TOKEN_EOF))
|
||||
{
|
||||
gtk_css_provider_invalid_token (scanner->provider, scanner, "':'");
|
||||
_gtk_css_parser_resync (scanner->parser, TRUE, '}');
|
||||
g_free (name);
|
||||
gtk_css_parser_warn_syntax (scanner->parser, "Empty declaration");
|
||||
gtk_css_parser_end_block (scanner->parser);
|
||||
return;
|
||||
}
|
||||
|
||||
name = gtk_css_parser_consume_ident (scanner->parser);
|
||||
if (name == NULL)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = _gtk_css_parser_try_name (parser, FALSE);
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected a valid name for class");
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_CLASS
|
||||
: >K_CSS_SELECTOR_CLASS,
|
||||
selector);
|
||||
selector->style_class.style_class = g_quark_from_string (name);
|
||||
|
||||
g_free (name);
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
static GtkCssSelector *
|
||||
parse_selector_id (GtkCssParser *parser,
|
||||
GtkCssSelector *selector,
|
||||
gboolean negate)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = _gtk_css_parser_try_name (parser, FALSE);
|
||||
|
||||
if (name == NULL)
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected a valid name for id");
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_ID
|
||||
: >K_CSS_SELECTOR_ID,
|
||||
selector);
|
||||
selector->id.name = g_intern_string (name);
|
||||
|
||||
g_free (name);
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
static GtkCssSelector *
|
||||
parse_selector_pseudo_class_nth_child (GtkCssParser *parser,
|
||||
gtk_css_selector_parse_selector_class (GtkCssParser *parser,
|
||||
GtkCssSelector *selector,
|
||||
PositionType type,
|
||||
gboolean negate)
|
||||
{
|
||||
int a, b;
|
||||
const GtkCssToken *token;
|
||||
|
||||
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
||||
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_error (parser, "Missing opening bracket for pseudo-class");
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
gtk_css_parser_consume_token (parser);
|
||||
}
|
||||
|
||||
if (_gtk_css_parser_try (parser, "even", TRUE))
|
||||
if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
|
||||
{
|
||||
a = 2;
|
||||
b = 0;
|
||||
}
|
||||
else if (_gtk_css_parser_try (parser, "odd", TRUE))
|
||||
{
|
||||
a = 2;
|
||||
b = 1;
|
||||
}
|
||||
else if (type == POSITION_FORWARD &&
|
||||
_gtk_css_parser_try (parser, "first", TRUE))
|
||||
{
|
||||
a = 0;
|
||||
b = 1;
|
||||
}
|
||||
else if (type == POSITION_FORWARD &&
|
||||
_gtk_css_parser_try (parser, "last", TRUE))
|
||||
{
|
||||
a = 0;
|
||||
b = 1;
|
||||
type = POSITION_BACKWARD;
|
||||
}
|
||||
else
|
||||
{
|
||||
int multiplier;
|
||||
|
||||
if (_gtk_css_parser_try (parser, "+", TRUE))
|
||||
multiplier = 1;
|
||||
else if (_gtk_css_parser_try (parser, "-", TRUE))
|
||||
multiplier = -1;
|
||||
else
|
||||
multiplier = 1;
|
||||
|
||||
if (gtk_css_parser_has_integer (parser))
|
||||
{
|
||||
if (!gtk_css_parser_consume_integer (parser, &a))
|
||||
{
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
if (a < 0)
|
||||
{
|
||||
_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))
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, "+", TRUE))
|
||||
multiplier = 1;
|
||||
else if (_gtk_css_parser_try (parser, "-", TRUE))
|
||||
multiplier = -1;
|
||||
else
|
||||
multiplier = 1;
|
||||
|
||||
if (gtk_css_parser_has_integer (parser))
|
||||
{
|
||||
if (!gtk_css_parser_consume_integer (parser, &b))
|
||||
{
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
if (b < 0)
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected an integer");
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
b = 0;
|
||||
|
||||
b *= multiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = a;
|
||||
a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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 ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
|
||||
: >K_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);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (pseudo_classes); i++)
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, pseudo_classes[i].name, FALSE))
|
||||
{
|
||||
if (pseudo_classes[i].state_flag)
|
||||
{
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
|
||||
: >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
|
||||
selector);
|
||||
selector->state.state = pseudo_classes[i].state_flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
|
||||
: >K_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;
|
||||
}
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
|
||||
_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 (>K_CSS_SELECTOR_NOT_NAME,
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_CLASS
|
||||
: >K_CSS_SELECTOR_CLASS,
|
||||
selector);
|
||||
selector->name.name = g_intern_string (name);
|
||||
g_free (name);
|
||||
selector->style_class.style_class = g_quark_from_string (token->string.string);
|
||||
gtk_css_parser_consume_token (parser);
|
||||
return selector;
|
||||
}
|
||||
else if (_gtk_css_parser_try (parser, "*", FALSE))
|
||||
selector = gtk_css_selector_new (>K_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()");
|
||||
gtk_css_parser_error_syntax (parser, "No class name after '.' in selector");
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
string_has_number (const char *string,
|
||||
const char *prefix,
|
||||
int *number)
|
||||
{
|
||||
gsize len = strlen (prefix);
|
||||
char *end;
|
||||
|
||||
if (g_ascii_strncasecmp (string, prefix, len) != 0)
|
||||
return FALSE;
|
||||
|
||||
errno = 0;
|
||||
*number = strtoul (string + len, &end, 10);
|
||||
if (*end != '\0' || errno != 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_plus_b (GtkCssParser *parser,
|
||||
gboolean negate,
|
||||
gint *b)
|
||||
{
|
||||
const GtkCssToken *token;
|
||||
gboolean has_seen_sign;
|
||||
|
||||
token = gtk_css_parser_get_token (parser);
|
||||
|
||||
if (negate)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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_skip_whitespace (parser);
|
||||
gtk_css_parser_error_syntax (parser, "Not a valid an+b type");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_gtk_css_parser_try (parser, ")", FALSE))
|
||||
static gboolean
|
||||
parse_n_plus_b (GtkCssParser *parser,
|
||||
gint before,
|
||||
gint *a,
|
||||
gint *b)
|
||||
{
|
||||
const GtkCssToken *token;
|
||||
|
||||
token = gtk_css_parser_get_token (parser);
|
||||
|
||||
if (gtk_css_token_is_ident (token, "n"))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Missing closing bracket for :not()");
|
||||
*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)
|
||||
{
|
||||
const GtkCssToken *token;
|
||||
|
||||
token = gtk_css_parser_get_token (parser);
|
||||
|
||||
if (!seen_sign && gtk_css_token_is_ident (token, "even"))
|
||||
{
|
||||
*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);
|
||||
|
||||
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-"))
|
||||
{
|
||||
return parse_n_plus_b (parser, seen_sign ? seen_sign : 1, a, b);
|
||||
}
|
||||
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT) &&
|
||||
string_has_number (token->string.string, "n-", b))
|
||||
{
|
||||
*a = seen_sign ? seen_sign : 1;
|
||||
*b = -*b;
|
||||
gtk_css_parser_consume_token (parser);
|
||||
return TRUE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
*flag = GTK_STATE_FLAG_DIR_RTL;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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_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 (g_ascii_strcasecmp (pseudo_classes[i].name, token->string.string) == 0)
|
||||
{
|
||||
if (pseudo_classes[i].state_flag)
|
||||
{
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
|
||||
: >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
|
||||
selector);
|
||||
selector->state.state = pseudo_classes[i].state_flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
|
||||
: >K_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;
|
||||
}
|
||||
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
|
||||
: >K_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))
|
||||
{
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_POSITION
|
||||
: >K_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 (negate)
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Nesting of :not() not allowed");
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (>K_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 (>K_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 (>K_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;
|
||||
}
|
||||
|
||||
token = gtk_css_parser_get_token (parser);
|
||||
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
|
||||
{
|
||||
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 if (gtk_css_token_is_function (token, "dir"))
|
||||
{
|
||||
GtkStateFlags flag;
|
||||
|
||||
if (!gtk_css_parser_consume_function (parser, 1, 1, parse_dir_arg, &flag))
|
||||
{
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
|
||||
: >K_CSS_SELECTOR_PSEUDOCLASS_STATE,
|
||||
selector);
|
||||
selector->state.state = flag;
|
||||
}
|
||||
else if (gtk_css_token_is_function (token, "drop"))
|
||||
{
|
||||
if (!gtk_css_parser_consume_function (parser, 1, 1, parse_identifier_arg, (gpointer) "active"))
|
||||
{
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
|
||||
: >K_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"))
|
||||
{
|
||||
if (selector)
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
selector = gtk_css_selector_new (negate ? >K_CSS_SELECTOR_NOT_PSEUDOCLASS_STATE
|
||||
: >K_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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (>K_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 (>K_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 (>K_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 (>K_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 (>K_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 (>K_CSS_SELECTOR_ADJACENT, selector);
|
||||
else if (_gtk_css_parser_try (parser, "~", TRUE))
|
||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_SIBLING, selector);
|
||||
else if (_gtk_css_parser_try (parser, ">", TRUE))
|
||||
selector = gtk_css_selector_new (>K_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 (>K_CSS_SELECTOR_ADJACENT, selector);
|
||||
gtk_css_parser_consume_token (parser);
|
||||
}
|
||||
else if (gtk_css_token_is_delim (token, '~'))
|
||||
{
|
||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_SIBLING, selector);
|
||||
gtk_css_parser_consume_token (parser);
|
||||
}
|
||||
else if (gtk_css_token_is_delim (token, '>'))
|
||||
{
|
||||
selector = gtk_css_selector_new (>K_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 (>K_CSS_SELECTOR_DESCENDANT, selector);
|
||||
}
|
||||
else
|
||||
selector = gtk_css_selector_new (>K_CSS_SELECTOR_DESCENDANT, selector);
|
||||
{
|
||||
gtk_css_parser_error_syntax (parser, "Expected a valid selector");
|
||||
_gtk_css_selector_free (selector);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return selector;
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user