move around - flatter.
[profile/ivi/evas.git] / src / modules / loaders / svg / evas_image_load_svg.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 #include <librsvg/rsvg.h>
5 #include <librsvg/rsvg-cairo.h>
6
7 int evas_image_load_file_head_svg(Image_Entry *ie, const char *file, const char *key);
8 int evas_image_load_file_data_svg(Image_Entry *ie, const char *file, const char *key);
9
10 Evas_Image_Load_Func evas_image_load_svg_func =
11 {
12   evas_image_load_file_head_svg,
13   evas_image_load_file_data_svg
14 };
15
16 static int  rsvg_initialized = 0;
17 static void svg_loader_unpremul_data(DATA32 *data, unsigned int len);
18
19 static void
20 svg_loader_unpremul_data(DATA32 *data, unsigned int len)
21 {
22    DATA32  *de = data + len;
23
24    while (data < de)
25      {
26         DATA32   a = A_VAL(data);
27         
28         if (a && (a < 255))
29           {
30              R_VAL(data) = (R_VAL(data) * 255) / a;
31              G_VAL(data) = (G_VAL(data) * 255) / a;
32              B_VAL(data) = (B_VAL(data) * 255) / a;
33           }
34         data++;
35      }
36 }
37
38 int
39 evas_image_load_file_head_svg(Image_Entry *ie, const char *file, const char *key)
40 {
41    char               cwd[PATH_MAX], pcwd[PATH_MAX], *p;
42    
43    RsvgHandle         *rsvg;
44    RsvgDimensionData   dim;
45    int                 w, h;
46    char               *ext;
47    
48    if (!file) return 0;
49
50    /* ignore all files not called .svg or .svg.gz - because rsvg has a leak
51     * where closing the handle doesn't free mem */
52    ext = strrchr(file, '.');
53    if (!ext) return 0;
54    if (!strcasecmp(ext, ".gz"))
55      {
56         if (p > file)
57           {
58              ext = p - 1;
59              while ((*p != '.') && (p > file))
60                {
61                   p--;
62                }
63              if (p <= file) return 0;
64              if (strcasecmp(p, ".svg.gz")) return 0;
65           }
66         else
67           return 0;
68      }
69    else if (strcasecmp(ext, ".svg")) return 0;
70
71    getcwd(pcwd, sizeof(pcwd));
72    strncpy(cwd, file, sizeof(cwd) - 1);
73    cwd[sizeof(cwd) - 1] = 0;
74    p = strrchr(cwd, '/');
75    if (p) *p = 0;
76    chdir(cwd);
77    
78    rsvg = rsvg_handle_new_from_file(file, NULL);
79    if (!rsvg)
80      {
81         chdir(pcwd);
82         return 0;
83      }
84
85    rsvg_handle_get_dimensions(rsvg, &dim);
86    w = dim.width;
87    h = dim.height;
88    if ((w < 1) || (h < 1) || (w > 8192) || (h > 8192))
89      {
90 //      rsvg_handle_close(rsvg, NULL);
91         g_object_unref(rsvg);
92 //      rsvg_handle_free(rsvg);
93         chdir(pcwd);
94         return 0;
95      }
96    if (ie->load_opts.scale_down_by > 1)
97      {
98         w /= ie->load_opts.scale_down_by;
99         h /= ie->load_opts.scale_down_by;
100      }
101    else if (ie->load_opts.dpi > 0.0)
102      {
103         w = (w * ie->load_opts.dpi) / 90.0;
104         h = (h * ie->load_opts.dpi) / 90.0;
105      }
106    else if ((ie->load_opts.w > 0) &&
107             (ie->load_opts.h > 0))
108      {
109         int w2, h2;
110         
111         w2 = ie->load_opts.w;
112         h2 = (ie->load_opts.w * h) / w;
113         if (h2 > ie->load_opts.h)
114           {
115              h2 = ie->load_opts.h;
116              w2 = (ie->load_opts.h * w) / h;
117           }
118         w = w2;
119         h = h2;
120      }
121    if (w < 1) w = 1;
122    if (h < 1) h = 1;
123    ie->w = w;
124    ie->h = h;
125    ie->flags.alpha = 1;
126 //   rsvg_handle_close(rsvg, NULL);
127    g_object_unref(rsvg);
128 //   rsvg_handle_free(rsvg);
129    chdir(pcwd);
130    return 1;
131 }
132
133 /** FIXME: All evas loaders need to be tightened up **/
134 int
135 evas_image_load_file_data_svg(Image_Entry *ie, const char *file, const char *key)
136 {
137    DATA32             *pixels;
138    char               cwd[PATH_MAX], pcwd[PATH_MAX], *p;
139    RsvgHandle         *rsvg;
140    RsvgDimensionData   dim;
141    int                 w, h;
142    cairo_surface_t    *surface;
143    cairo_t            *cr;
144    char               *ext;
145
146    if (!file) return 0;
147
148    /* ignore all files not called .svg or .svg.gz - because rsvg has a leak
149     * where closing the handle doesn't free mem */
150    ext = strrchr(file, '.');
151    if (!ext) return 0;
152    if (!strcasecmp(ext, ".gz"))
153      {
154         if (p > file)
155           {
156              ext = p - 1;
157              while ((*p != '.') && (p > file))
158                {
159                   p--;
160                }
161              if (p <= file) return 0;
162              if (strcasecmp(p, ".svg.gz")) return 0;
163           }
164         else
165           return 0;
166      }
167    else if (strcasecmp(ext, ".svg")) return 0;
168
169    getcwd(pcwd, sizeof(pcwd));
170    strncpy(cwd, file, sizeof(cwd) - 1);
171    cwd[sizeof(cwd) - 1] = 0;
172    p = strrchr(cwd, '/');
173    if (p) *p = 0;
174    chdir(cwd);
175    
176    rsvg = rsvg_handle_new_from_file(file, NULL);
177    if (!rsvg)
178      {
179         chdir(pcwd);
180         return 0;
181      }
182
183    rsvg_handle_get_dimensions(rsvg, &dim);
184    w = dim.width;
185    h = dim.height;
186    if ((w < 1) || (h < 1) || (w > 8192) || (h > 8192))
187      {
188 //      rsvg_handle_close(rsvg, NULL);
189         g_object_unref(rsvg);
190 //      rsvg_handle_free(rsvg);
191         chdir(pcwd);
192         return 0;
193      }
194    if (ie->load_opts.scale_down_by > 1)
195      {
196         w /= ie->load_opts.scale_down_by;
197         h /= ie->load_opts.scale_down_by;
198      }
199    else if (ie->load_opts.dpi > 0.0)
200      {
201         w = (w * ie->load_opts.dpi) / 90.0;
202         h = (h * ie->load_opts.dpi) / 90.0;
203      }
204    else if ((ie->load_opts.w > 0) &&
205             (ie->load_opts.h > 0))
206      {
207         int w2, h2;
208         
209         w2 = ie->load_opts.w;
210         h2 = (ie->load_opts.w * h) / w;
211         if (h2 > ie->load_opts.h)
212           {
213              h2 = ie->load_opts.h;
214              w2 = (ie->load_opts.h * w) / h;
215           }
216         w = w2;
217         h = h2;
218      }
219    if (w < 1) w = 1;
220    if (h < 1) h = 1;
221    ie->flags.alpha = 1;
222    evas_cache_image_surface_alloc(ie, w, h);
223    pixels = evas_cache_image_pixels(ie);
224    if (!pixels)
225      {
226 //      rsvg_handle_close(rsvg, NULL);
227         g_object_unref(rsvg);
228 //      rsvg_handle_free(rsvg);
229         chdir(pcwd);
230         return 0;
231      }
232
233    memset(pixels, 0, w * h * sizeof(DATA32));
234    
235    surface = cairo_image_surface_create_for_data((unsigned char *)pixels, CAIRO_FORMAT_ARGB32,
236                                                  w, h, w * sizeof(DATA32));
237    if (!surface)
238      {
239 //      rsvg_handle_close(rsvg, NULL);
240         g_object_unref(rsvg);
241 //      rsvg_handle_free(rsvg);
242         chdir(pcwd);
243         return 0;
244      }
245    cr = cairo_create(surface);
246    if (!cr)
247      {
248         cairo_surface_destroy(surface);
249 //      rsvg_handle_close(rsvg, NULL);
250         g_object_unref(rsvg);
251 //      rsvg_handle_free(rsvg);
252         chdir(pcwd);
253         return 0;
254      }
255    
256    cairo_scale(cr, 
257                (double)ie->w / dim.em, 
258                (double)ie->h / dim.ex);
259    rsvg_handle_render_cairo(rsvg, cr);
260    cairo_surface_destroy(surface);
261    /* need to check if this is required... */
262    cairo_destroy(cr);
263 //   rsvg_handle_close(rsvg, NULL);
264    g_object_unref(rsvg);
265 //   rsvg_handle_free(rsvg);
266    chdir(pcwd);
267    evas_common_image_set_alpha_sparse(ie);
268    return 1;
269 }
270
271 EAPI int
272 module_open(Evas_Module *em)
273 {
274    if (!em) return 0;
275    em->functions = (void *)(&evas_image_load_svg_func);
276    if (!rsvg_initialized) rsvg_init();
277    rsvg_initialized = 1;
278    return 1;
279 }
280
281 EAPI void
282 module_close(void)
283 {
284    if (!rsvg_initialized) return;
285    rsvg_term();
286    rsvg_initialized = 0;
287 }
288
289 EAPI Evas_Module_Api evas_modapi =
290 {
291    EVAS_MODULE_API_VERSION,
292      EVAS_MODULE_TYPE_IMAGE_LOADER,
293      "svg",
294      "none"
295 };
296