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"
28 #include "cairo-boilerplate-scaled-font.h"
29 #include "cairo-malloc-private.h"
33 #include <cairo-ctype-inline.h>
34 #include <cairo-types-private.h>
35 #include <cairo-scaled-font-private.h>
37 #if CAIRO_HAS_SCRIPT_SURFACE
38 #include <cairo-script.h>
50 #if HAVE_UNISTD_H && HAVE_FCNTL_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && HAVE_SYS_UN_H
55 #include <sys/socket.h>
59 #define SOCKET_PATH "./.any2ppm"
63 cairo_boilerplate_content (cairo_content_t content
)
65 if (content
== CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED
)
66 content
= CAIRO_CONTENT_COLOR_ALPHA
;
72 cairo_boilerplate_content_name (cairo_content_t content
)
74 /* For the purpose of the content name, we don't distinguish the
75 * flattened content value.
77 switch (cairo_boilerplate_content (content
)) {
78 case CAIRO_CONTENT_COLOR
:
80 case CAIRO_CONTENT_COLOR_ALPHA
:
82 case CAIRO_CONTENT_ALPHA
:
84 assert (0); /* not reached */
90 _cairo_boilerplate_content_visible_name (cairo_content_t content
)
92 switch (cairo_boilerplate_content (content
)) {
93 case CAIRO_CONTENT_COLOR
:
95 case CAIRO_CONTENT_COLOR_ALPHA
:
97 case CAIRO_CONTENT_ALPHA
:
100 assert (0); /* not reached */
106 cairo_boilerplate_format_from_content (cairo_content_t content
)
108 cairo_format_t format
;
111 case CAIRO_CONTENT_COLOR
:
112 format
= CAIRO_FORMAT_RGB24
;
114 case CAIRO_CONTENT_COLOR_ALPHA
:
115 format
= CAIRO_FORMAT_ARGB32
;
117 case CAIRO_CONTENT_ALPHA
:
118 format
= CAIRO_FORMAT_A8
;
121 assert (0); /* not reached */
122 format
= CAIRO_FORMAT_INVALID
;
129 static cairo_surface_t
*
130 _cairo_boilerplate_image_create_surface (const char *name
,
131 cairo_content_t content
,
136 cairo_boilerplate_mode_t mode
,
139 cairo_format_t format
;
143 if (content
== CAIRO_CONTENT_COLOR_ALPHA
) {
144 format
= CAIRO_FORMAT_ARGB32
;
145 } else if (content
== CAIRO_CONTENT_COLOR
) {
146 format
= CAIRO_FORMAT_RGB24
;
148 assert (0); /* not reached */
152 return cairo_image_surface_create (format
, ceil (width
), ceil (height
));
155 static const cairo_user_data_key_t key
;
157 static cairo_surface_t
*
158 _cairo_boilerplate_image_create_similar (cairo_surface_t
*other
,
159 cairo_content_t content
,
160 int width
, int height
)
162 cairo_format_t format
;
163 cairo_surface_t
*surface
;
168 case CAIRO_CONTENT_ALPHA
:
169 format
= CAIRO_FORMAT_A8
;
171 case CAIRO_CONTENT_COLOR
:
172 format
= CAIRO_FORMAT_RGB24
;
174 case CAIRO_CONTENT_COLOR_ALPHA
:
176 format
= CAIRO_FORMAT_ARGB32
;
180 stride
= cairo_format_stride_for_width(format
, width
);
181 ptr
= _cairo_malloc (stride
* height
);
183 surface
= cairo_image_surface_create_for_data (ptr
, format
,
184 width
, height
, stride
);
185 cairo_surface_set_user_data (surface
, &key
, ptr
, free
);
190 static cairo_surface_t
*
191 _cairo_boilerplate_image16_create_surface (const char *name
,
192 cairo_content_t content
,
197 cairo_boilerplate_mode_t mode
,
202 /* XXX force CAIRO_CONTENT_COLOR */
203 return cairo_image_surface_create (CAIRO_FORMAT_RGB16_565
, ceil (width
), ceil (height
));
206 static cairo_surface_t
*
207 _cairo_boilerplate_image16_create_similar (cairo_surface_t
*other
,
208 cairo_content_t content
,
209 int width
, int height
)
211 cairo_format_t format
;
212 cairo_surface_t
*surface
;
217 case CAIRO_CONTENT_ALPHA
:
218 format
= CAIRO_FORMAT_A8
;
220 case CAIRO_CONTENT_COLOR
:
221 format
= CAIRO_FORMAT_RGB16_565
;
223 case CAIRO_CONTENT_COLOR_ALPHA
:
225 format
= CAIRO_FORMAT_ARGB32
;
229 stride
= cairo_format_stride_for_width(format
, width
);
230 ptr
= _cairo_malloc (stride
* height
);
232 surface
= cairo_image_surface_create_for_data (ptr
, format
,
233 width
, height
, stride
);
234 cairo_surface_set_user_data (surface
, &key
, ptr
, free
);
240 _cairo_boilerplate_image_describe (void *closure
)
244 xasprintf (&s
, "pixman %s", pixman_version_string ());
249 #if CAIRO_HAS_RECORDING_SURFACE
250 static cairo_surface_t
*
251 _cairo_boilerplate_recording_create_surface (const char *name
,
252 cairo_content_t content
,
257 cairo_boilerplate_mode_t mode
,
260 cairo_rectangle_t extents
;
264 extents
.width
= width
;
265 extents
.height
= height
;
266 return *closure
= cairo_surface_reference (cairo_recording_surface_create (content
, &extents
));
270 _cairo_boilerplate_recording_surface_cleanup (void *closure
)
272 cairo_surface_finish (closure
);
273 cairo_surface_destroy (closure
);
277 const cairo_user_data_key_t cairo_boilerplate_output_basename_key
;
280 _cairo_boilerplate_get_image_surface (cairo_surface_t
*src
,
285 cairo_surface_t
*surface
, *image
;
287 cairo_status_t status
;
288 cairo_format_t format
;
290 if (cairo_surface_status (src
))
291 return cairo_surface_reference (src
);
294 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH
);
296 /* extract sub-surface */
297 switch (cairo_surface_get_content (src
)) {
298 case CAIRO_CONTENT_ALPHA
:
299 format
= CAIRO_FORMAT_A8
;
301 case CAIRO_CONTENT_COLOR
:
302 format
= CAIRO_FORMAT_RGB24
;
305 case CAIRO_CONTENT_COLOR_ALPHA
:
306 format
= CAIRO_FORMAT_ARGB32
;
309 surface
= cairo_image_surface_create (format
, width
, height
);
310 assert (cairo_surface_get_content (surface
) == cairo_surface_get_content (src
));
311 image
= cairo_surface_reference (surface
);
313 /* open a logging channel (only interesting for recording surfaces) */
314 #if CAIRO_HAS_SCRIPT_SURFACE && CAIRO_HAS_RECORDING_SURFACE
315 if (cairo_surface_get_type (src
) == CAIRO_SURFACE_TYPE_RECORDING
) {
316 const char *test_name
;
318 test_name
= cairo_surface_get_user_data (src
,
319 &cairo_boilerplate_output_basename_key
);
320 if (test_name
!= NULL
) {
324 cairo_surface_destroy (surface
);
326 xasprintf (&filename
, "%s.out.trace", test_name
);
327 ctx
= cairo_script_create (filename
);
328 surface
= cairo_script_surface_create_for_target (ctx
, image
);
329 cairo_device_destroy (ctx
);
335 cr
= cairo_create (surface
);
336 cairo_surface_destroy (surface
);
337 cairo_set_source_surface (cr
, src
, 0, 0);
340 status
= cairo_status (cr
);
342 cairo_surface_destroy (image
);
343 image
= cairo_surface_reference (cairo_get_target (cr
));
351 cairo_boilerplate_get_image_surface_from_png (const char *filename
,
354 cairo_bool_t flatten
)
356 cairo_surface_t
*surface
;
358 surface
= cairo_image_surface_create_from_png (filename
);
359 if (cairo_surface_status (surface
))
364 cairo_surface_t
*flattened
;
366 flattened
= cairo_image_surface_create (cairo_image_surface_get_format (surface
),
369 cr
= cairo_create (flattened
);
370 cairo_surface_destroy (flattened
);
372 cairo_set_source_rgb (cr
, 1, 1, 1);
375 cairo_set_source_surface (cr
, surface
,
376 width
- cairo_image_surface_get_width (surface
),
377 height
- cairo_image_surface_get_height (surface
));
380 cairo_surface_destroy (surface
);
381 surface
= cairo_surface_reference (cairo_get_target (cr
));
383 } else if (cairo_image_surface_get_width (surface
) != width
||
384 cairo_image_surface_get_height (surface
) != height
)
387 cairo_surface_t
*sub
;
389 sub
= cairo_image_surface_create (cairo_image_surface_get_format (surface
),
392 cr
= cairo_create (sub
);
393 cairo_surface_destroy (sub
);
395 cairo_set_source_surface (cr
, surface
,
396 width
- cairo_image_surface_get_width (surface
),
397 height
- cairo_image_surface_get_height (surface
));
398 cairo_set_operator (cr
, CAIRO_OPERATOR_SOURCE
);
401 cairo_surface_destroy (surface
);
402 surface
= cairo_surface_reference (cairo_get_target (cr
));
409 static const cairo_boilerplate_target_t builtin_targets
[] = {
410 /* I'm uncompromising about leaving the image backend as 0
411 * for tolerance. There shouldn't ever be anything that is out of
412 * our control here. */
414 "image", "image", NULL
, NULL
,
415 CAIRO_SURFACE_TYPE_IMAGE
, CAIRO_CONTENT_COLOR_ALPHA
, 0,
417 _cairo_boilerplate_image_create_surface
,
418 _cairo_boilerplate_image_create_similar
,
420 _cairo_boilerplate_get_image_surface
,
421 cairo_surface_write_to_png
,
423 _cairo_boilerplate_image_describe
,
427 "image", "image", NULL
, NULL
,
428 CAIRO_SURFACE_TYPE_IMAGE
, CAIRO_CONTENT_COLOR
, 0,
430 _cairo_boilerplate_image_create_surface
,
431 _cairo_boilerplate_image_create_similar
,
433 _cairo_boilerplate_get_image_surface
,
434 cairo_surface_write_to_png
,
436 _cairo_boilerplate_image_describe
,
440 "image16", "image", NULL
, NULL
,
441 CAIRO_SURFACE_TYPE_IMAGE
, CAIRO_CONTENT_COLOR
, 0,
443 _cairo_boilerplate_image16_create_surface
,
444 _cairo_boilerplate_image16_create_similar
,
446 _cairo_boilerplate_get_image_surface
,
447 cairo_surface_write_to_png
,
449 _cairo_boilerplate_image_describe
,
452 #if CAIRO_HAS_RECORDING_SURFACE
454 "recording", "image", NULL
, NULL
,
455 CAIRO_SURFACE_TYPE_RECORDING
, CAIRO_CONTENT_COLOR_ALPHA
, 0,
456 "cairo_recording_surface_create",
457 _cairo_boilerplate_recording_create_surface
,
458 cairo_surface_create_similar
,
460 _cairo_boilerplate_get_image_surface
,
461 cairo_surface_write_to_png
,
462 _cairo_boilerplate_recording_surface_cleanup
,
467 "recording", "image", NULL
, NULL
,
468 CAIRO_SURFACE_TYPE_RECORDING
, CAIRO_CONTENT_COLOR
, 0,
469 "cairo_recording_surface_create",
470 _cairo_boilerplate_recording_create_surface
,
471 cairo_surface_create_similar
,
473 _cairo_boilerplate_get_image_surface
,
474 cairo_surface_write_to_png
,
475 _cairo_boilerplate_recording_surface_cleanup
,
481 CAIRO_BOILERPLATE (builtin
, builtin_targets
)
483 static struct cairo_boilerplate_target_list
{
484 struct cairo_boilerplate_target_list
*next
;
485 const cairo_boilerplate_target_t
*target
;
486 } *cairo_boilerplate_targets
;
489 probe_target (const cairo_boilerplate_target_t
*target
)
491 if (target
->probe
== NULL
)
495 return dlsym (NULL
, target
->probe
) != NULL
;
502 _cairo_boilerplate_register_backend (const cairo_boilerplate_target_t
*targets
,
507 struct cairo_boilerplate_target_list
*list
;
510 if (! probe_target (targets
))
513 list
= xmalloc (sizeof (*list
));
514 list
->next
= cairo_boilerplate_targets
;
515 list
->target
= targets
;
516 cairo_boilerplate_targets
= list
;
521 _cairo_boilerplate_target_format_matches_name (const cairo_boilerplate_target_t
*target
,
522 const char *tcontent_name
,
523 const char *tcontent_end
)
525 char const *content_name
;
526 const char *content_end
= tcontent_end
;
529 content_name
= _cairo_boilerplate_content_visible_name (target
->content
);
531 content_len
= content_end
- tcontent_name
;
533 content_len
= strlen(tcontent_name
);
534 if (strlen(content_name
) != content_len
)
536 if (0 == strncmp (content_name
, tcontent_name
, content_len
))
543 _cairo_boilerplate_target_matches_name (const cairo_boilerplate_target_t
*target
,
547 char const *content_name
;
548 const char *content_start
= strpbrk (tname
, ".");
549 const char *content_end
= end
;
553 if (content_start
>= end
)
554 content_start
= NULL
;
555 if (content_start
!= NULL
)
556 end
= content_start
++;
558 name_len
= end
- tname
;
561 if (! (name_len
== 1 && 0 == strncmp (tname
, "?", 1))) { /* wildcard? */
562 if (0 != strncmp (target
->name
, tname
, name_len
)) /* exact match? */
564 if (_cairo_isalnum (target
->name
[name_len
]))
568 /* Check optional content. */
569 if (content_start
== NULL
) /* none given? */
572 /* Exact content match? */
573 content_name
= _cairo_boilerplate_content_visible_name (target
->content
);
574 content_len
= content_end
- content_start
;
575 if (strlen(content_name
) != content_len
)
577 if (0 == strncmp (content_name
, content_start
, content_len
))
583 const cairo_boilerplate_target_t
**
584 cairo_boilerplate_get_targets (int *pnum_targets
,
585 cairo_bool_t
*plimited_targets
)
587 size_t i
, num_targets
;
588 cairo_bool_t limited_targets
= FALSE
;
590 const cairo_boilerplate_target_t
**targets_to_test
;
591 struct cairo_boilerplate_target_list
*list
;
593 if (cairo_boilerplate_targets
== NULL
)
594 _cairo_boilerplate_register_all ();
596 if ((tname
= getenv ("CAIRO_TEST_TARGET")) != NULL
&& *tname
) {
597 /* check the list of targets specified by the user */
598 limited_targets
= TRUE
;
601 targets_to_test
= NULL
;
605 const char *end
= strpbrk (tname
, " \t\r\n;:,");
607 end
= tname
+ strlen (tname
);
614 for (list
= cairo_boilerplate_targets
;
618 const cairo_boilerplate_target_t
*target
= list
->target
;
619 const char *tcontent_name
;
620 const char *tcontent_end
;
621 if (_cairo_boilerplate_target_matches_name (target
, tname
, end
)) {
622 if ((tcontent_name
= getenv ("CAIRO_TEST_TARGET_FORMAT")) != NULL
&& *tcontent_name
) {
623 while(tcontent_name
) {
624 tcontent_end
= strpbrk (tcontent_name
, " \t\r\n;:,");
625 if (tcontent_end
== tcontent_name
) {
626 tcontent_name
= tcontent_end
+ 1;
629 if(_cairo_boilerplate_target_format_matches_name (target
,
630 tcontent_name
, tcontent_end
)) {
631 /* realloc isn't exactly the best thing here, but meh. */
632 targets_to_test
= xrealloc (targets_to_test
,
633 sizeof(cairo_boilerplate_target_t
*) * (num_targets
+1));
634 targets_to_test
[num_targets
++] = target
;
640 tcontent_name
= tcontent_end
;
643 /* realloc isn't exactly the best thing here, but meh. */
644 targets_to_test
= xrealloc (targets_to_test
,
645 sizeof(cairo_boilerplate_target_t
*) * (num_targets
+1));
646 targets_to_test
[num_targets
++] = target
;
653 const char *last_name
= NULL
;
655 fprintf (stderr
, "Cannot find target '%.*s'.\n",
656 (int)(end
- tname
), tname
);
657 fprintf (stderr
, "Known targets:");
658 for (list
= cairo_boilerplate_targets
;
662 const cairo_boilerplate_target_t
*target
= list
->target
;
663 if (last_name
!= NULL
) {
664 if (strcmp (target
->name
, last_name
) == 0) {
665 /* filter out repeats that differ in content */
668 fprintf (stderr
, ",");
670 fprintf (stderr
, " %s", target
->name
);
671 last_name
= target
->name
;
673 fprintf (stderr
, "\n");
683 int not_found_targets
= 0;
685 targets_to_test
= xmalloc (sizeof(cairo_boilerplate_target_t
*) * num_targets
);
686 for (list
= cairo_boilerplate_targets
; list
!= NULL
; list
= list
->next
)
688 const cairo_boilerplate_target_t
*target
= list
->target
;
689 const char *tcontent_name
;
690 const char *tcontent_end
;
691 if ((tcontent_name
= getenv ("CAIRO_TEST_TARGET_FORMAT")) != NULL
&& *tcontent_name
) {
692 while(tcontent_name
) {
693 tcontent_end
= strpbrk (tcontent_name
, " \t\r\n;:,");
694 if (tcontent_end
== tcontent_name
) {
695 tcontent_name
= tcontent_end
+ 1;
698 if (_cairo_boilerplate_target_format_matches_name (target
,
699 tcontent_name
, tcontent_end
)) {
700 /* realloc isn't exactly the best thing here, but meh. */
701 targets_to_test
= xrealloc (targets_to_test
,
702 sizeof(cairo_boilerplate_target_t
*) * (num_targets
+1));
703 targets_to_test
[num_targets
++] = target
;
714 tcontent_name
= tcontent_end
;
724 /* check all compiled in targets */
725 num_targets
= num_targets
+ not_found_targets
;
726 targets_to_test
= xrealloc (targets_to_test
,
727 sizeof(cairo_boilerplate_target_t
*) * num_targets
);
729 for (list
= cairo_boilerplate_targets
;
733 const cairo_boilerplate_target_t
*target
= list
->target
;
734 targets_to_test
[num_targets
++] = target
;
740 /* exclude targets as specified by the user */
741 if ((tname
= getenv ("CAIRO_TEST_TARGET_EXCLUDE")) != NULL
&& *tname
) {
742 limited_targets
= TRUE
;
746 const char *end
= strpbrk (tname
, " \t\r\n;:,");
748 end
= tname
+ strlen (tname
);
755 for (i
= j
= 0; i
< num_targets
; i
++) {
756 const cairo_boilerplate_target_t
*target
= targets_to_test
[i
];
757 if (! _cairo_boilerplate_target_matches_name (target
,
760 targets_to_test
[j
++] = targets_to_test
[i
];
772 *pnum_targets
= num_targets
;
774 if (plimited_targets
)
775 *plimited_targets
= limited_targets
;
777 return targets_to_test
;
780 const cairo_boilerplate_target_t
*
781 cairo_boilerplate_get_image_target (cairo_content_t content
)
783 if (cairo_boilerplate_targets
== NULL
)
784 _cairo_boilerplate_register_all ();
787 case CAIRO_CONTENT_COLOR
:
788 return &builtin_targets
[1];
789 case CAIRO_CONTENT_COLOR_ALPHA
:
790 return &builtin_targets
[0];
791 case CAIRO_CONTENT_ALPHA
:
797 const cairo_boilerplate_target_t
*
798 cairo_boilerplate_get_target_by_name (const char *name
,
799 cairo_content_t content
)
801 struct cairo_boilerplate_target_list
*list
;
803 if (cairo_boilerplate_targets
== NULL
)
804 _cairo_boilerplate_register_all ();
806 /* first return an exact match */
807 for (list
= cairo_boilerplate_targets
; list
!= NULL
; list
= list
->next
) {
808 const cairo_boilerplate_target_t
*target
= list
->target
;
809 if (strcmp (target
->name
, name
) == 0 &&
810 target
->content
== content
)
816 /* otherwise just return a match that may differ in content */
817 for (list
= cairo_boilerplate_targets
; list
!= NULL
; list
= list
->next
) {
818 const cairo_boilerplate_target_t
*target
= list
->target
;
819 if (strcmp (target
->name
, name
) == 0)
827 cairo_boilerplate_free_targets (const cairo_boilerplate_target_t
**targets
)
833 cairo_boilerplate_surface_create_in_error (cairo_status_t status
)
835 cairo_surface_t
*surface
= NULL
;
839 cairo_surface_t
*intermediate
;
843 intermediate
= cairo_image_surface_create (CAIRO_FORMAT_A8
, 0, 0);
844 cr
= cairo_create (intermediate
);
845 cairo_surface_destroy (intermediate
);
847 path
.status
= status
;
848 cairo_append_path (cr
, &path
);
850 cairo_surface_destroy (surface
);
851 surface
= cairo_surface_reference (cairo_get_target (cr
));
853 } while (cairo_surface_status (surface
) != status
&& --loop
);
859 cairo_boilerplate_scaled_font_set_max_glyphs_cached (cairo_scaled_font_t
*scaled_font
,
862 /* XXX CAIRO_DEBUG */
867 any2ppm_daemon_exists (void)
875 if (stat (SOCKET_PATH
, &st
) < 0)
878 fd
= open (SOCKET_PATH
".pid", O_RDONLY
);
883 ret
= read (fd
, buf
, sizeof (buf
) - 1);
890 return pid
> 0 && kill (pid
, 0) != -1;
895 cairo_boilerplate_open_any2ppm (const char *filename
,
898 int (**close_cb
) (FILE *))
904 struct sockaddr_un addr
;
908 any2ppm
= getenv ("ANY2PPM");
910 any2ppm
= "./any2ppm";
913 if (flags
& CAIRO_BOILERPLATE_OPEN_NO_DAEMON
)
916 if (! any2ppm_daemon_exists ()) {
917 if (system (any2ppm
) != 0)
921 sk
= socket (PF_UNIX
, SOCK_STREAM
, 0);
925 memset (&addr
, 0, sizeof (addr
));
926 addr
.sun_family
= AF_UNIX
;
927 strcpy (addr
.sun_path
, SOCKET_PATH
);
929 if (connect (sk
, (struct sockaddr
*) &addr
, sizeof (addr
)) == -1) {
934 len
= sprintf (command
, "%s %d\n", filename
, page
);
935 if (write (sk
, command
, len
) != len
) {
941 return fdopen (sk
, "rb");
947 sprintf (command
, "%s %s %d", any2ppm
, filename
, page
);
948 return popen (command
, "r");
952 freadn (unsigned char *buf
,
959 ret
= fread (buf
, 1, len
, file
);
961 if (ferror (file
) || feof (file
))
972 cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file
)
979 cairo_surface_t
*image
= NULL
;
981 if (fscanf (file
, "P%c %d %d 255\n", &format
, &width
, &height
) != 3)
986 image
= cairo_image_surface_create (CAIRO_FORMAT_ARGB32
, width
, height
);
989 image
= cairo_image_surface_create (CAIRO_FORMAT_RGB24
, width
, height
);
992 image
= cairo_image_surface_create (CAIRO_FORMAT_A8
, width
, height
);
997 if (cairo_surface_status (image
))
1000 data
= cairo_image_surface_get_data (image
);
1001 stride
= cairo_image_surface_get_stride (image
);
1002 for (y
= 0; y
< height
; y
++) {
1003 unsigned char *buf
= data
+ y
*stride
;
1006 if (! freadn (buf
, 4 * width
, file
))
1010 if (! freadn (buf
, 3*width
, file
))
1013 for (x
= width
; x
--; ) {
1015 ((uint32_t *) (data
+ y
*stride
))[x
] =
1016 (buf
[0] << 16) | (buf
[1] << 8) | (buf
[2] << 0);
1020 if (! freadn (buf
, width
, file
))
1025 cairo_surface_mark_dirty (image
);
1030 cairo_surface_destroy (image
);
1031 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR
);
1035 cairo_boilerplate_convert_to_image (const char *filename
,
1039 unsigned int flags
= 0;
1040 cairo_surface_t
*image
;
1041 int (*close_cb
) (FILE *);
1044 if (getenv ("CAIRO_BOILERPLATE_OPEN_NO_DAEMON") != NULL
) {
1045 flags
|= CAIRO_BOILERPLATE_OPEN_NO_DAEMON
;
1049 file
= cairo_boilerplate_open_any2ppm (filename
, page
, flags
, &close_cb
);
1053 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_NO_MEMORY
);
1055 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR
);
1059 image
= cairo_boilerplate_image_surface_create_from_ppm_stream (file
);
1060 ret
= close_cb (file
);
1061 /* check for fatal errors from the interpreter */
1062 if (ret
) { /* any2pmm should never die... */
1063 cairo_surface_destroy (image
);
1064 if (getenv ("CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR") != NULL
) {
1065 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR
);
1067 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS
);
1071 if (ret
== 0 && cairo_surface_status (image
) == CAIRO_STATUS_READ_ERROR
) {
1073 /* Try again in a standalone process. */
1074 cairo_surface_destroy (image
);
1075 flags
= CAIRO_BOILERPLATE_OPEN_NO_DAEMON
;
1084 cairo_boilerplate_version (void)
1086 return CAIRO_VERSION
;
1090 cairo_boilerplate_version_string (void)
1092 return CAIRO_VERSION_STRING
;
1096 cairo_boilerplate_fini (void)
1098 while (cairo_boilerplate_targets
!= NULL
) {
1099 struct cairo_boilerplate_target_list
*next
;
1101 next
= cairo_boilerplate_targets
->next
;
1103 free (cairo_boilerplate_targets
);
1104 cairo_boilerplate_targets
= next
;