Upload Tizen2.0 source
[framework/graphics/cairo.git] / boilerplate / cairo-boilerplate-ps.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /*
3  * Copyright © 2004,2006 Red Hat, Inc.
4  *
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.
15  *
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.
23  *
24  * Author: Carl D. Worth <cworth@cworth.org>
25  */
26
27 #include "cairo-boilerplate-private.h"
28
29 #if CAIRO_CAN_TEST_PS_SURFACE
30
31 #include <cairo-ps.h>
32
33 #include <cairo-ps-surface-private.h>
34 #include <cairo-paginated-surface-private.h>
35
36 #if HAVE_SIGNAL_H
37 #include <signal.h>
38 #endif
39
40 #if HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
43
44 #if ! CAIRO_HAS_RECORDING_SURFACE
45 #define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING
46 #endif
47
48 static const cairo_user_data_key_t ps_closure_key;
49
50 typedef struct _ps_target_closure {
51     char                *filename;
52     int                  width;
53     int                  height;
54     cairo_surface_t     *target;
55     cairo_ps_level_t     level;
56 } ps_target_closure_t;
57
58 static cairo_status_t
59 _cairo_boilerplate_ps_surface_set_creation_date (cairo_surface_t *abstract_surface,
60                                                  time_t           date)
61 {
62     cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface;
63     cairo_ps_surface_t *surface;
64
65     if (cairo_surface_get_type (abstract_surface) != CAIRO_SURFACE_TYPE_PS)
66         return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
67
68     surface = (cairo_ps_surface_t*) paginated->target;
69
70     surface->has_creation_date = TRUE;
71     surface->creation_date = date;
72
73     return CAIRO_STATUS_SUCCESS;
74 }
75
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,
80                                       double                     width,
81                                       double                     height,
82                                       double                     max_width,
83                                       double                     max_height,
84                                       cairo_boilerplate_mode_t   mode,
85                                       void                     **closure)
86 {
87     ps_target_closure_t *ptc;
88     cairo_surface_t *surface;
89     cairo_status_t status;
90
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;
94
95     *closure = ptc = xmalloc (sizeof (ps_target_closure_t));
96
97     xasprintf (&ptc->filename, "%s.out.ps", name);
98     xunlink (ptc->filename);
99
100     ptc->level = level;
101     ptc->width = ceil (width);
102     ptc->height = ceil (height);
103
104     surface = cairo_ps_surface_create (ptc->filename, width, height);
105     if (cairo_surface_status (surface))
106         goto CLEANUP_FILENAME;
107
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.);
111
112     if (content == CAIRO_CONTENT_COLOR) {
113         ptc->target = surface;
114         surface = cairo_surface_create_similar (ptc->target,
115                                                 CAIRO_CONTENT_COLOR,
116                                                 ptc->width, ptc->height);
117         if (cairo_surface_status (surface))
118             goto CLEANUP_TARGET;
119     } else {
120         ptc->target = NULL;
121     }
122
123     status = cairo_surface_set_user_data (surface, &ps_closure_key, ptc, NULL);
124     if (status == CAIRO_STATUS_SUCCESS)
125         return surface;
126
127     cairo_surface_destroy (surface);
128     surface = cairo_boilerplate_surface_create_in_error (status);
129
130   CLEANUP_TARGET:
131     cairo_surface_destroy (ptc->target);
132   CLEANUP_FILENAME:
133     free (ptc->filename);
134     free (ptc);
135     return surface;
136 }
137
138 static cairo_surface_t *
139 _cairo_boilerplate_ps2_create_surface (const char                *name,
140                                        cairo_content_t            content,
141                                        double                     width,
142                                        double                     height,
143                                        double                     max_width,
144                                        double                     max_height,
145                                        cairo_boilerplate_mode_t   mode,
146                                        void                     **closure)
147 {
148     return _cairo_boilerplate_ps_create_surface (name, content,
149                                                  CAIRO_PS_LEVEL_2,
150                                                  width, height,
151                                                  max_width, max_height,
152                                                  mode,
153                                                  closure);
154 }
155
156 static cairo_surface_t *
157 _cairo_boilerplate_ps3_create_surface (const char                *name,
158                                        cairo_content_t            content,
159                                        double                     width,
160                                        double                     height,
161                                        double                     max_width,
162                                        double                     max_height,
163                                        cairo_boilerplate_mode_t   mode,
164                                        void                     **closure)
165 {
166     return _cairo_boilerplate_ps_create_surface (name, content,
167                                                  CAIRO_PS_LEVEL_3,
168                                                  width, height,
169                                                  max_width, max_height,
170                                                  mode,
171                                                  closure);
172 }
173
174 static cairo_status_t
175 _cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface)
176 {
177     ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
178                                                             &ps_closure_key);
179     cairo_status_t status;
180
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.
184      *
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);
189
190     if (ptc->target) {
191         cairo_t *cr;
192
193         cr = cairo_create (ptc->target);
194         cairo_set_source_surface (cr, surface, 0, 0);
195         cairo_paint (cr);
196         cairo_show_page (cr);
197         status = cairo_status (cr);
198         cairo_destroy (cr);
199
200         if (status)
201             return status;
202
203         cairo_surface_finish (surface);
204         status = cairo_surface_status (surface);
205         if (status)
206             return status;
207
208         surface = ptc->target;
209     }
210
211     cairo_surface_finish (surface);
212     return cairo_surface_status (surface);
213 }
214
215 static cairo_status_t
216 _cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface,
217                                             const char      *filename)
218 {
219     ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
220                                                             &ps_closure_key);
221     char    command[4096];
222     int exitstatus;
223
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" : "",
227              ptc->filename);
228     exitstatus = system (command);
229 #if _XOPEN_SOURCE && HAVE_SIGNAL_H
230     if (WIFSIGNALED (exitstatus))
231         raise (WTERMSIG (exitstatus));
232 #endif
233     if (exitstatus)
234         return CAIRO_STATUS_WRITE_ERROR;
235
236     return CAIRO_STATUS_SUCCESS;
237 }
238
239 static cairo_surface_t *
240 _cairo_boilerplate_ps_get_image_surface (cairo_surface_t *surface,
241                                          int              page,
242                                          int              width,
243                                          int              height)
244 {
245     ps_target_closure_t *ptc = cairo_surface_get_user_data (surface,
246                                                             &ps_closure_key);
247     char *filename;
248     cairo_status_t status;
249
250     if (page == 0)
251         xasprintf (&filename, "%s.png", ptc->filename);
252     else
253         xasprintf (&filename, "%s-%%05d.png", ptc->filename);
254     status = _cairo_boilerplate_ps_surface_write_to_png (surface, filename);
255     if (status)
256         return cairo_boilerplate_surface_create_in_error (status);
257
258     if (page != 0) {
259         free (filename);
260         xasprintf (&filename, "%s-%05d.png", ptc->filename, page);
261     }
262     surface = cairo_boilerplate_get_image_surface_from_png (filename,
263                                                             width,
264                                                             height,
265                                                             ptc->target == NULL);
266
267     remove (filename);
268     free (filename);
269
270     return surface;
271 }
272
273 static void
274 _cairo_boilerplate_ps_cleanup (void *closure)
275 {
276     ps_target_closure_t *ptc = closure;
277     if (ptc->target) {
278         cairo_surface_finish (ptc->target);
279         cairo_surface_destroy (ptc->target);
280     }
281     free (ptc->filename);
282     free (ptc);
283 }
284
285 static void
286 _cairo_boilerplate_ps_force_fallbacks (cairo_surface_t *abstract_surface,
287                                        double            x_pixels_per_inch,
288                                        double            y_pixels_per_inch)
289 {
290     ps_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface,
291                                                             &ps_closure_key);
292
293     cairo_paginated_surface_t *paginated;
294     cairo_ps_surface_t *surface;
295
296     if (ptc->target)
297         abstract_surface = ptc->target;
298
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,
303                                            x_pixels_per_inch,
304                                            y_pixels_per_inch);
305 }
306
307 static const cairo_boilerplate_target_t targets[] = {
308     {
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
321     },
322     {
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
334     },
335     {
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
348     },
349     {
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
361     },
362 };
363 CAIRO_BOILERPLATE (ps, targets)
364
365 #else
366
367 CAIRO_NO_BOILERPLATE (ps)
368
369 #endif