Tizen 2.0 Release
[framework/graphics/cairo.git] / test / ps-eps.c
1 /*
2  * Copyright © 2006 Red Hat, Inc.
3  * Copyright © 2009 Adrian Johnson
4  * Copyright © 2008 Chris Wilson
5  *
6  * Permission to use, copy, modify, distribute, and sell this software
7  * and its documentation for any purpose is hereby granted without
8  * fee, provided that the above copyright notice appear in all copies
9  * and that both that copyright notice and this permission notice
10  * appear in supporting documentation, and that the name of
11  * Red Hat, Inc. not be used in advertising or publicity pertaining to
12  * distribution of the software without specific, written prior
13  * permission. Red Hat, Inc. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as
15  * is" without express or implied warranty.
16  *
17  * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19  * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
20  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
22  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
23  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24  *
25  * Author: Carl D. Worth <cworth@cworth.org>
26  *         Adrian Johnson <ajohnson@redneon.com>
27  *         Chris Wilson <chris@chris-wilson.co.uk>
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <math.h>
37 #include <cairo.h>
38 #include <cairo-ps.h>
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #include <errno.h>
43 #endif
44 #if HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47
48 #include "cairo-test.h"
49 #include "buffer-diff.h"
50
51 /* Test EPS output.
52  */
53
54 #define WIDTH 595
55 #define HEIGHT 842
56
57 /* Reference Bounding Box */
58 #define LLX  95
59 #define LLY 687
60 #define URX 155
61 #define URY 747
62
63 static void
64 _xunlink (const cairo_test_context_t *ctx, const char *pathname)
65 {
66     if (unlink (pathname) < 0 && errno != ENOENT) {
67         cairo_test_log (ctx, "Error: Cannot remove %s: %s\n",
68                         pathname, strerror (errno));
69         exit (1);
70     }
71 }
72
73 static cairo_bool_t
74 check_result (cairo_test_context_t *ctx,
75               const cairo_boilerplate_target_t *target,
76               const char *test_name,
77               const char *base_name,
78               cairo_surface_t *surface)
79 {
80     const char *format;
81     char *ref_name;
82     char *png_name;
83     char *diff_name;
84     cairo_surface_t *test_image, *ref_image, *diff_image;
85     buffer_diff_result_t result;
86     cairo_status_t status;
87     cairo_bool_t ret;
88
89     /* XXX log target, OUTPUT, REFERENCE, DIFFERENCE for index.html */
90
91     if (target->finish_surface != NULL) {
92         status = target->finish_surface (surface);
93         if (status) {
94             cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
95                     cairo_status_to_string (status));
96             cairo_surface_destroy (surface);
97             return FALSE;
98         }
99     }
100
101     xasprintf (&png_name,  "%s.out.png", base_name);
102     xasprintf (&diff_name, "%s.diff.png", base_name);
103
104     test_image = target->get_image_surface (surface, 0, WIDTH, HEIGHT);
105     if (cairo_surface_status (test_image)) {
106         cairo_test_log (ctx, "Error: Failed to extract page: %s\n",
107                         cairo_status_to_string (cairo_surface_status (test_image)));
108         cairo_surface_destroy (test_image);
109         free (png_name);
110         free (diff_name);
111         return FALSE;
112     }
113
114     _xunlink (ctx, png_name);
115     status = cairo_surface_write_to_png (test_image, png_name);
116     if (status) {
117         cairo_test_log (ctx, "Error: Failed to write output image: %s\n",
118                 cairo_status_to_string (status));
119         cairo_surface_destroy (test_image);
120         free (png_name);
121         free (diff_name);
122         return FALSE;
123     }
124
125     format = cairo_boilerplate_content_name (target->content);
126     ref_name = cairo_test_reference_filename (ctx,
127                                               base_name,
128                                               test_name,
129                                               target->name,
130                                               target->basename,
131                                               format,
132                                               CAIRO_TEST_REF_SUFFIX,
133                                               CAIRO_TEST_PNG_EXTENSION);
134     if (ref_name == NULL) {
135         cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
136                         base_name);
137         cairo_surface_destroy (test_image);
138         free (png_name);
139         free (diff_name);
140         return FALSE;
141     }
142
143     ref_image = cairo_test_get_reference_image (ctx, ref_name,
144             target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
145     if (cairo_surface_status (ref_image)) {
146         cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
147                         ref_name,
148                 cairo_status_to_string (cairo_surface_status (ref_image)));
149         cairo_surface_destroy (ref_image);
150         cairo_surface_destroy (test_image);
151         free (png_name);
152         free (diff_name);
153         free (ref_name);
154         return FALSE;
155     }
156
157     diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
158             WIDTH, HEIGHT);
159
160     ret = TRUE;
161     status = image_diff (ctx,
162             test_image, ref_image, diff_image,
163             &result);
164     _xunlink (ctx, diff_name);
165     if (status) {
166         cairo_test_log (ctx, "Error: Failed to compare images: %s\n",
167                         cairo_status_to_string (status));
168         ret = FALSE;
169     } else if (image_diff_is_failure (&result, target->error_tolerance))
170     {
171         ret = FALSE;
172
173         status = cairo_surface_write_to_png (diff_image, diff_name);
174         if (status) {
175             cairo_test_log (ctx, "Error: Failed to write differences image: %s\n",
176                     cairo_status_to_string (status));
177         }
178     }
179
180     cairo_surface_destroy (test_image);
181     cairo_surface_destroy (diff_image);
182     free (png_name);
183     free (diff_name);
184     free (ref_name);
185
186     return ret;
187 }
188
189
190 #define DOCUMENT_BBOX  "%%BoundingBox:"
191 #define PAGE_BBOX      "%%PageBoundingBox:"
192
193 static cairo_bool_t
194 check_bbox (cairo_test_context_t *ctx,
195             const char *base_name)
196 {
197     char *filename;
198     FILE *f;
199     char buf[256];
200     cairo_bool_t bbox_pass, page_bbox_pass;
201     int llx, lly, urx, ury;
202     int ret;
203
204     xasprintf (&filename,  "%s.out.ps", base_name);
205     f = fopen (filename, "r");
206     if (!f) {
207         cairo_test_log (ctx, "Error: Cannot open EPS output: %s\n",
208                         base_name);
209         free (filename);
210         return FALSE;
211     }
212
213     bbox_pass = FALSE;
214     page_bbox_pass = FALSE;
215     while (!feof(f)) {
216         fgets (buf, sizeof(buf), f);
217
218         if (strncmp (buf, DOCUMENT_BBOX, strlen (DOCUMENT_BBOX)) == 0) {
219             ret = sscanf (buf+strlen (DOCUMENT_BBOX), "%d %d %d %d", &llx, &lly, &urx, &ury);
220             if (ret == 4 && llx == LLX && lly == LLY && urx == URX && ury == URY)
221                 bbox_pass = TRUE;
222         }
223
224         if (strncmp (buf, PAGE_BBOX, strlen (PAGE_BBOX)) == 0) {
225             ret = sscanf (buf+strlen (PAGE_BBOX), "%d %d %d %d", &llx, &lly, &urx, &ury);
226             if (ret == 4 && llx == LLX && lly == LLY && urx == URX && ury == URY)
227                 page_bbox_pass = TRUE;
228         }
229     }
230     fclose (f);
231
232     if (!bbox_pass || !page_bbox_pass) {
233         cairo_test_log (ctx, "Error: EPS Bounding Box does not match reference Bounding Box\n");
234         return FALSE;
235     }
236
237     free (filename);
238
239     return TRUE;
240 }
241
242 static cairo_bool_t
243 _cairo_test_mkdir (const char *path)
244 {
245 #if ! HAVE_MKDIR
246     return FALSE;
247 #elif HAVE_MKDIR == 1
248     if (mkdir (path) == 0)
249         return TRUE;
250 #elif HAVE_MKDIR == 2
251     if (mkdir (path, 0770) == 0)
252         return TRUE;
253 #else
254 #error Bad value for HAVE_MKDIR
255 #endif
256
257     return errno == EEXIST;
258 }
259
260 static cairo_test_status_t
261 preamble (cairo_test_context_t *ctx)
262 {
263     cairo_t *cr;
264     cairo_test_status_t ret = CAIRO_TEST_UNTESTED;
265     const char *path = _cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : ".";
266     unsigned int i;
267
268     for (i = 0; i < ctx->num_targets; i++) {
269         const cairo_boilerplate_target_t *target = ctx->targets_to_test[i];
270         cairo_surface_t *surface = NULL;
271         char *base_name;
272         void *closure;
273         const char *format;
274         cairo_status_t status;
275         cairo_bool_t pass;
276         char *test_name;
277
278         if (! cairo_test_is_target_enabled (ctx, target->name))
279             continue;
280
281         format = cairo_boilerplate_content_name (target->content);
282         xasprintf (&test_name, "ps-eps");
283         xasprintf (&base_name, "%s/ps-eps.%s.%s",
284                    path, target->name, format);
285
286         surface = (target->create_surface) (base_name,
287                                             target->content,
288                                             WIDTH, HEIGHT,
289                                             WIDTH, HEIGHT,
290                                             CAIRO_BOILERPLATE_MODE_TEST,
291                                             &closure);
292
293         if (surface == NULL) {
294             free (base_name);
295             free (test_name);
296             continue;
297         }
298
299         cairo_ps_surface_set_eps (surface, TRUE);
300         if (!cairo_ps_surface_get_eps (surface)) {
301             cairo_surface_destroy (surface);
302             if (target->cleanup)
303                 target->cleanup (closure);
304
305             free (base_name);
306             free (test_name);
307             continue;
308         }
309         
310         cairo_test_log (ctx,
311                         "Testing ps-eps with %s target\n",
312                         target->name);
313         printf ("%s:\t", base_name);
314         fflush (stdout);
315
316         cairo_surface_set_device_offset (surface, 25, 25);
317         cr = cairo_create (surface);
318
319         cairo_new_sub_path (cr);
320         cairo_arc (cr, 100, 100, 25, 0, 2*M_PI);
321         cairo_set_line_width (cr, 10);
322         cairo_stroke (cr);
323
324         cairo_show_page (cr);
325
326         status = cairo_status (cr);
327         cairo_destroy (cr);
328
329         if (status) {
330             cairo_test_log (ctx, "Error: Failed to create target surface: %s\n",
331                             cairo_status_to_string (status));
332             pass = FALSE;
333         } else {
334             pass = TRUE;
335             /* extract the image and compare it to our reference */
336             if (! check_result (ctx, target, test_name, base_name, surface))
337                 pass = FALSE;
338
339             /* check the bounding box of the EPS file and compare it to our reference */
340             if (! check_bbox (ctx, base_name))
341                 pass = FALSE;
342         }
343         cairo_surface_destroy (surface);
344         if (target->cleanup)
345             target->cleanup (closure);
346
347         free (base_name);
348         free (test_name);
349
350         if (pass) {
351             printf ("PASS\n");
352             ret = CAIRO_TEST_SUCCESS;
353         } else {
354             printf ("FAIL\n");
355             ret = CAIRO_TEST_FAILURE;
356         }
357         fflush (stdout);
358     }
359
360     return ret;
361 }
362
363 CAIRO_TEST (ps_eps,
364             "Check EPS output from PS surface",
365             "ps, api", /* keywords */
366             NULL, /* requirements */
367             0, 0,
368             preamble, NULL)