rsvg-defs.c 5.14 KB
Newer Older
1
/* vim: set sw=4 sts=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 3 4 5 6 7
/* 
   rsvg-defs.c: Manage SVG defs and references.
 
   Copyright (C) 2000 Eazel, Inc.
  
   This program is free software; you can redistribute it and/or
8
   modify it under the terms of the GNU Library General Public License as
9 10 11 12 13 14
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
  
   This program 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
15
   Library General Public License for more details.
16
  
17
   You should have received a copy of the GNU Library General Public
18 19 20 21 22 23 24
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
   Author: Raph Levien <raph@artofcode.com>
*/

25
#include "config.h"
26
#include "rsvg-private.h"
27
#include "rsvg-defs.h"
28
#include "rsvg-styles.h"
29
#include "rsvg-image.h"
30

31
#include <glib.h>
32

33
struct _RsvgDefs {
34 35 36 37 38
    GHashTable *hash;
    GPtrArray *unnamed;
    GHashTable *externs;
    gchar *base_uri;
    GSList *toresolve;
39 40 41 42
};

typedef struct _RsvgResolutionPending RsvgResolutionPending;

43 44 45
struct _RsvgResolutionPending {
    RsvgNode **tochange;
    char *name;
46 47 48 49 50
};

RsvgDefs *
rsvg_defs_new (void)
{
51 52 53 54 55 56 57 58 59 60
    RsvgDefs *result = g_new (RsvgDefs, 1);

    result->hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
    result->externs =
        g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
    result->unnamed = g_ptr_array_new ();
    result->base_uri = NULL;
    result->toresolve = NULL;

    return result;
61 62
}

63 64 65
void
rsvg_defs_set_base_uri (RsvgDefs * self, gchar * base_uri)
{
66
    self->base_uri = base_uri;
67 68 69
}

static int
70
rsvg_defs_load_extern (const RsvgDefs * defs, const char *name)
71
{
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
    RsvgHandle *handle;
    gchar *filename, *base_uri;
    GByteArray *chars;

    filename = rsvg_get_file_path (name, defs->base_uri);

    chars = _rsvg_acquire_xlink_href_resource (name, defs->base_uri, NULL);

    if (chars) {
        handle = rsvg_handle_new ();

        base_uri = rsvg_get_base_uri_from_filename (filename);
        rsvg_handle_set_base_uri (handle, base_uri);
        g_free (base_uri);

        if (rsvg_handle_write (handle, chars->data, chars->len, NULL) &&
            rsvg_handle_close (handle, NULL)) {
            g_hash_table_insert (defs->externs, g_strdup (name), handle);
        }

        g_byte_array_free (chars, TRUE);
    }

    g_free (filename);
    return 0;
97 98
}

99
static RsvgNode *
100
rsvg_defs_extern_lookup (const RsvgDefs * defs, const char *filename, const char *name)
101
{
102 103 104 105 106 107 108 109 110 111 112 113
    RsvgHandle *file;
    file = (RsvgHandle *) g_hash_table_lookup (defs->externs, filename);
    if (file == NULL) {
        if (rsvg_defs_load_extern (defs, filename))
            return NULL;
        file = (RsvgHandle *) g_hash_table_lookup (defs->externs, filename);
    }

    if (file != NULL)
        return (RsvgNode *) g_hash_table_lookup (file->priv->defs->hash, name);
    else
        return NULL;
114 115
}

116
RsvgNode *
117
rsvg_defs_lookup (const RsvgDefs * defs, const char *name)
118
{
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    char *hashpos;
    hashpos = g_strrstr (name, "#");
    if (!hashpos) {
        return NULL;
    }
    if (hashpos == name) {
        return (RsvgNode *) g_hash_table_lookup (defs->hash, name + 1);
    } else {
        gchar **splitbits;
        RsvgNode *toreturn;
        splitbits = g_strsplit (name, "#", 2);
        toreturn = rsvg_defs_extern_lookup (defs, splitbits[0], splitbits[1]);
        g_strfreev (splitbits);
        return toreturn;
    }
134 135 136
}

void
137
rsvg_defs_set (RsvgDefs * defs, const char *name, RsvgNode * val)
138
{
139 140 141 142 143
    if (name == NULL);
    else if (name[0] == '\0');
    else
        rsvg_defs_register_name (defs, name, val);
    rsvg_defs_register_memory (defs, val);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
144 145 146
}

void
147
rsvg_defs_register_name (RsvgDefs * defs, const char *name, RsvgNode * val)
Caleb Michael Moore's avatar
Caleb Michael Moore committed
148
{
149
    g_hash_table_insert (defs->hash, g_strdup (name), val);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
150 151 152
}

void
153
rsvg_defs_register_memory (RsvgDefs * defs, RsvgNode * val)
Caleb Michael Moore's avatar
Caleb Michael Moore committed
154
{
155
    g_ptr_array_add (defs->unnamed, val);
156 157 158
}

void
159
rsvg_defs_free (RsvgDefs * defs)
160
{
161
    guint i;
162

163
    g_hash_table_destroy (defs->hash);
164

165 166 167 168
    for (i = 0; i < defs->unnamed->len; i++)
        ((RsvgNode *) g_ptr_array_index (defs->unnamed, i))->
            free (g_ptr_array_index (defs->unnamed, i));
    g_ptr_array_free (defs->unnamed, TRUE);
169

170
    g_hash_table_destroy (defs->externs);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
171

172
    g_free (defs);
173
}
174 175

void
176
rsvg_defs_add_resolver (RsvgDefs * defs, RsvgNode ** tochange, const gchar * name)
177
{
178 179 180 181 182
    RsvgResolutionPending *data;
    data = g_new (RsvgResolutionPending, 1);
    data->tochange = tochange;
    data->name = g_strdup (name);
    defs->toresolve = g_slist_prepend (defs->toresolve, data);
183 184 185
}

void
186
rsvg_defs_resolve_all (RsvgDefs * defs)
187
{
188 189 190 191 192 193 194 195 196
    while (defs->toresolve) {
        RsvgResolutionPending *data;
        data = defs->toresolve->data;
        *(data->tochange) = rsvg_defs_lookup (defs, data->name);
        g_free (data->name);
        g_free (data);
        defs->toresolve = g_slist_delete_link (defs->toresolve, defs->toresolve);

    }
197
}