1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
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>
44 #if ! CAIRO_HAS_RECORDING_SURFACE
45 #define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING
48 static const cairo_user_data_key_t svg_closure_key;
50 typedef struct _svg_target_closure {
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,
64 cairo_boilerplate_mode_t mode,
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,
90 ptc->width, ptc->height);
91 if (cairo_surface_status (surface))
96 status = cairo_surface_set_user_data (surface, &svg_closure_key, ptc, NULL);
97 if (status == CAIRO_STATUS_SUCCESS)
100 cairo_surface_destroy (surface);
101 surface = cairo_boilerplate_surface_create_in_error (status);
104 cairo_surface_destroy (ptc->target);
106 free (ptc->filename);
111 static cairo_surface_t *
112 _cairo_boilerplate_svg11_create_surface (const char *name,
113 cairo_content_t content,
118 cairo_boilerplate_mode_t mode,
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,
125 max_width, max_height,
130 static cairo_surface_t *
131 _cairo_boilerplate_svg12_create_surface (const char *name,
132 cairo_content_t content,
137 cairo_boilerplate_mode_t mode,
140 return _cairo_boilerplate_svg_create_surface (name, content,
141 CAIRO_SVG_VERSION_1_2,
143 max_width, max_height,
148 static cairo_status_t
149 _cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface)
151 svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
153 cairo_status_t status;
155 /* Both surface and ptc->target were originally created at the
156 * same dimensions. We want a 1:1 copy here, so we first clear any
157 * device offset on surface.
159 * In a more realistic use case of device offsets, the target of
160 * this copying would be of a different size than the source, and
161 * the offset would be desirable during the copy operation. */
162 cairo_surface_set_device_offset (surface, 0, 0);
166 cr = cairo_create (ptc->target);
167 cairo_set_source_surface (cr, surface, 0, 0);
169 cairo_show_page (cr);
170 status = cairo_status (cr);
176 cairo_surface_finish (surface);
177 status = cairo_surface_status (surface);
181 surface = ptc->target;
184 cairo_surface_finish (surface);
185 status = cairo_surface_status (surface);
189 return CAIRO_STATUS_SUCCESS;
192 static cairo_status_t
193 _cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface,
194 const char *filename)
196 svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
201 sprintf (command, "./svg2png %s %s",
202 ptc->filename, filename);
204 exitstatus = system (command);
205 #if _XOPEN_SOURCE && HAVE_SIGNAL_H
206 if (WIFSIGNALED (exitstatus))
207 raise (WTERMSIG (exitstatus));
210 return CAIRO_STATUS_WRITE_ERROR;
212 return CAIRO_STATUS_SUCCESS;
215 static cairo_surface_t *
216 _cairo_boilerplate_svg_convert_to_image (cairo_surface_t *surface)
218 svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
221 return cairo_boilerplate_convert_to_image (ptc->filename, 0);
224 static cairo_surface_t *
225 _cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface,
230 cairo_surface_t *image;
233 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
235 image = _cairo_boilerplate_svg_convert_to_image (surface);
236 cairo_surface_set_device_offset (image,
237 cairo_image_surface_get_width (image) - width,
238 cairo_image_surface_get_height (image) - height);
239 surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
240 cairo_surface_destroy (image);
246 _cairo_boilerplate_svg_cleanup (void *closure)
248 svg_target_closure_t *ptc = closure;
249 if (ptc->target != NULL) {
250 cairo_surface_finish (ptc->target);
251 cairo_surface_destroy (ptc->target);
253 free (ptc->filename);
258 _cairo_boilerplate_svg_force_fallbacks (cairo_surface_t *abstract_surface,
259 double x_pixels_per_inch,
260 double y_pixels_per_inch)
262 svg_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface,
265 cairo_paginated_surface_t *paginated;
266 cairo_svg_surface_t *surface;
269 abstract_surface = ptc->target;
271 paginated = (cairo_paginated_surface_t*) abstract_surface;
272 surface = (cairo_svg_surface_t*) paginated->target;
273 surface->force_fallbacks = TRUE;
274 cairo_surface_set_fallback_resolution (&paginated->base,
279 static const cairo_boilerplate_target_t targets[] = {
280 /* It seems we should be able to round-trip SVG content perfectly
281 * through librsvg and cairo, but for some mysterious reason, some
282 * systems get an error of 1 for some pixels on some of the text
283 * tests. XXX: I'd still like to chase these down at some point.
284 * For now just set the svg error tolerance to 1. */
286 "svg11", "svg", ".svg", NULL,
287 CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 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 "svg11", "svg", ".svg", NULL,
300 CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1,
301 "cairo_svg_surface_create",
302 _cairo_boilerplate_svg11_create_surface,
303 cairo_surface_create_similar,
304 _cairo_boilerplate_svg_force_fallbacks,
305 _cairo_boilerplate_svg_finish_surface,
306 _cairo_boilerplate_svg_get_image_surface,
307 _cairo_boilerplate_svg_surface_write_to_png,
308 _cairo_boilerplate_svg_cleanup,
309 NULL, NULL, FALSE, TRUE, TRUE
312 "svg12", "svg", ".svg", NULL,
313 CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
314 "cairo_svg_surface_create",
315 _cairo_boilerplate_svg12_create_surface,
316 cairo_surface_create_similar,
317 _cairo_boilerplate_svg_force_fallbacks,
318 _cairo_boilerplate_svg_finish_surface,
319 _cairo_boilerplate_svg_get_image_surface,
320 _cairo_boilerplate_svg_surface_write_to_png,
321 _cairo_boilerplate_svg_cleanup,
322 NULL, NULL, FALSE, TRUE, TRUE
325 "svg12", "svg", ".svg", NULL,
326 CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1,
327 "cairo_svg_surface_create",
328 _cairo_boilerplate_svg12_create_surface,
329 cairo_surface_create_similar,
330 _cairo_boilerplate_svg_force_fallbacks,
331 _cairo_boilerplate_svg_finish_surface,
332 _cairo_boilerplate_svg_get_image_surface,
333 _cairo_boilerplate_svg_surface_write_to_png,
334 _cairo_boilerplate_svg_cleanup,
335 NULL, NULL, FALSE, TRUE, TRUE
338 CAIRO_BOILERPLATE (svg, targets)
342 CAIRO_NO_BOILERPLATE (svg)