]> git.sur5r.net Git - glabels/blobdiff - src/label-image.c
Imported Upstream version 3.0.0
[glabels] / src / label-image.c
index 9d0bcaf2ffd6bc8ed197f8199073dc5a3ea97639..f5e458559ea87149080b91e1e2e91dd8fb37679b 100644 (file)
@@ -1,34 +1,35 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-
 /*
- *  (GLABELS) Label and Business Card Creation program for GNOME
- *
- *  label_image.c:  GLabels label image object
+ *  label-image.c
+ *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
  *
- *  Copyright (C) 2001-2007  Jim Evins <evins@snaught.com>.
+ *  This file is part of gLabels.
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  gLabels is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
+ *  gLabels 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 General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <config.h>
+
 #include "label-image.h"
 
-#include <glib/gmem.h>
-#include <glib/gstrfuncs.h>
-#include <glib/gmessages.h>
-#include <gdk/gdkcairo.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <librsvg/rsvg.h>
+#include <librsvg/rsvg-cairo.h>
 
+#include "pixbuf-util.h"
+#include "file-util.h"
 #include "pixmaps/checkerboard.xpm"
 
 #include "debug.h"
 /* Private types.                                         */
 /*========================================================*/
 
+typedef enum {
+        FILE_TYPE_NONE,
+        FILE_TYPE_PIXBUF,
+        FILE_TYPE_SVG
+} FileType;
+
+
 struct _glLabelImagePrivate {
-       glTextNode       *filename;
-       GdkPixbuf        *pixbuf;
+
+        glTextNode       *filename;
+
+        FileType          type;
+
+        GdkPixbuf        *pixbuf;
+        RsvgHandle       *svg_handle;
 };
 
+
 /*========================================================*/
 /* Private globals.                                       */
 /*========================================================*/
 
 static GdkPixbuf *default_pixbuf = NULL;
 
+
 /*========================================================*/
 /* Private function prototypes.                           */
 /*========================================================*/
@@ -59,94 +74,140 @@ static GdkPixbuf *default_pixbuf = NULL;
 static void gl_label_image_finalize      (GObject           *object);
 
 static void copy                         (glLabelObject     *dst_object,
-                                         glLabelObject     *src_object);
+                                          glLabelObject     *src_object);
+
+static void set_size                     (glLabelObject     *object,
+                                          gdouble            w,
+                                          gdouble            h,
+                                          gboolean           checkpoint);
 
-static void set_size                      (glLabelObject      *object,
-                                          gdouble             w,
-                                          gdouble             h);
+static void draw_object                  (glLabelObject     *object,
+                                          cairo_t           *cr,
+                                          gboolean           screen_flag,
+                                          glMergeRecord     *record);
 
-static void    draw_object               (glLabelObject     *object,
+static void draw_shadow                  (glLabelObject     *object,
                                           cairo_t           *cr,
                                           gboolean           screen_flag,
                                           glMergeRecord     *record);
 
+static gboolean object_at                (glLabelObject     *object,
+                                          cairo_t           *cr,
+                                          gdouble            x_pixels,
+                                          gdouble            y_pixels);
+
 
-\f
 /*****************************************************************************/
 /* Boilerplate object stuff.                                                 */
 /*****************************************************************************/
-G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT);
+G_DEFINE_TYPE (glLabelImage, gl_label_image, GL_TYPE_LABEL_OBJECT)
+
 
 static void
 gl_label_image_class_init (glLabelImageClass *class)
 {
-       GObjectClass       *object_class       = G_OBJECT_CLASS (class);
-       glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
-
-       gl_label_image_parent_class = g_type_class_peek_parent (class);
+        GObjectClass       *object_class       = G_OBJECT_CLASS (class);
+        glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
+        GdkPixbuf          *pixbuf;
 
-       label_object_class->copy           = copy;
-       label_object_class->set_size       = set_size;
-        label_object_class->draw_object    = draw_object;
-        label_object_class->draw_shadow    = NULL;
+        gl_label_image_parent_class = g_type_class_peek_parent (class);
 
-       object_class->finalize = gl_label_image_finalize;
-}
+        label_object_class->copy              = copy;
+        label_object_class->set_size          = set_size;
+        label_object_class->draw_object       = draw_object;
+        label_object_class->draw_shadow       = draw_shadow;
+        label_object_class->object_at         = object_at;
 
-static void
-gl_label_image_init (glLabelImage *limage)
-{
-        GdkPixbuf *pixbuf;
+        object_class->finalize = gl_label_image_finalize;
 
-       if ( default_pixbuf == NULL ) {
-               pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
+        if ( default_pixbuf == NULL ) {
+                pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)checkerboard_xpm);
                 default_pixbuf =
                         gdk_pixbuf_scale_simple (pixbuf, 128, 128, GDK_INTERP_NEAREST);
                 g_object_unref (pixbuf);
-       }
+        }
+}
 
-       limage->priv = g_new0 (glLabelImagePrivate, 1);
 
-       limage->priv->filename = g_new0 (glTextNode, 1);
+static void
+gl_label_image_init (glLabelImage *this)
+{
+        this->priv = g_new0 (glLabelImagePrivate, 1);
+
+        this->priv->filename = g_new0 (glTextNode, 1);
 
-       limage->priv->pixbuf = default_pixbuf;
+        this->priv->type       = FILE_TYPE_NONE;
+        this->priv->pixbuf     = NULL;
+        this->priv->svg_handle = NULL;
 }
 
+
 static void
 gl_label_image_finalize (GObject *object)
 {
-       glLabelObject *lobject = GL_LABEL_OBJECT (object);
-       glLabelImage  *limage  = GL_LABEL_IMAGE (object);;
-       GHashTable    *pixbuf_cache;
+        glLabelObject *lobject = GL_LABEL_OBJECT (object);
+        glLabelImage  *this  = GL_LABEL_IMAGE (object);
+        glLabel       *label;
+        GHashTable    *cache;
 
-       g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
+        g_return_if_fail (object && GL_IS_LABEL_IMAGE (object));
 
-       if (!limage->priv->filename->field_flag) {
-               pixbuf_cache = gl_label_get_pixbuf_cache (lobject->parent);
-               gl_pixbuf_cache_remove_pixbuf (pixbuf_cache,
-                                              limage->priv->filename->data);
-       }
-       gl_text_node_free (&limage->priv->filename);
-       g_free (limage->priv);
+        if (!this->priv->filename->field_flag) {
+                
+                label = gl_label_object_get_parent (lobject);
+
+                switch ( this->priv->type )
+                {
+
+                case FILE_TYPE_PIXBUF:
+                        cache = gl_label_get_pixbuf_cache (label);
+                        gl_pixbuf_cache_remove_pixbuf (cache, this->priv->filename->data);
+                        break;
+
+                case FILE_TYPE_SVG:
+                        cache = gl_label_get_svg_cache (label);
+                        gl_svg_cache_remove_svg (cache, this->priv->filename->data);
+                        break;
+
+                default:
+                        break;
+
+                }
+
+        }
+        gl_text_node_free (&this->priv->filename);
+        g_free (this->priv);
 
-       G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
+        G_OBJECT_CLASS (gl_label_image_parent_class)->finalize (object);
 }
 
+
 /*****************************************************************************/
 /* NEW label "image" object.                                                 */
 /*****************************************************************************/
 GObject *
-gl_label_image_new (glLabel *label)
+gl_label_image_new (glLabel *label,
+                    gboolean checkpoint)
 {
-       glLabelImage *limage;
+        glLabelImage *this;
+
+        this = g_object_new (gl_label_image_get_type(), NULL);
 
-       limage = g_object_new (gl_label_image_get_type(), NULL);
+        if (label != NULL)
+        {
+                if ( checkpoint )
+                {
+                        gl_label_checkpoint (label, _("Create image object"));
+                }
 
-       gl_label_object_set_parent (GL_LABEL_OBJECT(limage), label);
+                gl_label_add_object (label, GL_LABEL_OBJECT (this));
+                gl_label_object_set_parent (GL_LABEL_OBJECT (this), label);
+        }
 
-       return G_OBJECT (limage);
+        return G_OBJECT (this);
 }
 
+
 /*****************************************************************************/
 /* Copy object contents.                                                     */
 /*****************************************************************************/
@@ -154,32 +215,58 @@ static void
 copy (glLabelObject *dst_object,
       glLabelObject *src_object)
 {
-       glLabelImage     *limage     = (glLabelImage *)src_object;
-       glLabelImage     *new_limage = (glLabelImage *)dst_object;
-       glTextNode       *filename;
-       GdkPixbuf        *pixbuf;
-       GHashTable       *pixbuf_cache;
+        glLabelImage     *src_limage = (glLabelImage *)src_object;
+        glLabelImage     *new_limage = (glLabelImage *)dst_object;
+        glTextNode       *filename;
+        GdkPixbuf        *pixbuf;
+        gchar            *contents;
+        glLabel          *src_label, *dst_label;
+        GHashTable       *cache;
 
-       gl_debug (DEBUG_LABEL, "START");
+        gl_debug (DEBUG_LABEL, "START");
 
-       g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
-       g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
+        g_return_if_fail (src_limage && GL_IS_LABEL_IMAGE (src_limage));
+        g_return_if_fail (new_limage && GL_IS_LABEL_IMAGE (new_limage));
 
-       filename = gl_label_image_get_filename (limage);
+        filename = gl_label_image_get_filename (src_limage);
 
-       /* Make sure destination label has data suitably cached. */
-       if ( !filename->field_flag && (filename->data != NULL) ) {
-               pixbuf = limage->priv->pixbuf;
-               if ( pixbuf != default_pixbuf ) {
-                       pixbuf_cache = gl_label_get_pixbuf_cache (dst_object->parent);
-                       gl_pixbuf_cache_add_pixbuf (pixbuf_cache, filename->data, pixbuf);
-               }
-       }
+        /* Make sure destination label has data suitably cached. */
+        if ( !filename->field_flag && (src_limage->priv->type != FILE_TYPE_NONE) )
+        {
+                src_label = gl_label_object_get_parent (src_object);
+                dst_label = gl_label_object_get_parent (dst_object);
+
+                switch ( src_limage->priv->type )
+                {
+
+                case FILE_TYPE_PIXBUF:
+                        pixbuf = src_limage->priv->pixbuf;
+                        if ( pixbuf != NULL ) {
+                                cache = gl_label_get_pixbuf_cache (dst_label);
+                                gl_pixbuf_cache_add_pixbuf (cache, filename->data, pixbuf);
+                        }
+                        break;
+
+                case FILE_TYPE_SVG:
+                        cache = gl_label_get_svg_cache (src_label);
+                        contents = gl_svg_cache_get_contents (cache, filename->data);
+                        if ( contents != NULL ) {
+                                cache = gl_label_get_svg_cache (dst_label);
+                                gl_svg_cache_add_svg (cache, filename->data, contents);
+                                g_free (contents);
+                        }
+                        break;
+
+                default:
+                        break;
+
+                }
+        }
 
-       gl_label_image_set_filename (new_limage, filename);
-       gl_text_node_free (&filename);
+        gl_label_image_set_filename (new_limage, filename, FALSE);
+        gl_text_node_free (&filename);
 
-       gl_debug (DEBUG_LABEL, "END");
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
@@ -188,10 +275,11 @@ copy (glLabelObject *dst_object,
 /*---------------------------------------------------------------------------*/
 static void
 set_size (glLabelObject *object,
-         gdouble        w,
-         gdouble        h)
+          gdouble        w,
+          gdouble        h,
+          gboolean       checkpoint)
 {
-       g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
+        g_return_if_fail (object && GL_IS_LABEL_OBJECT (object));
 
         if (w < MIN_IMAGE_SIZE)
         {
@@ -203,7 +291,7 @@ set_size (glLabelObject *object,
                 h = MIN_IMAGE_SIZE;
         }
 
-       GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h);
+        GL_LABEL_OBJECT_CLASS (gl_label_image_parent_class)->set_size (object, w, h, checkpoint);
 }
 
 
@@ -211,114 +299,382 @@ set_size (glLabelObject *object,
 /* Set object params.                                                        */
 /*****************************************************************************/
 void
-gl_label_image_set_filename (glLabelImage *limage,
-                            glTextNode   *filename)
+gl_label_image_set_filename (glLabelImage *this,
+                             glTextNode   *filename,
+                             gboolean      checkpoint)
 {
-       glTextNode  *old_filename;
-       GHashTable  *pixbuf_cache;
-       GdkPixbuf   *pixbuf;
-       gdouble      image_w, image_h, aspect_ratio, w, h;
+        glTextNode        *old_filename;
+        glLabel           *label;
+        GHashTable        *pixbuf_cache;
+        GHashTable        *svg_cache;
+        GdkPixbuf         *pixbuf;
+        RsvgHandle        *svg_handle;
+        RsvgDimensionData  svg_dim;
+        gdouble            image_w, image_h, aspect_ratio, w, h;
 
-       gl_debug (DEBUG_LABEL, "START");
+        gl_debug (DEBUG_LABEL, "START");
 
-       g_return_if_fail (limage && GL_IS_LABEL_IMAGE (limage));
-       g_return_if_fail (filename != NULL);
+        g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
+        g_return_if_fail (filename != NULL);
 
-       old_filename = limage->priv->filename;
+        old_filename = this->priv->filename;
 
-       /* If Unchanged don't do anything */
-       if ( gl_text_node_equal (filename, old_filename ) ) {
-               return;
-       }
+        /* If Unchanged don't do anything */
+        if ( gl_text_node_equal (filename, old_filename ) ) {
+                return;
+        }
 
-       pixbuf_cache = gl_label_get_pixbuf_cache (GL_LABEL_OBJECT(limage)->parent);
+        label = gl_label_object_get_parent (GL_LABEL_OBJECT (this));
+        pixbuf_cache = gl_label_get_pixbuf_cache (label);
+        svg_cache    = gl_label_get_svg_cache (label);
 
-       /* Remove reference to previous pixbuf from cache, if needed. */
-       if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
-               gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
-       }
+        if ( checkpoint )
+        {
+                gl_label_checkpoint (label, _("Set image"));
+        }
 
-       /* Set new filename. */
-       limage->priv->filename = gl_text_node_dup(filename);
-       gl_text_node_free (&old_filename);
+        /* Set new filename. */
+        this->priv->filename = gl_text_node_dup(filename);
 
-       /* Now set the pixbuf. */
-       if ( filename->field_flag || (filename->data == NULL) ) {
+        /* Remove reference to previous item. */
+        switch (this->priv->type)
+        {
 
-               limage->priv->pixbuf = default_pixbuf;
+        case FILE_TYPE_PIXBUF:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
+                }
+                break;
 
-       } else {
+        case FILE_TYPE_SVG:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_svg_cache_remove_svg (svg_cache, old_filename->data);
+                }
+                break;
 
-               pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
+        default:
+                break;
 
-               if (pixbuf != NULL) {
-                       limage->priv->pixbuf = pixbuf;
-               } else {
-                       limage->priv->pixbuf = default_pixbuf;
-               }
-       }
+        }
 
-       /* Treat current size as a bounding box, scale image to maintain aspect
-        * ratio while fitting it in this bounding box. */
-       image_w = gdk_pixbuf_get_width (limage->priv->pixbuf);
-       image_h = gdk_pixbuf_get_height (limage->priv->pixbuf);
-       aspect_ratio = image_h / image_w;
-       gl_label_object_get_size (GL_LABEL_OBJECT(limage), &w, &h);
-       if ( h > w*aspect_ratio ) {
-               h = w * aspect_ratio;
-       } else {
-               w = h / aspect_ratio;
-       }
-       gl_label_object_set_size (GL_LABEL_OBJECT(limage), w, h);
+        gl_text_node_free (&old_filename);
+
+
+        /* Now set the new file type and the pixbuf or svg_handle. */
+        if ( !filename->field_flag && (filename->data != NULL) )
+        {
+
+                if ( gl_file_util_is_extension (filename->data, ".svg") )
+                {
+                        svg_handle = gl_svg_cache_get_handle (svg_cache, filename->data);
+
+                        if (svg_handle != NULL)
+                        {
+                                this->priv->type       = FILE_TYPE_SVG;
+                                this->priv->pixbuf     = NULL;
+                                this->priv->svg_handle = svg_handle;
+                        }
+                        else
+                        {
+                                this->priv->type       = FILE_TYPE_NONE;
+                                this->priv->pixbuf     = NULL;
+                                this->priv->svg_handle = NULL;
+                        }
+
+                }
+                else
+                {
+
+                        pixbuf = gl_pixbuf_cache_get_pixbuf (pixbuf_cache, filename->data);
+
+                        if (pixbuf != NULL)
+                        {
+                                this->priv->type       = FILE_TYPE_PIXBUF;
+                                this->priv->pixbuf     = pixbuf;
+                                this->priv->svg_handle = NULL;
+                        }
+                        else
+                        {
+                                this->priv->type       = FILE_TYPE_NONE;
+                                this->priv->pixbuf     = NULL;
+                                this->priv->svg_handle = NULL;
+                        }
+
+                }
+        }
+        else
+        {
+                this->priv->type       = FILE_TYPE_NONE;
+                this->priv->pixbuf     = NULL;
+                this->priv->svg_handle = NULL;
+        }
+
+
+        /* Treat current size as a bounding box, scale image to maintain aspect
+         * ratio while fitting it in this bounding box. */
+        switch (this->priv->type)
+        {
+
+        case FILE_TYPE_PIXBUF:
+                image_w = gdk_pixbuf_get_width (this->priv->pixbuf);
+                image_h = gdk_pixbuf_get_height (this->priv->pixbuf);
+                break;
+
+        case FILE_TYPE_SVG:
+                rsvg_handle_get_dimensions (this->priv->svg_handle, &svg_dim);
+                image_w = svg_dim.width;
+                image_h = svg_dim.height;
+                break;
+
+        default:
+                image_w = gdk_pixbuf_get_width (default_pixbuf);
+                image_h = gdk_pixbuf_get_height (default_pixbuf);
+                break;
+
+        }
+        aspect_ratio = image_h / image_w;
+        gl_label_object_get_size (GL_LABEL_OBJECT(this), &w, &h);
+        if ( h > w*aspect_ratio ) {
+                h = w * aspect_ratio;
+        } else {
+                w = h / aspect_ratio;
+        }
+        gl_label_object_set_size (GL_LABEL_OBJECT(this), w, h, FALSE);
+
+        gl_label_object_emit_changed (GL_LABEL_OBJECT(this));
+
+        gl_debug (DEBUG_LABEL, "END");
+}
+
+
+void
+gl_label_image_set_pixbuf (glLabelImage  *this,
+                           GdkPixbuf     *pixbuf,
+                           gboolean       checkpoint)
+{
+        glTextNode  *old_filename;
+        glLabel     *label;
+        GHashTable  *pixbuf_cache;
+        GHashTable  *svg_cache;
+        gchar       *cs;
+        gchar       *name;
+        gdouble      image_w, image_h;
+
+        gl_debug (DEBUG_LABEL, "START");
+
+        g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
+        g_return_if_fail (pixbuf && GDK_IS_PIXBUF (pixbuf));
+
+        old_filename = this->priv->filename;
+
+        label = gl_label_object_get_parent (GL_LABEL_OBJECT (this));
+
+        if ( checkpoint )
+        {
+                gl_label_checkpoint (label, _("Set image"));
+        }
+
+        pixbuf_cache = gl_label_get_pixbuf_cache (label);
+        svg_cache = gl_label_get_svg_cache (label);
+
+        /* Remove reference to previous item. */
+        switch (this->priv->type)
+        {
+
+        case FILE_TYPE_PIXBUF:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_pixbuf_cache_remove_pixbuf (pixbuf_cache, old_filename->data);
+                }
+                break;
+
+        case FILE_TYPE_SVG:
+                if ( !old_filename->field_flag && (old_filename->data != NULL) ) {
+                        gl_svg_cache_remove_svg (svg_cache, old_filename->data);
+                }
+                break;
+
+        default:
+                break;
+
+        }
+
+        /* Set new filename. */
+        cs = g_compute_checksum_for_data (G_CHECKSUM_MD5,
+                                          gdk_pixbuf_get_pixels (pixbuf),
+                                          gdk_pixbuf_get_rowstride (pixbuf)*gdk_pixbuf_get_height (pixbuf));
+        name = g_strdup_printf ("%s.bitmap", cs);
+        this->priv->filename = gl_text_node_new_from_text(name);
+        gl_text_node_free (&old_filename);
 
-       gl_label_object_emit_changed (GL_LABEL_OBJECT(limage));
+        this->priv->pixbuf = g_object_ref (pixbuf);
+        gl_pixbuf_cache_add_pixbuf (pixbuf_cache, name, pixbuf);
 
-       gl_debug (DEBUG_LABEL, "END");
+        g_free (cs);
+        g_free (name);
+
+        this->priv->type       = FILE_TYPE_PIXBUF;
+        this->priv->svg_handle = NULL;
+
+        image_w = gdk_pixbuf_get_width (this->priv->pixbuf);
+        image_h = gdk_pixbuf_get_height (this->priv->pixbuf);
+        gl_label_object_set_size (GL_LABEL_OBJECT(this), image_w, image_h, FALSE);
+
+        gl_label_object_emit_changed (GL_LABEL_OBJECT(this));
+
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
 /*****************************************************************************/
 /* Get object params.                                                        */
 /*****************************************************************************/
-glTextNode *
-gl_label_image_get_filename (glLabelImage *limage)
+GdkPixbuf *
+gl_label_image_get_pixbuf (glLabelImage  *this,
+                           glMergeRecord *record)
 {
-       g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
+        g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
+
+        if ((record != NULL) && this->priv->filename->field_flag)
+        {
+
+                GdkPixbuf   *pixbuf = NULL;
+                gchar       *real_filename;
+
+                /* Indirect filename, re-evaluate for given record. */
+
+                real_filename = gl_merge_eval_key (record,
+                                                  this->priv->filename->data);
+
+                if (real_filename != NULL)
+                {
+                        pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
+                }
+                return pixbuf;
+        }
 
-       return gl_text_node_dup (limage->priv->filename);
+        if ( this->priv->type == FILE_TYPE_PIXBUF )
+        {
+                return g_object_ref (this->priv->pixbuf);
+        }
+        else
+        {
+                return NULL;
+        }
 }
 
-const GdkPixbuf *
-gl_label_image_get_pixbuf (glLabelImage  *limage,
-                          glMergeRecord *record)
+
+RsvgHandle *
+gl_label_image_get_svg_handle (glLabelImage  *this,
+                               glMergeRecord *record)
 {
-       g_return_val_if_fail (limage && GL_IS_LABEL_IMAGE (limage), NULL);
+       g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
 
-       if ((record != NULL) && limage->priv->filename->field_flag) {
+       if ((record != NULL) && this->priv->filename->field_flag)
+        {
 
-               GdkPixbuf   *pixbuf = NULL;
+               RsvgHandle  *svg_handle = NULL;
                gchar       *real_filename;
 
                /* Indirect filename, re-evaluate for given record. */
 
                real_filename = gl_merge_eval_key (record,
-                                                  limage->priv->filename->data);
-
-               if (real_filename != NULL) {
-                       pixbuf = gdk_pixbuf_new_from_file (real_filename, NULL);
-               }
-               if ( pixbuf != NULL ) {
-                       return pixbuf;
-               } else {
-                       return default_pixbuf;
+                                                  this->priv->filename->data);
+
+               if (real_filename != NULL)
+                {
+                        if ( gl_file_util_is_extension (real_filename, ".svg") )
+                        {
+                                svg_handle = rsvg_handle_new_from_file (real_filename, NULL);
+                        }
                }
-
+                return svg_handle;
        }
 
-       return limage->priv->pixbuf;
+        if ( this->priv->type == FILE_TYPE_SVG )
+        {
+                return g_object_ref (this->priv->svg_handle);
+        }
+        else
+        {
+                return NULL;
+        }
+}
+
+
+static FileType
+get_type (glLabelImage  *this,
+          glMergeRecord *record)
+{
+       g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), FALSE);
+
+       if ((record != NULL) && this->priv->filename->field_flag)
+        {
+               gchar       *real_filename;
+
+               real_filename = gl_merge_eval_key (record,
+                                                  this->priv->filename->data);
+
+                if ( gl_file_util_is_extension (real_filename, ".svg") )
+                {
+                        return FILE_TYPE_SVG;
+                }
+                else
+                {
+                        /* Assume a pixbuf compat file.  If not, queries for
+                           pixbufs should return NULL and do the right thing. */
+                        return FILE_TYPE_PIXBUF;
+                }
+        }
+        else
+        {
+                return (this->priv->type);
+        }
+}
+
+
+glTextNode *
+gl_label_image_get_filename (glLabelImage *this)
+{
+        g_return_val_if_fail (this && GL_IS_LABEL_IMAGE (this), NULL);
+
+        return gl_text_node_dup (this->priv->filename);
+}
+
+
+void
+gl_label_image_get_base_size (glLabelImage *this,
+                              gdouble      *w,
+                              gdouble      *h)
+{
+        RsvgDimensionData  svg_dim;
+
+        g_return_if_fail (this && GL_IS_LABEL_IMAGE (this));
+        g_return_if_fail (w != NULL);
+        g_return_if_fail (h != NULL);
+
+        switch (this->priv->type)
+        {
+
+        case FILE_TYPE_PIXBUF:
+                *w = gdk_pixbuf_get_width (this->priv->pixbuf);
+                *h = gdk_pixbuf_get_height (this->priv->pixbuf);
+                break;
+
+        case FILE_TYPE_SVG:
+                rsvg_handle_get_dimensions (this->priv->svg_handle, &svg_dim);
+                *w = svg_dim.width;
+                *h = svg_dim.height;
+                break;
 
+        default:
+                *w = gdk_pixbuf_get_width (default_pixbuf);
+                *h = gdk_pixbuf_get_height (default_pixbuf);
+                break;
+
+        }
 }
 
+
 /*****************************************************************************/
 /* Draw object method.                                                       */
 /*****************************************************************************/
@@ -328,32 +684,168 @@ draw_object (glLabelObject *object,
              gboolean       screen_flag,
              glMergeRecord *record)
 {
-        gdouble          x0, y0;
-       gdouble          w, h;
-       const GdkPixbuf *pixbuf;
-       gint             image_w, image_h;
+        glLabelImage      *this = GL_LABEL_IMAGE (object);
+        gdouble            w, h;
+        gdouble            image_w, image_h;
+        GdkPixbuf         *pixbuf;
+        RsvgHandle        *svg_handle;
+        RsvgDimensionData  svg_dim;
 
-       gl_debug (DEBUG_LABEL, "START");
+        gl_debug (DEBUG_LABEL, "START");
 
-       gl_label_object_get_size (object, &w, &h);
-        gl_label_object_get_position (object, &x0, &y0);
+        gl_label_object_get_size (object, &w, &h);
 
-       pixbuf = gl_label_image_get_pixbuf (GL_LABEL_IMAGE (object), record);
-       image_w = gdk_pixbuf_get_width (pixbuf);
-       image_h = gdk_pixbuf_get_height (pixbuf);
+        cairo_save (cr);
 
-       cairo_save (cr);
+        switch (get_type (this, record))
+        {
 
-        cairo_rectangle (cr, 0.0, 0.0, w, h);
+        case FILE_TYPE_PIXBUF:
+                pixbuf = gl_label_image_get_pixbuf (this, record);
+                if ( pixbuf )
+                {
+                        image_w = gdk_pixbuf_get_width (pixbuf);
+                        image_h = gdk_pixbuf_get_height (pixbuf);
+                        cairo_rectangle (cr, 0.0, 0.0, w, h);
+                        cairo_scale (cr, w/image_w, h/image_h);
+                        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+                        cairo_fill (cr);
+                        g_object_unref (pixbuf);
+                }
+                break;
+
+        case FILE_TYPE_SVG:
+                svg_handle = gl_label_image_get_svg_handle (this, record);
+                if ( svg_handle )
+                {
+                        rsvg_handle_get_dimensions (svg_handle, &svg_dim);
+                        cairo_scale (cr, w/svg_dim.width, h/svg_dim.height);
+                        rsvg_handle_render_cairo (svg_handle, cr);
+                }
+                break;
+
+        default:
+                cairo_rectangle (cr, 0.0, 0.0, w, h);
+                image_w = gdk_pixbuf_get_width (default_pixbuf);
+                image_h = gdk_pixbuf_get_height (default_pixbuf);
+                cairo_scale (cr, w/image_w, h/image_h);
+                gdk_cairo_set_source_pixbuf (cr, default_pixbuf, 0, 0);
+                cairo_fill (cr);
+                break;
 
-       cairo_scale (cr, w/image_w, h/image_h);
-        gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)pixbuf, 0, 0);
-        cairo_fill (cr);
+        }
 
-       cairo_restore (cr);
+        cairo_restore (cr);
 
-       gl_debug (DEBUG_LABEL, "END");
+        gl_debug (DEBUG_LABEL, "END");
 }
 
 
+/*****************************************************************************/
+/* Draw shadow method.                                                       */
+/*****************************************************************************/
+static void
+draw_shadow (glLabelObject *object,
+             cairo_t       *cr,
+             gboolean       screen_flag,
+             glMergeRecord *record)
+{
+        glLabelImage    *this = GL_LABEL_IMAGE (object);
+        gdouble          w, h;
+        GdkPixbuf       *pixbuf;
+        GdkPixbuf       *shadow_pixbuf;
+        gdouble          image_w, image_h;
+        glColorNode     *shadow_color_node;
+        guint            shadow_color;
+        gdouble          shadow_opacity;
+
+        gl_debug (DEBUG_LABEL, "START");
+
+        gl_label_object_get_size (object, &w, &h);
+
+        shadow_color_node = gl_label_object_get_shadow_color (object);
+        shadow_color = gl_color_node_expand (shadow_color_node, record);
+        if (shadow_color_node->field_flag && screen_flag)
+        {
+                shadow_color = GL_COLOR_SHADOW_MERGE_DEFAULT;
+        }
+        shadow_opacity = gl_label_object_get_shadow_opacity (object);
+
+        cairo_save (cr);
+
+        switch (get_type (this, record))
+        {
 
+        case FILE_TYPE_PIXBUF:
+                pixbuf = gl_label_image_get_pixbuf (this, record);
+                if ( pixbuf )
+                {
+                        image_w = gdk_pixbuf_get_width (pixbuf);
+                        image_h = gdk_pixbuf_get_height (pixbuf);
+
+                        shadow_pixbuf = gl_pixbuf_util_create_shadow_pixbuf (pixbuf,
+                                                                             shadow_color, shadow_opacity);
+                        cairo_rectangle (cr, 0.0, 0.0, w, h);
+                        cairo_scale (cr, w/image_w, h/image_h);
+                        gdk_cairo_set_source_pixbuf (cr, (GdkPixbuf *)shadow_pixbuf, 0, 0);
+                        cairo_fill (cr);
+
+                        g_object_unref (G_OBJECT (shadow_pixbuf));
+                        g_object_unref (G_OBJECT (pixbuf));
+                }
+                break;
+
+        case FILE_TYPE_SVG:
+                /* FIXME: no shadow support, yet. */
+                break;
+
+        default:
+                shadow_color = gl_color_set_opacity (shadow_color, shadow_opacity);
+
+                cairo_rectangle (cr, 0.0, 0.0, w, h);
+                cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (shadow_color));
+                cairo_fill (cr);
+                break;
+        }
+
+        cairo_restore (cr);
+
+        gl_debug (DEBUG_LABEL, "END");
+}
+
+
+/*****************************************************************************/
+/* Is object at coordinates?                                                 */
+/*****************************************************************************/
+static gboolean
+object_at (glLabelObject *object,
+           cairo_t       *cr,
+           gdouble        x,
+           gdouble        y)
+{
+        gdouble           w, h;
+
+        gl_label_object_get_size (object, &w, &h);
+
+        cairo_new_path (cr);
+        cairo_rectangle (cr, 0.0, 0.0, w, h);
+
+        if (cairo_in_fill (cr, x, y))
+        {
+                return TRUE;
+        }
+
+        return FALSE;
+}
+
+
+
+
+/*
+ * Local Variables:       -- emacs
+ * mode: C                -- emacs
+ * c-basic-offset: 8      -- emacs
+ * tab-width: 8           -- emacs
+ * indent-tabs-mode: nil  -- emacs
+ * End:                   -- emacs
+ */