[gtk+/gtk-style-context] GtkCssProvider: Add a parser for 9slice typed properties.



commit bb057e38ee7ada090cb6abd5b0e8cda9149bdc86
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Sep 24 22:05:20 2010 +0200

    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 files changed, 199 insertions(+), 6 deletions(-)
---
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 7e78106..09e9bed 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -23,8 +23,10 @@
 #include <stdlib.h>
 #include <gtk/gtk.h>
 #include <gtkstyleprovider.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 #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
             {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]