Merge branch 'mingw11' into 'master'
[cairo.git] / boilerplate / cairo-boilerplate-svg.c
blob0c9a3833eeb177dd261ef23249f31ce889b1d63b
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /*
3 * Copyright © 2004,2006 Red Hat, Inc.
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Red Hat, Inc. not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. Red Hat, Inc. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
22 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: Carl D. Worth <cworth@cworth.org>
27 #include "cairo-boilerplate-private.h"
29 #if CAIRO_CAN_TEST_SVG_SURFACE
31 #include <cairo-svg.h>
32 #include <cairo-svg-surface-private.h>
33 #include <cairo-paginated-surface-private.h>
35 #if HAVE_SIGNAL_H
36 #include <stdlib.h>
37 #include <signal.h>
38 #endif
40 #if HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
44 #if ! CAIRO_HAS_RECORDING_SURFACE
45 #define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING
46 #endif
48 static const cairo_user_data_key_t svg_closure_key;
50 typedef struct _svg_target_closure {
51 char *filename;
52 int width, height;
53 cairo_surface_t *target;
54 } svg_target_closure_t;
56 static cairo_surface_t *
57 _cairo_boilerplate_svg_create_surface (const char *name,
58 cairo_content_t content,
59 cairo_svg_version_t version,
60 double width,
61 double height,
62 double max_width,
63 double max_height,
64 cairo_boilerplate_mode_t mode,
65 void **closure)
67 svg_target_closure_t *ptc;
68 cairo_surface_t *surface;
69 cairo_status_t status;
71 *closure = ptc = xmalloc (sizeof (svg_target_closure_t));
73 ptc->width = ceil (width);
74 ptc->height = ceil (height);
76 xasprintf (&ptc->filename, "%s.out.svg", name);
77 xunlink (ptc->filename);
79 surface = cairo_svg_surface_create (ptc->filename, width, height);
80 if (cairo_surface_status (surface))
81 goto CLEANUP_FILENAME;
83 cairo_svg_surface_restrict_to_version (surface, version);
84 cairo_surface_set_fallback_resolution (surface, 72., 72.);
86 if (content == CAIRO_CONTENT_COLOR) {
87 ptc->target = surface;
88 surface = cairo_surface_create_similar (ptc->target,
89 CAIRO_CONTENT_COLOR,
90 ptc->width, ptc->height);
91 if (cairo_surface_status (surface))
92 goto CLEANUP_TARGET;
93 } else
94 ptc->target = NULL;
96 status = cairo_surface_set_user_data (surface, &svg_closure_key, ptc, NULL);
97 if (status == CAIRO_STATUS_SUCCESS)
98 return surface;
100 cairo_surface_destroy (surface);
101 surface = cairo_boilerplate_surface_create_in_error (status);
103 CLEANUP_TARGET:
104 cairo_surface_destroy (ptc->target);
105 CLEANUP_FILENAME:
106 free (ptc->filename);
107 free (ptc);
108 return surface;
111 static cairo_surface_t *
112 _cairo_boilerplate_svg11_create_surface (const char *name,
113 cairo_content_t content,
114 double width,
115 double height,
116 double max_width,
117 double max_height,
118 cairo_boilerplate_mode_t mode,
119 void **closure)
121 /* current default, but be explicit in case the default changes */
122 return _cairo_boilerplate_svg_create_surface (name, content,
123 CAIRO_SVG_VERSION_1_1,
124 width, height,
125 max_width, max_height,
126 mode,
127 closure);
130 static cairo_status_t
131 _cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface)
133 svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
134 &svg_closure_key);
135 cairo_status_t status;
137 if (ptc->target) {
138 /* Both surface and ptc->target were originally created at the
139 * same dimensions. We want a 1:1 copy here, so we first clear any
140 * device offset and scale on surface.
142 * In a more realistic use case of device offsets, the target of
143 * this copying would be of a different size than the source, and
144 * the offset would be desirable during the copy operation. */
145 double x_offset, y_offset;
146 double x_scale, y_scale;
147 cairo_surface_get_device_offset (surface, &x_offset, &y_offset);
148 cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
149 cairo_surface_set_device_offset (surface, 0, 0);
150 cairo_surface_set_device_scale (surface, 1, 1);
151 cairo_t *cr;
152 cr = cairo_create (ptc->target);
153 cairo_set_source_surface (cr, surface, 0, 0);
154 cairo_paint (cr);
155 cairo_show_page (cr);
156 status = cairo_status (cr);
157 cairo_destroy (cr);
158 cairo_surface_set_device_offset (surface, x_offset, y_offset);
159 cairo_surface_set_device_scale (surface, x_scale, y_scale);
161 if (status)
162 return status;
164 cairo_surface_finish (surface);
165 status = cairo_surface_status (surface);
166 if (status)
167 return status;
169 surface = ptc->target;
172 cairo_surface_finish (surface);
173 status = cairo_surface_status (surface);
174 if (status)
175 return status;
177 return CAIRO_STATUS_SUCCESS;
180 static cairo_status_t
181 _cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface,
182 const char *filename)
184 svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
185 &svg_closure_key);
186 char command[4096];
187 int exitstatus;
189 sprintf (command, "./svg2png %s %s",
190 ptc->filename, filename);
192 exitstatus = system (command);
193 #if _XOPEN_SOURCE && HAVE_SIGNAL_H
194 if (WIFSIGNALED (exitstatus))
195 raise (WTERMSIG (exitstatus));
196 #endif
197 if (exitstatus)
198 return CAIRO_STATUS_WRITE_ERROR;
200 return CAIRO_STATUS_SUCCESS;
203 static cairo_surface_t *
204 _cairo_boilerplate_svg_convert_to_image (cairo_surface_t *surface)
206 svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
207 &svg_closure_key);
209 return cairo_boilerplate_convert_to_image (ptc->filename, 0);
212 static cairo_surface_t *
213 _cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface,
214 int page,
215 int width,
216 int height)
218 cairo_surface_t *image;
219 double x_offset, y_offset;
220 double x_scale, y_scale;
222 if (page != 0)
223 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
225 image = _cairo_boilerplate_svg_convert_to_image (surface);
226 cairo_surface_get_device_offset (surface, &x_offset, &y_offset);
227 cairo_surface_get_device_scale (surface, &x_scale, &y_scale);
228 cairo_surface_set_device_offset (image, x_offset, y_offset);
229 cairo_surface_set_device_scale (image, x_scale, y_scale);
230 surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
231 cairo_surface_destroy (image);
233 return surface;
236 static void
237 _cairo_boilerplate_svg_cleanup (void *closure)
239 svg_target_closure_t *ptc = closure;
240 if (ptc->target != NULL) {
241 cairo_surface_finish (ptc->target);
242 cairo_surface_destroy (ptc->target);
244 free (ptc->filename);
245 free (ptc);
248 static void
249 _cairo_boilerplate_svg_force_fallbacks (cairo_surface_t *abstract_surface,
250 double x_pixels_per_inch,
251 double y_pixels_per_inch)
253 svg_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface,
254 &svg_closure_key);
256 if (ptc->target)
257 abstract_surface = ptc->target;
259 cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface;
260 _cairo_svg_surface_set_force_fallbacks (paginated->target, TRUE);
261 cairo_surface_set_fallback_resolution (&paginated->base,
262 x_pixels_per_inch,
263 y_pixels_per_inch);
266 static const cairo_boilerplate_target_t targets[] = {
267 /* It seems we should be able to round-trip SVG content perfectly
268 * through librsvg and cairo, but for some mysterious reason, some
269 * systems get an error of 1 for some pixels on some of the text
270 * tests. XXX: I'd still like to chase these down at some point.
271 * For now just set the svg error tolerance to 1. */
273 "svg11", "svg", ".svg", NULL,
274 CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
275 "cairo_svg_surface_create",
276 _cairo_boilerplate_svg11_create_surface,
277 cairo_surface_create_similar,
278 _cairo_boilerplate_svg_force_fallbacks,
279 _cairo_boilerplate_svg_finish_surface,
280 _cairo_boilerplate_svg_get_image_surface,
281 _cairo_boilerplate_svg_surface_write_to_png,
282 _cairo_boilerplate_svg_cleanup,
283 NULL, NULL, FALSE, TRUE, TRUE
286 "svg11", "svg", ".svg", NULL,
287 CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1,
288 "cairo_svg_surface_create",
289 _cairo_boilerplate_svg11_create_surface,
290 cairo_surface_create_similar,
291 _cairo_boilerplate_svg_force_fallbacks,
292 _cairo_boilerplate_svg_finish_surface,
293 _cairo_boilerplate_svg_get_image_surface,
294 _cairo_boilerplate_svg_surface_write_to_png,
295 _cairo_boilerplate_svg_cleanup,
296 NULL, NULL, FALSE, TRUE, TRUE
299 CAIRO_BOILERPLATE (svg, targets)
301 #else
303 CAIRO_NO_BOILERPLATE (svg)
305 #endif