X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcssparser.c;h=ab38fc9d93560a279dc025aeb925ff48b7c3c3f0;hb=1247a842a228980a06893e6167ae8c73a4bb6eed;hp=cf87ef929a744830b4578b5c4396ac66e32e134d;hpb=e0efeba27e5ab7f72901d4e46630cc2d8b68b18d;p=~andy%2Fgtk diff --git a/gtk/gtkcssparser.c b/gtk/gtkcssparser.c index cf87ef929..ab38fc9d9 100644 --- a/gtk/gtkcssparser.c +++ b/gtk/gtkcssparser.c @@ -12,14 +12,14 @@ * 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. + * License along with this library. If not, see . */ #include "config.h" #include "gtkcssparserprivate.h" + +#include "gtkcssnumbervalueprivate.h" #include "gtkwin32themeprivate.h" #include @@ -38,26 +38,31 @@ struct _GtkCssParser { - const char *data; - GtkCssParserErrorFunc error_func; - gpointer user_data; + const char *data; + GFile *file; + GtkCssParserErrorFunc error_func; + gpointer user_data; - const char *line_start; - guint line; + const char *line_start; + guint line; }; GtkCssParser * _gtk_css_parser_new (const char *data, + GFile *file, GtkCssParserErrorFunc error_func, gpointer user_data) { GtkCssParser *parser; g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); parser = g_slice_new0 (GtkCssParser); parser->data = data; + if (file) + parser->file = g_object_ref (file); parser->error_func = error_func; parser->user_data = user_data; @@ -72,6 +77,9 @@ _gtk_css_parser_free (GtkCssParser *parser) { g_return_if_fail (GTK_IS_CSS_PARSER (parser)); + if (parser->file) + g_object_unref (parser->file); + g_slice_free (GtkCssParser, parser); } @@ -117,6 +125,49 @@ _gtk_css_parser_get_position (GtkCssParser *parser) return parser->data - parser->line_start; } +static GFile * +gtk_css_parser_get_base_file (GtkCssParser *parser) +{ + GFile *base; + + if (parser->file) + { + base = g_file_get_parent (parser->file); + } + else + { + char *dir = g_get_current_dir (); + base = g_file_new_for_path (dir); + g_free (dir); + } + + return base; +} + +GFile * +_gtk_css_parser_get_file_for_path (GtkCssParser *parser, + const char *path) +{ + GFile *base, *file; + + g_return_val_if_fail (parser != NULL, NULL); + g_return_val_if_fail (path != NULL, NULL); + + base = gtk_css_parser_get_base_file (parser); + file = g_file_resolve_relative_path (base, path); + g_object_unref (base); + + return file; +} + +GFile * +_gtk_css_parser_get_file (GtkCssParser *parser) +{ + g_return_val_if_fail (parser != NULL, NULL); + + return parser->file; +} + void _gtk_css_parser_take_error (GtkCssParser *parser, GError *error) @@ -144,6 +195,23 @@ _gtk_css_parser_error (GtkCssParser *parser, _gtk_css_parser_take_error (parser, error); } +void +_gtk_css_parser_error_full (GtkCssParser *parser, + GtkCssProviderError code, + const char *format, + ...) +{ + GError *error; + + va_list args; + + va_start (args, format); + error = g_error_new_valist (GTK_CSS_PROVIDER_ERROR, + code, format, args); + va_end (args); + + _gtk_css_parser_take_error (parser, error); +} static gboolean gtk_css_parser_new_line (GtkCssParser *parser) { @@ -189,7 +257,7 @@ gtk_css_parser_skip_comment (GtkCssParser *parser) parser->data++; - if (parser->data[-2] == '*') + if (len > 0 && parser->data[-2] == '*') return TRUE; if (parser->data[0] == '*') _gtk_css_parser_error (parser, "'/*' in comment block"); @@ -529,6 +597,132 @@ _gtk_css_parser_try_double (GtkCssParser *parser, return TRUE; } +gboolean +_gtk_css_parser_has_number (GtkCssParser *parser) +{ + /* ahem */ + return strchr ("+-0123456789.", parser->data[0]) != NULL; +} + +GtkCssValue * +_gtk_css_number_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 }, + { "pc", GTK_CSS_PC, GTK_CSS_PARSE_LENGTH }, + { "in", GTK_CSS_IN, GTK_CSS_PARSE_LENGTH }, + { "cm", GTK_CSS_CM, GTK_CSS_PARSE_LENGTH }, + { "mm", GTK_CSS_MM, GTK_CSS_PARSE_LENGTH }, + { "rad", GTK_CSS_RAD, GTK_CSS_PARSE_ANGLE }, + { "deg", GTK_CSS_DEG, GTK_CSS_PARSE_ANGLE }, + { "grad", GTK_CSS_GRAD, GTK_CSS_PARSE_ANGLE }, + { "turn", GTK_CSS_TURN, GTK_CSS_PARSE_ANGLE }, + { "s", GTK_CSS_S, GTK_CSS_PARSE_TIME }, + { "ms", GTK_CSS_MS, GTK_CSS_PARSE_TIME } + }; + char *end, *unit_name; + double value; + GtkCssUnit unit; + + g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); + + errno = 0; + value = g_ascii_strtod (parser->data, &end); + if (errno) + { + _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno)); + return NULL; + } + if (parser->data == end) + { + _gtk_css_parser_error (parser, "not a number"); + return NULL; + } + + parser->data = end; + + if (flags & GTK_CSS_POSITIVE_ONLY && + value < 0) + { + _gtk_css_parser_error (parser, "negative values are not allowed."); + return NULL; + } + + unit_name = _gtk_css_parser_try_ident (parser, FALSE); + + if (unit_name) + { + guint i; + + for (i = 0; i < G_N_ELEMENTS (units); i++) + { + if (flags & units[i].required_flags && + g_ascii_strcasecmp (unit_name, units[i].name) == 0) + break; + } + + if (i >= G_N_ELEMENTS (units)) + { + _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit_name); + g_free (unit_name); + return NULL; + } + + unit = units[i].unit; + + g_free (unit_name); + } + else + { + if ((flags & GTK_CSS_PARSE_PERCENT) && + _gtk_css_parser_try (parser, "%", FALSE)) + { + unit = GTK_CSS_PERCENT; + } + else if (value == 0.0) + { + if (flags & GTK_CSS_PARSE_NUMBER) + unit = GTK_CSS_NUMBER; + else if (flags & GTK_CSS_PARSE_LENGTH) + unit = GTK_CSS_PX; + else if (flags & GTK_CSS_PARSE_ANGLE) + unit = GTK_CSS_DEG; + else if (flags & GTK_CSS_PARSE_TIME) + unit = GTK_CSS_S; + else + unit = GTK_CSS_PERCENT; + } + else if (flags & GTK_CSS_NUMBER_AS_PIXELS) + { + _gtk_css_parser_error_full (parser, + GTK_CSS_PROVIDER_ERROR_DEPRECATED, + "Not using units is deprecated. Assuming 'px'."); + unit = GTK_CSS_PX; + } + else if (flags & GTK_CSS_PARSE_NUMBER) + { + unit = GTK_CSS_NUMBER; + } + else + { + _gtk_css_parser_error (parser, "Unit is missing."); + return NULL; + } + } + + _gtk_css_parser_skip_whitespace (parser); + + return _gtk_css_number_value_new (value, unit); +} + /* XXX: we should introduce GtkCssLenght that deals with * different kind of units */ gboolean @@ -594,285 +788,47 @@ _gtk_css_parser_try_enum (GtkCssParser *parser, return result; } -typedef enum { - COLOR_RGBA, - COLOR_RGB, - COLOR_LIGHTER, - COLOR_DARKER, - COLOR_SHADE, - COLOR_ALPHA, - COLOR_MIX, - COLOR_WIN32 -} 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 if (color == COLOR_WIN32) - { - symbolic = _gtk_win32_theme_color_parse (parser); - if (symbolic == NULL) - return NULL; - } - 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) - { - gtk_symbolic_color_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_css_parser_error (parser, "Expected ')' in color definition"); - gtk_symbolic_color_unref (symbolic); - return NULL; - } - - return symbolic; -} - -static GtkSymbolicColor * -gtk_css_parser_try_hash_color (GtkCssParser *parser) +gboolean +_gtk_css_parser_try_hash_color (GtkCssParser *parser, + GdkRGBA *rgba) { if (parser->data[0] == '#' && g_ascii_isxdigit (parser->data[1]) && g_ascii_isxdigit (parser->data[2]) && g_ascii_isxdigit (parser->data[3])) { - 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; + 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; + 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", - GTK_WIN32_THEME_SYMBOLIC_COLOR_NAME}; - char *name; - - g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), NULL); - - if (_gtk_css_parser_try (parser, "transparent", TRUE)) - { - GdkRGBA transparent = { 0, 0, 0, 0 }; - - return gtk_symbolic_color_new_literal (&transparent); - } - - 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; + return TRUE; } - _gtk_css_parser_error (parser, "Not a color definition"); - return NULL; + return FALSE; } GFile * -_gtk_css_parser_read_url (GtkCssParser *parser, - GFile *base) +_gtk_css_parser_read_url (GtkCssParser *parser) { gchar *path; + char *scheme; GFile *file; if (_gtk_css_parser_try (parser, "url", FALSE)) @@ -882,13 +838,9 @@ _gtk_css_parser_read_url (GtkCssParser *parser, _gtk_css_parser_skip_whitespace (parser); if (_gtk_css_parser_try (parser, "(", TRUE)) { - GError *error; - - error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR, - GTK_CSS_PROVIDER_ERROR_DEPRECATED, - "Whitespace between 'url' and '(' is deprecated"); - - _gtk_css_parser_take_error (parser, error); + _gtk_css_parser_error_full (parser, + GTK_CSS_PROVIDER_ERROR_DEPRECATED, + "Whitespace between 'url' and '(' is deprecated"); } else { @@ -907,6 +859,15 @@ _gtk_css_parser_read_url (GtkCssParser *parser, g_free (path); return NULL; } + + scheme = g_uri_parse_scheme (path); + if (scheme != NULL) + { + file = g_file_new_for_uri (path); + g_free (path); + g_free (scheme); + return file; + } } else { @@ -918,17 +879,17 @@ _gtk_css_parser_read_url (GtkCssParser *parser, } } - file = g_file_resolve_relative_path (base, path); + file = _gtk_css_parser_get_file_for_path (parser, path); g_free (path); return file; } -void -_gtk_css_parser_resync_internal (GtkCssParser *parser, - gboolean sync_at_semicolon, - gboolean read_sync_token, - char terminator) +static void +gtk_css_parser_resync_internal (GtkCssParser *parser, + gboolean sync_at_semicolon, + gboolean read_sync_token, + char terminator) { gsize len; @@ -1023,7 +984,7 @@ _gtk_css_parser_read_value (GtkCssParser *parser) start = parser->data; /* This needs to be done better */ - _gtk_css_parser_resync_internal (parser, TRUE, FALSE, '}'); + gtk_css_parser_resync_internal (parser, TRUE, FALSE, '}'); result = g_strndup (start, parser->data - start); if (result) @@ -1049,5 +1010,5 @@ _gtk_css_parser_resync (GtkCssParser *parser, { g_return_if_fail (GTK_IS_CSS_PARSER (parser)); - _gtk_css_parser_resync_internal (parser, sync_at_semicolon, TRUE, terminator); + gtk_css_parser_resync_internal (parser, sync_at_semicolon, TRUE, terminator); }