css: Rewrite the parser

Instead of relying on GScanner and its idea of syntax, code up a parser
that obeys the CSS spec.
This also has the great side effect of reporting correct line numbers
and positions.

Also included is a reorganization of the returned error values. Instead
of error values describing what type of syntax error was returned, the
code just returns SYNTAX_ERROR. Other messages exist for when actual
values don't work or when errors shouldn't be fatal due to backwards
compatibility.
This commit is contained in:
Benjamin Otte
2011-04-14 04:47:18 +02:00
parent 058bbb2aec
commit 7ccb9db79e
11 changed files with 1981 additions and 1097 deletions

View File

@ -386,6 +386,7 @@ gtk_private_h_sources = \
gtkbuilderprivate.h \
gtkbuttonprivate.h \
gtkcellareaboxcontextprivate.h \
gtkcssparserprivate.h \
gtkcssproviderprivate.h \
gtkcssstringfuncsprivate.h \
gtkcustompaperunixdialog.h \
@ -512,6 +513,7 @@ gtk_base_c_sources = \
gtkcombobox.c \
gtkcomboboxtext.c \
gtkcontainer.c \
gtkcssparser.c \
gtkcssprovider.c \
gtkcssstringfuncs.c \
gtkdialog.c \

938
gtk/gtkcssparser.c Normal file
View File

@ -0,0 +1,938 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gtkcssparserprivate.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;
GtkCssParserErrorFunc error_func;
gpointer user_data;
const char *line_start;
guint line;
};
GtkCssParser *
_gtk_css_parser_new (const char *data,
GtkCssParserErrorFunc error_func,
gpointer user_data)
{
GtkCssParser *parser;
g_return_val_if_fail (data != NULL, NULL);
parser = g_slice_new0 (GtkCssParser);
parser->data = data;
parser->error_func = error_func;
parser->user_data = user_data;
parser->line_start = data;
parser->line = 1;
return parser;
}
void
_gtk_css_parser_free (GtkCssParser *parser)
{
g_return_if_fail (GTK_IS_CSS_PARSER (parser));
g_slice_free (GtkCssParser, parser);
}
gboolean
_gtk_css_parser_is_eof (GtkCssParser *parser)
{
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), TRUE);
return *parser->data == 0;
}
gboolean
_gtk_css_parser_begins_with (GtkCssParser *parser,
char c)
{
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), TRUE);
return *parser->data == c;
}
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;
}
void
_gtk_css_parser_error (GtkCssParser *parser,
const char *format,
...)
{
GError *error;
va_list args;
va_start (args, format);
error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
format, args);
va_end (args);
parser->error_func (parser, error, parser->user_data);
g_error_free (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 (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)
{
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
g_return_val_if_fail (string != NULL, FALSE);
if (g_ascii_strncasecmp (parser->data, string, strlen (string)) != 0)
return FALSE;
parser->data += strlen (string);
if (skip_whitespace)
_gtk_css_parser_skip_whitespace (parser);
return TRUE;
}
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;
}
char *
_gtk_css_parser_try_name (GtkCssParser *parser,
gboolean skip_whitespace)
{
GString *name;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
name = g_string_new (NULL);
while (_gtk_css_parser_read_char (parser, name, NMCHAR))
;
if (skip_whitespace)
_gtk_css_parser_skip_whitespace (parser);
return g_string_free (name, FALSE);
}
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;
ident = g_string_new (NULL);
if (*parser->data == '-')
{
g_string_append_c (ident, '-');
parser->data++;
}
if (!_gtk_css_parser_read_char (parser, ident, NMSTART))
{
parser->data = start;
g_string_free (ident, TRUE);
return NULL;
}
while (_gtk_css_parser_read_char (parser, ident, NMCHAR))
;
if (skip_whitespace)
_gtk_css_parser_skip_whitespace (parser);
return g_string_free (ident, FALSE);
}
gboolean
_gtk_css_parser_is_string (GtkCssParser *parser)
{
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
return *parser->data == '"' || *parser->data == '\'';
}
char *
_gtk_css_parser_read_string (GtkCssParser *parser)
{
GString *str;
char quote;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
quote = *parser->data;
if (quote != '"' && quote != '\'')
return NULL;
parser->data++;
str = g_string_new (NULL);
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 g_string_free (str, FALSE);
}
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_free (str, TRUE);
return NULL;
default:
_gtk_css_parser_error (parser,
"Invalid character in string. Must be escaped.");
g_string_free (str, TRUE);
return NULL;
}
}
g_assert_not_reached ();
return NULL;
}
char *
_gtk_css_parser_read_uri (GtkCssParser *parser)
{
char *result;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
if (!_gtk_css_parser_try (parser, "url(", TRUE))
{
_gtk_css_parser_error (parser, "expected 'url('");
return NULL;
}
_gtk_css_parser_skip_whitespace (parser);
if (_gtk_css_parser_is_string (parser))
{
result = _gtk_css_parser_read_string (parser);
}
else
{
GString *str = g_string_new (NULL);
while (_gtk_css_parser_read_char (parser, str, URLCHAR))
;
result = g_string_free (str, FALSE);
if (result == NULL)
_gtk_css_parser_error (parser, "not a url");
}
if (result == NULL)
return NULL;
_gtk_css_parser_skip_whitespace (parser);
if (*parser->data != ')')
{
_gtk_css_parser_error (parser, "missing ')' for url");
g_free (result);
return NULL;
}
parser->data++;
_gtk_css_parser_skip_whitespace (parser);
return result;
}
gboolean
_gtk_css_parser_try_int (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 == '+')
return FALSE;
errno = 0;
result = g_ascii_strtoll (parser->data, &end, 10);
if (errno)
return FALSE;
if (result > G_MAXINT || result < G_MININT)
return FALSE;
if (parser->data == end)
return FALSE;
parser->data = end;
*value = result;
_gtk_css_parser_skip_whitespace (parser);
return TRUE;
}
gboolean
_gtk_css_parser_try_uint (GtkCssParser *parser,
uint *value)
{
guint64 result;
char *end;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
g_return_val_if_fail (value != NULL, FALSE);
errno = 0;
result = g_ascii_strtoull (parser->data, &end, 10);
if (errno)
return FALSE;
if (result > G_MAXUINT)
return FALSE;
if (parser->data == end)
return FALSE;
parser->data = end;
*value = result;
_gtk_css_parser_skip_whitespace (parser);
return TRUE;
}
gboolean
_gtk_css_parser_try_double (GtkCssParser *parser,
gdouble *value)
{
gdouble result;
char *end;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
g_return_val_if_fail (value != NULL, FALSE);
errno = 0;
result = g_ascii_strtod (parser->data, &end);
if (errno)
return FALSE;
if (parser->data == end)
return FALSE;
parser->data = end;
*value = result;
_gtk_css_parser_skip_whitespace (parser);
return TRUE;
}
typedef enum {
COLOR_RGBA,
COLOR_RGB,
COLOR_LIGHTER,
COLOR_DARKER,
COLOR_SHADE,
COLOR_ALPHA,
COLOR_MIX
} ColorType;
static GtkSymbolicColor *
gtk_css_parser_read_symbolic_color_function (GtkCssParser *parser,
ColorType color)
{
GtkSymbolicColor *symbolic;
GtkSymbolicColor *child1, *child2;
double value;
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;
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_try_double (parser, &tmp))
{
_gtk_css_parser_error (parser, "Invalid number for color value");
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 ();
}
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_try_double (parser, &rgba.alpha))
{
_gtk_css_parser_error (parser, "Invalid number for alpha value");
return NULL;
}
}
else
rgba.alpha = 1.0;
symbolic = gtk_symbolic_color_new_literal (&rgba);
}
else
{
child1 = _gtk_css_parser_read_symbolic_color (parser);
if (child1 == NULL)
return NULL;
if (color == COLOR_MIX)
{
if (!_gtk_css_parser_try (parser, ",", TRUE))
{
_gtk_css_parser_error (parser, "Expected ',' in color definition");
gtk_symbolic_color_unref (child1);
return NULL;
}
child2 = _gtk_css_parser_read_symbolic_color (parser);
if (child2 == NULL)
{
g_object_unref (child1);
return NULL;
}
}
else
child2 = NULL;
if (color == COLOR_LIGHTER)
value = 1.3;
else if (color == COLOR_DARKER)
value = 0.7;
else
{
if (!_gtk_css_parser_try (parser, ",", TRUE))
{
_gtk_css_parser_error (parser, "Expected ',' in color definition");
gtk_symbolic_color_unref (child1);
if (child2)
gtk_symbolic_color_unref (child2);
return NULL;
}
if (!_gtk_css_parser_try_double (parser, &value))
{
_gtk_css_parser_error (parser, "Expected number in color definition");
gtk_symbolic_color_unref (child1);
if (child2)
gtk_symbolic_color_unref (child2);
return NULL;
}
}
switch (color)
{
case COLOR_LIGHTER:
case COLOR_DARKER:
case COLOR_SHADE:
symbolic = gtk_symbolic_color_new_shade (child1, value);
break;
case COLOR_ALPHA:
symbolic = gtk_symbolic_color_new_alpha (child1, value);
break;
case COLOR_MIX:
symbolic = gtk_symbolic_color_new_mix (child1, child2, value);
break;
default:
g_assert_not_reached ();
symbolic = NULL;
}
gtk_symbolic_color_unref (child1);
if (child2)
gtk_symbolic_color_unref (child2);
}
if (!_gtk_css_parser_try (parser, ")", TRUE))
{
gtk_symbolic_color_unref (symbolic);
return NULL;
}
return symbolic;
}
static GtkSymbolicColor *
gtk_css_parser_try_hash_color (GtkCssParser *parser)
{
if (parser->data[0] == '#' &&
g_ascii_isxdigit (parser->data[1]) &&
g_ascii_isxdigit (parser->data[2]) &&
g_ascii_isxdigit (parser->data[3]))
{
GdkRGBA rgba;
if (g_ascii_isxdigit (parser->data[4]) &&
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;
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 = 1.0;
parser->data += 4;
}
_gtk_css_parser_skip_whitespace (parser);
return gtk_symbolic_color_new_literal (&rgba);
}
return NULL;
}
GtkSymbolicColor *
_gtk_css_parser_read_symbolic_color (GtkCssParser *parser)
{
GtkSymbolicColor *symbolic;
guint color;
const char *names[] = {"rgba", "rgb", "lighter", "darker", "shade", "alpha", "mix" };
char *name;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
if (_gtk_css_parser_try (parser, "@", FALSE))
{
name = _gtk_css_parser_try_name (parser, TRUE);
if (name)
{
symbolic = gtk_symbolic_color_new_name (name);
}
else
{
_gtk_css_parser_error (parser, "'%s' is not a valid symbolic color name", name);
symbolic = NULL;
}
g_free (name);
return symbolic;
}
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_parser_read_symbolic_color_function (parser, color);
symbolic = gtk_css_parser_try_hash_color (parser);
if (symbolic)
return symbolic;
name = _gtk_css_parser_try_name (parser, TRUE);
if (name)
{
GdkRGBA rgba;
if (gdk_rgba_parse (&rgba, name))
{
symbolic = gtk_symbolic_color_new_literal (&rgba);
}
else
{
_gtk_css_parser_error (parser, "'%s' is not a valid color name", name);
symbolic = NULL;
}
g_free (name);
return symbolic;
}
_gtk_css_parser_error (parser, "Not a color definition");
return NULL;
}
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_is_string (parser))
{
/* Hrm, this emits errors, and i suspect it shouldn't... */
char *free_me = _gtk_css_parser_read_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, ')');
parser->data++;
break;
case '[':
parser->data++;
_gtk_css_parser_resync (parser, FALSE, ']');
parser->data++;
break;
case '{':
parser->data++;
_gtk_css_parser_resync (parser, FALSE, '}');
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;
default:
break;
}
} while (*parser->data);
}
char *
_gtk_css_parser_read_value (GtkCssParser *parser)
{
const char *start;
char *result;
g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL);
start = parser->data;
/* This needs to be done better */
_gtk_css_parser_resync_internal (parser, TRUE, FALSE, '}');
result = g_strndup (start, parser->data - start);
if (result)
{
g_strchomp (result);
if (result[0] == 0)
{
g_free (result);
result = NULL;
}
}
if (result == NULL)
_gtk_css_parser_error (parser, "Expected a property value");
return result;
}
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);
}

85
gtk/gtkcssparserprivate.h Normal file
View File

@ -0,0 +1,85 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_CSS_PARSER_PRIVATE_H__
#define __GTK_CSS_PARSER_PRIVATE_H__
#include <gtk/gtksymboliccolor.h>
G_BEGIN_DECLS
typedef struct _GtkCssParser GtkCssParser;
typedef void (* GtkCssParserErrorFunc) (GtkCssParser *parser,
const GError *error,
gpointer user_data);
GtkCssParser * _gtk_css_parser_new (const char *data,
GtkCssParserErrorFunc error_func,
gpointer user_data);
void _gtk_css_parser_free (GtkCssParser *parser);
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);
gboolean _gtk_css_parser_is_eof (GtkCssParser *parser);
gboolean _gtk_css_parser_begins_with (GtkCssParser *parser,
char c);
gboolean _gtk_css_parser_is_string (GtkCssParser *parser);
/* 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 (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_int (GtkCssParser *parser,
int *value);
gboolean _gtk_css_parser_try_uint (GtkCssParser *parser,
uint *value);
gboolean _gtk_css_parser_try_double (GtkCssParser *parser,
gdouble *value);
void _gtk_css_parser_skip_whitespace (GtkCssParser *parser);
char * _gtk_css_parser_read_string (GtkCssParser *parser);
char * _gtk_css_parser_read_uri (GtkCssParser *parser);
char * _gtk_css_parser_read_value (GtkCssParser *parser);
GtkSymbolicColor *_gtk_css_parser_read_symbolic_color
(GtkCssParser *parser);
void _gtk_css_parser_resync (GtkCssParser *parser,
gboolean sync_at_semicolon,
char terminator);
G_END_DECLS
#endif /* __GTK_CSS_PARSER_PRIVATE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -37,15 +37,9 @@ typedef enum
{
GTK_CSS_PROVIDER_ERROR_FAILED,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SELECTOR,
GTK_CSS_PROVIDER_ERROR_COMBINATOR,
GTK_CSS_PROVIDER_ERROR_CLASS,
GTK_CSS_PROVIDER_ERROR_PSEUDO_CLASS,
GTK_CSS_PROVIDER_ERROR_AT_RULE,
GTK_CSS_PROVIDER_ERROR_IMPORT,
GTK_CSS_PROVIDER_ERROR_DEFINE_COLOR
GTK_CSS_PROVIDER_ERROR_NAME,
GTK_CSS_PROVIDER_ERROR_DEPRECATED
} GtkCssProviderError;
GQuark gtk_css_provider_error_quark (void);

View File

@ -29,6 +29,7 @@
#include <cairo-gobject.h>
#include "gtkcssprovider.h"
#include "gtkcssparserprivate.h"
/* the actual parsers we have */
#include "gtkanimationdescription.h"
@ -62,7 +63,7 @@ set_default_error (GError **error,
{
g_set_error (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Could not convert property value to type '%s'",
g_type_name (type));
return FALSE;
@ -73,257 +74,35 @@ set_default_error (GError **error,
#define SKIP_SPACES(s) while (g_ascii_isspace (*(s))) (s)++
#define SKIP_SPACES_BACK(s) while (g_ascii_isspace (*(s))) (s)--
static GtkSymbolicColor *
symbolic_color_parse_str (const gchar *string,
gchar **end_ptr)
static void
propagate_parser_error (GtkCssParser *parser,
const GError *error,
gpointer user_data)
{
GtkSymbolicColor *symbolic_color = NULL;
gchar *str;
GError **propagate_here = user_data;
str = (gchar *) string;
*end_ptr = str;
if (propagate_here == NULL)
return;
if (str[0] == '@')
{
const gchar *end;
gchar *name;
/* only copy the first error */
if (*propagate_here == NULL)
*propagate_here = g_error_copy (error);
}
str++;
end = str;
static GtkSymbolicColor *
_gtk_css_parse_symbolic_color (const char *str,
GError **error)
{
GtkSymbolicColor *symbolic;
GtkCssParser *parser;
while (*end == '-' || *end == '_' || g_ascii_isalnum (*end))
end++;
parser = _gtk_css_parser_new (str,
propagate_parser_error,
error);
symbolic = _gtk_css_parser_read_symbolic_color (parser);
_gtk_css_parser_free (parser);
name = g_strndup (str, end - str);
symbolic_color = gtk_symbolic_color_new_name (name);
g_free (name);
*end_ptr = (gchar *) end;
}
else if (g_str_has_prefix (str, "lighter") ||
g_str_has_prefix (str, "darker"))
{
GtkSymbolicColor *param_color;
gboolean is_lighter = FALSE;
is_lighter = g_str_has_prefix (str, "lighter");
if (is_lighter)
str += strlen ("lighter");
else
str += strlen ("darker");
SKIP_SPACES (str);
if (*str != '(')
{
*end_ptr = (gchar *) str;
return NULL;
}
str++;
SKIP_SPACES (str);
param_color = symbolic_color_parse_str (str, end_ptr);
if (!param_color)
return NULL;
str = *end_ptr;
SKIP_SPACES (str);
*end_ptr = (gchar *) str;
if (*str != ')')
{
gtk_symbolic_color_unref (param_color);
return NULL;
}
if (is_lighter)
symbolic_color = gtk_symbolic_color_new_shade (param_color, 1.3);
else
symbolic_color = gtk_symbolic_color_new_shade (param_color, 0.7);
gtk_symbolic_color_unref (param_color);
(*end_ptr)++;
}
else if (g_str_has_prefix (str, "shade") ||
g_str_has_prefix (str, "alpha"))
{
GtkSymbolicColor *param_color;
gboolean is_shade = FALSE;
gdouble factor;
is_shade = g_str_has_prefix (str, "shade");
if (is_shade)
str += strlen ("shade");
else
str += strlen ("alpha");
SKIP_SPACES (str);
if (*str != '(')
{
*end_ptr = (gchar *) str;
return NULL;
}
str++;
SKIP_SPACES (str);
param_color = symbolic_color_parse_str (str, end_ptr);
if (!param_color)
return NULL;
str = *end_ptr;
SKIP_SPACES (str);
if (str[0] != ',')
{
gtk_symbolic_color_unref (param_color);
*end_ptr = (gchar *) str;
return NULL;
}
str++;
SKIP_SPACES (str);
factor = g_ascii_strtod (str, end_ptr);
str = *end_ptr;
SKIP_SPACES (str);
*end_ptr = (gchar *) str;
if (str[0] != ')')
{
gtk_symbolic_color_unref (param_color);
return NULL;
}
if (is_shade)
symbolic_color = gtk_symbolic_color_new_shade (param_color, factor);
else
symbolic_color = gtk_symbolic_color_new_alpha (param_color, factor);
gtk_symbolic_color_unref (param_color);
(*end_ptr)++;
}
else if (g_str_has_prefix (str, "mix"))
{
GtkSymbolicColor *color1, *color2;
gdouble factor;
str += strlen ("mix");
SKIP_SPACES (str);
if (*str != '(')
{
*end_ptr = (gchar *) str;
return NULL;
}
str++;
SKIP_SPACES (str);
color1 = symbolic_color_parse_str (str, end_ptr);
if (!color1)
return NULL;
str = *end_ptr;
SKIP_SPACES (str);
if (str[0] != ',')
{
gtk_symbolic_color_unref (color1);
*end_ptr = (gchar *) str;
return NULL;
}
str++;
SKIP_SPACES (str);
color2 = symbolic_color_parse_str (str, end_ptr);
if (!color2 || *end_ptr[0] != ',')
{
gtk_symbolic_color_unref (color1);
return NULL;
}
str = *end_ptr;
SKIP_SPACES (str);
if (str[0] != ',')
{
gtk_symbolic_color_unref (color1);
gtk_symbolic_color_unref (color2);
*end_ptr = (gchar *) str;
return NULL;
}
str++;
SKIP_SPACES (str);
factor = g_ascii_strtod (str, end_ptr);
str = *end_ptr;
SKIP_SPACES (str);
*end_ptr = (gchar *) str;
if (str[0] != ')')
{
gtk_symbolic_color_unref (color1);
gtk_symbolic_color_unref (color2);
return NULL;
}
symbolic_color = gtk_symbolic_color_new_mix (color1, color2, factor);
gtk_symbolic_color_unref (color1);
gtk_symbolic_color_unref (color2);
(*end_ptr)++;
}
else
{
GdkRGBA color;
gchar *color_str;
const gchar *end;
end = str + 1;
if (str[0] == '#')
{
/* Color in hex format */
while (g_ascii_isxdigit (*end))
end++;
}
else if (g_str_has_prefix (str, "rgb"))
{
/* color in rgb/rgba format */
while (*end != ')' && *end != '\0')
end++;
if (*end == ')')
end++;
}
else
{
/* Color name */
while (*end != '\0' &&
(g_ascii_isalnum (*end) || *end == ' '))
end++;
}
color_str = g_strndup (str, end - str);
*end_ptr = (gchar *) end;
if (!gdk_rgba_parse (&color, color_str))
{
g_free (color_str);
return NULL;
}
symbolic_color = gtk_symbolic_color_new_literal (&color);
g_free (color_str);
}
return symbolic_color;
return symbolic;
}
static gboolean
@ -489,6 +268,9 @@ int_value_from_string (const char *str,
gint64 i;
char *end;
if (*str == '+')
return set_default_error (error, G_VALUE_TYPE (value));
i = g_ascii_strtoll (str, &end, 10);
if (*end != '\0')
@ -498,7 +280,7 @@ int_value_from_string (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Number too big");
return FALSE;
}
@ -522,6 +304,9 @@ uint_value_from_string (const char *str,
guint64 u;
char *end;
if (*str == '+')
return set_default_error (error, G_VALUE_TYPE (value));
u = g_ascii_strtoull (str, &end, 10);
if (*end != '\0')
@ -531,7 +316,7 @@ uint_value_from_string (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Number too big");
return FALSE;
}
@ -564,7 +349,7 @@ double_value_from_string (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Number not representable");
return FALSE;
}
@ -601,7 +386,7 @@ float_value_from_string (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Number not representable");
return FALSE;
}
@ -634,7 +419,7 @@ gtk_css_string_unescape (const char *string,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"String value not properly quoted.");
return NULL;
}
@ -659,7 +444,7 @@ gtk_css_string_unescape (const char *string,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"FIXME: Implement unicode escape sequences.");
g_string_free (str, TRUE);
return NULL;
@ -685,7 +470,7 @@ gtk_css_string_unescape (const char *string,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Junk after end of string.");
g_string_free (str, TRUE);
return NULL;
@ -695,14 +480,14 @@ gtk_css_string_unescape (const char *string,
case '\0':
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Missing end quote in string.");
g_string_free (str, TRUE);
return NULL;
default:
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Invalid character in string. Must be escaped.");
g_string_free (str, TRUE);
return NULL;
@ -783,7 +568,7 @@ theming_engine_value_from_string (const char *str,
{
g_set_error (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Themeing engine '%s' not found", str);
return FALSE;
}
@ -850,7 +635,7 @@ parse_border_value (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Number out of range for border");
return FALSE;
}
@ -859,7 +644,7 @@ parse_border_value (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"No number given for border value");
return FALSE;
}
@ -875,7 +660,7 @@ parse_border_value (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Junk at end of border value");
return FALSE;
}
@ -921,7 +706,7 @@ border_value_from_string (const char *str,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Junk at end of border value");
return FALSE;
}
@ -947,143 +732,92 @@ border_value_to_string (const GValue *value)
return g_strdup_printf ("%d", border->top);
}
static gboolean
gradient_value_from_string (const char *str,
GFile *base,
GValue *value,
GError **error)
static GtkGradient *
_gtk_css_parse_gradient (GtkCssParser *parser)
{
GtkGradient *gradient;
cairo_pattern_type_t type;
gdouble coords[6];
gchar *end;
guint i;
str += strlen ("-gtk-gradient");
SKIP_SPACES (str);
if (*str != '(')
if (!_gtk_css_parser_try (parser, "-gtk-gradient", TRUE))
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
"Expected '(' after '-gtk-gradient'");
return FALSE;
_gtk_css_parser_error (parser,
"Expected '-gtk-gradient'");
return NULL;
}
str++;
SKIP_SPACES (str);
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
_gtk_css_parser_error (parser,
"Expected '(' after '-gtk-gradient'");
return NULL;
}
/* Parse gradient type */
if (g_str_has_prefix (str, "linear"))
{
if (_gtk_css_parser_try (parser, "linear", TRUE))
type = CAIRO_PATTERN_TYPE_LINEAR;
str += strlen ("linear");
}
else if (g_str_has_prefix (str, "radial"))
{
else if (_gtk_css_parser_try (parser, "radial", TRUE))
type = CAIRO_PATTERN_TYPE_RADIAL;
str += strlen ("radial");
}
else
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
_gtk_css_parser_error (parser,
"Gradient type must be 'radial' or 'linear'");
return FALSE;
return NULL;
}
SKIP_SPACES (str);
/* Parse start/stop position parameters */
for (i = 0; i < 2; i++)
{
if (*str != ',')
if (! _gtk_css_parser_try (parser, ",", TRUE))
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
_gtk_css_parser_error (parser,
"Expected ','");
return FALSE;
return NULL;
}
str++;
SKIP_SPACES (str);
if (strncmp (str, "left", 4) == 0)
{
if (_gtk_css_parser_try (parser, "left", TRUE))
coords[i * 3] = 0;
str += strlen ("left");
}
else if (strncmp (str, "right", 5) == 0)
{
else if (_gtk_css_parser_try (parser, "right", TRUE))
coords[i * 3] = 1;
str += strlen ("right");
}
else if (strncmp (str, "center", 6) == 0)
{
else if (_gtk_css_parser_try (parser, "center", TRUE))
coords[i * 3] = 0.5;
str += strlen ("center");
}
else
else if (!_gtk_css_parser_try_double (parser, &coords[i * 3]))
{
coords[i * 3] = g_ascii_strtod (str, &end);
if (str == end)
return set_default_error (error, G_VALUE_TYPE (value));
str = end;
_gtk_css_parser_error (parser,
"Expected a valid X coordinate");
return NULL;
}
SKIP_SPACES (str);
if (strncmp (str, "top", 3) == 0)
if (_gtk_css_parser_try (parser, "top", TRUE))
coords[i * 3 + 1] = 0;
else if (_gtk_css_parser_try (parser, "bottom", TRUE))
coords[i * 3 + 1] = 1;
else if (_gtk_css_parser_try (parser, "center", TRUE))
coords[i * 3 + 1] = 0.5;
else if (!_gtk_css_parser_try_double (parser, &coords[i * 3 + 1]))
{
coords[(i * 3) + 1] = 0;
str += strlen ("top");
_gtk_css_parser_error (parser,
"Expected a valid Y coordinate");
return NULL;
}
else if (strncmp (str, "bottom", 6) == 0)
{
coords[(i * 3) + 1] = 1;
str += strlen ("bottom");
}
else if (strncmp (str, "center", 6) == 0)
{
coords[(i * 3) + 1] = 0.5;
str += strlen ("center");
}
else
{
coords[(i * 3) + 1] = g_ascii_strtod (str, &end);
if (str == end)
return set_default_error (error, G_VALUE_TYPE (value));
str = end;
}
SKIP_SPACES (str);
if (type == CAIRO_PATTERN_TYPE_RADIAL)
{
/* Parse radius */
if (*str != ',')
if (! _gtk_css_parser_try (parser, ",", TRUE))
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
_gtk_css_parser_error (parser,
"Expected ','");
return FALSE;
return NULL;
}
str++;
SKIP_SPACES (str);
coords[(i * 3) + 2] = g_ascii_strtod (str, &end);
str = end;
SKIP_SPACES (str);
if (! _gtk_css_parser_try_double (parser, &coords[(i * 3) + 2]))
{
_gtk_css_parser_error (parser,
"Expected a numer for the radius");
return NULL;
}
}
}
@ -1093,102 +827,120 @@ gradient_value_from_string (const char *str,
gradient = gtk_gradient_new_radial (coords[0], coords[1], coords[2],
coords[3], coords[4], coords[5]);
while (*str == ',')
while (_gtk_css_parser_try (parser, ",", TRUE))
{
GtkSymbolicColor *color;
gdouble position;
str++;
SKIP_SPACES (str);
if (g_str_has_prefix (str, "from"))
if (_gtk_css_parser_try (parser, "from", TRUE))
{
position = 0;
str += strlen ("from");
SKIP_SPACES (str);
if (*str != '(')
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected '('");
return NULL;
}
}
else if (g_str_has_prefix (str, "to"))
else if (_gtk_css_parser_try (parser, "to", TRUE))
{
position = 1;
str += strlen ("to");
SKIP_SPACES (str);
if (*str != '(')
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
}
}
else if (g_str_has_prefix (str, "color-stop"))
{
str += strlen ("color-stop");
SKIP_SPACES (str);
if (*str != '(')
{
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected '('");
return NULL;
}
str++;
SKIP_SPACES (str);
position = g_ascii_strtod (str, &end);
str = end;
SKIP_SPACES (str);
if (*str != ',')
}
else if (_gtk_css_parser_try (parser, "color-stop", TRUE))
{
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
if (!_gtk_css_parser_try (parser, "(", TRUE))
{
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected '('");
return NULL;
}
if (!_gtk_css_parser_try_double (parser, &position))
{
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected a valid number");
return NULL;
}
if (!_gtk_css_parser_try (parser, ",", TRUE))
{
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected a comma");
return NULL;
}
}
else
{
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Not a valid color-stop definition");
return NULL;
}
str++;
SKIP_SPACES (str);
color = symbolic_color_parse_str (str, &end);
str = end;
SKIP_SPACES (str);
if (*str != ')')
color = _gtk_css_parser_read_symbolic_color (parser);
if (color == NULL)
{
if (color)
gtk_symbolic_color_unref (color);
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
gtk_gradient_unref (gradient);
return NULL;
}
str++;
SKIP_SPACES (str);
if (color)
{
gtk_gradient_add_color_stop (gradient, position, color);
gtk_symbolic_color_unref (color);
}
}
if (*str != ')')
if (!_gtk_css_parser_try (parser, ")", TRUE))
{
g_object_unref (gradient);
return set_default_error (error, G_VALUE_TYPE (value));
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected ')'");
return NULL;
}
}
g_value_take_boxed (value, gradient);
if (!_gtk_css_parser_try (parser, ")", TRUE))
{
gtk_gradient_unref (gradient);
_gtk_css_parser_error (parser,
"Expected ')'");
return NULL;
}
return gradient;
}
static gboolean
gradient_value_from_string (const char *str,
GFile *base,
GValue *value,
GError **error)
{
GtkGradient *gradient;
GtkCssParser *parser;
parser = _gtk_css_parser_new (str,
propagate_parser_error,
error);
gradient = _gtk_css_parse_gradient (parser);
_gtk_css_parser_free (parser);
if (gradient == NULL)
return FALSE;
g_value_set_boxed (value, gradient);
return TRUE;
}
@ -1422,7 +1174,7 @@ flags_value_from_string (const char *str,
{
g_set_error (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Unknown flag value '%s' for type '%s'",
strv[i], g_type_name (G_VALUE_TYPE (value)));
g_type_class_unref (flags_class);
@ -1559,7 +1311,7 @@ _gtk_css_value_from_string (GValue *value,
{
g_set_error (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Cannot convert to type '%s'",
g_type_name (G_VALUE_TYPE (value)));
return FALSE;
@ -1587,32 +1339,6 @@ _gtk_css_value_to_string (const GValue *value)
return g_strdup_value_contents (value);
}
GtkSymbolicColor *
_gtk_css_parse_symbolic_color (const char *str,
GError **error)
{
GtkSymbolicColor *color;
gchar *end;
color = symbolic_color_parse_str (str, &end);
if (*end != '\0')
{
if (color)
{
gtk_symbolic_color_unref (color);
color = NULL;
}
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
"Failed to parse symbolic color");
}
return color;
}
GFile *
_gtk_css_parse_url (GFile *base,
const char *str,
@ -1631,7 +1357,7 @@ _gtk_css_parse_url (GFile *base,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Expected '(' after 'url'");
return NULL;
}
@ -1641,7 +1367,7 @@ _gtk_css_parse_url (GFile *base,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"No closing ')' found for 'url'");
return NULL;
}
@ -1665,7 +1391,7 @@ _gtk_css_parse_url (GFile *base,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"Did not find closing quote for url");
return NULL;
}
@ -1674,7 +1400,7 @@ _gtk_css_parse_url (GFile *base,
{
g_set_error_literal (error,
GTK_CSS_PROVIDER_ERROR,
GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
"url not properly escaped");
return NULL;
}

View File

@ -30,9 +30,6 @@ gboolean _gtk_css_value_from_string (GValue *value,
GError **error);
char * _gtk_css_value_to_string (const GValue *value);
GtkSymbolicColor * _gtk_css_parse_symbolic_color (const char *str,
GError **error);
GFile * _gtk_css_parse_url (GFile *base,
const char *str,
char **end,

View File

@ -1,8 +1,8 @@
boolean.css:26: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:29: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:32: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:35: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:38: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:41: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:44: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:47: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
boolean.css:26: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:29: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:32: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:35: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:38: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:41: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:44: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
boolean.css:47: error: GTK_CSS_PROVIDER_ERROR_SYNTAX

View File

@ -1,8 +1,8 @@
border.css:26: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:30: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:34: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:38: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:42: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:46: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:50: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
border.css:54: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME
border.css:26: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:30: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:34: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:38: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:42: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:46: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:50: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
border.css:54: error: GTK_CSS_PROVIDER_ERROR_SYNTAX

View File

@ -1 +1 @@
does-not-exist.css:2: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_NAME
does-not-exist.css:2: error: GTK_CSS_PROVIDER_ERROR_NAME

View File

@ -1,8 +1,8 @@
integer.css:17: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:20: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:23: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:29: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:32: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:17: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:20: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:23: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:29: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:32: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:35: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:38: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:41: error: GTK_CSS_PROVIDER_ERROR_PROPERTY_VALUE
integer.css:38: error: GTK_CSS_PROVIDER_ERROR_SYNTAX
integer.css:41: error: GTK_CSS_PROVIDER_ERROR_SYNTAX