io-svg.c 6.82 KB
Newer Older
1 2 3 4
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - SVG image loader
 *
 * Copyright (C) 2002 Matthias Clasen
5
 * Copyright (C) 2002-2004 Dom Lachowicz
6 7
 *
 * Authors: Matthias Clasen <maclas@gmx.de>
Dom Lachowicz's avatar
Dom Lachowicz committed
8
 *          Dom Lachowicz <cinamod@hotmail.com>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more  * 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.
 */

24 25
#define RSVG_DISABLE_DEPRECATION_WARNINGS

26 27
#include "config.h"

Dom Lachowicz's avatar
Dom Lachowicz committed
28
#include <stdlib.h>
29

30
#include "librsvg/rsvg.h"
31
#include <gdk-pixbuf/gdk-pixbuf.h>
32 33 34 35

#define N_(string) (string)
#define _(string) (string)

36 37
typedef struct {
        RsvgHandle                 *handle;
38

Dom Lachowicz's avatar
Dom Lachowicz committed
39 40 41
        GdkPixbufModuleUpdatedFunc  updated_func;
        GdkPixbufModulePreparedFunc prepared_func;
        GdkPixbufModuleSizeFunc     size_func;
42

43 44
        gboolean                    first_write;

45
        gpointer                    user_data;
46 47
} SvgContext;

Dom Lachowicz's avatar
Dom Lachowicz committed
48 49 50
G_MODULE_EXPORT void fill_vtable (GdkPixbufModule *module);
G_MODULE_EXPORT void fill_info (GdkPixbufFormat *info);

Dom Lachowicz's avatar
Dom Lachowicz committed
51 52 53 54 55 56
enum {
        ERROR_WRITING = 1,
        ERROR_DISPLAYING_IMAGE
} RsvgLoaderErrorReasons;

static void
57
rsvg_propagate_error (GError ** err,
Dom Lachowicz's avatar
Dom Lachowicz committed
58 59 60 61 62
                      const char * reason,
                      gint code)
{
        if (err) {
                *err = NULL;
63
                g_set_error (err, rsvg_error_quark (), code, "%s", reason);
Dom Lachowicz's avatar
Dom Lachowicz committed
64 65 66
        }
}

67 68
static gpointer
gdk_pixbuf__svg_image_begin_load (GdkPixbufModuleSizeFunc size_func,
69
                                  GdkPixbufModulePreparedFunc prepared_func,
70 71 72 73
                                  GdkPixbufModuleUpdatedFunc  updated_func,
                                  gpointer user_data,
                                  GError **error)
{
Dom Lachowicz's avatar
Dom Lachowicz committed
74
        SvgContext *context    = g_new0 (SvgContext, 1);
75

76 77
        if (error)
                *error = NULL;
Dom Lachowicz's avatar
Dom Lachowicz committed
78

79
        context->first_write   = TRUE;
Dom Lachowicz's avatar
Dom Lachowicz committed
80
        context->size_func     = size_func;
81

82
        context->prepared_func = prepared_func;
Dom Lachowicz's avatar
Dom Lachowicz committed
83 84 85
        context->updated_func  = updated_func;
        context->user_data     = user_data;

86 87 88
        return context;
}

89
static void
90
emit_updated (SvgContext *context, GdkPixbuf *pixbuf)
91
{
92 93
        if (context->updated_func != NULL)
                (* context->updated_func) (pixbuf,
94
                                           0, 0,
95 96
                                           gdk_pixbuf_get_width (pixbuf),
                                           gdk_pixbuf_get_height (pixbuf),
97 98 99 100
                                           context->user_data);
}

static void
101
emit_prepared (SvgContext *context, GdkPixbuf *pixbuf)
102
{
103 104
        if (context->prepared_func != NULL)
                (* context->prepared_func) (pixbuf, NULL, context->user_data);
105 106
}

107 108 109 110 111 112
static gboolean
gdk_pixbuf__svg_image_load_increment (gpointer data,
				      const guchar *buf, guint size,
				      GError **error)
{
        SvgContext *context = (SvgContext *)data;
113

114 115
        if (error)
                *error = NULL;
Dom Lachowicz's avatar
Dom Lachowicz committed
116

117 118 119
        if (context->first_write == TRUE) {
                context->first_write = FALSE;

120
                context->handle = rsvg_handle_new ();
Dom Lachowicz's avatar
Dom Lachowicz committed
121

122
                if (!context->handle) {
123
                        rsvg_propagate_error (error, _("Error displaying image"), ERROR_DISPLAYING_IMAGE);
124
                        return FALSE;
125
                }
126

Dom Lachowicz's avatar
Dom Lachowicz committed
127
                rsvg_handle_set_size_callback (context->handle, context->size_func, context->user_data, NULL);
128 129
        }

130
        if (!context->handle) {
131
                rsvg_propagate_error (error, _("Error displaying image"), ERROR_DISPLAYING_IMAGE);
132 133 134
                return FALSE;
        }

Dom Lachowicz's avatar
Dom Lachowicz committed
135
        if (!rsvg_handle_write (context->handle, buf, size, error)) {
136
                g_clear_error(error);
137
                rsvg_propagate_error (error, _("Error writing"), ERROR_WRITING);
Dom Lachowicz's avatar
Dom Lachowicz committed
138 139
                return FALSE;
        }
Dom Lachowicz's avatar
Dom Lachowicz committed
140

Dom Lachowicz's avatar
Dom Lachowicz committed
141
        return TRUE;
142 143 144 145 146
}

static gboolean
gdk_pixbuf__svg_image_stop_load (gpointer data, GError **error)
{
147
        SvgContext *context = (SvgContext *)data;
148
        GdkPixbuf *pixbuf;
Dom Lachowicz's avatar
Dom Lachowicz committed
149
        gboolean result = TRUE;
Dom Lachowicz's avatar
Dom Lachowicz committed
150

151 152
        if (error)
                *error = NULL;
Dom Lachowicz's avatar
Dom Lachowicz committed
153

154
        if (!context->handle) {
155
                rsvg_propagate_error (error, _("Error displaying image"), ERROR_DISPLAYING_IMAGE);
156 157 158
                return FALSE;
        }

Benedikt Heine's avatar
Benedikt Heine committed
159 160 161
        if (!rsvg_handle_close (context->handle, error)) {
                g_object_unref (context->handle);
                g_free (context);
162
                return FALSE;
Benedikt Heine's avatar
Benedikt Heine committed
163
        }
164

165
        pixbuf = rsvg_handle_get_pixbuf (context->handle);
166

167 168 169 170
        if (pixbuf != NULL) {
                emit_prepared (context, pixbuf);
                emit_updated (context, pixbuf);
                g_object_unref (pixbuf);
171
        }
172
        else {
173
                rsvg_propagate_error (error, _("Error displaying image"), ERROR_DISPLAYING_IMAGE);
Dom Lachowicz's avatar
Dom Lachowicz committed
174 175
                result = FALSE;
        }
176

177
        g_object_unref (context->handle);
178 179
        g_free (context);

180
        return result;
181 182
}

Dom Lachowicz's avatar
Dom Lachowicz committed
183
void
184 185
fill_vtable (GdkPixbufModule *module)
{
Dom Lachowicz's avatar
Dom Lachowicz committed
186 187
        module->begin_load     = gdk_pixbuf__svg_image_begin_load;
        module->stop_load      = gdk_pixbuf__svg_image_stop_load;
188 189 190
        module->load_increment = gdk_pixbuf__svg_image_load_increment;
}

Dom Lachowicz's avatar
Dom Lachowicz committed
191
void
192 193
fill_info (GdkPixbufFormat *info)
{
194
        static const GdkPixbufModulePattern signature[] = {
195 196 197 198 199
                {  " <svg",  "*    ", 100 },
                {  " <!DOCTYPE svg",  "*             ", 100 },
                { NULL, NULL, 0 }
        };

200
        static const gchar *mime_types[] = { /* yes folks, i actually have run into all of these in the wild... */
201
                "image/svg+xml",
202 203 204 205
                "image/svg",
                "image/svg-xml",
                "image/vnd.adobe.svg+xml",
                "text/xml-svg",
206
                "image/svg+xml-compressed",
207
                NULL
208
        };
209
        static const gchar *extensions[] = {
210
                "svg",
211
                "svgz",
212
                "svg.gz",
213
                NULL
214
        };
215

Dom Lachowicz's avatar
Dom Lachowicz committed
216
        info->name        = "svg";
217
        info->signature   = (GdkPixbufModulePattern *) signature;
218
        info->description = _("Scalable Vector Graphics");
219 220
        info->mime_types  = (gchar **) mime_types;
        info->extensions  = (gchar **) extensions;
221
        info->flags       = GDK_PIXBUF_FORMAT_SCALABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
222
        info->license     = "LGPL";
223
}