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_status_t
131 _cairo_boilerplate_svg_finish_surface (cairo_surface_t
*surface
)
133 svg_target_closure_t
*ptc
= cairo_surface_get_user_data (surface
,
135 cairo_status_t status
;
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);
152 cr
= cairo_create (ptc
->target
);
153 cairo_set_source_surface (cr
, surface
, 0, 0);
155 cairo_show_page (cr
);
156 status
= cairo_status (cr
);
158 cairo_surface_set_device_offset (surface
, x_offset
, y_offset
);
159 cairo_surface_set_device_scale (surface
, x_scale
, y_scale
);
164 cairo_surface_finish (surface
);
165 status
= cairo_surface_status (surface
);
169 surface
= ptc
->target
;
172 cairo_surface_finish (surface
);
173 status
= cairo_surface_status (surface
);
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
,
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
));
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
,
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
,
218 cairo_surface_t
*image
;
219 double x_offset
, y_offset
;
220 double x_scale
, y_scale
;
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
);
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
);
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
,
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
,
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
)
303 CAIRO_NO_BOILERPLATE (svg
)