Merge branch 'mingw11' into 'master'
[cairo.git] / boilerplate / cairo-boilerplate.c
bloba3e710f0832081082b5ef617f91653602e17ffdd
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /*
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"
31 #include <pixman.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>
39 #endif
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <assert.h>
44 #include <errno.h>
46 #if HAVE_DLFCN_H
47 #include <dlfcn.h>
48 #endif
50 #if HAVE_UNISTD_H && HAVE_FCNTL_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && HAVE_SYS_UN_H
51 #include <unistd.h>
52 #include <fcntl.h>
53 #include <signal.h>
54 #include <sys/stat.h>
55 #include <sys/socket.h>
56 #include <sys/un.h>
58 #define HAS_DAEMON 1
59 #define SOCKET_PATH "./.any2ppm"
60 #endif
62 cairo_content_t
63 cairo_boilerplate_content (cairo_content_t content)
65 if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
66 content = CAIRO_CONTENT_COLOR_ALPHA;
68 return content;
71 const char *
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:
79 return "rgb24";
80 case CAIRO_CONTENT_COLOR_ALPHA:
81 return "argb32";
82 case CAIRO_CONTENT_ALPHA:
83 default:
84 assert (0); /* not reached */
85 return "---";
89 static const char *
90 _cairo_boilerplate_content_visible_name (cairo_content_t content)
92 switch (cairo_boilerplate_content (content)) {
93 case CAIRO_CONTENT_COLOR:
94 return "rgb";
95 case CAIRO_CONTENT_COLOR_ALPHA:
96 return "rgba";
97 case CAIRO_CONTENT_ALPHA:
98 return "a";
99 default:
100 assert (0); /* not reached */
101 return "---";
105 cairo_format_t
106 cairo_boilerplate_format_from_content (cairo_content_t content)
108 cairo_format_t format;
110 switch (content) {
111 case CAIRO_CONTENT_COLOR:
112 format = CAIRO_FORMAT_RGB24;
113 break;
114 case CAIRO_CONTENT_COLOR_ALPHA:
115 format = CAIRO_FORMAT_ARGB32;
116 break;
117 case CAIRO_CONTENT_ALPHA:
118 format = CAIRO_FORMAT_A8;
119 break;
120 default:
121 assert (0); /* not reached */
122 format = CAIRO_FORMAT_INVALID;
123 break;
126 return format;
129 static cairo_surface_t *
130 _cairo_boilerplate_image_create_surface (const char *name,
131 cairo_content_t content,
132 double width,
133 double height,
134 double max_width,
135 double max_height,
136 cairo_boilerplate_mode_t mode,
137 void **closure)
139 cairo_format_t format;
141 *closure = NULL;
143 if (content == CAIRO_CONTENT_COLOR_ALPHA) {
144 format = CAIRO_FORMAT_ARGB32;
145 } else if (content == CAIRO_CONTENT_COLOR) {
146 format = CAIRO_FORMAT_RGB24;
147 } else {
148 assert (0); /* not reached */
149 return NULL;
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;
164 int stride;
165 void *ptr;
167 switch (content) {
168 case CAIRO_CONTENT_ALPHA:
169 format = CAIRO_FORMAT_A8;
170 break;
171 case CAIRO_CONTENT_COLOR:
172 format = CAIRO_FORMAT_RGB24;
173 break;
174 case CAIRO_CONTENT_COLOR_ALPHA:
175 default:
176 format = CAIRO_FORMAT_ARGB32;
177 break;
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);
187 return surface;
190 static cairo_surface_t *
191 _cairo_boilerplate_image16_create_surface (const char *name,
192 cairo_content_t content,
193 double width,
194 double height,
195 double max_width,
196 double max_height,
197 cairo_boilerplate_mode_t mode,
198 void **closure)
200 *closure = NULL;
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;
213 int stride;
214 void *ptr;
216 switch (content) {
217 case CAIRO_CONTENT_ALPHA:
218 format = CAIRO_FORMAT_A8;
219 break;
220 case CAIRO_CONTENT_COLOR:
221 format = CAIRO_FORMAT_RGB16_565;
222 break;
223 case CAIRO_CONTENT_COLOR_ALPHA:
224 default:
225 format = CAIRO_FORMAT_ARGB32;
226 break;
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);
236 return surface;
239 static char *
240 _cairo_boilerplate_image_describe (void *closure)
242 char *s;
244 xasprintf (&s, "pixman %s", pixman_version_string ());
246 return s;
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,
253 double width,
254 double height,
255 double max_width,
256 double max_height,
257 cairo_boilerplate_mode_t mode,
258 void **closure)
260 cairo_rectangle_t extents;
262 extents.x = 0;
263 extents.y = 0;
264 extents.width = width;
265 extents.height = height;
266 return *closure = cairo_surface_reference (cairo_recording_surface_create (content, &extents));
269 static void
270 _cairo_boilerplate_recording_surface_cleanup (void *closure)
272 cairo_surface_finish (closure);
273 cairo_surface_destroy (closure);
275 #endif
277 const cairo_user_data_key_t cairo_boilerplate_output_basename_key;
279 cairo_surface_t *
280 _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
281 int page,
282 int width,
283 int height)
285 cairo_surface_t *surface, *image;
286 cairo_t *cr;
287 cairo_status_t status;
288 cairo_format_t format;
290 if (cairo_surface_status (src))
291 return cairo_surface_reference (src);
293 if (page != 0)
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;
300 break;
301 case CAIRO_CONTENT_COLOR:
302 format = CAIRO_FORMAT_RGB24;
303 break;
304 default:
305 case CAIRO_CONTENT_COLOR_ALPHA:
306 format = CAIRO_FORMAT_ARGB32;
307 break;
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) {
321 cairo_device_t *ctx;
322 char *filename;
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);
330 free (filename);
333 #endif
335 cr = cairo_create (surface);
336 cairo_surface_destroy (surface);
337 cairo_set_source_surface (cr, src, 0, 0);
338 cairo_paint (cr);
340 status = cairo_status (cr);
341 if (status) {
342 cairo_surface_destroy (image);
343 image = cairo_surface_reference (cairo_get_target (cr));
345 cairo_destroy (cr);
347 return image;
350 cairo_surface_t *
351 cairo_boilerplate_get_image_surface_from_png (const char *filename,
352 int width,
353 int height,
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))
360 return surface;
362 if (flatten) {
363 cairo_t *cr;
364 cairo_surface_t *flattened;
366 flattened = cairo_image_surface_create (cairo_image_surface_get_format (surface),
367 width,
368 height);
369 cr = cairo_create (flattened);
370 cairo_surface_destroy (flattened);
372 cairo_set_source_rgb (cr, 1, 1, 1);
373 cairo_paint (cr);
375 cairo_set_source_surface (cr, surface,
376 width - cairo_image_surface_get_width (surface),
377 height - cairo_image_surface_get_height (surface));
378 cairo_paint (cr);
380 cairo_surface_destroy (surface);
381 surface = cairo_surface_reference (cairo_get_target (cr));
382 cairo_destroy (cr);
383 } else if (cairo_image_surface_get_width (surface) != width ||
384 cairo_image_surface_get_height (surface) != height)
386 cairo_t *cr;
387 cairo_surface_t *sub;
389 sub = cairo_image_surface_create (cairo_image_surface_get_format (surface),
390 width,
391 height);
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);
399 cairo_paint (cr);
401 cairo_surface_destroy (surface);
402 surface = cairo_surface_reference (cairo_get_target (cr));
403 cairo_destroy (cr);
406 return surface;
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,
416 NULL,
417 _cairo_boilerplate_image_create_surface,
418 _cairo_boilerplate_image_create_similar,
419 NULL, NULL,
420 _cairo_boilerplate_get_image_surface,
421 cairo_surface_write_to_png,
422 NULL, NULL,
423 _cairo_boilerplate_image_describe,
424 TRUE, FALSE, FALSE
427 "image", "image", NULL, NULL,
428 CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
429 NULL,
430 _cairo_boilerplate_image_create_surface,
431 _cairo_boilerplate_image_create_similar,
432 NULL, NULL,
433 _cairo_boilerplate_get_image_surface,
434 cairo_surface_write_to_png,
435 NULL, NULL,
436 _cairo_boilerplate_image_describe,
437 FALSE, FALSE, FALSE
440 "image16", "image", NULL, NULL,
441 CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0,
442 NULL,
443 _cairo_boilerplate_image16_create_surface,
444 _cairo_boilerplate_image16_create_similar,
445 NULL, NULL,
446 _cairo_boilerplate_get_image_surface,
447 cairo_surface_write_to_png,
448 NULL, NULL,
449 _cairo_boilerplate_image_describe,
450 TRUE, FALSE, FALSE
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,
459 NULL, NULL,
460 _cairo_boilerplate_get_image_surface,
461 cairo_surface_write_to_png,
462 _cairo_boilerplate_recording_surface_cleanup,
463 NULL, NULL,
464 FALSE, FALSE, TRUE
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,
472 NULL, NULL,
473 _cairo_boilerplate_get_image_surface,
474 cairo_surface_write_to_png,
475 _cairo_boilerplate_recording_surface_cleanup,
476 NULL, NULL,
477 FALSE, FALSE, TRUE
479 #endif
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;
488 static cairo_bool_t
489 probe_target (const cairo_boilerplate_target_t *target)
491 if (target->probe == NULL)
492 return TRUE;
494 #if HAVE_DLSYM
495 return dlsym (NULL, target->probe) != NULL;
496 #else
497 return TRUE;
498 #endif
501 void
502 _cairo_boilerplate_register_backend (const cairo_boilerplate_target_t *targets,
503 unsigned int count)
505 targets += count;
506 while (count--) {
507 struct cairo_boilerplate_target_list *list;
509 --targets;
510 if (! probe_target (targets))
511 continue;
513 list = xmalloc (sizeof (*list));
514 list->next = cairo_boilerplate_targets;
515 list->target = targets;
516 cairo_boilerplate_targets = list;
520 static cairo_bool_t
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;
527 size_t content_len;
529 content_name = _cairo_boilerplate_content_visible_name (target->content);
530 if (tcontent_end)
531 content_len = content_end - tcontent_name;
532 else
533 content_len = strlen(tcontent_name);
534 if (strlen(content_name) != content_len)
535 return FALSE;
536 if (0 == strncmp (content_name, tcontent_name, content_len))
537 return TRUE;
539 return FALSE;
542 static cairo_bool_t
543 _cairo_boilerplate_target_matches_name (const cairo_boilerplate_target_t *target,
544 const char *tname,
545 const char *end)
547 char const *content_name;
548 const char *content_start = strpbrk (tname, ".");
549 const char *content_end = end;
550 size_t name_len;
551 size_t content_len;
553 if (content_start >= end)
554 content_start = NULL;
555 if (content_start != NULL)
556 end = content_start++;
558 name_len = end - tname;
560 /* Check name. */
561 if (! (name_len == 1 && 0 == strncmp (tname, "?", 1))) { /* wildcard? */
562 if (0 != strncmp (target->name, tname, name_len)) /* exact match? */
563 return FALSE;
564 if (_cairo_isalnum (target->name[name_len]))
565 return FALSE;
568 /* Check optional content. */
569 if (content_start == NULL) /* none given? */
570 return TRUE;
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)
576 return FALSE;
577 if (0 == strncmp (content_name, content_start, content_len))
578 return TRUE;
580 return FALSE;
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;
589 const char *tname;
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;
600 num_targets = 0;
601 targets_to_test = NULL;
603 while (*tname) {
604 int found = 0;
605 const char *end = strpbrk (tname, " \t\r\n;:,");
606 if (!end)
607 end = tname + strlen (tname);
609 if (end == tname) {
610 tname = end + 1;
611 continue;
614 for (list = cairo_boilerplate_targets;
615 list != NULL;
616 list = list->next)
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;
627 continue;
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;
635 found = 1;
638 if (tcontent_end)
639 tcontent_end++;
640 tcontent_name = tcontent_end;
642 } else {
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;
647 found = 1;
652 if (!found) {
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;
659 list != NULL;
660 list = list->next)
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 */
666 continue;
668 fprintf (stderr, ",");
670 fprintf (stderr, " %s", target->name);
671 last_name = target->name;
673 fprintf (stderr, "\n");
674 exit(-1);
677 if (*end)
678 end++;
679 tname = end;
681 } else {
682 int found = 0;
683 int not_found_targets = 0;
684 num_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;
696 continue;
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;
704 found =1;
706 else
708 not_found_targets++;
711 if (tcontent_end)
712 tcontent_end++;
714 tcontent_name = tcontent_end;
717 else
719 num_targets++;
722 if (!found)
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);
728 num_targets = 0;
729 for (list = cairo_boilerplate_targets;
730 list != NULL;
731 list = list->next)
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;
744 while (*tname) {
745 int j;
746 const char *end = strpbrk (tname, " \t\r\n;:,");
747 if (!end)
748 end = tname + strlen (tname);
750 if (end == tname) {
751 tname = end + 1;
752 continue;
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,
758 tname, end))
760 targets_to_test[j++] = targets_to_test[i];
763 num_targets = j;
765 if (*end)
766 end++;
767 tname = end;
771 if (pnum_targets)
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 ();
786 switch (content) {
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:
792 default:
793 return NULL;
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)
812 return target;
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)
820 return target;
823 return NULL;
826 void
827 cairo_boilerplate_free_targets (const cairo_boilerplate_target_t **targets)
829 free (targets);
832 cairo_surface_t *
833 cairo_boilerplate_surface_create_in_error (cairo_status_t status)
835 cairo_surface_t *surface = NULL;
836 int loop = 5;
838 do {
839 cairo_surface_t *intermediate;
840 cairo_t *cr;
841 cairo_path_t path;
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));
852 cairo_destroy (cr);
853 } while (cairo_surface_status (surface) != status && --loop);
855 return surface;
858 void
859 cairo_boilerplate_scaled_font_set_max_glyphs_cached (cairo_scaled_font_t *scaled_font,
860 int max_glyphs)
862 /* XXX CAIRO_DEBUG */
865 #if HAS_DAEMON
866 static int
867 any2ppm_daemon_exists (void)
869 struct stat st;
870 int fd;
871 char buf[80];
872 int pid;
873 int ret;
875 if (stat (SOCKET_PATH, &st) < 0)
876 return 0;
878 fd = open (SOCKET_PATH ".pid", O_RDONLY);
879 if (fd < 0)
880 return 0;
882 pid = 0;
883 ret = read (fd, buf, sizeof (buf) - 1);
884 if (ret > 0) {
885 buf[ret] = '\0';
886 pid = atoi (buf);
888 close (fd);
890 return pid > 0 && kill (pid, 0) != -1;
892 #endif
894 FILE *
895 cairo_boilerplate_open_any2ppm (const char *filename,
896 int page,
897 unsigned int flags,
898 int (**close_cb) (FILE *))
900 char command[4096];
901 const char *any2ppm;
902 #if HAS_DAEMON
903 int sk;
904 struct sockaddr_un addr;
905 int len;
906 #endif
908 any2ppm = getenv ("ANY2PPM");
909 if (any2ppm == NULL)
910 any2ppm = "./any2ppm";
912 #if HAS_DAEMON
913 if (flags & CAIRO_BOILERPLATE_OPEN_NO_DAEMON)
914 goto POPEN;
916 if (! any2ppm_daemon_exists ()) {
917 if (system (any2ppm) != 0)
918 goto POPEN;
921 sk = socket (PF_UNIX, SOCK_STREAM, 0);
922 if (sk == -1)
923 goto POPEN;
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) {
930 close (sk);
931 goto POPEN;
934 len = sprintf (command, "%s %d\n", filename, page);
935 if (write (sk, command, len) != len) {
936 close (sk);
937 goto POPEN;
940 *close_cb = fclose;
941 return fdopen (sk, "rb");
943 POPEN:
944 #endif
946 *close_cb = pclose;
947 sprintf (command, "%s %s %d", any2ppm, filename, page);
948 return popen (command, "r");
951 static cairo_bool_t
952 freadn (unsigned char *buf,
953 int len,
954 FILE *file)
956 int ret;
958 while (len) {
959 ret = fread (buf, 1, len, file);
960 if (ret != len) {
961 if (ferror (file) || feof (file))
962 return FALSE;
964 len -= ret;
965 buf += len;
968 return TRUE;
971 cairo_surface_t *
972 cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file)
974 char format;
975 int width, height;
976 ptrdiff_t stride;
977 int x, y;
978 unsigned char *data;
979 cairo_surface_t *image = NULL;
981 if (fscanf (file, "P%c %d %d 255\n", &format, &width, &height) != 3)
982 goto FAIL;
984 switch (format) {
985 case '7': /* XXX */
986 image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
987 break;
988 case '6':
989 image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
990 break;
991 case '5':
992 image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
993 break;
994 default:
995 goto FAIL;
997 if (cairo_surface_status (image))
998 return 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;
1004 switch (format) {
1005 case '7':
1006 if (! freadn (buf, 4 * width, file))
1007 goto FAIL;
1008 break;
1009 case '6':
1010 if (! freadn (buf, 3*width, file))
1011 goto FAIL;
1012 buf += 3*width;
1013 for (x = width; x--; ) {
1014 buf -= 3;
1015 ((uint32_t *) (data + y*stride))[x] =
1016 (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
1018 break;
1019 case '5':
1020 if (! freadn (buf, width, file))
1021 goto FAIL;
1022 break;
1025 cairo_surface_mark_dirty (image);
1027 return image;
1029 FAIL:
1030 cairo_surface_destroy (image);
1031 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR);
1034 cairo_surface_t *
1035 cairo_boilerplate_convert_to_image (const char *filename,
1036 int page)
1038 FILE *file;
1039 unsigned int flags = 0;
1040 cairo_surface_t *image;
1041 int (*close_cb) (FILE *);
1042 int ret;
1044 if (getenv ("CAIRO_BOILERPLATE_OPEN_NO_DAEMON") != NULL) {
1045 flags |= CAIRO_BOILERPLATE_OPEN_NO_DAEMON;
1048 RETRY:
1049 file = cairo_boilerplate_open_any2ppm (filename, page, flags, &close_cb);
1050 if (file == NULL) {
1051 switch (errno) {
1052 case ENOMEM:
1053 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
1054 default:
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);
1066 } else {
1067 return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS);
1071 if (ret == 0 && cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
1072 if (flags == 0) {
1073 /* Try again in a standalone process. */
1074 cairo_surface_destroy (image);
1075 flags = CAIRO_BOILERPLATE_OPEN_NO_DAEMON;
1076 goto RETRY;
1080 return image;
1084 cairo_boilerplate_version (void)
1086 return CAIRO_VERSION;
1089 const char*
1090 cairo_boilerplate_version_string (void)
1092 return CAIRO_VERSION_STRING;
1095 void
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;