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_PS_SURFACE
33 #include <cairo-ps-surface-private.h>
34 #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 ps_closure_key;
50 typedef struct _ps_target_closure {
54 cairo_surface_t *target;
55 cairo_ps_level_t level;
56 } ps_target_closure_t;
59 _cairo_boilerplate_ps_surface_set_creation_date (cairo_surface_t *abstract_surface,
62 cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface;
63 cairo_ps_surface_t *surface;
65 if (cairo_surface_get_type (abstract_surface) != CAIRO_SURFACE_TYPE_PS)
66 return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
68 surface = (cairo_ps_surface_t*) paginated->target;
70 surface->has_creation_date = TRUE;
71 surface->creation_date = date;
73 return CAIRO_STATUS_SUCCESS;
76 static cairo_surface_t *
77 _cairo_boilerplate_ps_create_surface (const char *name,
78 cairo_content_t content,
79 cairo_ps_level_t level,
84 cairo_boilerplate_mode_t mode,
87 ps_target_closure_t *ptc;
88 cairo_surface_t *surface;
89 cairo_status_t status;
91 /* Sanitize back to a real cairo_content_t value. */
92 if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
93 content = CAIRO_CONTENT_COLOR_ALPHA;
95 *closure = ptc = xmalloc (sizeof (ps_target_closure_t));
97 xasprintf (&ptc->filename, "%s.out.ps", name);
98 xunlink (ptc->filename);
101 ptc->width = ceil (width);
102 ptc->height = ceil (height);
104 surface = cairo_ps_surface_create (ptc->filename, width, height);
105 if (cairo_surface_status (surface))
106 goto CLEANUP_FILENAME;
108 cairo_ps_surface_restrict_to_level (surface, level);
109 _cairo_boilerplate_ps_surface_set_creation_date (surface, 0);
110 cairo_surface_set_fallback_resolution (surface, 72., 72.);
112 if (content == CAIRO_CONTENT_COLOR) {
113 ptc->target = surface;
114 surface = cairo_surface_create_similar (ptc->target,
116 ptc->width, ptc->height);
117 if (cairo_surface_status (surface))
123 status = cairo_surface_set_user_data (surface, &ps_closure_key, ptc, NULL);
124 if (status == CAIRO_STATUS_SUCCESS)
127 cairo_surface_destroy (surface);
128 surface = cairo_boilerplate_surface_create_in_error (status);
131 cairo_surface_destroy (ptc->target);
133 free (ptc->filename);
138 static cairo_surface_t *
139 _cairo_boilerplate_ps2_create_surface (const char *name,
140 cairo_content_t content,
145 cairo_boilerplate_mode_t mode,
148 return _cairo_boilerplate_ps_create_surface (name, content,
151 max_width, max_height,
156 static cairo_surface_t *
157 _cairo_boilerplate_ps3_create_surface (const char *name,
158 cairo_content_t content,
163 cairo_boilerplate_mode_t mode,
166 return _cairo_boilerplate_ps_create_surface (name, content,
169 max_width, max_height,
174 static cairo_status_t
175 _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
177 ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
179 cairo_status_t status;
181 /* Both surface and ptc->target were originally created at the
182 * same dimensions. We want a 1:1 copy here, so we first clear any
183 * device offset on surface.
185 * In a more realistic use case of device offsets, the target of
186 * this copying would be of a different size than the source, and
187 * the offset would be desirable during the copy operation. */
188 cairo_surface_set_device_offset (surface, 0, 0);
193 cr = cairo_create (ptc->target);
194 cairo_set_source_surface (cr, surface, 0, 0);
196 cairo_show_page (cr);
197 status = cairo_status (cr);
203 cairo_surface_finish (surface);
204 status = cairo_surface_status (surface);
208 surface = ptc->target;
211 cairo_surface_finish (surface);
212 return cairo_surface_status (surface);
215 static cairo_status_t
216 _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface,
217 const char *filename)
219 ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
224 sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s %s",
225 ptc->width, ptc->height, filename,
226 ptc->level == CAIRO_PS_LEVEL_2 ? "-c 2 .setlanguagelevel -f" : "",
228 exitstatus = system (command);
229 #if _XOPEN_SOURCE && HAVE_SIGNAL_H
230 if (WIFSIGNALED (exitstatus))
231 raise (WTERMSIG (exitstatus));
234 return CAIRO_STATUS_WRITE_ERROR;
236 return CAIRO_STATUS_SUCCESS;
239 static cairo_surface_t *
240 _cairo_boilerplate_ps_get_image_surface (cairo_surface_t *surface,
245 ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
248 cairo_status_t status;
251 xasprintf (&filename, "%s.png", ptc->filename);
253 xasprintf (&filename, "%s-%%05d.png", ptc->filename);
254 status = _cairo_boilerplate_ps_surface_write_to_png (surface, filename);
256 return cairo_boilerplate_surface_create_in_error (status);
260 xasprintf (&filename, "%s-%05d.png", ptc->filename, page);
262 surface = cairo_boilerplate_get_image_surface_from_png (filename,
265 ptc->target == NULL);
274 _cairo_boilerplate_ps_cleanup (void *closure)
276 ps_target_closure_t *ptc = closure;
278 cairo_surface_finish (ptc->target);
279 cairo_surface_destroy (ptc->target);
281 free (ptc->filename);
286 _cairo_boilerplate_ps_force_fallbacks (cairo_surface_t *abstract_surface,
287 double x_pixels_per_inch,
288 double y_pixels_per_inch)
290 ps_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface,
293 cairo_paginated_surface_t *paginated;
294 cairo_ps_surface_t *surface;
297 abstract_surface = ptc->target;
299 paginated = (cairo_paginated_surface_t*) abstract_surface;
300 surface = (cairo_ps_surface_t*) paginated->target;
301 surface->force_fallbacks = TRUE;
302 cairo_surface_set_fallback_resolution (&paginated->base,
307 static const cairo_boilerplate_target_t targets[] = {
309 "ps2", "ps", ".ps", NULL,
310 CAIRO_SURFACE_TYPE_PS,
311 CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
312 "cairo_ps_surface_create",
313 _cairo_boilerplate_ps2_create_surface,
314 cairo_surface_create_similar,
315 _cairo_boilerplate_ps_force_fallbacks,
316 _cairo_boilerplate_ps_finish_surface,
317 _cairo_boilerplate_ps_get_image_surface,
318 _cairo_boilerplate_ps_surface_write_to_png,
319 _cairo_boilerplate_ps_cleanup,
320 NULL, NULL, FALSE, TRUE, TRUE
323 "ps2", "ps", ".ps", NULL,
324 CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0,
325 "cairo_ps_surface_create",
326 _cairo_boilerplate_ps2_create_surface,
327 cairo_surface_create_similar,
328 _cairo_boilerplate_ps_force_fallbacks,
329 _cairo_boilerplate_ps_finish_surface,
330 _cairo_boilerplate_ps_get_image_surface,
331 _cairo_boilerplate_ps_surface_write_to_png,
332 _cairo_boilerplate_ps_cleanup,
333 NULL, NULL, FALSE, TRUE, TRUE
336 "ps3", "ps", ".ps", NULL,
337 CAIRO_SURFACE_TYPE_PS,
338 CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
339 "cairo_ps_surface_create",
340 _cairo_boilerplate_ps3_create_surface,
341 cairo_surface_create_similar,
342 _cairo_boilerplate_ps_force_fallbacks,
343 _cairo_boilerplate_ps_finish_surface,
344 _cairo_boilerplate_ps_get_image_surface,
345 _cairo_boilerplate_ps_surface_write_to_png,
346 _cairo_boilerplate_ps_cleanup,
347 NULL, NULL, FALSE, TRUE, TRUE
350 "ps3", "ps", ".ps", NULL,
351 CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0,
352 "cairo_ps_surface_create",
353 _cairo_boilerplate_ps3_create_surface,
354 cairo_surface_create_similar,
355 _cairo_boilerplate_ps_force_fallbacks,
356 _cairo_boilerplate_ps_finish_surface,
357 _cairo_boilerplate_ps_get_image_surface,
358 _cairo_boilerplate_ps_surface_write_to_png,
359 _cairo_boilerplate_ps_cleanup,
360 NULL, NULL, FALSE, TRUE, TRUE
363 CAIRO_BOILERPLATE (ps, targets)
367 CAIRO_NO_BOILERPLATE (ps)