Update change log.
[platform/upstream/cairo.git] / boilerplate / cairo-boilerplate-pdf.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_PDF_SURFACE
30
31 #include <cairo-pdf.h>
32 #include <cairo-pdf-surface-private.h>
33 #include <cairo-paginated-surface-private.h>
34
35 #if HAVE_SIGNAL_H
36 #include <signal.h>
37 #endif
38
39 #if HAVE_SYS_WAIT_H
40 #include <sys/wait.h>
41 #endif
42
43 #if ! CAIRO_HAS_RECORDING_SURFACE
44 #define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING
45 #endif
46
47 static const cairo_user_data_key_t pdf_closure_key;
48
49 typedef struct _pdf_target_closure
50 {
51     char                *filename;
52     int                  width;
53     int                  height;
54     cairo_surface_t     *target;
55 } pdf_target_closure_t;
56
57 #define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
58
59 static cairo_surface_t *
60 _cairo_boilerplate_pdf_create_surface (const char                *name,
61                                        cairo_content_t            content,
62                                        double                     width,
63                                        double                     height,
64                                        double                     max_width,
65                                        double                     max_height,
66                                        cairo_boilerplate_mode_t   mode,
67                                        void                     **closure)
68 {
69     pdf_target_closure_t *ptc;
70     cairo_surface_t *surface;
71     cairo_status_t status;
72
73     /* Sanitize back to a real cairo_content_t value. */
74     if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
75         content = CAIRO_CONTENT_COLOR_ALPHA;
76
77     *closure = ptc = xmalloc (sizeof (pdf_target_closure_t));
78
79     ptc->width = ceil (width);
80     ptc->height = ceil (height);
81
82     xasprintf (&ptc->filename, "%s.out.pdf", name);
83     xunlink (ptc->filename);
84
85     surface = cairo_pdf_surface_create (ptc->filename, width, height);
86     if (cairo_surface_status (surface))
87         goto CLEANUP_FILENAME;
88
89     cairo_surface_set_fallback_resolution (surface, 72., 72.);
90
91     if (content == CAIRO_CONTENT_COLOR) {
92         ptc->target = surface;
93         surface = cairo_surface_create_similar (ptc->target,
94                                                 CAIRO_CONTENT_COLOR,
95                                                 ptc->width, ptc->height);
96         if (cairo_surface_status (surface))
97             goto CLEANUP_TARGET;
98     } else {
99         ptc->target = NULL;
100     }
101
102     status = cairo_surface_set_user_data (surface, &pdf_closure_key, ptc, NULL);
103     if (status == CAIRO_STATUS_SUCCESS)
104         return surface;
105
106     cairo_surface_destroy (surface);
107     surface = cairo_boilerplate_surface_create_in_error (status);
108
109   CLEANUP_TARGET:
110     cairo_surface_destroy (ptc->target);
111   CLEANUP_FILENAME:
112     free (ptc->filename);
113     free (ptc);
114     return surface;
115 }
116
117 static cairo_status_t
118 _cairo_boilerplate_pdf_finish_surface (cairo_surface_t *surface)
119 {
120     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface,
121                                                              &pdf_closure_key);
122     cairo_status_t status;
123
124     /* Both surface and ptc->target were originally created at the
125      * same dimensions. We want a 1:1 copy here, so we first clear any
126      * device offset on surface.
127      *
128      * In a more realistic use case of device offsets, the target of
129      * this copying would be of a different size than the source, and
130      * the offset would be desirable during the copy operation. */
131     cairo_surface_set_device_offset (surface, 0, 0);
132
133     if (ptc->target) {
134         cairo_t *cr;
135         cr = cairo_create (ptc->target);
136         cairo_set_source_surface (cr, surface, 0, 0);
137         cairo_paint (cr);
138         cairo_show_page (cr);
139         status = cairo_status (cr);
140         cairo_destroy (cr);
141
142         if (status)
143             return status;
144
145         cairo_surface_finish (surface);
146         status = cairo_surface_status (surface);
147         if (status)
148             return status;
149
150         surface = ptc->target;
151     }
152
153     cairo_surface_finish (surface);
154     status = cairo_surface_status (surface);
155     if (status)
156         return status;
157
158     return CAIRO_STATUS_SUCCESS;
159 }
160
161 static cairo_status_t
162 _cairo_boilerplate_pdf_surface_write_to_png (cairo_surface_t *surface,
163                                              const char      *filename)
164 {
165     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
166     char    command[4096];
167     int exitstatus;
168
169     sprintf (command, "./pdf2png %s %s 1",
170              ptc->filename, filename);
171
172     exitstatus = system (command);
173 #if _XOPEN_SOURCE && HAVE_SIGNAL_H
174     if (WIFSIGNALED (exitstatus))
175         raise (WTERMSIG (exitstatus));
176 #endif
177     if (exitstatus)
178         return CAIRO_STATUS_WRITE_ERROR;
179
180     return CAIRO_STATUS_SUCCESS;
181 }
182
183 static cairo_surface_t *
184 _cairo_boilerplate_pdf_convert_to_image (cairo_surface_t *surface,
185                                          int              page)
186 {
187     pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface,
188                                                              &pdf_closure_key);
189
190     return cairo_boilerplate_convert_to_image (ptc->filename, page+1);
191 }
192
193 static cairo_surface_t *
194 _cairo_boilerplate_pdf_get_image_surface (cairo_surface_t *surface,
195                                           int              page,
196                                           int              width,
197                                           int              height)
198 {
199     cairo_surface_t *image;
200
201     image = _cairo_boilerplate_pdf_convert_to_image (surface, page);
202     cairo_surface_set_device_offset (image,
203                                      cairo_image_surface_get_width (image) - width,
204                                      cairo_image_surface_get_height (image) - height);
205     surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
206     cairo_surface_destroy (image);
207
208     return surface;
209 }
210
211 static void
212 _cairo_boilerplate_pdf_cleanup (void *closure)
213 {
214     pdf_target_closure_t *ptc = closure;
215     if (ptc->target) {
216         cairo_surface_finish (ptc->target);
217         cairo_surface_destroy (ptc->target);
218     }
219     free (ptc->filename);
220     free (ptc);
221 }
222
223 static void
224 _cairo_boilerplate_pdf_force_fallbacks (cairo_surface_t *abstract_surface,
225                                        double            x_pixels_per_inch,
226                                        double            y_pixels_per_inch)
227 {
228     pdf_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface,
229                                                              &pdf_closure_key);
230
231     cairo_paginated_surface_t *paginated;
232     cairo_pdf_surface_t *surface;
233
234     if (ptc->target)
235         abstract_surface = ptc->target;
236
237     paginated = (cairo_paginated_surface_t*) abstract_surface;
238     surface = (cairo_pdf_surface_t*) paginated->target;
239     surface->force_fallbacks = TRUE;
240     cairo_surface_set_fallback_resolution (&paginated->base,
241                                            x_pixels_per_inch,
242                                            y_pixels_per_inch);
243 }
244
245 static const cairo_boilerplate_target_t targets[] = {
246     {
247         "pdf", "pdf", ".pdf", NULL,
248         CAIRO_SURFACE_TYPE_PDF,
249         CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0,
250         "cairo_pdf_surface_create",
251         _cairo_boilerplate_pdf_create_surface,
252         cairo_surface_create_similar,
253         _cairo_boilerplate_pdf_force_fallbacks,
254         _cairo_boilerplate_pdf_finish_surface,
255         _cairo_boilerplate_pdf_get_image_surface,
256         _cairo_boilerplate_pdf_surface_write_to_png,
257         _cairo_boilerplate_pdf_cleanup,
258         NULL, NULL, FALSE, TRUE, TRUE
259     },
260     {
261         "pdf", "pdf", ".pdf", NULL,
262         CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0,
263         "cairo_pdf_surface_create",
264         _cairo_boilerplate_pdf_create_surface,
265         cairo_surface_create_similar,
266         _cairo_boilerplate_pdf_force_fallbacks,
267         _cairo_boilerplate_pdf_finish_surface,
268         _cairo_boilerplate_pdf_get_image_surface,
269         _cairo_boilerplate_pdf_surface_write_to_png,
270         _cairo_boilerplate_pdf_cleanup,
271         NULL, NULL, FALSE, TRUE, TRUE
272     },
273 };
274 CAIRO_BOILERPLATE (pdf, targets)
275
276 #else
277
278 CAIRO_NO_BOILERPLATE (pdf)
279
280 #endif