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);
}