From 7ee564c7cd02c2756dd54d46bfad3caf3e82c7ac Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 24 Sep 2010 22:05:20 +0200 Subject: [PATCH] GtkCssProvider: Add a parser for 9slice typed properties. The value it parses is similar to the border-image CSS3 property, so strings like this will be accepted: border-image: url (foo.png) 4 3 4 3 repeat repeat; the image path is relative to the parsed CSS file dirname if no absolute path is provided. --- gtk/gtkcssprovider.c | 205 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 199 insertions(+), 6 deletions(-) diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c index e118c1a781..de28e26553 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -23,8 +23,10 @@ #include #include #include +#include #include "gtkanimationdescription.h" +#include "gtk9slice.h" #include "gtkcssprovider.h" typedef struct GtkCssProviderPrivate GtkCssProviderPrivate; @@ -125,8 +127,9 @@ static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface); static void css_provider_apply_scope (GtkCssProvider *css_provider, ParserScope scope); -static gboolean css_provider_parse_value (const gchar *value_str, - GValue *value); +static gboolean css_provider_parse_value (GtkCssProvider *css_provider, + const gchar *value_str, + GValue *value); G_DEFINE_TYPE_EXTENDED (GtkCssProvider, gtk_css_provider, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER, @@ -696,7 +699,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider, val_str = g_value_get_string (val); found = TRUE; - css_provider_parse_value (val_str, value); + css_provider_parse_value (GTK_CSS_PROVIDER (provider), val_str, value); break; } } @@ -1564,9 +1567,188 @@ gradient_parse (const gchar *str) return gradient; } +static gchar * +url_parse_str (const gchar *str, + gchar **end_ptr) +{ + gchar *path, *chr; + + if (!g_str_has_prefix (str, "url")) + { + *end_ptr = (gchar *) str; + return NULL; + } + + str += strlen ("url"); + SKIP_SPACES (str); + + if (*str != '(') + { + *end_ptr = (gchar *) str; + return NULL; + } + + chr = strchr (str, ')'); + + if (!chr) + { + *end_ptr = (gchar *) str; + return NULL; + } + + str++; + SKIP_SPACES (str); + + path = g_strndup (str, chr - str); + g_strstrip (path); + + *end_ptr = chr + 1; + + return path; +} + +static Gtk9Slice * +slice_parse_str (GtkCssProvider *css_provider, + const gchar *str, + gchar **end_ptr) +{ + gdouble distance_top, distance_bottom; + gdouble distance_left, distance_right; + GtkSliceSideModifier mods[2]; + GError *error = NULL; + GdkPixbuf *pixbuf; + gchar *path; + gint i = 0; + + SKIP_SPACES (str); + + /* Parse image url */ + path = url_parse_str (str, end_ptr); + + if (!path) + return NULL; + + if (!g_path_is_absolute (path)) + { + GtkCssProviderPrivate *priv; + gchar *dirname, *full_path; + + priv = css_provider->priv; + + /* Use relative path to the current CSS file path, if any */ + dirname = g_path_get_dirname (priv->filename); + + full_path = g_build_filename (dirname, path, NULL); + g_free (path); + path = full_path; + } + + str = *end_ptr; + SKIP_SPACES (str); + + /* Parse top/left/bottom/right distances */ + distance_top = g_strtod (str, end_ptr); + + str = *end_ptr; + SKIP_SPACES (str); + + distance_right = g_strtod (str, end_ptr); + + str = *end_ptr; + SKIP_SPACES (str); + + distance_bottom = g_strtod (str, end_ptr); + + str = *end_ptr; + SKIP_SPACES (str); + + distance_left = g_strtod (str, end_ptr); + + str = *end_ptr; + SKIP_SPACES (str); + + while (*str && i < 2) + { + if (g_str_has_prefix (str, "stretch")) + { + str += strlen ("stretch"); + mods[i] = GTK_SLICE_STRETCH; + } + else if (g_str_has_prefix (str, "repeat")) + { + str += strlen ("repeat"); + mods[i] = GTK_SLICE_REPEAT; + } + else + { + g_free (path); + *end_ptr = (gchar *) str; + return NULL; + } + + SKIP_SPACES (str); + i++; + } + + *end_ptr = (gchar *) str; + + if (*str != '\0') + { + g_free (path); + return NULL; + } + + if (i != 2) + { + /* Fill in second modifier, same as the first */ + mods[1] = mods[1]; + } + + pixbuf = gdk_pixbuf_new_from_file (path, &error); + g_free (path); + + if (error) + { + g_warning ("Pixbuf could not be loaded: %s\n", error->message); + g_error_free (error); + *end_ptr = (gchar *) str; + return NULL; + } + + return gtk_9slice_new (pixbuf, + distance_top, distance_bottom, + distance_left, distance_right, + mods[0], mods[1]); +} + +static Gtk9Slice * +slice_parse (GtkCssProvider *css_provider, + const gchar *str) +{ + Gtk9Slice *slice; + gchar *end; + + slice = slice_parse_str (css_provider, str, &end); + + if (*end != '\0') + { + g_warning ("Error parsing sliced image \"%s\", stopped at char %ld : '%c'", + str, end - str, *end); + + if (slice) + { + gtk_9slice_unref (slice); + slice = NULL; + } + } + + return slice; +} + static gboolean -css_provider_parse_value (const gchar *value_str, - GValue *value) +css_provider_parse_value (GtkCssProvider *css_provider, + const gchar *value_str, + GValue *value) { GType type; gboolean parsed = TRUE; @@ -1682,6 +1864,17 @@ css_provider_parse_value (const gchar *value_str, else parsed = FALSE; } + else if (type == GTK_TYPE_9SLICE) + { + Gtk9Slice *slice; + + slice = slice_parse (css_provider, value_str); + + if (slice) + g_value_take_boxed (value, slice); + else + parsed = FALSE; + } else { g_warning ("Cannot parse string '%s' for type %s", value_str, g_type_name (type)); @@ -1814,7 +2007,7 @@ parse_rule (GtkCssProvider *css_provider, g_hash_table_insert (priv->cur_properties, prop, val); } else if ((parse_func && (parse_func) (value_str, val, &error)) || - (!parse_func && css_provider_parse_value (value_str, val))) + (!parse_func && css_provider_parse_value (css_provider, value_str, val))) g_hash_table_insert (priv->cur_properties, prop, val); else {