1 /* cairo-trace - a utility to record and replay calls to the Cairo library.
2 *
3 * Copyright © 2008 Chris Wilson
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define _GNU_SOURCE
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 /* The autoconf on OpenBSD 4.5 produces the malformed constant name
26 * SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */
27 #if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__)
28 # define SIZEOF_VOID_P SIZEOF_VOID__
29 #endif
30
31 #include <dlfcn.h>
32 #include <stdint.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <zlib.h>
41 #include <math.h>
42 #include <locale.h> /* for locale independent %f printing */
43 #include <ctype.h>
44 #include <assert.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 #include <stdarg.h>
48
49 #include <cairo.h>
50 #if CAIRO_HAS_FT_FONT
51 # include <cairo-ft.h>
52 #endif
53
54 #ifndef TRUE
55 #define TRUE 1
56 #define FALSE 0
57 #endif
58
59 #ifndef CAIRO_TRACE_OUTDIR
60 #define CAIRO_TRACE_OUTDIR "."
61 #endif
62
63 #define DEBUG_STACK 0
64
65 #if HAVE_BYTESWAP_H
66 # include <byteswap.h>
67 #endif
68 #ifndef bswap_16
69 # define bswap_16(p) \
70 (((((uint16_t)(p)) & 0x00ff) << 8) | \
71 (((uint16_t)(p)) >> 8))
72 #endif
73 #ifndef bswap_32
74 # define bswap_32(p) \
75 (((((uint32_t)(p)) & 0x000000ff) << 24) | \
76 ((((uint32_t)(p)) & 0x0000ff00) << 8) | \
77 ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \
78 ((((uint32_t)(p))) >> 24))
79 #endif
80
81 #if WORDS_BIGENDIAN
82 #define le16(x) bswap_16 (x)
83 #define le32(x) bswap_32 (x)
84 #define be16(x) x
85 #define be32(x) x
86 #define to_be32(x) x
87 #else
88 #define le16(x) x
89 #define le32(x) x
90 #define be16(x) bswap_16 (x)
91 #define be32(x) bswap_32 (x)
92 #define to_be32(x) bswap_32 (x)
93 #endif
94
95 #if CAIRO_HAS_SYMBOL_LOOKUP
96 #include "lookup-symbol.h"
97 #endif
98
99 /* Reverse the bits in a byte with 7 operations (no 64-bit):
100 * Devised by Sean Anderson, July 13, 2001.
101 * Source: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
102 */
103 #define CAIRO_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
104
105 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
106 #define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
107 __attribute__((__format__(__printf__, fmt_index, va_index)))
108 #else
109 #define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
110 #endif
111
112 /* XXX implement manual vprintf so that the user can control precision of
113 * printed numbers.
114 */
115
116 static void *_dlhandle = RTLD_NEXT;
117 #define DLCALL(name, args...) ({ \
118 static typeof (&name) name##_real; \
119 if (name##_real == NULL) { \
120 name##_real = (typeof (&name))(dlsym (_dlhandle, #name)); \
121 if (name##_real == NULL && _dlhandle == RTLD_NEXT) { \
122 _dlhandle = dlopen ("libcairo." SHARED_LIB_EXT, RTLD_LAZY); \
123 name##_real = (typeof (&name))(dlsym (_dlhandle, #name)); \
124 assert (name##_real != NULL); \
125 } \
126 } \
127 (*name##_real) (args); \
128 })
129
130 #ifndef ARRAY_LENGTH
131 #define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
132 #endif
133
134 #if SIZEOF_VOID_P == 4
135 #define PTR_SHIFT 2
136 #elif SIZEOF_VOID_P == 8
137 #define PTR_SHIFT 3
138 #else
139 #error Unexpected pointer size
140 #endif
141 #define BUCKET(b, ptr) (((unsigned long) (ptr) >> PTR_SHIFT) % ARRAY_LENGTH (b))
142
143 #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
144 #define _BOOLEAN_EXPR(expr) \
145 __extension__ ({ \
146 int _boolean_var_; \
147 if (expr) \
148 _boolean_var_ = 1; \
149 else \
150 _boolean_var_ = 0; \
151 _boolean_var_; \
152 })
153 #define LIKELY(expr) (__builtin_expect (_BOOLEAN_EXPR(expr), 1))
154 #define UNLIKELY(expr) (__builtin_expect (_BOOLEAN_EXPR(expr), 0))
155 #else
156 #define LIKELY(expr) (expr)
157 #define UNLIKELY(expr) (expr)
158 #endif
159
160 typedef struct _object Object;
161 typedef struct _type Type;
162
163 struct _object {
164 const void *addr;
165 Type *type;
166 unsigned long int token;
167 int width, height;
168 cairo_bool_t foreign;
169 cairo_bool_t defined;
170 cairo_bool_t unknown;
171 int operand;
172 void *data;
173 void (*destroy)(void *);
174 Object *next, *prev;
175 };
176
177 struct _type {
178 const char *name;
179
180 enum operand_type {
181 NONE,
182 SURFACE,
183 CONTEXT,
184 FONT_FACE,
185 PATTERN,
186 SCALED_FONT,
187 _N_OP_TYPES
188 } op_type;
189 const char *op_code;
190
191 pthread_mutex_t mutex;
192 struct _bitmap {
193 unsigned long int min;
194 unsigned long int count;
195 unsigned int map[64];
196 struct _bitmap *next;
197 } map;
198 Object *objects[607];
199 Type *next;
200 };
201
202 static struct _type_table {
203 pthread_mutex_t mutex;
204 Type *op_types[_N_OP_TYPES];
205 } Types;
206
207 static FILE *logfile;
208 static cairo_bool_t _flush;
209 static cairo_bool_t _error;
210 static cairo_bool_t _line_info;
211 static cairo_bool_t _mark_dirty;
212 static const cairo_user_data_key_t destroy_key;
213 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
214 static pthread_key_t counter_key;
215
216 static void _init_trace (void);
217
218 #define INIT_TRACE_ONCE() pthread_once (&once_control, _init_trace)
219
220 #if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
221 # define _enter_trace() INIT_TRACE_ONCE ()
222 # define _exit_trace() do { } while (0)
223 # define _should_trace() 1
224 # define USE_ENTER_EXIT 0
225 #else
226 static void _enter_trace (void);
227 static void _exit_trace (void);
228 static cairo_bool_t _should_trace (void);
229 # define USE_ENTER_EXIT 1
230 #endif
231
232 #if HAVE_BUILTIN_RETURN_ADDRESS && CAIRO_HAS_SYMBOL_LOOKUP
233 #define _emit_line_info() do { \
234 if (_line_info && _write_lock ()) { \
235 void *addr = __builtin_return_address(0); \
236 char caller[1024]; \
237 _trace_printf ("%% %s() called by %s\n", __FUNCTION__, \
238 lookup_symbol (caller, sizeof (caller), addr)); \
239 _write_unlock (); \
240 } \
241 } while (0)
242 #else
243 #define _emit_line_info()
244 #endif
245
246 static void
_type_release_token(Type * t,unsigned long int token)247 _type_release_token (Type *t, unsigned long int token)
248 {
249 struct _bitmap *b, **prev = NULL;
250
251 b = &t->map;
252 while (b != NULL) {
253 if (token < b->min + sizeof (b->map) * CHAR_BIT) {
254 unsigned int bit, elem;
255
256 token -= b->min;
257 elem = token / (sizeof (b->map[0]) * CHAR_BIT);
258 bit = token % (sizeof (b->map[0]) * CHAR_BIT);
259 b->map[elem] &= ~(1 << bit);
260 if (! --b->count && prev) {
261 *prev = b->next;
262 free (b);
263 }
264 return;
265 }
266 prev = &b->next;
267 b = b->next;
268 }
269 }
270
271 static unsigned long int
_type_next_token(Type * t)272 _type_next_token (Type *t)
273 {
274 struct _bitmap *b, *bb, **prev = NULL;
275 unsigned long int min = 0;
276
277 b = &t->map;
278 while (b != NULL) {
279 if (b->min != min)
280 break;
281
282 if (b->count < sizeof (b->map) * CHAR_BIT) {
283 unsigned int n, m, bit;
284 for (n = 0; n < ARRAY_LENGTH (b->map); n++) {
285 if (b->map[n] == (unsigned int) -1)
286 continue;
287
288 for (m=0, bit=1; m<sizeof (b->map[0])*CHAR_BIT; m++, bit<<=1) {
289 if ((b->map[n] & bit) == 0) {
290 b->map[n] |= bit;
291 b->count++;
292 return n * sizeof (b->map[0])*CHAR_BIT + m + b->min;
293 }
294 }
295 }
296 }
297 min += sizeof (b->map) * CHAR_BIT;
298
299 prev = &b->next;
300 b = b->next;
301 }
302 assert (prev != NULL);
303
304 bb = malloc (sizeof (struct _bitmap));
305
306 *prev = bb;
307 bb->next = b;
308 bb->min = min;
309 bb->count = 1;
310 bb->map[0] = 0x1;
311 memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0]));
312
313 return min;
314 }
315
316 static void
_object_destroy(Object * obj)317 _object_destroy (Object *obj)
318 {
319 int bucket;
320
321 pthread_mutex_lock (&obj->type->mutex);
322 bucket = BUCKET (obj->type->objects, obj->addr);
323 _type_release_token (obj->type, obj->token);
324
325 if (obj->prev != NULL)
326 obj->prev->next = obj->next;
327 else
328 obj->type->objects[bucket] = obj->next;
329
330 if (obj->next != NULL)
331 obj->next->prev = obj->prev;
332 pthread_mutex_unlock (&obj->type->mutex);
333
334 if (obj->data != NULL && obj->destroy != NULL)
335 obj->destroy (obj->data);
336
337 free (obj);
338 }
339
340 static void
_type_create(const char * typename,enum operand_type op_type,const char * op_code)341 _type_create (const char *typename,
342 enum operand_type op_type,
343 const char *op_code)
344 {
345 Type *t;
346
347 pthread_mutex_lock (&Types.mutex);
348
349 t = malloc (sizeof (Type));
350 t->name = typename;
351 t->op_type = op_type;
352 t->op_code = op_code;
353
354 pthread_mutex_init (&t->mutex, NULL);
355
356 t->map.min = 0;
357 t->map.count = 0;
358 memset (t->map.map, 0, sizeof (t->map.map));
359 t->map.next = NULL;
360
361 memset (t->objects, 0, sizeof (t->objects));
362
363 t->next = NULL;
364
365 Types.op_types[op_type] = t;
366 pthread_mutex_unlock (&Types.mutex);
367 }
368
369 static Type *
_get_type(enum operand_type type)370 _get_type (enum operand_type type)
371 {
372 return Types.op_types[type];
373 }
374
375 static void
_type_destroy(Type * t)376 _type_destroy (Type *t)
377 {
378 int n;
379 struct _bitmap *b;
380
381 for (n = 0; n < ARRAY_LENGTH (t->objects); n++) {
382 Object *obj = t->objects[n];
383 while (obj != NULL) {
384 Object *next = obj->next;
385 _object_destroy (obj);
386 obj = next;
387 }
388 }
389
390 b = t->map.next;
391 while (b != NULL) {
392 struct _bitmap *next = b->next;
393 free (b);
394 b = next;
395 }
396
397 pthread_mutex_destroy (&t->mutex);
398 free (t);
399 }
400
401 static Object *
_type_get_object(Type * type,const void * ptr)402 _type_get_object (Type *type, const void *ptr)
403 {
404 Object *obj;
405 int bucket = BUCKET (type->objects, ptr);
406
407 for (obj = type->objects[bucket]; obj != NULL; obj = obj->next) {
408 if (obj->addr == ptr) {
409 if (obj->prev != NULL) { /* mru */
410 obj->prev->next = obj->next;
411 if (obj->next != NULL)
412 obj->next->prev = obj->prev;
413 obj->prev = NULL;
414 type->objects[bucket]->prev = obj;
415 obj->next = type->objects[bucket];
416 type->objects[bucket] = obj;
417 }
418 return obj;
419 }
420 }
421
422 return NULL;
423 }
424
425 static Object *
_object_create(Type * type,const void * ptr)426 _object_create (Type *type, const void *ptr)
427 {
428 Object *obj;
429 int bucket = BUCKET (type->objects, ptr);
430
431 obj = malloc (sizeof (Object));
432 obj->unknown = TRUE;
433 obj->defined = FALSE;
434 obj->foreign = FALSE;
435 obj->operand = -1;
436 obj->type = type;
437 obj->addr = ptr;
438 obj->token = _type_next_token (type);
439 obj->data = NULL;
440 obj->destroy = NULL;
441 obj->prev = NULL;
442 obj->next = type->objects[bucket];
443 if (type->objects[bucket] != NULL)
444 type->objects[bucket]->prev = obj;
445 type->objects[bucket] = obj;
446
447 return obj;
448 }
449
450 #if USE_ENTER_EXIT
451 static int *
_get_counter(void)452 _get_counter (void)
453 {
454 int *counter = pthread_getspecific (counter_key);
455 if (counter == NULL) {
456 counter = calloc(1, sizeof(int));
457 pthread_setspecific (counter_key, counter);
458 }
459 return counter;
460 }
461
462 static void
_enter_trace(void)463 _enter_trace (void)
464 {
465 INIT_TRACE_ONCE ();
466 _get_counter ()[0]++;
467 }
468
469 static void
_exit_trace(void)470 _exit_trace (void)
471 {
472 _get_counter ()[0]--;
473 }
474
475 static cairo_bool_t
_should_trace(void)476 _should_trace (void)
477 {
478 return _get_counter ()[0] <= 1;
479 }
480 #endif /* USE_ENTER_EXIT */
481
482 static void
_init_trace(void)483 _init_trace (void)
484 {
485 pthread_mutex_init (&Types.mutex, NULL);
486 pthread_key_create (&counter_key, free);
487
488 _type_create ("unclassed", NONE, "");
489 _type_create ("cairo_t", CONTEXT, "c");
490 _type_create ("cairo_font_face_t", FONT_FACE, "f");
491 _type_create ("cairo_pattern_t", PATTERN, "p");
492 _type_create ("cairo_scaled_font_t", SCALED_FONT, "sf");
493 _type_create ("cairo_surface_t", SURFACE, "s");
494 }
495
496 static void
_close_trace(void)497 _close_trace (void)
498 {
499 if (logfile != NULL) {
500 fclose (logfile);
501 logfile = NULL;
502 }
503 }
504
505 static void __attribute__ ((destructor))
_fini_trace(void)506 _fini_trace (void)
507 {
508 int n;
509
510 _close_trace ();
511
512 for (n = 0; n < ARRAY_LENGTH (Types.op_types); n++) {
513 if (Types.op_types[n]) {
514 _type_destroy (Types.op_types[n]);
515 Types.op_types[n] = NULL;
516 }
517 }
518
519 pthread_mutex_destroy (&Types.mutex);
520 }
521
522 /* Format a double in a locale independent way and trim trailing
523 * zeros. Based on code from Alex Larson <alexl@redhat.com>.
524 * https://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
525 *
526 * The code in the patch is copyright Red Hat, Inc under the LGPL.
527 */
528 #define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
529 static void
_trace_dtostr(char * buffer,size_t size,double d)530 _trace_dtostr (char *buffer, size_t size, double d)
531 {
532 struct lconv *locale_data;
533 const char *decimal_point;
534 int decimal_point_len;
535 char *p;
536 int decimal_len;
537 int num_zeros, decimal_digits;
538
539 /* Omit the minus sign from negative zero. */
540 if (d == 0.0)
541 d = 0.0;
542
543 locale_data = localeconv ();
544 decimal_point = locale_data->decimal_point;
545 decimal_point_len = strlen (decimal_point);
546
547 /* Using "%f" to print numbers less than 0.1 will result in
548 * reduced precision due to the default 6 digits after the
549 * decimal point.
550 *
551 * For numbers is < 0.1, we print with maximum precision and count
552 * the number of zeros between the decimal point and the first
553 * significant digit. We then print the number again with the
554 * number of decimal places that gives us the required number of
555 * significant digits. This ensures the number is correctly
556 * rounded.
557 */
558 if (fabs (d) >= 0.1) {
559 snprintf (buffer, size, "%f", d);
560 } else {
561 snprintf (buffer, size, "%.18f", d);
562 p = buffer;
563
564 if (*p == '+' || *p == '-')
565 p++;
566
567 while (isdigit (*p))
568 p++;
569
570 if (strncmp (p, decimal_point, decimal_point_len) == 0)
571 p += decimal_point_len;
572
573 num_zeros = 0;
574 while (*p++ == '0')
575 num_zeros++;
576
577 decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
578
579 if (decimal_digits < 18)
580 snprintf (buffer, size, "%.*f", decimal_digits, d);
581 }
582 p = buffer;
583
584 if (*p == '+' || *p == '-')
585 p++;
586
587 while (isdigit (*p))
588 p++;
589
590 if (strncmp (p, decimal_point, decimal_point_len) == 0) {
591 *p = '.';
592 decimal_len = strlen (p + decimal_point_len);
593 memmove (p + 1, p + decimal_point_len, decimal_len);
594 p[1 + decimal_len] = 0;
595
596 /* Remove trailing zeros and decimal point if possible. */
597 for (p = p + decimal_len; *p == '0'; p--)
598 *p = 0;
599
600 if (*p == '.') {
601 *p = 0;
602 p--;
603 }
604 }
605 }
606
607 enum {
608 LENGTH_MODIFIER_LONG = 0x100
609 };
610
611 /* Here's a limited reimplementation of printf. The reason for doing
612 * this is primarily to special case handling of doubles. We want
613 * locale independent formatting of doubles and we want to trim
614 * trailing zeros. This is handled by dtostr() above, and the code
615 * below handles everything else by calling snprintf() to do the
616 * formatting. This functionality is only for internal use and we
617 * only implement the formats we actually use.
618 */
619 static void CAIRO_PRINTF_FORMAT(1, 0)
_trace_vprintf(const char * fmt,va_list ap)620 _trace_vprintf (const char *fmt, va_list ap)
621 {
622 #define SINGLE_FMT_BUFFER_SIZE 32
623 char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
624 int single_fmt_length;
625 char *p;
626 const char *f, *start;
627 int length_modifier, width;
628 cairo_bool_t var_width;
629 int ret_ignored;
630
631 assert (_should_trace ());
632
633 f = fmt;
634 p = buffer;
635 while (*f != '\0') {
636 if (*f != '%') {
637 *p++ = *f++;
638 continue;
639 }
640
641 start = f;
642 f++;
643
644 if (*f == '0')
645 f++;
646
647 var_width = 0;
648 if (*f == '*') {
649 var_width = 1;
650 f++;
651 }
652
653 while (isdigit (*f))
654 f++;
655
656 length_modifier = 0;
657 if (*f == 'l') {
658 length_modifier = LENGTH_MODIFIER_LONG;
659 f++;
660 }
661
662 /* The only format strings exist in the cairo implementation
663 * itself. So there's an internal consistency problem if any
664 * of them is larger than our format buffer size. */
665 single_fmt_length = f - start + 1;
666
667 /* Reuse the format string for this conversion. */
668 memcpy (single_fmt, start, single_fmt_length);
669 single_fmt[single_fmt_length] = '\0';
670
671 /* Flush contents of buffer before snprintf()'ing into it. */
672 ret_ignored = fwrite (buffer, 1, p-buffer, logfile);
673
674 /* We group signed and unsigned together in this switch, the
675 * only thing that matters here is the size of the arguments,
676 * since we're just passing the data through to sprintf(). */
677 switch (*f | length_modifier) {
678 case '%':
679 buffer[0] = *f;
680 buffer[1] = 0;
681 break;
682 case 'd':
683 case 'u':
684 case 'o':
685 case 'x':
686 case 'X':
687 if (var_width) {
688 width = va_arg (ap, int);
689 snprintf (buffer, sizeof buffer,
690 single_fmt, width, va_arg (ap, int));
691 } else {
692 snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
693 }
694 break;
695 case 'd' | LENGTH_MODIFIER_LONG:
696 case 'u' | LENGTH_MODIFIER_LONG:
697 case 'o' | LENGTH_MODIFIER_LONG:
698 case 'x' | LENGTH_MODIFIER_LONG:
699 case 'X' | LENGTH_MODIFIER_LONG:
700 if (var_width) {
701 width = va_arg (ap, int);
702 snprintf (buffer, sizeof buffer,
703 single_fmt, width, va_arg (ap, long int));
704 } else {
705 snprintf (buffer, sizeof buffer,
706 single_fmt, va_arg (ap, long int));
707 }
708 break;
709 case 's':
710 snprintf (buffer, sizeof buffer,
711 single_fmt, va_arg (ap, const char *));
712 break;
713 case 'f':
714 case 'g':
715 _trace_dtostr (buffer, sizeof buffer, va_arg (ap, double));
716 break;
717 case 'c':
718 buffer[0] = va_arg (ap, int);
719 buffer[1] = 0;
720 break;
721 default:
722 break;
723 }
724 p = buffer + strlen (buffer);
725 f++;
726 }
727
728 ret_ignored = fwrite (buffer, 1, p-buffer, logfile);
729 (void)ret_ignored;
730 }
731
732 static void CAIRO_PRINTF_FORMAT(1, 2)
_trace_printf(const char * fmt,...)733 _trace_printf (const char *fmt, ...)
734 {
735 va_list ap;
736
737 va_start (ap, fmt);
738 _trace_vprintf (fmt, ap);
739 va_end (ap);
740 }
741
742 static void
get_prog_name(char * buf,int length)743 get_prog_name (char *buf, int length)
744 {
745 char *slash;
746 FILE *file;
747
748 memset (buf, 0, length);
749 if (length == 0)
750 return;
751
752 file = fopen ("/proc/self/cmdline", "rb");
753 if (file != NULL) {
754 slash = fgets (buf, length, file);
755 fclose (file);
756
757 if (slash == NULL)
758 return;
759 } else {
760 char const *name = getenv ("CAIRO_TRACE_PROG_NAME");
761 if (name != NULL) {
762 strncpy (buf, name, length-1);
763 }
764 }
765
766 slash = strrchr (buf, '/');
767 if (slash != NULL) {
768 size_t len = strlen (slash+1);
769 memmove (buf, slash+1, len+1);
770 }
771 }
772
773 static void
_emit_header(void)774 _emit_header (void)
775 {
776 char name[4096] = "";
777
778 get_prog_name (name, sizeof (name));
779
780 _trace_printf ("%%!CairoScript - %s\n", name);
781 }
782
783 static cairo_bool_t
_init_logfile(void)784 _init_logfile (void)
785 {
786 static cairo_bool_t initialized;
787 char buf[4096];
788 const char *filename;
789 const char *env;
790
791 if (initialized)
792 return logfile != NULL;
793
794 initialized = TRUE;
795
796 env = getenv ("CAIRO_TRACE_FLUSH");
797 if (env != NULL)
798 _flush = atoi (env);
799
800 _line_info = TRUE;
801 env = getenv ("CAIRO_TRACE_LINE_INFO");
802 if (env != NULL)
803 _line_info = atoi (env);
804
805 _mark_dirty = TRUE;
806 env = getenv ("CAIRO_TRACE_MARK_DIRTY");
807 if (env != NULL)
808 _mark_dirty = atoi (env);
809
810 filename = getenv ("CAIRO_TRACE_FD");
811 if (filename != NULL) {
812 int fd = atoi (filename);
813 if (fd == -1)
814 return FALSE;
815
816 logfile = fdopen (fd, "w");
817 if (logfile == NULL) {
818 fprintf (stderr, "Failed to open trace file descriptor '%s': %s\n",
819 filename, strerror (errno));
820 return FALSE;
821 }
822
823 setenv ("CAIRO_TRACE_FD", "-1", 1);
824 goto done;
825 }
826
827 filename = getenv ("CAIRO_TRACE_OUTFILE_EXACT");
828 if (filename == NULL) {
829 char name[4096] = "";
830
831 filename = getenv ("CAIRO_TRACE_OUTDIR");
832 if (filename == NULL)
833 filename = CAIRO_TRACE_OUTDIR;
834
835 get_prog_name (name, sizeof (name));
836 if (*name == '\0')
837 strcpy (name, "cairo-trace.dat");
838
839 if (snprintf (buf, sizeof (buf), "%s/%s.%d.trace",
840 filename, name, getpid()) >= (int) sizeof (buf))
841 {
842 fprintf (stderr, "cairo-trace: Trace file name too long\n");
843 return FALSE;
844 }
845
846 filename = buf;
847 } else {
848 setenv ("CAIRO_TRACE_FD", "-1", 1);
849 }
850
851 logfile = fopen (filename, "wb");
852 if (logfile == NULL) {
853 fprintf (stderr, "Failed to open trace file '%s': %s\n",
854 filename, strerror (errno));
855 return FALSE;
856 }
857
858 fprintf (stderr, "cairo-trace: Recording cairo trace data to %s\n",
859 filename);
860
861 done:
862 atexit (_close_trace);
863 _emit_header ();
864 return TRUE;
865 }
866
867 static cairo_bool_t
_write_lock(void)868 _write_lock (void)
869 {
870 if (_error)
871 return FALSE;
872
873 if (! _should_trace ())
874 return FALSE;
875
876 if (! _init_logfile ())
877 return FALSE;
878
879 #if HAVE_FLOCKFILE && HAVE_FUNLOCKFILE
880 flockfile (logfile);
881 #endif
882 return TRUE;
883 }
884
885 static void
_write_unlock(void)886 _write_unlock (void)
887 {
888 if (logfile == NULL)
889 return;
890
891 #if HAVE_FLOCKFILE && HAVE_FUNLOCKFILE
892 funlockfile (logfile);
893 #endif
894
895 if (_flush)
896 fflush (logfile);
897 }
898
899
900 static Object *
_type_object_create(enum operand_type op_type,const void * ptr)901 _type_object_create (enum operand_type op_type, const void *ptr)
902 {
903 Type *type;
904 Object *obj;
905
906 type = _get_type (op_type);
907
908 pthread_mutex_lock (&type->mutex);
909 obj = _object_create (type, ptr);
910 pthread_mutex_unlock (&type->mutex);
911
912 return obj;
913 }
914
915 static Object *
_get_object(enum operand_type op_type,const void * ptr)916 _get_object (enum operand_type op_type, const void *ptr)
917 {
918 Type *type;
919 Object *obj;
920
921 type = _get_type (op_type);
922 pthread_mutex_lock (&type->mutex);
923 obj = _type_get_object (type, ptr);
924 pthread_mutex_unlock (&type->mutex);
925
926 return obj;
927 }
928
929 static Object *current_object[2048]; /* XXX limit operand stack */
930 static int current_stack_depth;
931
932 static void
dump_stack(const char * func)933 dump_stack(const char *func)
934 {
935 #if DEBUG_STACK
936 int n;
937
938 _trace_printf ("%% %s: stack[%d] = [", func, current_stack_depth);
939 fflush (logfile);
940 for (n = 0; n < current_stack_depth; n++) {
941 Object *obj = current_object[n];
942 assert(obj && obj->type);
943 _trace_printf (" %s%s%ld",
944 obj->defined ? "" : "*",
945 obj->type->op_code, obj->token);
946 fflush (logfile);
947 }
948 _trace_printf (" ]\n");
949 fflush (logfile);
950 #endif
951 }
952
953 static void
ensure_operands(int num_operands)954 ensure_operands (int num_operands)
955 {
956 if (current_stack_depth < num_operands) {
957 int n;
958
959 fprintf (stderr, "Operand stack underflow!\n");
960 for (n = 0; n < current_stack_depth; n++) {
961 Object *obj = current_object[n];
962
963 fprintf (stderr, " [%3d] = %s%ld\n",
964 n, obj->type->op_code, obj->token);
965 }
966
967 abort ();
968 }
969 }
970
971 static void
_consume_operand(bool discard)972 _consume_operand (bool discard)
973 {
974 Object *obj;
975
976 ensure_operands (1);
977 obj = current_object[--current_stack_depth];
978 if (!discard && ! obj->defined) {
979 _trace_printf ("dup /%s%ld exch def\n",
980 obj->type->op_code,
981 obj->token);
982 obj->defined = TRUE;
983 }
984 obj->operand = -1;
985 }
986
987 static void
_exch_operands(void)988 _exch_operands (void)
989 {
990 Object *tmp;
991
992 ensure_operands (2);
993 tmp = current_object[current_stack_depth-1];
994 tmp->operand--;
995 current_object[current_stack_depth-1] = current_object[current_stack_depth-2];
996 current_object[current_stack_depth-2] = tmp;
997 tmp = current_object[current_stack_depth-1];
998 tmp->operand++;
999 }
1000
1001 static cairo_bool_t
_pop_operands_to_depth(int depth)1002 _pop_operands_to_depth (int depth)
1003 {
1004 if (depth < 0)
1005 return FALSE;
1006
1007 assert(current_stack_depth >= depth);
1008 if (current_stack_depth == depth)
1009 return TRUE;
1010
1011 while (current_stack_depth > depth + 1) {
1012 Object *c_obj;
1013
1014 ensure_operands (1);
1015 c_obj = current_object[--current_stack_depth];
1016
1017 assert(c_obj);
1018 assert(c_obj->type);
1019
1020 if (! c_obj->defined) {
1021 current_stack_depth++;
1022 return FALSE;
1023 }
1024
1025 _trace_printf ("pop %% %s%ld\n",
1026 c_obj->type->op_code, c_obj->token);
1027 c_obj->operand = -1;
1028 }
1029
1030 _exch_operands ();
1031 _trace_printf ("exch\n");
1032
1033 dump_stack(__func__);
1034 return TRUE;
1035 }
1036
1037 static cairo_bool_t
_pop_operands_to_object(Object * obj)1038 _pop_operands_to_object (Object *obj)
1039 {
1040 if (!obj)
1041 return FALSE;
1042
1043 if (obj->operand == -1)
1044 return FALSE;
1045
1046 if (obj->operand == current_stack_depth - 1)
1047 return TRUE;
1048
1049 if (obj->operand == current_stack_depth - 2) {
1050 _exch_operands ();
1051 _trace_printf ("exch ");
1052 return TRUE;
1053 }
1054
1055 return _pop_operands_to_depth (obj->operand + 1);
1056 }
1057
1058 static cairo_bool_t
_pop_operands_to(enum operand_type t,const void * ptr)1059 _pop_operands_to (enum operand_type t, const void *ptr)
1060 {
1061 return _pop_operands_to_object (_get_object (t, ptr));
1062 }
1063
1064 static cairo_bool_t
_is_current_object(Object * obj,int depth)1065 _is_current_object (Object *obj, int depth)
1066 {
1067 if (current_stack_depth <= depth)
1068 return FALSE;
1069 return current_object[current_stack_depth-depth-1] == obj;
1070 }
1071
1072 static cairo_bool_t
_is_current(enum operand_type type,const void * ptr,int depth)1073 _is_current (enum operand_type type, const void *ptr, int depth)
1074 {
1075 return _is_current_object (_get_object (type, ptr), depth);
1076 }
1077
1078 static void
_push_object(Object * obj)1079 _push_object(Object *obj)
1080 {
1081 assert(obj->operand == -1);
1082
1083 if (current_stack_depth == ARRAY_LENGTH (current_object)) {
1084 int n;
1085
1086 fprintf (stderr, "Operand stack overflow!\n");
1087 for (n = 0; n < current_stack_depth; n++) {
1088 obj = current_object[n];
1089
1090 fprintf (stderr, " [%3d] = %s%ld\n",
1091 n, obj->type->op_code, obj->token);
1092 }
1093
1094 abort ();
1095 }
1096
1097 obj->operand = current_stack_depth;
1098 current_object[current_stack_depth++] = obj;
1099 }
1100
1101 static void
_push_operand(enum operand_type t,const void * ptr)1102 _push_operand (enum operand_type t, const void *ptr)
1103 {
1104 _push_object(_get_object(t, ptr));
1105 }
1106
1107 static void
_object_remove(Object * obj)1108 _object_remove (Object *obj)
1109 {
1110 if (obj->operand != -1) {
1111 ensure_operands (1);
1112 if (obj->operand == current_stack_depth - 1) {
1113 _trace_printf ("pop %% %s%ld destroyed\n",
1114 obj->type->op_code, obj->token);
1115 } else if (obj->operand == current_stack_depth - 2) {
1116 _exch_operands ();
1117 _trace_printf ("exch pop %% %s%ld destroyed\n",
1118 obj->type->op_code, obj->token);
1119 } else {
1120 int n;
1121
1122 _trace_printf ("%d -1 roll pop %% %s%ld destroyed\n",
1123 current_stack_depth - obj->operand,
1124 obj->type->op_code, obj->token);
1125
1126 for (n = obj->operand; n < current_stack_depth - 1; n++) {
1127 current_object[n] = current_object[n+1];
1128 current_object[n]->operand = n;
1129 }
1130 }
1131 obj->operand = -1;
1132
1133 current_stack_depth--;
1134 dump_stack(__func__);
1135 }
1136 }
1137
1138 static void
_object_undef(void * ptr)1139 _object_undef (void *ptr)
1140 {
1141 Object *obj = ptr;
1142
1143 if (_write_lock ()) {
1144 _object_remove (obj);
1145
1146 if (obj->defined) {
1147 _trace_printf ("/%s%ld undef\n",
1148 obj->type->op_code, obj->token);
1149 }
1150
1151 _write_unlock ();
1152 }
1153
1154 _object_destroy (obj);
1155 }
1156
1157 static long
_create_context_id(cairo_t * cr)1158 _create_context_id (cairo_t *cr)
1159 {
1160 Object *obj;
1161
1162 obj = _get_object (CONTEXT, cr);
1163 if (obj == NULL) {
1164 obj = _type_object_create (CONTEXT, cr);
1165 DLCALL (cairo_set_user_data,
1166 cr, &destroy_key, obj, _object_undef);
1167 }
1168
1169 return obj->token;
1170 }
1171
1172 static long
_get_id(enum operand_type op_type,const void * ptr)1173 _get_id (enum operand_type op_type, const void *ptr)
1174 {
1175 Object *obj;
1176
1177 obj = _get_object (op_type, ptr);
1178 if (obj == NULL) {
1179 if (logfile != NULL) {
1180 _trace_printf ("%% Unknown object of type %s, trace is incomplete.",
1181 _get_type (op_type)->name);
1182 }
1183 _error = TRUE;
1184 return -1;
1185 }
1186
1187 return obj->token;
1188 }
1189
1190 static cairo_bool_t
_has_id(enum operand_type op_type,const void * ptr)1191 _has_id (enum operand_type op_type, const void *ptr)
1192 {
1193 return _get_object (op_type, ptr) != NULL;
1194 }
1195
1196 static long
_create_font_face_id(cairo_font_face_t * font_face)1197 _create_font_face_id (cairo_font_face_t *font_face)
1198 {
1199 Object *obj;
1200
1201 obj = _get_object (FONT_FACE, font_face);
1202 if (obj == NULL) {
1203 obj = _type_object_create (FONT_FACE, font_face);
1204 DLCALL (cairo_font_face_set_user_data,
1205 font_face, &destroy_key, obj, _object_undef);
1206 }
1207
1208 return obj->token;
1209 }
1210
1211 static long
_get_font_face_id(cairo_font_face_t * font_face)1212 _get_font_face_id (cairo_font_face_t *font_face)
1213 {
1214 return _get_id (FONT_FACE, font_face);
1215 }
1216
1217 static void
_emit_font_face_id(cairo_font_face_t * font_face)1218 _emit_font_face_id (cairo_font_face_t *font_face)
1219 {
1220 Object *obj = _get_object (FONT_FACE, font_face);
1221 if (obj == NULL) {
1222 _trace_printf ("null ");
1223 } else {
1224 if (obj->defined) {
1225 _trace_printf ("f%ld ", obj->token);
1226 } else {
1227 _trace_printf ("%d index ", current_stack_depth - obj->operand - 1);
1228 }
1229 }
1230 }
1231
1232 static cairo_bool_t
_has_pattern_id(cairo_pattern_t * pattern)1233 _has_pattern_id (cairo_pattern_t *pattern)
1234 {
1235 return _has_id (PATTERN, pattern);
1236 }
1237
1238 static long
_create_pattern_id(cairo_pattern_t * pattern)1239 _create_pattern_id (cairo_pattern_t *pattern)
1240 {
1241 Object *obj;
1242
1243 obj = _get_object (PATTERN, pattern);
1244 if (obj == NULL) {
1245 obj = _type_object_create (PATTERN, pattern);
1246 DLCALL (cairo_pattern_set_user_data,
1247 pattern, &destroy_key, obj, _object_undef);
1248 }
1249
1250 return obj->token;
1251 }
1252
1253 static void
_emit_pattern_id(cairo_pattern_t * pattern)1254 _emit_pattern_id (cairo_pattern_t *pattern)
1255 {
1256 Object *obj = _get_object (PATTERN, pattern);
1257 if (obj == NULL) {
1258 _trace_printf ("null ");
1259 } else {
1260 if (obj->defined) {
1261 _trace_printf ("p%ld ", obj->token);
1262 } else {
1263 _trace_printf ("%d index ",
1264 current_stack_depth - obj->operand - 1);
1265 }
1266 }
1267 }
1268
1269 static void
_emit_scaled_font_id(const cairo_scaled_font_t * scaled_font)1270 _emit_scaled_font_id (const cairo_scaled_font_t *scaled_font)
1271 {
1272 Object *obj = _get_object (SCALED_FONT, scaled_font);
1273 if (obj == NULL) {
1274 _trace_printf ("null ");
1275 } else {
1276 if (obj->defined) {
1277 _trace_printf ("sf%ld ", obj->token);
1278 } else {
1279 _trace_printf ("%d index ",
1280 current_stack_depth - obj->operand - 1);
1281 }
1282 }
1283 }
1284
1285 static long
_create_scaled_font_id(cairo_scaled_font_t * font)1286 _create_scaled_font_id (cairo_scaled_font_t *font)
1287 {
1288 Object *obj;
1289
1290 assert(_get_object (SCALED_FONT, font) == NULL);
1291 obj = _type_object_create (SCALED_FONT, font);
1292 DLCALL (cairo_scaled_font_set_user_data,
1293 font, &destroy_key, obj, _object_undef);
1294
1295 return obj->token;
1296 }
1297
1298 static cairo_bool_t
_has_scaled_font_id(const cairo_scaled_font_t * font)1299 _has_scaled_font_id (const cairo_scaled_font_t *font)
1300 {
1301 return _has_id (SCALED_FONT, font);
1302 }
1303
1304 static Object *
_create_surface(cairo_surface_t * surface)1305 _create_surface (cairo_surface_t *surface)
1306 {
1307 Object *obj;
1308
1309 obj = _get_object (SURFACE, surface);
1310 if (obj == NULL) {
1311 obj = _type_object_create (SURFACE, surface);
1312 DLCALL (cairo_surface_set_user_data,
1313 surface, &destroy_key, obj, _object_undef);
1314 }
1315
1316 return obj;
1317 }
1318
1319 static long
_get_surface_id(cairo_surface_t * surface)1320 _get_surface_id (cairo_surface_t *surface)
1321 {
1322 return _get_id (SURFACE, surface);
1323 }
1324
1325 static cairo_bool_t
_matrix_is_identity(const cairo_matrix_t * m)1326 _matrix_is_identity (const cairo_matrix_t *m)
1327 {
1328 return m->xx == 1. && m->yx == 0. &&
1329 m->xy == 0. && m->yy == 1. &&
1330 m->x0 == 0. && m->y0 == 0.;
1331 }
1332
1333 #define BUFFER_SIZE 16384
1334 struct _data_stream {
1335 z_stream zlib_stream;
1336 unsigned char zin_buf[BUFFER_SIZE];
1337 unsigned char zout_buf[BUFFER_SIZE];
1338 unsigned char four_tuple[4];
1339 int base85_pending;
1340 };
1341
1342 static void
_write_zlib_data_start(struct _data_stream * stream)1343 _write_zlib_data_start (struct _data_stream *stream)
1344 {
1345 stream->zlib_stream.zalloc = Z_NULL;
1346 stream->zlib_stream.zfree = Z_NULL;
1347 stream->zlib_stream.opaque = Z_NULL;
1348
1349 deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION);
1350
1351 stream->zlib_stream.next_in = stream->zin_buf;
1352 stream->zlib_stream.avail_in = 0;
1353 stream->zlib_stream.next_out = stream->zout_buf;
1354 stream->zlib_stream.avail_out = BUFFER_SIZE;
1355 }
1356
1357 static void
_write_base85_data_start(struct _data_stream * stream)1358 _write_base85_data_start (struct _data_stream *stream)
1359 {
1360 stream->base85_pending = 0;
1361 }
1362
1363 static cairo_bool_t
_expand_four_tuple_to_five(unsigned char four_tuple[4],unsigned char five_tuple[5])1364 _expand_four_tuple_to_five (unsigned char four_tuple[4],
1365 unsigned char five_tuple[5])
1366 {
1367 uint32_t value;
1368 int digit, i;
1369 cairo_bool_t all_zero = TRUE;
1370
1371 value = four_tuple[0] << 24 |
1372 four_tuple[1] << 16 |
1373 four_tuple[2] << 8 |
1374 four_tuple[3] << 0;
1375 for (i = 0; i < 5; i++) {
1376 digit = value % 85;
1377 if (digit != 0 && all_zero)
1378 all_zero = FALSE;
1379 five_tuple[4-i] = digit + 33;
1380 value = value / 85;
1381 }
1382
1383 return all_zero;
1384 }
1385
1386 static void
_write_base85_data(struct _data_stream * stream,const unsigned char * data,unsigned long length)1387 _write_base85_data (struct _data_stream *stream,
1388 const unsigned char *data,
1389 unsigned long length)
1390 {
1391 unsigned char five_tuple[5];
1392 int ret;
1393
1394 assert (_should_trace ());
1395
1396 while (length--) {
1397 stream->four_tuple[stream->base85_pending++] = *data++;
1398 if (stream->base85_pending == 4) {
1399 if (_expand_four_tuple_to_five (stream->four_tuple, five_tuple))
1400 ret = fwrite ("z", 1, 1, logfile);
1401 else
1402 ret = fwrite (five_tuple, 5, 1, logfile);
1403 (void)ret;
1404 stream->base85_pending = 0;
1405 }
1406 }
1407 }
1408
1409 static void
_write_zlib_data(struct _data_stream * stream,cairo_bool_t flush)1410 _write_zlib_data (struct _data_stream *stream, cairo_bool_t flush)
1411 {
1412 cairo_bool_t finished;
1413
1414 do {
1415 int ret = deflate (&stream->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH);
1416 if (flush || stream->zlib_stream.avail_out == 0) {
1417 _write_base85_data (stream,
1418 stream->zout_buf,
1419 BUFFER_SIZE - stream->zlib_stream.avail_out);
1420 stream->zlib_stream.next_out = stream->zout_buf;
1421 stream->zlib_stream.avail_out = BUFFER_SIZE;
1422 }
1423
1424 finished = TRUE;
1425 if (stream->zlib_stream.avail_in != 0)
1426 finished = FALSE;
1427 if (flush && ret != Z_STREAM_END)
1428 finished = FALSE;
1429 } while (! finished);
1430
1431 stream->zlib_stream.next_in = stream->zin_buf;
1432 }
1433
1434 static void
_write_data_start(struct _data_stream * stream,uint32_t len)1435 _write_data_start (struct _data_stream *stream, uint32_t len)
1436 {
1437 _write_zlib_data_start (stream);
1438 _write_base85_data_start (stream);
1439
1440 _trace_printf ("<|");
1441 len = to_be32 (len);
1442 _write_base85_data (stream, (unsigned char *) &len, sizeof (len));
1443 }
1444
1445 static void
_write_data(struct _data_stream * stream,const void * data,unsigned int length)1446 _write_data (struct _data_stream *stream,
1447 const void *data,
1448 unsigned int length)
1449 {
1450 unsigned int count;
1451 const unsigned char *p = data;
1452
1453 while (length) {
1454 count = length;
1455 if (count > BUFFER_SIZE - stream->zlib_stream.avail_in)
1456 count = BUFFER_SIZE - stream->zlib_stream.avail_in;
1457 memcpy (stream->zin_buf + stream->zlib_stream.avail_in, p, count);
1458 p += count;
1459 stream->zlib_stream.avail_in += count;
1460 length -= count;
1461
1462 if (stream->zlib_stream.avail_in == BUFFER_SIZE)
1463 _write_zlib_data (stream, FALSE);
1464 }
1465 }
1466
1467 static void
_write_zlib_data_end(struct _data_stream * stream)1468 _write_zlib_data_end (struct _data_stream *stream)
1469 {
1470 _write_zlib_data (stream, TRUE);
1471 deflateEnd (&stream->zlib_stream);
1472
1473 }
1474
1475 static void
_write_base85_data_end(struct _data_stream * stream)1476 _write_base85_data_end (struct _data_stream *stream)
1477 {
1478 unsigned char five_tuple[5];
1479 int ret;
1480
1481 assert (_should_trace ());
1482
1483 if (stream->base85_pending) {
1484 memset (stream->four_tuple + stream->base85_pending,
1485 0, 4 - stream->base85_pending);
1486 _expand_four_tuple_to_five (stream->four_tuple, five_tuple);
1487 ret = fwrite (five_tuple, stream->base85_pending+1, 1, logfile);
1488 (void) ret;
1489 }
1490 }
1491
1492 static void
_write_data_end(struct _data_stream * stream)1493 _write_data_end (struct _data_stream *stream)
1494 {
1495 _write_zlib_data_end (stream);
1496 _write_base85_data_end (stream);
1497
1498 _trace_printf ("~>");
1499 }
1500
1501 static void
_emit_data(const void * data,unsigned int length)1502 _emit_data (const void *data, unsigned int length)
1503 {
1504 struct _data_stream stream;
1505
1506 _write_data_start (&stream, length);
1507 _write_data (&stream, data, length);
1508 _write_data_end (&stream);
1509 }
1510
1511 static const char *
_format_to_string(cairo_format_t format)1512 _format_to_string (cairo_format_t format)
1513 {
1514 #define f(name) case CAIRO_FORMAT_ ## name: return #name
1515 switch (format) {
1516 f(INVALID);
1517 f(RGBA128F);
1518 f(RGB96F);
1519 f(ARGB32);
1520 f(RGB30);
1521 f(RGB24);
1522 f(RGB16_565);
1523 f(A8);
1524 f(A1);
1525 }
1526 #undef f
1527 return "UNKNOWN_FORMAT";
1528 }
1529
1530 static const char *
_format_to_content_string(cairo_format_t format)1531 _format_to_content_string (cairo_format_t format)
1532 {
1533 switch (format) {
1534 case CAIRO_FORMAT_INVALID:
1535 return "INVALID";
1536 case CAIRO_FORMAT_RGBA128F:
1537 case CAIRO_FORMAT_ARGB32:
1538 return "COLOR_ALPHA";
1539 case CAIRO_FORMAT_RGB96F:
1540 case CAIRO_FORMAT_RGB30:
1541 case CAIRO_FORMAT_RGB24:
1542 case CAIRO_FORMAT_RGB16_565:
1543 return "COLOR";
1544 case CAIRO_FORMAT_A8:
1545 case CAIRO_FORMAT_A1:
1546 return "ALPHA";
1547 }
1548 return "UNKNOWN";
1549 }
1550
1551 static const char *
_status_to_string(cairo_status_t status)1552 _status_to_string (cairo_status_t status)
1553 {
1554 #define f(name) case CAIRO_STATUS_ ## name: return "STATUS_" #name
1555 switch (status) {
1556 f(SUCCESS);
1557 f(NO_MEMORY);
1558 f(INVALID_RESTORE);
1559 f(INVALID_POP_GROUP);
1560 f(NO_CURRENT_POINT);
1561 f(INVALID_MATRIX);
1562 f(INVALID_STATUS);
1563 f(NULL_POINTER);
1564 f(INVALID_STRING);
1565 f(INVALID_PATH_DATA);
1566 f(READ_ERROR);
1567 f(WRITE_ERROR);
1568 f(SURFACE_FINISHED);
1569 f(SURFACE_TYPE_MISMATCH);
1570 f(PATTERN_TYPE_MISMATCH);
1571 f(INVALID_CONTENT);
1572 f(INVALID_FORMAT);
1573 f(INVALID_VISUAL);
1574 f(FILE_NOT_FOUND);
1575 f(INVALID_DASH);
1576 f(INVALID_DSC_COMMENT);
1577 f(INVALID_INDEX);
1578 f(CLIP_NOT_REPRESENTABLE);
1579 f(TEMP_FILE_ERROR);
1580 f(INVALID_STRIDE);
1581 f(FONT_TYPE_MISMATCH);
1582 f(USER_FONT_IMMUTABLE);
1583 f(USER_FONT_ERROR);
1584 f(NEGATIVE_COUNT);
1585 f(INVALID_CLUSTERS);
1586 f(INVALID_SLANT);
1587 f(INVALID_WEIGHT);
1588 f(INVALID_SIZE);
1589 f(USER_FONT_NOT_IMPLEMENTED);
1590 f(DEVICE_TYPE_MISMATCH);
1591 f(DEVICE_ERROR);
1592 f(INVALID_MESH_CONSTRUCTION);
1593 f(DEVICE_FINISHED);
1594 f(JBIG2_GLOBAL_MISSING);
1595 f(PNG_ERROR);
1596 f(FREETYPE_ERROR);
1597 f(WIN32_GDI_ERROR);
1598 f(TAG_ERROR);
1599 case CAIRO_STATUS_LAST_STATUS:
1600 break;
1601 }
1602 return "UNKNOWN_STATUS";
1603 #undef f
1604 }
1605
1606 static void CAIRO_PRINTF_FORMAT(2, 3)
_emit_image(cairo_surface_t * image,const char * info,...)1607 _emit_image (cairo_surface_t *image,
1608 const char *info,
1609 ...)
1610 {
1611 int stride, row, width, height;
1612 uint32_t len;
1613 cairo_format_t format;
1614 uint8_t row_stack[BUFFER_SIZE];
1615 uint8_t *rowdata;
1616 uint8_t *data;
1617 struct _data_stream stream;
1618 cairo_status_t status;
1619
1620 status = DLCALL (cairo_surface_status, image);
1621 if (status) {
1622 _trace_printf ("<< /status //%s >> image",
1623 _status_to_string (status));
1624 return;
1625 }
1626
1627 width = DLCALL (cairo_image_surface_get_width, image);
1628 height = DLCALL (cairo_image_surface_get_height, image);
1629 stride = DLCALL (cairo_image_surface_get_stride, image);
1630 format = DLCALL (cairo_image_surface_get_format, image);
1631 data = DLCALL (cairo_image_surface_get_data, image);
1632
1633 _trace_printf ("dict\n"
1634 " /width %d set\n"
1635 " /height %d set\n"
1636 " /format //%s set\n",
1637 width, height,
1638 _format_to_string (format));
1639 if (info != NULL) {
1640 va_list ap;
1641
1642 va_start (ap, info);
1643 _trace_vprintf (info, ap);
1644 va_end (ap);
1645 }
1646
1647 if (DLCALL (cairo_version) >= CAIRO_VERSION_ENCODE (1, 9, 0)) {
1648 const char *mime_types[] = {
1649 CAIRO_MIME_TYPE_JPEG,
1650 CAIRO_MIME_TYPE_JP2,
1651 CAIRO_MIME_TYPE_PNG,
1652 NULL
1653 }, **mime_type;
1654
1655 for (mime_type = mime_types; *mime_type; mime_type++) {
1656 const unsigned char *mime_data;
1657 unsigned long mime_length;
1658
1659 DLCALL (cairo_surface_get_mime_data,
1660 image, *mime_type, &mime_data, &mime_length);
1661 if (mime_data != NULL) {
1662 _trace_printf (" /mime-type (%s) set\n"
1663 " /source <~",
1664 *mime_type);
1665 _write_base85_data_start (&stream);
1666 _write_base85_data (&stream, mime_data, mime_length);
1667 _write_base85_data_end (&stream);
1668 _trace_printf ("~> set\n"
1669 " image");
1670 return;
1671 }
1672 }
1673 }
1674
1675 switch (format) {
1676 case CAIRO_FORMAT_A1: len = (width + 7)/8; break;
1677 case CAIRO_FORMAT_A8: len = width; break;
1678 case CAIRO_FORMAT_RGB16_565: len = 2*width; break;
1679 case CAIRO_FORMAT_RGB24: len = 3*width; break;
1680 default:
1681 case CAIRO_FORMAT_RGB30:
1682 case CAIRO_FORMAT_INVALID:
1683 case CAIRO_FORMAT_ARGB32: len = 4*width; break;
1684 case CAIRO_FORMAT_RGB96F: len = 12*width; break;
1685 case CAIRO_FORMAT_RGBA128F: len = 16*width; break;
1686 }
1687
1688 _trace_printf (" /source ");
1689 _write_data_start (&stream, len * height);
1690
1691 #ifdef WORDS_BIGENDIAN
1692 switch (format) {
1693 case CAIRO_FORMAT_RGB24:
1694 for (row = height; row--; ) {
1695 int col;
1696 rowdata = data;
1697 for (col = width; col--; ) {
1698 _write_data (&stream, rowdata, 3);
1699 rowdata+=4;
1700 }
1701 data += stride;
1702 }
1703 break;
1704 case CAIRO_FORMAT_A1:
1705 case CAIRO_FORMAT_A8:
1706 case CAIRO_FORMAT_RGB16_565:
1707 case CAIRO_FORMAT_RGB30:
1708 case CAIRO_FORMAT_ARGB32:
1709 case CAIRO_FORMAT_RGB96F:
1710 case CAIRO_FORMAT_RGBA128F:
1711 for (row = height; row--; ) {
1712 _write_data (&stream, data, len);
1713 data += stride;
1714 }
1715 break;
1716 case CAIRO_FORMAT_INVALID:
1717 default:
1718 break;
1719 }
1720 #else
1721 if (stride > ARRAY_LENGTH (row_stack)) {
1722 rowdata = malloc (stride);
1723 if (rowdata == NULL)
1724 goto BAIL;
1725 } else
1726 rowdata = row_stack;
1727
1728 switch (format) {
1729 case CAIRO_FORMAT_A1:
1730 for (row = height; row--; ) {
1731 int col;
1732 for (col = 0; col < (width + 7)/8; col++)
1733 rowdata[col] = CAIRO_BITSWAP8 (data[col]);
1734 _write_data (&stream, rowdata, (width+7)/8);
1735 data += stride;
1736 }
1737 break;
1738 case CAIRO_FORMAT_A8:
1739 for (row = height; row--; ) {
1740 _write_data (&stream, rowdata, width);
1741 data += stride;
1742 }
1743 break;
1744 case CAIRO_FORMAT_RGB16_565: /* XXX endianness */
1745 for (row = height; row--; ) {
1746 uint16_t *src = (uint16_t *) data;
1747 uint16_t *dst = (uint16_t *)rowdata;
1748 int col;
1749 for (col = 0; col < width; col++)
1750 dst[col] = bswap_16 (src[col]);
1751 _write_data (&stream, rowdata, 2*width);
1752 data += stride;
1753 }
1754 break;
1755 case CAIRO_FORMAT_RGB24:
1756 for (row = height; row--; ) {
1757 uint8_t *src = data;
1758 int col;
1759 for (col = 0; col < width; col++) {
1760 rowdata[3*col+2] = *src++;
1761 rowdata[3*col+1] = *src++;
1762 rowdata[3*col+0] = *src++;
1763 src++;
1764 }
1765 _write_data (&stream, rowdata, 3*width);
1766 data += stride;
1767 }
1768 break;
1769 case CAIRO_FORMAT_RGB96F:
1770 case CAIRO_FORMAT_RGBA128F:
1771 case CAIRO_FORMAT_RGB30:
1772 case CAIRO_FORMAT_ARGB32:
1773 for (row = height; row--; ) {
1774 uint32_t *src = (uint32_t *) data;
1775 uint32_t *dst = (uint32_t *) rowdata;
1776 int col;
1777 for (col = 0; col < width; col++)
1778 dst[col] = bswap_32 (src[col]);
1779 _write_data (&stream, rowdata, len);
1780 data += stride;
1781 }
1782 break;
1783 case CAIRO_FORMAT_INVALID:
1784 default:
1785 break;
1786 }
1787 if (rowdata != row_stack)
1788 free (rowdata);
1789
1790 BAIL:
1791 _write_data_end (&stream);
1792 #endif
1793 _trace_printf (" set\n image");
1794 }
1795
1796 static void
_encode_string_literal(char * out,int max,const char * utf8,int len)1797 _encode_string_literal (char *out, int max,
1798 const char *utf8, int len)
1799 {
1800 char c;
1801 const char *end;
1802
1803 *out++ = '(';
1804 max--;
1805
1806 if (utf8 == NULL)
1807 goto DONE;
1808
1809 if (len < 0)
1810 len = strlen (utf8);
1811 end = utf8 + len;
1812
1813 while (utf8 < end) {
1814 if (max < 5)
1815 break;
1816
1817 switch ((c = *utf8++)) {
1818 case '\n':
1819 *out++ = '\\';
1820 *out++ = 'n';
1821 max -= 2;
1822 break;
1823 case '\r':
1824 *out++ = '\\';
1825 *out++ = 'r';
1826 max -= 2;
1827 break;
1828 case '\t':
1829 *out++ = '\\';
1830 *out++ = 't';
1831 max -= 2;
1832 break;
1833 case '\b':
1834 *out++ = '\\';
1835 *out++ = 'b';
1836 max -= 2;
1837 break;
1838 case '\f':
1839 *out++ = '\\';
1840 *out++ = 'f';
1841 max -= 2;
1842 break;
1843 case '\\':
1844 case '(':
1845 case ')':
1846 *out++ = '\\';
1847 *out++ = c;
1848 max -= 2;
1849 break;
1850 default:
1851 if (isprint (c) || isspace (c)) {
1852 *out++ = c;
1853 } else {
1854 int octal = 0;
1855 while (c) {
1856 octal *= 10;
1857 octal += c&7;
1858 c /= 8;
1859 }
1860 octal = snprintf (out, max, "\\%03d", octal);
1861 out += octal;
1862 max -= octal;
1863 }
1864 break;
1865 }
1866 }
1867 DONE:
1868 *out++ = ')';
1869 *out = '\0';
1870 }
1871
1872 static void
to_octal(int value,char * buf,size_t size)1873 to_octal (int value, char *buf, size_t size)
1874 {
1875 do {
1876 buf[--size] = '0' + (value & 7);
1877 value >>= 3;
1878 } while (size);
1879 }
1880
1881 static void
_emit_string_literal(const char * utf8,int len)1882 _emit_string_literal (const char *utf8, int len)
1883 {
1884 char c;
1885 const char *end;
1886
1887 if (utf8 == NULL) {
1888 _trace_printf ("()");
1889 return;
1890 }
1891
1892 if (len < 0)
1893 len = strlen (utf8);
1894 end = utf8 + len;
1895
1896 _trace_printf ("(");
1897 while (utf8 < end) {
1898 switch ((c = *utf8++)) {
1899 case '\n':
1900 c = 'n';
1901 goto ESCAPED_CHAR;
1902 case '\r':
1903 c = 'r';
1904 goto ESCAPED_CHAR;
1905 case '\t':
1906 c = 't';
1907 goto ESCAPED_CHAR;
1908 case '\b':
1909 c = 'b';
1910 goto ESCAPED_CHAR;
1911 case '\f':
1912 c = 'f';
1913 goto ESCAPED_CHAR;
1914 case '\\':
1915 case '(':
1916 case ')':
1917 ESCAPED_CHAR:
1918 _trace_printf ("\\%c", c);
1919 break;
1920 default:
1921 if (isprint (c) || isspace (c)) {
1922 _trace_printf ("%c", c);
1923 } else {
1924 char buf[4] = { '\\' };
1925 int ret_ignored;
1926
1927 to_octal (c, buf+1, 3);
1928 ret_ignored = fwrite (buf, 4, 1, logfile);
1929 (void)ret_ignored;
1930 }
1931 break;
1932 }
1933 }
1934 _trace_printf (")");
1935 }
1936
1937 static void
_emit_current(Object * obj)1938 _emit_current (Object *obj)
1939 {
1940 if (obj != NULL && ! _pop_operands_to_object (obj)) {
1941 if (obj->operand != -1) {
1942 int n;
1943
1944 _trace_printf ("%d -1 roll %% %s%ld\n",
1945 current_stack_depth - obj->operand,
1946 obj->type->op_code, obj->token);
1947
1948 for (n = obj->operand; n < current_stack_depth - 1; n++) {
1949 current_object[n] = current_object[n+1];
1950 current_object[n]->operand = n;
1951 }
1952 obj->operand = -1;
1953 current_stack_depth--;
1954 } else {
1955 assert(obj->defined);
1956 _trace_printf ("%s%ld\n", obj->type->op_code, obj->token);
1957 }
1958
1959 _push_object (obj);
1960 dump_stack(__func__);
1961 }
1962 }
1963
1964 static void
_emit_context(cairo_t * cr)1965 _emit_context (cairo_t *cr)
1966 {
1967 _emit_current (_get_object (CONTEXT, cr));
1968 }
1969
1970 static void
_emit_pattern(cairo_pattern_t * pattern)1971 _emit_pattern (cairo_pattern_t *pattern)
1972 {
1973 _emit_current (_get_object (PATTERN, pattern));
1974 }
1975
1976 static void
_emit_surface(cairo_surface_t * surface)1977 _emit_surface (cairo_surface_t *surface)
1978 {
1979 _emit_current (_get_object (SURFACE, surface));
1980 }
1981
1982 static void CAIRO_PRINTF_FORMAT(2, 3)
_emit_cairo_op(cairo_t * cr,const char * fmt,...)1983 _emit_cairo_op (cairo_t *cr, const char *fmt, ...)
1984 {
1985 va_list ap;
1986
1987 if (cr == NULL || ! _write_lock ())
1988 return;
1989
1990 _emit_context (cr);
1991
1992 va_start (ap, fmt);
1993 _trace_vprintf ( fmt, ap);
1994 va_end (ap);
1995
1996 _write_unlock ();
1997 }
1998
1999 cairo_t *
cairo_create(cairo_surface_t * target)2000 cairo_create (cairo_surface_t *target)
2001 {
2002 cairo_t *ret;
2003 long surface_id;
2004 long context_id;
2005
2006 _enter_trace ();
2007
2008 ret = DLCALL (cairo_create, target);
2009 context_id = _create_context_id (ret);
2010
2011 _emit_line_info ();
2012 if (target != NULL && _write_lock ()) {
2013 surface_id = _get_surface_id (target);
2014 if (surface_id != -1) {
2015 _get_object (SURFACE, target)->foreign = FALSE;
2016
2017 /* we presume that we will continue to use the context */
2018 if (_pop_operands_to (SURFACE, target)){
2019 _consume_operand (false);
2020 } else {
2021 _trace_printf ("s%ld ", surface_id);
2022 }
2023 _trace_printf ("context %% c%ld\n", context_id);
2024 _push_operand (CONTEXT, ret);
2025 dump_stack(__func__);
2026 }
2027 _write_unlock ();
2028 }
2029
2030 _exit_trace ();
2031 return ret;
2032 }
2033
2034 void
cairo_save(cairo_t * cr)2035 cairo_save (cairo_t *cr)
2036 {
2037 _enter_trace ();
2038 _emit_line_info ();
2039 _emit_cairo_op (cr, "save\n");
2040 DLCALL (cairo_save, cr);
2041 _exit_trace ();
2042 }
2043
2044 void
cairo_restore(cairo_t * cr)2045 cairo_restore (cairo_t *cr)
2046 {
2047 _enter_trace ();
2048 _emit_line_info ();
2049 _emit_cairo_op (cr, "restore\n");
2050 DLCALL (cairo_restore, cr);
2051 _exit_trace ();
2052 }
2053
2054 void
cairo_push_group(cairo_t * cr)2055 cairo_push_group (cairo_t *cr)
2056 {
2057 _enter_trace ();
2058 _emit_line_info ();
2059 _emit_cairo_op (cr, "//COLOR_ALPHA push-group\n");
2060 DLCALL (cairo_push_group, cr);
2061 _exit_trace ();
2062 }
2063
2064 static const char *
_content_to_string(cairo_content_t content)2065 _content_to_string (cairo_content_t content)
2066 {
2067 switch (content) {
2068 case CAIRO_CONTENT_ALPHA: return "ALPHA";
2069 case CAIRO_CONTENT_COLOR: return "COLOR";
2070 default:
2071 case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA";
2072 }
2073 }
2074
2075 void
cairo_push_group_with_content(cairo_t * cr,cairo_content_t content)2076 cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
2077 {
2078 _enter_trace ();
2079 _emit_line_info ();
2080 _emit_cairo_op (cr, "//%s push-group\n", _content_to_string (content));
2081 DLCALL (cairo_push_group_with_content, cr, content);
2082 _exit_trace ();
2083 }
2084
2085 cairo_pattern_t *
cairo_pop_group(cairo_t * cr)2086 cairo_pop_group (cairo_t *cr)
2087 {
2088 cairo_pattern_t *ret;
2089
2090 _enter_trace ();
2091
2092 ret = DLCALL (cairo_pop_group, cr);
2093
2094 _emit_line_info ();
2095 _emit_cairo_op (cr, "pop-group %% p%ld\n", _create_pattern_id (ret));
2096 _push_operand (PATTERN, ret);
2097 dump_stack(__func__);
2098
2099 _exit_trace ();
2100 return ret;
2101 }
2102
2103 void
cairo_pop_group_to_source(cairo_t * cr)2104 cairo_pop_group_to_source (cairo_t *cr)
2105 {
2106 _enter_trace ();
2107 _emit_line_info ();
2108 _emit_cairo_op (cr, "pop-group set-source\n");
2109 DLCALL (cairo_pop_group_to_source, cr);
2110 _exit_trace ();
2111 }
2112
2113 static const char *
_operator_to_string(cairo_operator_t op)2114 _operator_to_string (cairo_operator_t op)
2115 {
2116 #define f(name) case CAIRO_OPERATOR_ ## name: return #name
2117 switch (op) {
2118 f(OVER);
2119 f(SOURCE);
2120 f(CLEAR);
2121 f(IN);
2122 f(OUT);
2123 f(ATOP);
2124 f(DEST);
2125 f(DEST_OVER);
2126 f(DEST_IN);
2127 f(DEST_OUT);
2128 f(DEST_ATOP);
2129 f(XOR);
2130 f(ADD);
2131 f(SATURATE);
2132 f(MULTIPLY);
2133 f(SCREEN);
2134 f(OVERLAY);
2135 f(DARKEN);
2136 f(LIGHTEN);
2137 case CAIRO_OPERATOR_COLOR_DODGE: return "DODGE";
2138 case CAIRO_OPERATOR_COLOR_BURN: return "BURN";
2139 f(HARD_LIGHT);
2140 f(SOFT_LIGHT);
2141 f(DIFFERENCE);
2142 f(EXCLUSION);
2143 f(HSL_HUE);
2144 f(HSL_SATURATION);
2145 f(HSL_COLOR);
2146 f(HSL_LUMINOSITY);
2147 }
2148 #undef f
2149 return "UNKNOWN_OPERATOR";
2150 }
2151
2152 void
cairo_set_operator(cairo_t * cr,cairo_operator_t op)2153 cairo_set_operator (cairo_t *cr, cairo_operator_t op)
2154 {
2155 _enter_trace ();
2156 _emit_line_info ();
2157 _emit_cairo_op (cr, "//%s set-operator\n", _operator_to_string (op));
2158 DLCALL (cairo_set_operator, cr, op);
2159 _exit_trace ();
2160 }
2161
2162 void
cairo_set_source_rgb(cairo_t * cr,double red,double green,double blue)2163 cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
2164 {
2165 _enter_trace ();
2166 _emit_line_info ();
2167 _emit_cairo_op (cr, "%g %g %g set-source-rgb\n", red, green, blue);
2168 DLCALL (cairo_set_source_rgb, cr, red, green, blue);
2169 _exit_trace ();
2170 }
2171
2172 void
cairo_set_source_rgba(cairo_t * cr,double red,double green,double blue,double alpha)2173 cairo_set_source_rgba (cairo_t *cr, double red, double green, double blue, double alpha)
2174 {
2175 _enter_trace ();
2176 _emit_line_info ();
2177 _emit_cairo_op (cr, "%g %g %g %g set-source-rgba\n",
2178 red, green, blue, alpha);
2179 DLCALL (cairo_set_source_rgba, cr, red, green, blue, alpha);
2180 _exit_trace ();
2181 }
2182
2183 static void
_emit_source_image(cairo_surface_t * surface)2184 _emit_source_image (cairo_surface_t *surface)
2185 {
2186 Object *obj;
2187 cairo_surface_t *image;
2188 cairo_t *cr;
2189
2190 obj = _get_object (SURFACE, surface);
2191 if (obj == NULL)
2192 return;
2193
2194 image = DLCALL (cairo_image_surface_create,
2195 CAIRO_FORMAT_ARGB32,
2196 obj->width,
2197 obj->height);
2198 cr = DLCALL (cairo_create, image);
2199 DLCALL (cairo_set_source_surface, cr, surface, 0, 0);
2200 DLCALL (cairo_paint, cr);
2201 DLCALL (cairo_destroy, cr);
2202
2203 _emit_image (image, NULL);
2204 _trace_printf (" set-source-image ");
2205 DLCALL (cairo_surface_destroy, image);
2206
2207 obj->foreign = FALSE;
2208 }
2209
2210 static void
_emit_source_image_rectangle(cairo_surface_t * surface,int x,int y,int width,int height)2211 _emit_source_image_rectangle (cairo_surface_t *surface,
2212 int x, int y,
2213 int width, int height)
2214 {
2215 Object *obj;
2216 cairo_surface_t *image;
2217 cairo_t *cr;
2218
2219 obj = _get_object (SURFACE, surface);
2220 if (obj == NULL)
2221 return;
2222
2223 if (obj->foreign) {
2224 _emit_source_image (surface);
2225 return;
2226 }
2227
2228 image = DLCALL (cairo_image_surface_create,
2229 CAIRO_FORMAT_ARGB32,
2230 width,
2231 height);
2232 cr = DLCALL (cairo_create, image);
2233 DLCALL (cairo_set_source_surface, cr, surface, x, y);
2234 DLCALL (cairo_paint, cr);
2235 DLCALL (cairo_destroy, cr);
2236
2237 _emit_image (image, NULL);
2238 _trace_printf (" %d %d set-device-offset set-source-image ",
2239 x, y);
2240 DLCALL (cairo_surface_destroy, image);
2241 }
2242
2243 void
cairo_set_source_surface(cairo_t * cr,cairo_surface_t * surface,double x,double y)2244 cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y)
2245 {
2246 _enter_trace ();
2247 _emit_line_info ();
2248 if (cr != NULL && surface != NULL && _write_lock ()) {
2249 Object *obj = _get_object (SURFACE, surface);
2250
2251 if (_is_current (SURFACE, surface, 0) &&
2252 _is_current (CONTEXT, cr, 1))
2253 {
2254 _consume_operand (false);
2255 }
2256 else if (_is_current (SURFACE, surface, 1) &&
2257 _is_current (CONTEXT, cr, 0) &&
2258 obj->defined)
2259 {
2260 _trace_printf ("exch ");
2261 _exch_operands ();
2262 _consume_operand (false);
2263 } else if (obj->defined) {
2264 _emit_context (cr);
2265 _trace_printf ("s%ld ", obj->token);
2266 } else {
2267 _emit_context (cr);
2268 _trace_printf ("%d index ",
2269 current_stack_depth - obj->operand - 1);
2270 }
2271
2272 if (obj->foreign)
2273 _emit_source_image (surface);
2274
2275 _trace_printf ("pattern");
2276 if (x != 0. || y != 0.)
2277 _trace_printf (" %g %g translate", -x, -y);
2278
2279 _trace_printf (" set-source\n");
2280 _write_unlock ();
2281 }
2282
2283 DLCALL (cairo_set_source_surface, cr, surface, x, y);
2284 _exit_trace ();
2285 }
2286
2287 void
cairo_set_source(cairo_t * cr,cairo_pattern_t * source)2288 cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
2289 {
2290 _enter_trace ();
2291 _emit_line_info ();
2292 if (cr != NULL && source != NULL && _write_lock ()) {
2293 Object *obj = _get_object (PATTERN, source);
2294 cairo_bool_t need_context_and_pattern = TRUE;
2295
2296 if (_is_current (PATTERN, source, 0) &&
2297 _is_current (CONTEXT, cr, 1))
2298 {
2299 if (obj->defined) {
2300 _consume_operand (false);
2301 } else {
2302 _trace_printf ("exch 1 index ");
2303 _exch_operands ();
2304 }
2305 need_context_and_pattern = FALSE;
2306 }
2307 else if (_is_current (PATTERN, source, 1) &&
2308 _is_current (CONTEXT, cr, 0))
2309 {
2310 if (obj->defined) {
2311 _trace_printf ("exch ");
2312 _exch_operands ();
2313 _consume_operand (false);
2314 need_context_and_pattern = FALSE;
2315 }
2316 }
2317
2318 if (need_context_and_pattern) {
2319 _emit_context (cr);
2320 _emit_pattern_id (source);
2321 }
2322
2323 _trace_printf ("set-source %% p%ld\n", obj->token);
2324 _write_unlock ();
2325 }
2326
2327 DLCALL (cairo_set_source, cr, source);
2328 _exit_trace ();
2329 }
2330
2331 cairo_pattern_t *
cairo_get_source(cairo_t * cr)2332 cairo_get_source (cairo_t *cr)
2333 {
2334 cairo_pattern_t *ret;
2335
2336 _enter_trace ();
2337
2338 ret = DLCALL (cairo_get_source, cr);
2339
2340 if (! _has_pattern_id (ret)) {
2341 _emit_cairo_op (cr, "/source get /p%ld exch def\n",
2342 _create_pattern_id (ret));
2343 _get_object (PATTERN, ret)->defined = TRUE;
2344 }
2345
2346 _exit_trace ();
2347 return ret;
2348 }
2349
2350 void
cairo_set_tolerance(cairo_t * cr,double tolerance)2351 cairo_set_tolerance (cairo_t *cr, double tolerance)
2352 {
2353 _enter_trace ();
2354 _emit_line_info ();
2355 _emit_cairo_op (cr, "%g set-tolerance\n", tolerance);
2356 DLCALL (cairo_set_tolerance, cr, tolerance);
2357 _exit_trace ();
2358 }
2359
2360 static const char *
_antialias_to_string(cairo_antialias_t antialias)2361 _antialias_to_string (cairo_antialias_t antialias)
2362 {
2363 #define f(name) case CAIRO_ANTIALIAS_ ## name: return "ANTIALIAS_" #name
2364 switch (antialias) {
2365 f(DEFAULT);
2366
2367 f(NONE);
2368 f(GRAY);
2369 f(SUBPIXEL);
2370
2371 f(FAST);
2372 f(GOOD);
2373 f(BEST);
2374 };
2375 #undef f
2376 return "UNKNOWN_ANTIALIAS";
2377 }
2378
2379 void
cairo_set_antialias(cairo_t * cr,cairo_antialias_t antialias)2380 cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias)
2381 {
2382 _enter_trace ();
2383 _emit_line_info ();
2384 _emit_cairo_op (cr,
2385 "//%s set-antialias\n", _antialias_to_string (antialias));
2386 DLCALL (cairo_set_antialias, cr, antialias);
2387 _exit_trace ();
2388 }
2389
2390 static const char *
_fill_rule_to_string(cairo_fill_rule_t rule)2391 _fill_rule_to_string (cairo_fill_rule_t rule)
2392 {
2393 #define f(name) case CAIRO_FILL_RULE_ ## name: return #name
2394 switch (rule) {
2395 f(WINDING);
2396 f(EVEN_ODD);
2397 };
2398 #undef f
2399 return "UNKNOWN_FILL_RULE";
2400 }
2401
2402 void
cairo_set_fill_rule(cairo_t * cr,cairo_fill_rule_t fill_rule)2403 cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
2404 {
2405 _enter_trace ();
2406 _emit_line_info ();
2407 _emit_cairo_op (cr,
2408 "//%s set-fill-rule\n", _fill_rule_to_string (fill_rule));
2409 DLCALL (cairo_set_fill_rule, cr, fill_rule);
2410 _exit_trace ();
2411 }
2412
2413 void
cairo_set_line_width(cairo_t * cr,double width)2414 cairo_set_line_width (cairo_t *cr, double width)
2415 {
2416 _enter_trace ();
2417 _emit_line_info ();
2418 _emit_cairo_op (cr, "%g set-line-width\n", width);
2419 DLCALL (cairo_set_line_width, cr, width);
2420 _exit_trace ();
2421 }
2422
2423 static const char *
_line_cap_to_string(cairo_line_cap_t line_cap)2424 _line_cap_to_string (cairo_line_cap_t line_cap)
2425 {
2426 #define f(name) case CAIRO_LINE_CAP_ ## name: return "LINE_CAP_" #name
2427 switch (line_cap) {
2428 f(BUTT);
2429 f(ROUND);
2430 f(SQUARE);
2431 };
2432 #undef f
2433 return "UNKNOWN_LINE_CAP";
2434 }
2435
2436 void
cairo_set_line_cap(cairo_t * cr,cairo_line_cap_t line_cap)2437 cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
2438 {
2439 _enter_trace ();
2440 _emit_line_info ();
2441 _emit_cairo_op (cr, "//%s set-line-cap\n", _line_cap_to_string (line_cap));
2442 DLCALL (cairo_set_line_cap, cr, line_cap);
2443 _exit_trace ();
2444 }
2445
2446 static const char *
_line_join_to_string(cairo_line_join_t line_join)2447 _line_join_to_string (cairo_line_join_t line_join)
2448 {
2449 #define f(name) case CAIRO_LINE_JOIN_ ## name: return "LINE_JOIN_" #name
2450 switch (line_join) {
2451 f(MITER);
2452 f(ROUND);
2453 f(BEVEL);
2454 };
2455 #undef f
2456 return "UNKNOWN_LINE_JOIN";
2457 }
2458
2459 void
cairo_set_line_join(cairo_t * cr,cairo_line_join_t line_join)2460 cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
2461 {
2462 _enter_trace ();
2463 _emit_line_info ();
2464 _emit_cairo_op (cr,
2465 "//%s set-line-join\n", _line_join_to_string (line_join));
2466 DLCALL (cairo_set_line_join, cr, line_join);
2467 _exit_trace ();
2468 }
2469
2470 void
cairo_set_dash(cairo_t * cr,const double * dashes,int num_dashes,double offset)2471 cairo_set_dash (cairo_t *cr, const double *dashes, int num_dashes, double offset)
2472 {
2473 _enter_trace ();
2474 _emit_line_info ();
2475 if (cr != NULL && _write_lock ()) {
2476 int n;
2477
2478 _emit_context (cr);
2479
2480 _trace_printf ("[");
2481 for (n = 0; n < num_dashes; n++) {
2482 if (n != 0)
2483 _trace_printf (" ");
2484 _trace_printf ("%g", dashes[n]);
2485 }
2486 _trace_printf ("] %g set-dash\n", offset);
2487
2488 _write_unlock ();
2489 }
2490
2491 DLCALL (cairo_set_dash, cr, dashes, num_dashes, offset);
2492 _exit_trace ();
2493 }
2494
2495 void
cairo_set_miter_limit(cairo_t * cr,double limit)2496 cairo_set_miter_limit (cairo_t *cr, double limit)
2497 {
2498 _enter_trace ();
2499 _emit_line_info ();
2500 _emit_cairo_op (cr, "%g set-miter-limit\n", limit);
2501 DLCALL (cairo_set_miter_limit, cr, limit);
2502 _exit_trace ();
2503 }
2504
2505 void
cairo_translate(cairo_t * cr,double tx,double ty)2506 cairo_translate (cairo_t *cr, double tx, double ty)
2507 {
2508 _enter_trace ();
2509 _emit_line_info ();
2510 _emit_cairo_op (cr, "%g %g translate\n", tx, ty);
2511 DLCALL (cairo_translate, cr, tx, ty);
2512 _exit_trace ();
2513 }
2514
2515 void
cairo_scale(cairo_t * cr,double sx,double sy)2516 cairo_scale (cairo_t *cr, double sx, double sy)
2517 {
2518 _enter_trace ();
2519 _emit_line_info ();
2520 _emit_cairo_op (cr, "%g %g scale\n", sx, sy);
2521 DLCALL (cairo_scale, cr, sx, sy);
2522 _exit_trace ();
2523 }
2524
2525 void
cairo_rotate(cairo_t * cr,double angle)2526 cairo_rotate (cairo_t *cr, double angle)
2527 {
2528 _enter_trace ();
2529 _emit_line_info ();
2530 _emit_cairo_op (cr, "%g rotate\n", angle);
2531 DLCALL (cairo_rotate, cr, angle);
2532 _exit_trace ();
2533 }
2534
2535 void
cairo_transform(cairo_t * cr,const cairo_matrix_t * matrix)2536 cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix)
2537 {
2538 _enter_trace ();
2539 _emit_line_info ();
2540 _emit_cairo_op (cr, "%g %g %g %g %g %g matrix transform\n",
2541 matrix->xx, matrix->yx,
2542 matrix->xy, matrix->yy,
2543 matrix->x0, matrix->y0);
2544 DLCALL (cairo_transform, cr, matrix);
2545 _exit_trace ();
2546 }
2547
2548 void
cairo_set_matrix(cairo_t * cr,const cairo_matrix_t * matrix)2549 cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix)
2550 {
2551 _enter_trace ();
2552 _emit_line_info ();
2553 if (_matrix_is_identity (matrix)) {
2554 _emit_cairo_op (cr, "identity set-matrix\n");
2555 } else {
2556 _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set-matrix\n",
2557 matrix->xx, matrix->yx,
2558 matrix->xy, matrix->yy,
2559 matrix->x0, matrix->y0);
2560 }
2561 DLCALL (cairo_set_matrix, cr, matrix);
2562 _exit_trace ();
2563 }
2564
2565 cairo_surface_t *
cairo_get_target(cairo_t * cr)2566 cairo_get_target (cairo_t *cr)
2567 {
2568 cairo_surface_t *ret;
2569
2570 _enter_trace ();
2571
2572 ret = DLCALL (cairo_get_target, cr);
2573 if (cr != NULL) {
2574 Object *obj = _create_surface (ret);
2575
2576 if (! obj->defined) {
2577 _emit_cairo_op (cr,
2578 "/target get /s%ld exch def\n",
2579 obj->token);
2580 obj->defined = TRUE;
2581 }
2582 }
2583
2584 _exit_trace ();
2585 return ret;
2586 }
2587
2588 cairo_surface_t *
cairo_get_group_target(cairo_t * cr)2589 cairo_get_group_target (cairo_t *cr)
2590 {
2591 cairo_surface_t *ret;
2592
2593 _enter_trace ();
2594
2595 ret = DLCALL (cairo_get_group_target, cr);
2596 if (cr != NULL) {
2597 Object *obj = _create_surface (ret);
2598
2599 if (! obj->defined) {
2600 _emit_cairo_op (cr,
2601 "/group-target get /s%ld exch def\n",
2602 obj->token);
2603 obj->defined = TRUE;
2604 }
2605 }
2606
2607 _exit_trace ();
2608 return ret;
2609 }
2610
2611 void
cairo_identity_matrix(cairo_t * cr)2612 cairo_identity_matrix (cairo_t *cr)
2613 {
2614 _enter_trace ();
2615 _emit_line_info ();
2616 _emit_cairo_op (cr, "identity set-matrix\n");
2617 DLCALL (cairo_identity_matrix, cr);
2618 _exit_trace ();
2619 }
2620
2621 void
cairo_new_path(cairo_t * cr)2622 cairo_new_path (cairo_t *cr)
2623 {
2624 _enter_trace ();
2625 _emit_line_info ();
2626 _emit_cairo_op (cr, "n ");
2627 DLCALL (cairo_new_path, cr);
2628 _exit_trace ();
2629 }
2630
2631 void
cairo_move_to(cairo_t * cr,double x,double y)2632 cairo_move_to (cairo_t *cr, double x, double y)
2633 {
2634 _enter_trace ();
2635 _emit_cairo_op (cr, "%g %g m ", x, y);
2636 DLCALL (cairo_move_to, cr, x, y);
2637 _exit_trace ();
2638 }
2639
2640 void
cairo_new_sub_path(cairo_t * cr)2641 cairo_new_sub_path (cairo_t *cr)
2642 {
2643 _enter_trace ();
2644 _emit_cairo_op (cr, "N ");
2645 DLCALL (cairo_new_sub_path, cr);
2646 _exit_trace ();
2647 }
2648
2649 void
cairo_line_to(cairo_t * cr,double x,double y)2650 cairo_line_to (cairo_t *cr, double x, double y)
2651 {
2652 _enter_trace ();
2653 _emit_cairo_op (cr, "%g %g l ", x, y);
2654 DLCALL (cairo_line_to, cr, x, y);
2655 _exit_trace ();
2656 }
2657
2658 void
cairo_curve_to(cairo_t * cr,double x1,double y1,double x2,double y2,double x3,double y3)2659 cairo_curve_to (cairo_t *cr, double x1, double y1, double x2, double y2, double x3, double y3)
2660 {
2661 _enter_trace ();
2662 _emit_cairo_op (cr, "%g %g %g %g %g %g c ", x1, y1, x2, y2, x3, y3);
2663 DLCALL (cairo_curve_to, cr, x1, y1, x2, y2, x3, y3);
2664 _exit_trace ();
2665 }
2666
2667 void
cairo_arc(cairo_t * cr,double xc,double yc,double radius,double angle1,double angle2)2668 cairo_arc (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2)
2669 {
2670 _enter_trace ();
2671 _emit_cairo_op (cr, "%g %g %g %g %g arc\n", xc, yc, radius, angle1, angle2);
2672 DLCALL (cairo_arc, cr, xc, yc, radius, angle1, angle2);
2673 _exit_trace ();
2674 }
2675
2676 void
cairo_arc_negative(cairo_t * cr,double xc,double yc,double radius,double angle1,double angle2)2677 cairo_arc_negative (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2)
2678 {
2679 _enter_trace ();
2680 _emit_cairo_op (cr, "%g %g %g %g %g arc-\n",
2681 xc, yc, radius, angle1, angle2);
2682 DLCALL (cairo_arc_negative, cr, xc, yc, radius, angle1, angle2);
2683 _exit_trace ();
2684 }
2685
2686 void
cairo_rel_move_to(cairo_t * cr,double dx,double dy)2687 cairo_rel_move_to (cairo_t *cr, double dx, double dy)
2688 {
2689 _enter_trace ();
2690 _emit_cairo_op (cr, "%g %g M ", dx, dy);
2691 DLCALL (cairo_rel_move_to, cr, dx, dy);
2692 _exit_trace ();
2693 }
2694
2695 void
cairo_rel_line_to(cairo_t * cr,double dx,double dy)2696 cairo_rel_line_to (cairo_t *cr, double dx, double dy)
2697 {
2698 _enter_trace ();
2699 _emit_cairo_op (cr, "%g %g L ", dx, dy);
2700 DLCALL (cairo_rel_line_to, cr, dx, dy);
2701 _exit_trace ();
2702 }
2703
2704 void
cairo_rel_curve_to(cairo_t * cr,double dx1,double dy1,double dx2,double dy2,double dx3,double dy3)2705 cairo_rel_curve_to (cairo_t *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3)
2706 {
2707 _enter_trace ();
2708 _emit_cairo_op (cr, "%g %g %g %g %g %g C ",
2709 dx1, dy1, dx2, dy2, dx3, dy3);
2710 DLCALL (cairo_rel_curve_to, cr, dx1, dy1, dx2, dy2, dx3, dy3);
2711 _exit_trace ();
2712 }
2713
2714 void
cairo_rectangle(cairo_t * cr,double x,double y,double width,double height)2715 cairo_rectangle (cairo_t *cr, double x, double y, double width, double height)
2716 {
2717 _enter_trace ();
2718 _emit_cairo_op (cr, "%g %g %g %g rectangle\n", x, y, width, height);
2719 DLCALL (cairo_rectangle, cr, x, y, width, height);
2720 _exit_trace ();
2721 }
2722
2723 void
cairo_close_path(cairo_t * cr)2724 cairo_close_path (cairo_t *cr)
2725 {
2726 _enter_trace ();
2727 _emit_cairo_op (cr, "h\n");
2728 DLCALL (cairo_close_path, cr);
2729 _exit_trace ();
2730 }
2731
2732 void
cairo_paint(cairo_t * cr)2733 cairo_paint (cairo_t *cr)
2734 {
2735 _enter_trace ();
2736 _emit_line_info ();
2737 _emit_cairo_op (cr, "paint\n");
2738 DLCALL (cairo_paint, cr);
2739 _exit_trace ();
2740 }
2741
2742 void
cairo_paint_with_alpha(cairo_t * cr,double alpha)2743 cairo_paint_with_alpha (cairo_t *cr, double alpha)
2744 {
2745 _enter_trace ();
2746 _emit_line_info ();
2747 _emit_cairo_op (cr, "%g paint-with-alpha\n", alpha);
2748 DLCALL (cairo_paint_with_alpha, cr, alpha);
2749 _exit_trace ();
2750 }
2751
2752 void
cairo_mask(cairo_t * cr,cairo_pattern_t * pattern)2753 cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
2754 {
2755 _enter_trace ();
2756 _emit_line_info ();
2757 if (cr != NULL && pattern != NULL && _write_lock ()) {
2758 Object *obj = _get_object (PATTERN, pattern);
2759 cairo_bool_t need_context_and_pattern = TRUE;
2760
2761 if (_is_current (PATTERN, pattern, 0) &&
2762 _is_current (CONTEXT, cr, 1))
2763 {
2764 if (obj->defined) {
2765 _consume_operand (false);
2766 need_context_and_pattern = FALSE;
2767 }
2768 }
2769 else if (_is_current (PATTERN, pattern, 1) &&
2770 _is_current (CONTEXT, cr, 0))
2771 {
2772 if (obj->defined) {
2773 _trace_printf ("exch ");
2774 _exch_operands ();
2775 _consume_operand (false);
2776 need_context_and_pattern = FALSE;
2777 }
2778 }
2779
2780 if (need_context_and_pattern) {
2781 _emit_context (cr);
2782 _emit_pattern_id (pattern);
2783 }
2784
2785 _trace_printf (" mask\n");
2786 _write_unlock ();
2787 }
2788 DLCALL (cairo_mask, cr, pattern);
2789 _exit_trace ();
2790 }
2791
2792 void
cairo_mask_surface(cairo_t * cr,cairo_surface_t * surface,double x,double y)2793 cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y)
2794 {
2795 _enter_trace ();
2796 _emit_line_info ();
2797 if (cr != NULL && surface != NULL && _write_lock ()) {
2798 Object *obj = _get_object (SURFACE, surface);
2799 if (_is_current (SURFACE, surface, 0) &&
2800 _is_current (CONTEXT, cr, 1))
2801 {
2802 _consume_operand (false);
2803 }
2804 else if (_is_current (SURFACE, surface, 1) &&
2805 _is_current (CONTEXT, cr, 0))
2806 {
2807 _trace_printf ("exch ");
2808 _exch_operands ();
2809 _consume_operand (false);
2810 } else if (obj->defined){
2811 _emit_context (cr);
2812 _trace_printf ("s%ld ", obj->token);
2813 } else {
2814 _emit_context (cr);
2815 _trace_printf ("%d index ",
2816 current_stack_depth - obj->operand - 1);
2817 }
2818 _trace_printf ("pattern");
2819
2820 if (x != 0. || y != 0.)
2821 _trace_printf (" %g %g translate", -x, -y);
2822
2823 _trace_printf (" mask\n");
2824 _write_unlock ();
2825 }
2826
2827 DLCALL (cairo_mask_surface, cr, surface, x, y);
2828 _exit_trace ();
2829 }
2830
2831 void
cairo_stroke(cairo_t * cr)2832 cairo_stroke (cairo_t *cr)
2833 {
2834 _enter_trace ();
2835 _emit_line_info ();
2836 _emit_cairo_op (cr, "stroke\n");
2837 DLCALL (cairo_stroke, cr);
2838 _exit_trace ();
2839 }
2840
2841 void
cairo_stroke_preserve(cairo_t * cr)2842 cairo_stroke_preserve (cairo_t *cr)
2843 {
2844 _enter_trace ();
2845 _emit_line_info ();
2846 _emit_cairo_op (cr, "stroke+\n");
2847 DLCALL (cairo_stroke_preserve, cr);
2848 _exit_trace ();
2849 }
2850
2851 void
cairo_fill(cairo_t * cr)2852 cairo_fill (cairo_t *cr)
2853 {
2854 _enter_trace ();
2855 _emit_line_info ();
2856 _emit_cairo_op (cr, "fill\n");
2857 DLCALL (cairo_fill, cr);
2858 _exit_trace ();
2859 }
2860
2861 void
cairo_fill_preserve(cairo_t * cr)2862 cairo_fill_preserve (cairo_t *cr)
2863 {
2864 _enter_trace ();
2865 _emit_line_info ();
2866 _emit_cairo_op (cr, "fill+\n");
2867 DLCALL (cairo_fill_preserve, cr);
2868 _exit_trace ();
2869 }
2870
2871 void
cairo_copy_page(cairo_t * cr)2872 cairo_copy_page (cairo_t *cr)
2873 {
2874 _enter_trace ();
2875 _emit_line_info ();
2876 _emit_cairo_op (cr, "copy-page\n");
2877 DLCALL (cairo_copy_page, cr);
2878 _exit_trace ();
2879 }
2880
2881 void
cairo_show_page(cairo_t * cr)2882 cairo_show_page (cairo_t *cr)
2883 {
2884 _enter_trace ();
2885 _emit_line_info ();
2886 _emit_cairo_op (cr, "show-page\n");
2887 DLCALL (cairo_show_page, cr);
2888 _exit_trace ();
2889 }
2890
2891 void
cairo_clip(cairo_t * cr)2892 cairo_clip (cairo_t *cr)
2893 {
2894 _enter_trace ();
2895 _emit_line_info ();
2896 _emit_cairo_op (cr, "clip\n");
2897 DLCALL (cairo_clip, cr);
2898 _exit_trace ();
2899 }
2900
2901 void
cairo_clip_preserve(cairo_t * cr)2902 cairo_clip_preserve (cairo_t *cr)
2903 {
2904 _enter_trace ();
2905 _emit_line_info ();
2906 _emit_cairo_op (cr, "clip+\n");
2907 DLCALL (cairo_clip_preserve, cr);
2908 _exit_trace ();
2909 }
2910
2911 void
cairo_reset_clip(cairo_t * cr)2912 cairo_reset_clip (cairo_t *cr)
2913 {
2914 _enter_trace ();
2915 _emit_line_info ();
2916 _emit_cairo_op (cr, "reset-clip\n");
2917 DLCALL (cairo_reset_clip, cr);
2918 _exit_trace ();
2919 }
2920
2921
2922 static const char *
_slant_to_string(cairo_font_slant_t font_slant)2923 _slant_to_string (cairo_font_slant_t font_slant)
2924 {
2925 #define f(name) case CAIRO_FONT_SLANT_ ## name: return "SLANT_" #name
2926 switch (font_slant) {
2927 f(NORMAL);
2928 f(ITALIC);
2929 f(OBLIQUE);
2930 };
2931 #undef f
2932 return "UNKNOWN_SLANT";
2933 }
2934
2935 static const char *
_weight_to_string(cairo_font_weight_t font_weight)2936 _weight_to_string (cairo_font_weight_t font_weight)
2937 {
2938 #define f(name) case CAIRO_FONT_WEIGHT_ ## name: return "WEIGHT_" #name
2939 switch (font_weight) {
2940 f(NORMAL);
2941 f(BOLD);
2942 };
2943 #undef f
2944 return "UNKNOWN_WEIGHT";
2945 }
2946
2947 void
cairo_select_font_face(cairo_t * cr,const char * family,cairo_font_slant_t slant,cairo_font_weight_t weight)2948 cairo_select_font_face (cairo_t *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight)
2949 {
2950 _enter_trace ();
2951 _emit_line_info ();
2952 if (cr != NULL && _write_lock ()) {
2953 _emit_context (cr);
2954 _emit_string_literal (family, -1);
2955 _trace_printf (" //%s //%s select-font-face\n",
2956 _slant_to_string (slant),
2957 _weight_to_string (weight));
2958 _write_unlock ();
2959 }
2960 DLCALL (cairo_select_font_face, cr, family, slant, weight);
2961 _exit_trace ();
2962 }
2963
2964 cairo_font_face_t *
cairo_get_font_face(cairo_t * cr)2965 cairo_get_font_face (cairo_t *cr)
2966 {
2967 cairo_font_face_t *ret;
2968 long font_face_id;
2969
2970 _enter_trace ();
2971
2972 ret = DLCALL (cairo_get_font_face, cr);
2973 font_face_id = _create_font_face_id (ret);
2974
2975 _emit_cairo_op (cr, "/font-face get %% f%ld\n", font_face_id);
2976 _push_operand (FONT_FACE, ret);
2977 dump_stack(__func__);
2978
2979 _exit_trace ();
2980 return ret;
2981 }
2982
2983 void
cairo_set_font_face(cairo_t * cr,cairo_font_face_t * font_face)2984 cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face)
2985 {
2986 _enter_trace ();
2987 _emit_line_info ();
2988 if (cr != NULL && font_face != NULL && _write_lock ()) {
2989 if (_is_current (FONT_FACE, font_face, 0) &&
2990 _is_current (CONTEXT, cr, 1))
2991 {
2992 _consume_operand (false);
2993 }
2994 else if (_is_current (FONT_FACE, font_face, 1) &&
2995 _is_current (CONTEXT, cr, 0))
2996 {
2997 _trace_printf ("exch ");
2998 _exch_operands ();
2999 _consume_operand (false);
3000 }
3001 else
3002 {
3003 _emit_context (cr);
3004 _emit_font_face_id (font_face);
3005 }
3006
3007 _trace_printf ("set-font-face\n");
3008 _write_unlock ();
3009 }
3010
3011 DLCALL (cairo_set_font_face, cr, font_face);
3012 _exit_trace ();
3013 }
3014
3015 void
cairo_set_font_size(cairo_t * cr,double size)3016 cairo_set_font_size (cairo_t *cr, double size)
3017 {
3018 _enter_trace ();
3019 _emit_line_info ();
3020 _emit_cairo_op (cr, "%g set-font-size\n", size);
3021 DLCALL (cairo_set_font_size, cr, size);
3022 _exit_trace ();
3023 }
3024
3025 void
cairo_set_font_matrix(cairo_t * cr,const cairo_matrix_t * matrix)3026 cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix)
3027 {
3028 _enter_trace ();
3029 _emit_line_info ();
3030 _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set-font-matrix\n",
3031 matrix->xx, matrix->yx,
3032 matrix->xy, matrix->yy,
3033 matrix->x0, matrix->y0);
3034 DLCALL (cairo_set_font_matrix, cr, matrix);
3035 _exit_trace ();
3036 }
3037
3038 static const char *
_subpixel_order_to_string(cairo_subpixel_order_t subpixel_order)3039 _subpixel_order_to_string (cairo_subpixel_order_t subpixel_order)
3040 {
3041 #define f(name) case CAIRO_SUBPIXEL_ORDER_ ## name: return "SUBPIXEL_ORDER_" #name
3042 switch (subpixel_order) {
3043 f(DEFAULT);
3044 f(RGB);
3045 f(BGR);
3046 f(VRGB);
3047 f(VBGR);
3048 };
3049 #undef f
3050 return "UNKNOWN_SUBPIXEL_ORDER";
3051 }
3052
3053 static const char *
_hint_style_to_string(cairo_hint_style_t hint_style)3054 _hint_style_to_string (cairo_hint_style_t hint_style)
3055 {
3056 #define f(name) case CAIRO_HINT_STYLE_ ## name: return "HINT_STYLE_" #name
3057 switch (hint_style) {
3058 f(DEFAULT);
3059 f(NONE);
3060 f(SLIGHT);
3061 f(MEDIUM);
3062 f(FULL);
3063 };
3064 #undef f
3065 return "UNKNOWN_HINT_STYLE";
3066 }
3067
3068 static const char *
_hint_metrics_to_string(cairo_hint_metrics_t hint_metrics)3069 _hint_metrics_to_string (cairo_hint_metrics_t hint_metrics)
3070 {
3071 #define f(name) case CAIRO_HINT_METRICS_ ## name: return "HINT_METRICS_" #name
3072 switch (hint_metrics) {
3073 f(DEFAULT);
3074 f(OFF);
3075 f(ON);
3076 };
3077 #undef f
3078 return "UNKNOWN_HINT_METRICS";
3079 }
3080
3081 static void
_emit_font_options(const cairo_font_options_t * options)3082 _emit_font_options (const cairo_font_options_t *options)
3083 {
3084 cairo_antialias_t antialias;
3085 cairo_subpixel_order_t subpixel_order;
3086 cairo_hint_style_t hint_style;
3087 cairo_hint_metrics_t hint_metrics;
3088
3089 _trace_printf ("<<");
3090
3091 antialias = DLCALL (cairo_font_options_get_antialias, options);
3092 if (antialias != CAIRO_ANTIALIAS_DEFAULT) {
3093 _trace_printf (" /antialias //%s",
3094 _antialias_to_string (antialias));
3095 }
3096
3097 subpixel_order = DLCALL (cairo_font_options_get_subpixel_order, options);
3098 if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
3099 _trace_printf (" /subpixel-order //%s",
3100 _subpixel_order_to_string (subpixel_order));
3101 }
3102
3103 hint_style = DLCALL (cairo_font_options_get_hint_style, options);
3104 if (hint_style != CAIRO_HINT_STYLE_DEFAULT) {
3105 _trace_printf (" /hint-style //%s",
3106 _hint_style_to_string (hint_style));
3107 }
3108
3109 hint_metrics = DLCALL (cairo_font_options_get_hint_metrics, options);
3110 if (hint_metrics != CAIRO_HINT_METRICS_DEFAULT) {
3111 _trace_printf (" /hint-metrics //%s",
3112 _hint_metrics_to_string (hint_metrics));
3113 }
3114
3115 _trace_printf (" >>");
3116 }
3117
3118 void
cairo_set_font_options(cairo_t * cr,const cairo_font_options_t * options)3119 cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options)
3120 {
3121 _enter_trace ();
3122 _emit_line_info ();
3123 if (cr != NULL && options != NULL && _write_lock ()) {
3124 _emit_context (cr);
3125 _emit_font_options (options);
3126 _trace_printf (" set-font-options\n");
3127 _write_unlock ();
3128 }
3129
3130 DLCALL (cairo_set_font_options, cr, options);
3131 _exit_trace ();
3132 }
3133
3134 cairo_scaled_font_t *
cairo_get_scaled_font(cairo_t * cr)3135 cairo_get_scaled_font (cairo_t *cr)
3136 {
3137 cairo_scaled_font_t *ret;
3138
3139 _enter_trace ();
3140
3141 ret = DLCALL (cairo_get_scaled_font, cr);
3142
3143 if (cr != NULL && ! _has_scaled_font_id (ret)) {
3144 _emit_cairo_op (cr, "/scaled-font get /sf%ld exch def\n",
3145 _create_scaled_font_id (ret));
3146 _get_object (SCALED_FONT, ret)->defined = TRUE;
3147 }
3148
3149 _exit_trace ();
3150 return ret;
3151 }
3152
3153 void
cairo_set_scaled_font(cairo_t * cr,const cairo_scaled_font_t * scaled_font)3154 cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font)
3155 {
3156 _enter_trace ();
3157 _emit_line_info ();
3158 if (cr != NULL && scaled_font != NULL && _write_lock ()) {
3159 Object *obj = _get_object (SCALED_FONT, scaled_font);
3160 cairo_bool_t need_context_and_font = TRUE;
3161
3162 if (_is_current (SCALED_FONT, scaled_font, 0) &&
3163 _is_current (CONTEXT, cr, 1))
3164 {
3165 if (obj->defined) {
3166 _consume_operand (false);
3167 } else {
3168 _trace_printf ("exch 1 index ");
3169 _exch_operands ();
3170 }
3171 need_context_and_font = FALSE;
3172 }
3173 else if (_is_current (SCALED_FONT, scaled_font, 1) &&
3174 _is_current (CONTEXT, cr, 0))
3175 {
3176 if (obj->defined) {
3177 _trace_printf ("exch ");
3178 _exch_operands ();
3179 _consume_operand (false);
3180 need_context_and_font = FALSE;
3181 }
3182 }
3183
3184 if (need_context_and_font) {
3185 _emit_context (cr);
3186 _emit_scaled_font_id (scaled_font);
3187 }
3188
3189 _trace_printf ("set-scaled-font\n");
3190
3191 _write_unlock ();
3192 }
3193 DLCALL (cairo_set_scaled_font, cr, scaled_font);
3194 _exit_trace ();
3195 }
3196
3197 static void
_emit_matrix(const cairo_matrix_t * m)3198 _emit_matrix (const cairo_matrix_t *m)
3199 {
3200 if (_matrix_is_identity(m))
3201 {
3202 _trace_printf ("identity");
3203 }
3204 else
3205 {
3206 _trace_printf ("%g %g %g %g %g %g matrix",
3207 m->xx, m->yx,
3208 m->xy, m->yy,
3209 m->x0, m->y0);
3210 }
3211 }
3212
3213 cairo_scaled_font_t *
cairo_scaled_font_create(cairo_font_face_t * font_face,const cairo_matrix_t * font_matrix,const cairo_matrix_t * ctm,const cairo_font_options_t * options)3214 cairo_scaled_font_create (cairo_font_face_t *font_face,
3215 const cairo_matrix_t *font_matrix,
3216 const cairo_matrix_t *ctm,
3217 const cairo_font_options_t *options)
3218 {
3219 cairo_scaled_font_t *ret;
3220
3221 _enter_trace ();
3222
3223 ret = DLCALL (cairo_scaled_font_create, font_face, font_matrix, ctm, options);
3224 if (_has_scaled_font_id (ret))
3225 goto out;
3226
3227 _emit_line_info ();
3228 if (font_face != NULL &&
3229 font_matrix != NULL &&
3230 ctm != NULL &&
3231 options != NULL
3232 && _write_lock ())
3233 {
3234 Object *obj;
3235
3236 obj = _type_object_create (SCALED_FONT, ret);
3237 DLCALL (cairo_scaled_font_set_user_data,
3238 ret, &destroy_key, obj, _object_undef);
3239
3240 if (_pop_operands_to (FONT_FACE, font_face))
3241 _consume_operand (false);
3242 else
3243 _trace_printf ("f%ld ", _get_font_face_id (font_face));
3244
3245 _emit_matrix (font_matrix);
3246 _trace_printf (" ");
3247
3248 _emit_matrix (ctm);
3249 _trace_printf (" ");
3250
3251 _emit_font_options (options);
3252
3253 _trace_printf (" scaled-font /sf%ld exch def\n",
3254 obj->token);
3255 obj->defined = TRUE;
3256
3257 _write_unlock ();
3258 }
3259
3260 out:
3261 _exit_trace ();
3262 return ret;
3263 }
3264
3265 void
cairo_show_text(cairo_t * cr,const char * utf8)3266 cairo_show_text (cairo_t *cr, const char *utf8)
3267 {
3268 _enter_trace ();
3269 _emit_line_info ();
3270 if (cr != NULL && _write_lock ()) {
3271 _emit_context (cr);
3272 _emit_string_literal (utf8, -1);
3273 _trace_printf (" show-text\n");
3274 _write_unlock ();
3275 }
3276 DLCALL (cairo_show_text, cr, utf8);
3277 _exit_trace ();
3278 }
3279
3280 static void
_glyph_advance(cairo_scaled_font_t * font,const cairo_glyph_t * glyph,double * x,double * y)3281 _glyph_advance (cairo_scaled_font_t *font,
3282 const cairo_glyph_t *glyph,
3283 double *x, double *y)
3284 {
3285 cairo_text_extents_t extents;
3286
3287 DLCALL (cairo_scaled_font_glyph_extents, font, glyph, 1, &extents);
3288 *x += extents.x_advance;
3289 *y += extents.y_advance;
3290 }
3291
3292 #define TOLERANCE 1e-5
3293 static void
_emit_glyphs(cairo_scaled_font_t * font,const cairo_glyph_t * glyphs,int num_glyphs)3294 _emit_glyphs (cairo_scaled_font_t *font,
3295 const cairo_glyph_t *glyphs,
3296 int num_glyphs)
3297 {
3298 double x,y;
3299 int n;
3300
3301 if (num_glyphs == 0) {
3302 _trace_printf ("[]");
3303 return;
3304 }
3305
3306 for (n = 0; n < num_glyphs; n++) {
3307 if (glyphs[n].index > 255)
3308 break;
3309 }
3310
3311 x = glyphs->x;
3312 y = glyphs->y;
3313 if (n < num_glyphs) { /* need full glyph range */
3314 cairo_bool_t first;
3315
3316 _trace_printf ("[%g %g [", x, y);
3317 first = TRUE;
3318 while (num_glyphs--) {
3319 if (fabs (glyphs->x - x) > TOLERANCE ||
3320 fabs (glyphs->y - y) > TOLERANCE)
3321 {
3322 x = glyphs->x;
3323 y = glyphs->y;
3324 _trace_printf ("] %g %g [", x, y);
3325 first = TRUE;
3326 }
3327
3328 if (! first)
3329 _trace_printf (" ");
3330 _trace_printf ("%lu", glyphs->index);
3331 first = FALSE;
3332
3333 _glyph_advance (font, glyphs, &x, &y);
3334 glyphs++;
3335 }
3336 _trace_printf ("]]");
3337 } else {
3338 struct _data_stream stream;
3339
3340 if (num_glyphs == 1) {
3341 _trace_printf ("[%g %g <%02lx>]", x, y, glyphs->index);
3342 } else {
3343 _trace_printf ("[%g %g <~", x, y);
3344 _write_base85_data_start (&stream);
3345 while (num_glyphs--) {
3346 unsigned char c;
3347
3348 if (fabs (glyphs->x - x) > TOLERANCE ||
3349 fabs (glyphs->y - y) > TOLERANCE)
3350 {
3351 x = glyphs->x;
3352 y = glyphs->y;
3353 _write_base85_data_end (&stream);
3354 _trace_printf ("~> %g %g <~", x, y);
3355 _write_base85_data_start (&stream);
3356 }
3357
3358 c = glyphs->index;
3359 _write_base85_data (&stream, &c, 1);
3360
3361 _glyph_advance (font, glyphs, &x, &y);
3362 glyphs++;
3363 }
3364 _write_base85_data_end (&stream);
3365 _trace_printf ("~>]");
3366 }
3367 }
3368 }
3369
3370 void
cairo_show_glyphs(cairo_t * cr,const cairo_glyph_t * glyphs,int num_glyphs)3371 cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
3372 {
3373 _enter_trace ();
3374 _emit_line_info ();
3375 if (cr != NULL && glyphs != NULL && _write_lock ()) {
3376 cairo_scaled_font_t *font;
3377
3378 _emit_context (cr);
3379 font = DLCALL (cairo_get_scaled_font, cr);
3380
3381 _emit_glyphs (font, glyphs, num_glyphs);
3382 _trace_printf (" show-glyphs\n");
3383 _write_unlock ();
3384 }
3385
3386 DLCALL (cairo_show_glyphs, cr, glyphs, num_glyphs);
3387 _exit_trace ();
3388 }
3389
3390 static const char *
_direction_to_string(cairo_bool_t backward)3391 _direction_to_string (cairo_bool_t backward)
3392 {
3393 const char *names[] = {
3394 "FORWARD",
3395 "BACKWARD"
3396 };
3397 return names[!!backward];
3398 }
3399
3400 void
cairo_show_text_glyphs(cairo_t * cr,const char * utf8,int utf8_len,const cairo_glyph_t * glyphs,int num_glyphs,const cairo_text_cluster_t * clusters,int num_clusters,cairo_text_cluster_flags_t backward)3401 cairo_show_text_glyphs (cairo_t *cr,
3402 const char *utf8,
3403 int utf8_len,
3404 const cairo_glyph_t *glyphs,
3405 int num_glyphs,
3406 const cairo_text_cluster_t *clusters,
3407 int num_clusters,
3408 cairo_text_cluster_flags_t backward)
3409 {
3410 cairo_scaled_font_t *font;
3411
3412 _enter_trace ();
3413
3414 font = DLCALL (cairo_get_scaled_font, cr);
3415
3416 _emit_line_info ();
3417 if (cr != NULL && glyphs != NULL && clusters != NULL && _write_lock ()) {
3418 int n;
3419
3420 _emit_context (cr);
3421
3422 _emit_string_literal (utf8, utf8_len);
3423
3424 _emit_glyphs (font, glyphs, num_glyphs);
3425 _trace_printf (" [");
3426 for (n = 0; n < num_clusters; n++) {
3427 _trace_printf (" %d %d",
3428 clusters[n].num_bytes,
3429 clusters[n].num_glyphs);
3430 }
3431 _trace_printf (" ] //%s show-text-glyphs\n",
3432 _direction_to_string (backward));
3433
3434 _write_unlock ();
3435 }
3436
3437 DLCALL (cairo_show_text_glyphs, cr,
3438 utf8, utf8_len,
3439 glyphs, num_glyphs,
3440 clusters, num_clusters,
3441 backward);
3442 _exit_trace ();
3443 }
3444
3445 void
cairo_text_path(cairo_t * cr,const char * utf8)3446 cairo_text_path (cairo_t *cr, const char *utf8)
3447 {
3448 _enter_trace ();
3449 _emit_line_info ();
3450 if (cr != NULL && _write_lock ()) {
3451 _emit_context (cr);
3452 _emit_string_literal (utf8, -1);
3453 _trace_printf (" text-path\n");
3454 _write_unlock ();
3455 }
3456 DLCALL (cairo_text_path, cr, utf8);
3457 _exit_trace ();
3458 }
3459
3460 void
cairo_glyph_path(cairo_t * cr,const cairo_glyph_t * glyphs,int num_glyphs)3461 cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
3462 {
3463 cairo_scaled_font_t *font;
3464
3465 _enter_trace ();
3466
3467 font = DLCALL (cairo_get_scaled_font, cr);
3468
3469 _emit_line_info ();
3470 if (cr != NULL && glyphs != NULL && _write_lock ()) {
3471 _emit_context (cr);
3472 _emit_glyphs (font, glyphs, num_glyphs);
3473 _trace_printf (" glyph-path\n");
3474
3475 _write_unlock ();
3476 }
3477
3478 DLCALL (cairo_glyph_path, cr, glyphs, num_glyphs);
3479 _exit_trace ();
3480 }
3481
3482 void
cairo_append_path(cairo_t * cr,const cairo_path_t * path)3483 cairo_append_path (cairo_t *cr, const cairo_path_t *path)
3484 {
3485 /* XXX no support for named paths, so manually reconstruct */
3486 int i;
3487 cairo_path_data_t *p;
3488
3489 _enter_trace ();
3490
3491 _emit_line_info ();
3492 if (cr == NULL || path == NULL) {
3493 DLCALL (cairo_append_path, cr, path);
3494 _exit_trace ();
3495 return;
3496 }
3497
3498 for (i=0; i < path->num_data; i += path->data[i].header.length) {
3499 p = &path->data[i];
3500 switch (p->header.type) {
3501 case CAIRO_PATH_MOVE_TO:
3502 if (p->header.length >= 2)
3503 cairo_move_to (cr, p[1].point.x, p[1].point.y);
3504 break;
3505 case CAIRO_PATH_LINE_TO:
3506 if (p->header.length >= 2)
3507 cairo_line_to (cr, p[1].point.x, p[1].point.y);
3508 break;
3509 case CAIRO_PATH_CURVE_TO:
3510 if (p->header.length >= 4)
3511 cairo_curve_to (cr,
3512 p[1].point.x, p[1].point.y,
3513 p[2].point.x, p[2].point.y,
3514 p[3].point.x, p[3].point.y);
3515 break;
3516 case CAIRO_PATH_CLOSE_PATH:
3517 if (p->header.length >= 1)
3518 cairo_close_path (cr);
3519 break;
3520 default:
3521 break;
3522 }
3523 }
3524 _exit_trace ();
3525 }
3526
3527 cairo_surface_t *
cairo_image_surface_create(cairo_format_t format,int width,int height)3528 cairo_image_surface_create (cairo_format_t format, int width, int height)
3529 {
3530 cairo_surface_t *ret;
3531
3532 _enter_trace ();
3533
3534 ret = DLCALL (cairo_image_surface_create, format, width, height);
3535
3536 _emit_line_info ();
3537 if (_write_lock ()) {
3538 Object *obj = _create_surface (ret);
3539 const char *format_str = _format_to_string (format);
3540 const char *content_str = _format_to_content_string (format);
3541
3542 _trace_printf ("dict\n"
3543 " /width %d set\n"
3544 " /height %d set\n"
3545 " /format //%s set\n"
3546 " /content //%s set\n"
3547 " image dup /s%ld exch def\n",
3548 width, height, format_str, content_str, obj->token);
3549 obj->width = width;
3550 obj->height = height;
3551 obj->defined = TRUE;
3552 _push_object (obj);
3553 dump_stack(__func__);
3554 _write_unlock ();
3555 }
3556
3557 _exit_trace ();
3558 return ret;
3559 }
3560
3561 cairo_surface_t *
cairo_image_surface_create_for_data(unsigned char * data,cairo_format_t format,int width,int height,int stride)3562 cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, int width, int height, int stride)
3563 {
3564 cairo_surface_t *ret;
3565
3566 _enter_trace ();
3567
3568 ret = DLCALL (cairo_image_surface_create_for_data, data, format, width, height, stride);
3569
3570 _emit_line_info ();
3571 if (_write_lock ()) {
3572 Object *obj = _create_surface (ret);
3573
3574 /* cairo_image_surface_create_for_data() is both used to supply
3575 * foreign pixel data to cairo and in order to read pixels back.
3576 * Defer grabbing the pixel contents until we have to, but only for
3577 * "large" images, for small images the overhead of embedding pixels
3578 * is negligible.
3579 *
3580 * Choose 32x32 as that captures most icons which thanks to GdkPixbuf
3581 * are frequently reloaded.
3582 */
3583 if (width * height < 32*32) {
3584 _emit_image (ret, NULL);
3585 _trace_printf (" dup /s%ld exch def\n",
3586 obj->token);
3587 } else {
3588 _trace_printf ("dict\n"
3589 " /width %d set\n"
3590 " /height %d set\n"
3591 " /format //%s set\n"
3592 " image dup /s%ld exch def\n",
3593 width, height,
3594 _format_to_string (format),
3595 obj->token);
3596
3597 obj->foreign = TRUE;
3598 }
3599
3600 obj->width = width;
3601 obj->height = height;
3602 obj->defined = TRUE;
3603 _push_object (obj);
3604 dump_stack(__func__);
3605 _write_unlock ();
3606 }
3607
3608 _exit_trace ();
3609 return ret;
3610 }
3611
3612 unsigned char *
cairo_image_surface_get_data(cairo_surface_t * surface)3613 cairo_image_surface_get_data (cairo_surface_t *surface)
3614 {
3615 unsigned char *ptr;
3616
3617 /* Just leave some breadcrumbs */
3618 _enter_trace ();
3619 _emit_line_info ();
3620 if (surface != NULL && _write_lock ()) {
3621 _trace_printf ("%% s%ld get-data\n", _get_surface_id (surface));
3622 _write_unlock ();
3623 }
3624 ptr = DLCALL (cairo_image_surface_get_data, surface);
3625 _exit_trace ();
3626
3627 return ptr;
3628 }
3629
3630 cairo_pattern_t *
cairo_pattern_create_raster_source(void * data,cairo_content_t content,int width,int height)3631 cairo_pattern_create_raster_source (void *data, cairo_content_t content, int width, int height)
3632 {
3633 cairo_pattern_t *ret;
3634
3635 _enter_trace ();
3636
3637 ret = DLCALL (cairo_pattern_create_raster_source, data, content, width, height);
3638
3639 _emit_line_info ();
3640 if (_write_lock ()) {
3641 long pattern_id = _create_pattern_id (ret);
3642 cairo_format_t format;
3643 cairo_surface_t *image;
3644 cairo_t *cr;
3645
3646 /* Impossible to accurately record the interaction with this custom
3647 * pattern so just suck all the data into an image upfront */
3648 switch (content) {
3649 case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break;
3650 case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break;
3651 default:
3652 case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break;
3653 }
3654
3655 _trace_printf ("%% raster-source\n");
3656
3657 image = DLCALL (cairo_image_surface_create, format, width, height);
3658 cr = DLCALL (cairo_create, image);
3659 DLCALL (cairo_set_source, cr, ret);
3660 DLCALL (cairo_paint, cr);
3661 DLCALL (cairo_destroy, cr);
3662
3663 _emit_image (image, NULL);
3664 DLCALL (cairo_surface_destroy, image);
3665 _trace_printf (" pattern dup /s%ld exch def\n",
3666 pattern_id);
3667
3668 _push_operand (PATTERN, ret);
3669 _get_object (PATTERN, ret)->defined = TRUE;
3670 dump_stack(__func__);
3671 _write_unlock ();
3672 }
3673
3674 _exit_trace ();
3675 return ret;
3676 }
3677
3678 cairo_surface_t *
cairo_surface_create_similar(cairo_surface_t * other,cairo_content_t content,int width,int height)3679 cairo_surface_create_similar (cairo_surface_t *other,
3680 cairo_content_t content,
3681 int width, int height)
3682 {
3683 cairo_surface_t *ret;
3684
3685 _enter_trace ();
3686
3687 ret = DLCALL (cairo_surface_create_similar, other, content, width, height);
3688
3689 _emit_line_info ();
3690 if (other != NULL && _write_lock ()) {
3691 Object *other_obj = _get_object(SURFACE, other);
3692 Object *new_obj = _create_surface (ret);
3693
3694 if (other_obj->operand != -1) {
3695 if (current_stack_depth == other_obj->operand + 1)
3696 _trace_printf ("dup ");
3697 else
3698 _trace_printf ("%d index ",
3699 current_stack_depth - other_obj->operand - 1);
3700 } else {
3701 assert(other_obj->defined);
3702 _trace_printf ("s%ld ", other_obj->token);
3703 }
3704
3705 _trace_printf ("%d %d //%s similar dup /s%ld exch def\n",
3706 width, height,
3707 _content_to_string (content),
3708 new_obj->token);
3709
3710 new_obj->width = width;
3711 new_obj->height = height;
3712 new_obj->defined = TRUE;
3713
3714 _push_object (new_obj);
3715 dump_stack(__func__);
3716 _write_unlock ();
3717 }
3718
3719 _exit_trace ();
3720 return ret;
3721 }
3722
3723 cairo_surface_t *
cairo_surface_create_similar_image(cairo_surface_t * other,cairo_format_t format,int width,int height)3724 cairo_surface_create_similar_image (cairo_surface_t *other,
3725 cairo_format_t format,
3726 int width, int height)
3727 {
3728 cairo_surface_t *ret;
3729
3730 _enter_trace ();
3731
3732 ret = DLCALL (cairo_surface_create_similar_image,
3733 other, format, width, height);
3734
3735 _emit_line_info ();
3736 if (other != NULL && _write_lock ()) {
3737 Object *other_obj = _get_object(SURFACE, other);
3738 Object *new_obj = _create_surface (ret);
3739
3740 if (other_obj->defined)
3741 _trace_printf ("s%ld ", other_obj->token);
3742 else if (current_stack_depth == other_obj->operand + 1)
3743 _trace_printf ("dup ");
3744 else
3745 _trace_printf ("%d index ",
3746 current_stack_depth - other_obj->operand - 1);
3747 _trace_printf ("//%s %d %d similar-image %% s%ld\n",
3748 _format_to_string (format),
3749 width, height,
3750 new_obj->token);
3751 new_obj->width = width;
3752 new_obj->height = height;
3753
3754 _push_object (new_obj);
3755 dump_stack(__func__);
3756 _write_unlock ();
3757 }
3758
3759 _exit_trace ();
3760 return ret;
3761 }
3762
3763 cairo_surface_t *
cairo_surface_map_to_image(cairo_surface_t * surface,const cairo_rectangle_int_t * extents)3764 cairo_surface_map_to_image (cairo_surface_t *surface,
3765 const cairo_rectangle_int_t *extents)
3766 {
3767 cairo_surface_t *ret;
3768
3769 _enter_trace ();
3770
3771 ret = DLCALL (cairo_surface_map_to_image, surface, extents);
3772
3773 _emit_line_info ();
3774 if (_write_lock ()) {
3775 Object *obj = _create_surface (ret);
3776
3777 _emit_surface (surface);
3778 if (extents) {
3779 _trace_printf ("[%d %d %d %d] map-to-image %% s%ld\n",
3780 extents->x, extents->y,
3781 extents->width, extents->height,
3782 obj->token);
3783 obj->width = extents->width;
3784 obj->height = extents->height;
3785 } else {
3786 _trace_printf ("[ ] map-to-image %% s%ld\n", obj->token);
3787 }
3788
3789 _push_object (obj);
3790 dump_stack(__func__);
3791 _write_unlock ();
3792 }
3793
3794 _exit_trace ();
3795 return ret;
3796 }
3797
3798 void
cairo_surface_unmap_image(cairo_surface_t * surface,cairo_surface_t * image)3799 cairo_surface_unmap_image (cairo_surface_t *surface,
3800 cairo_surface_t *image)
3801 {
3802 _enter_trace ();
3803
3804 _emit_line_info ();
3805 if (_write_lock ()) {
3806 Object *s = _get_object (SURFACE, surface);
3807 Object *i = _get_object (SURFACE, image);
3808 if (!(s->operand == current_stack_depth - 2 &&
3809 i->operand == current_stack_depth - 1)) {
3810 if (i->operand != s->operand + 1 || ! _pop_operands_to_depth (i->operand + 1)) {
3811 _emit_surface (surface);
3812 _emit_surface (image);
3813 }
3814 }
3815 _trace_printf ("unmap-image\n");
3816 _consume_operand (true);
3817 _write_unlock ();
3818 }
3819
3820 DLCALL (cairo_surface_unmap_image, surface, image);
3821
3822 _exit_trace ();
3823 }
3824
3825 cairo_surface_t *
cairo_surface_create_for_rectangle(cairo_surface_t * target,double x,double y,double width,double height)3826 cairo_surface_create_for_rectangle (cairo_surface_t *target,
3827 double x, double y,
3828 double width, double height)
3829 {
3830 cairo_surface_t *ret;
3831
3832 _enter_trace ();
3833
3834 ret = DLCALL (cairo_surface_create_for_rectangle, target, x, y, width, height);
3835
3836 _emit_line_info ();
3837 if (target != NULL && _write_lock ()) {
3838 Object *target_obj = _get_object (SURFACE, target);
3839 Object *child_obj = _create_surface (ret);
3840
3841 if (target_obj->defined)
3842 _trace_printf ("s%ld ", target_obj->token);
3843 else if (current_stack_depth == target_obj->operand + 1)
3844 _trace_printf ("dup ");
3845 else
3846 _trace_printf ("%d index ", current_stack_depth - target_obj->operand - 1);
3847 _trace_printf ("%f %f %f %f subsurface %% s%ld\n",
3848 x, y, width, height,
3849 child_obj->token);
3850
3851 _push_object (child_obj);
3852 dump_stack(__func__);
3853 _write_unlock ();
3854 }
3855
3856 _exit_trace ();
3857 return ret;
3858 }
3859
3860 static void CAIRO_PRINTF_FORMAT(2, 3)
_emit_surface_op(cairo_surface_t * surface,const char * fmt,...)3861 _emit_surface_op (cairo_surface_t *surface, const char *fmt, ...)
3862 {
3863 va_list ap;
3864
3865 if (surface == NULL || ! _write_lock ())
3866 return;
3867
3868 _emit_surface (surface);
3869
3870 va_start (ap, fmt);
3871 _trace_vprintf ( fmt, ap);
3872 va_end (ap);
3873
3874 _write_unlock ();
3875 }
3876
3877 void
cairo_surface_finish(cairo_surface_t * surface)3878 cairo_surface_finish (cairo_surface_t *surface)
3879 {
3880 _enter_trace ();
3881 _emit_line_info ();
3882 DLCALL (cairo_surface_finish, surface);
3883 _exit_trace ();
3884 }
3885
3886 void
cairo_surface_flush(cairo_surface_t * surface)3887 cairo_surface_flush (cairo_surface_t *surface)
3888 {
3889 _enter_trace ();
3890 _emit_line_info ();
3891 if (surface != NULL && _write_lock ()) {
3892 _trace_printf ("%% s%ld flush\n", _get_surface_id (surface));
3893 _write_unlock ();
3894 }
3895 DLCALL (cairo_surface_flush, surface);
3896 _exit_trace ();
3897 }
3898
3899 void
cairo_surface_mark_dirty(cairo_surface_t * surface)3900 cairo_surface_mark_dirty (cairo_surface_t *surface)
3901 {
3902 _enter_trace ();
3903 _emit_line_info ();
3904
3905 /* Call cairo before emitting the trace since _emit_surface() might cause
3906 * snapshots to be creates while mark_dirty assert()s that there are none.
3907 */
3908 DLCALL (cairo_surface_mark_dirty, surface);
3909
3910 if (surface != NULL && _write_lock ()) {
3911 if (_mark_dirty) {
3912 _emit_surface (surface);
3913 _trace_printf ("%% mark-dirty\n");
3914 _emit_source_image (surface);
3915 } else
3916 _trace_printf ("%% s%ld mark-dirty\n", _get_surface_id (surface));
3917 _write_unlock ();
3918 }
3919 _exit_trace ();
3920 }
3921
3922 void
cairo_surface_mark_dirty_rectangle(cairo_surface_t * surface,int x,int y,int width,int height)3923 cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
3924 int x, int y, int width, int height)
3925 {
3926 _enter_trace ();
3927
3928 /* Call cairo before emitting the trace since _emit_surface() might cause
3929 * snapshots to be creates while mark_dirty assert()s that there are none.
3930 */
3931 DLCALL (cairo_surface_mark_dirty_rectangle, surface, x, y, width, height);
3932
3933 _emit_line_info ();
3934 if (surface != NULL && _write_lock ()) {
3935 if (_mark_dirty) {
3936 _emit_surface (surface);
3937 _trace_printf ("%% %d %d %d %d mark-dirty-rectangle\n",
3938 x, y, width, height);
3939 _emit_source_image_rectangle (surface, x,y, width, height);
3940 } else
3941 _trace_printf ("%% s%ld %d %d %d %d mark-dirty-rectangle\n",
3942 _get_surface_id (surface), x, y, width, height);
3943 _write_unlock ();
3944 }
3945 _exit_trace ();
3946 }
3947
3948 void
cairo_surface_set_device_offset(cairo_surface_t * surface,double x_offset,double y_offset)3949 cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset)
3950 {
3951 _enter_trace ();
3952 _emit_line_info ();
3953 _emit_surface_op (surface, "%g %g set-device-offset\n",
3954 x_offset, y_offset);
3955 DLCALL (cairo_surface_set_device_offset, surface, x_offset, y_offset);
3956 _exit_trace ();
3957 }
3958
3959 void
cairo_surface_set_device_scale(cairo_surface_t * surface,double x_offset,double y_offset)3960 cairo_surface_set_device_scale (cairo_surface_t *surface, double x_offset, double y_offset)
3961 {
3962 _enter_trace ();
3963 _emit_line_info ();
3964 _emit_surface_op (surface, "%g %g set-device-scale\n",
3965 x_offset, y_offset);
3966 DLCALL (cairo_surface_set_device_scale, surface, x_offset, y_offset);
3967 _exit_trace ();
3968 }
3969
3970
3971 void
cairo_surface_set_fallback_resolution(cairo_surface_t * surface,double x_pixels_per_inch,double y_pixels_per_inch)3972 cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch)
3973 {
3974 _enter_trace ();
3975 _emit_line_info ();
3976 _emit_surface_op (surface, "%g %g set-fallback-resolution\n",
3977 x_pixels_per_inch, y_pixels_per_inch);
3978 DLCALL (cairo_surface_set_fallback_resolution, surface, x_pixels_per_inch, y_pixels_per_inch);
3979 _exit_trace ();
3980 }
3981
3982 void
cairo_surface_copy_page(cairo_surface_t * surface)3983 cairo_surface_copy_page (cairo_surface_t *surface)
3984 {
3985 _enter_trace ();
3986 _emit_line_info ();
3987 _emit_surface_op (surface, "copy-page\n");
3988 DLCALL (cairo_surface_copy_page, surface);
3989 _exit_trace ();
3990 }
3991
3992 void
cairo_surface_show_page(cairo_surface_t * surface)3993 cairo_surface_show_page (cairo_surface_t *surface)
3994 {
3995 _enter_trace ();
3996 _emit_line_info ();
3997 _emit_surface_op (surface, "show-page\n");
3998 DLCALL (cairo_surface_show_page, surface);
3999 _exit_trace ();
4000 }
4001
4002 cairo_status_t
cairo_surface_set_mime_data(cairo_surface_t * surface,const char * mime_type,const unsigned char * data,unsigned long length,cairo_destroy_func_t destroy,void * closure)4003 cairo_surface_set_mime_data (cairo_surface_t *surface,
4004 const char *mime_type,
4005 const unsigned char *data,
4006 unsigned long length,
4007 cairo_destroy_func_t destroy,
4008 void *closure)
4009 {
4010 cairo_status_t ret;
4011 _enter_trace ();
4012 _emit_line_info ();
4013 if (surface != NULL && _write_lock ()) {
4014 _emit_surface (surface);
4015 _emit_string_literal (mime_type, -1);
4016 _trace_printf (" ");
4017 _emit_data (data, length);
4018 _trace_printf (" /deflate filter set-mime-data\n");
4019
4020 _write_unlock ();
4021 }
4022
4023 ret = DLCALL (cairo_surface_set_mime_data,
4024 surface,
4025 mime_type,
4026 data, length,
4027 destroy,
4028 closure);
4029 _exit_trace ();
4030 return ret;
4031 }
4032
4033 #if CAIRO_HAS_PNG_FUNCTIONS
4034 cairo_status_t
cairo_surface_write_to_png(cairo_surface_t * surface,const char * filename)4035 cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename)
4036 {
4037 cairo_status_t ret;
4038 _enter_trace ();
4039 _emit_line_info ();
4040 if (surface != NULL && _write_lock ()) {
4041 _trace_printf ("%% s%ld ", _get_surface_id (surface));
4042 _emit_string_literal (filename, -1);
4043 _trace_printf (" write-to-png pop\n");
4044 _write_unlock ();
4045 }
4046 ret = DLCALL (cairo_surface_write_to_png, surface, filename);
4047 _exit_trace ();
4048 return ret;
4049 }
4050
4051 cairo_status_t
cairo_surface_write_to_png_stream(cairo_surface_t * surface,cairo_write_func_t write_func,void * data)4052 cairo_surface_write_to_png_stream (cairo_surface_t *surface,
4053 cairo_write_func_t write_func,
4054 void *data)
4055 {
4056 cairo_status_t ret;
4057 _enter_trace ();
4058 _emit_line_info ();
4059 if (surface != NULL && _write_lock ()) {
4060 char symbol[1024];
4061
4062 _trace_printf ("%% s%ld ", _get_surface_id (surface));
4063 #if CAIRO_HAS_SYMBOL_LOOKUP
4064 lookup_symbol (symbol, sizeof (symbol), write_func);
4065 #else
4066 symbol[0] = '\0';
4067 #endif
4068 _emit_string_literal (symbol, -1);
4069 _trace_printf (" write-to-png-stream pop\n");
4070 _write_unlock ();
4071 }
4072 ret = DLCALL (cairo_surface_write_to_png_stream,
4073 surface, write_func, data);
4074 _exit_trace ();
4075 return ret;
4076 }
4077 #endif
4078
4079 static void CAIRO_PRINTF_FORMAT(2, 3)
_emit_pattern_op(cairo_pattern_t * pattern,const char * fmt,...)4080 _emit_pattern_op (cairo_pattern_t *pattern, const char *fmt, ...)
4081 {
4082 va_list ap;
4083
4084 if (pattern == NULL || ! _write_lock ())
4085 return;
4086
4087 _emit_pattern (pattern);
4088
4089 va_start (ap, fmt);
4090 _trace_vprintf (fmt, ap);
4091 va_end (ap);
4092
4093 _write_unlock ();
4094 }
4095
4096 cairo_pattern_t *
cairo_pattern_create_rgb(double red,double green,double blue)4097 cairo_pattern_create_rgb (double red, double green, double blue)
4098 {
4099 cairo_pattern_t *ret;
4100 long pattern_id;
4101
4102 _enter_trace ();
4103
4104 ret = DLCALL (cairo_pattern_create_rgb, red, green, blue);
4105 pattern_id = _create_pattern_id (ret);
4106
4107 _emit_line_info ();
4108 if (_write_lock ()) {
4109 _trace_printf ("/p%ld %g %g %g rgb def\n",
4110 pattern_id, red, green, blue);
4111 _get_object (PATTERN, ret)->defined = TRUE;
4112 _write_unlock ();
4113 }
4114
4115 _exit_trace ();
4116 return ret;
4117 }
4118
4119 cairo_pattern_t *
cairo_pattern_create_rgba(double red,double green,double blue,double alpha)4120 cairo_pattern_create_rgba (double red, double green, double blue, double alpha)
4121 {
4122 cairo_pattern_t *ret;
4123 long pattern_id;
4124
4125 _enter_trace ();
4126
4127 ret = DLCALL (cairo_pattern_create_rgba, red, green, blue, alpha);
4128 pattern_id = _create_pattern_id (ret);
4129
4130 _emit_line_info ();
4131 if (_write_lock ()) {
4132 _trace_printf ("/p%ld %g %g %g %g rgba def\n",
4133 pattern_id, red, green, blue, alpha);
4134 _get_object (PATTERN, ret)->defined = TRUE;
4135 _write_unlock ();
4136 }
4137
4138 _exit_trace ();
4139 return ret;
4140 }
4141
4142 cairo_pattern_t *
cairo_pattern_create_for_surface(cairo_surface_t * surface)4143 cairo_pattern_create_for_surface (cairo_surface_t *surface)
4144 {
4145 cairo_pattern_t *ret;
4146 long pattern_id;
4147 long surface_id;
4148
4149 _enter_trace ();
4150
4151 ret = DLCALL (cairo_pattern_create_for_surface, surface);
4152 pattern_id = _create_pattern_id (ret);
4153
4154 _emit_line_info ();
4155 if (surface != NULL && _write_lock ()) {
4156 surface_id = _get_surface_id (surface);
4157
4158 if (_pop_operands_to (SURFACE, surface)) {
4159 _consume_operand (false);
4160 } else {
4161 _trace_printf ("s%ld ", surface_id);
4162 }
4163
4164 if (_get_object (SURFACE, surface)->foreign)
4165 _emit_source_image (surface);
4166
4167 _trace_printf ("pattern %% p%ld\n", pattern_id);
4168 _push_operand (PATTERN, ret);
4169 dump_stack(__func__);
4170 _write_unlock ();
4171 }
4172
4173 _exit_trace ();
4174 return ret;
4175 }
4176
4177 cairo_pattern_t *
cairo_pattern_create_linear(double x0,double y0,double x1,double y1)4178 cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
4179 {
4180 cairo_pattern_t *ret;
4181 long pattern_id;
4182
4183 _enter_trace ();
4184
4185 ret = DLCALL (cairo_pattern_create_linear, x0, y0, x1, y1);
4186 pattern_id = _create_pattern_id (ret);
4187
4188 _emit_line_info ();
4189 if (_write_lock ()) {
4190 _trace_printf ("%g %g %g %g linear %% p%ld\n",
4191 x0, y0, x1, y1, pattern_id);
4192 _push_operand (PATTERN, ret);
4193 dump_stack(__func__);
4194 _write_unlock ();
4195 }
4196
4197 _exit_trace ();
4198 return ret;
4199 }
4200
4201 cairo_pattern_t *
cairo_pattern_create_radial(double cx0,double cy0,double radius0,double cx1,double cy1,double radius1)4202 cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1)
4203 {
4204 cairo_pattern_t *ret;
4205 long pattern_id;
4206
4207 _enter_trace ();
4208
4209 ret = DLCALL (cairo_pattern_create_radial,
4210 cx0, cy0, radius0,
4211 cx1, cy1, radius1);
4212 pattern_id = _create_pattern_id (ret);
4213
4214 _emit_line_info ();
4215 if (_write_lock ()) {
4216 _trace_printf ("%g %g %g %g %g %g radial %% p%ld\n",
4217 cx0, cy0, radius0, cx1, cy1, radius1,
4218 pattern_id);
4219 _push_operand (PATTERN, ret);
4220 dump_stack(__func__);
4221 _write_unlock ();
4222 }
4223
4224 _exit_trace ();
4225 return ret;
4226 }
4227
4228 void
cairo_pattern_add_color_stop_rgb(cairo_pattern_t * pattern,double offset,double red,double green,double blue)4229 cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, double green, double blue)
4230 {
4231 _enter_trace ();
4232 _emit_line_info ();
4233 _emit_pattern_op (pattern,
4234 "%g %g %g %g 1 add-color-stop\n",
4235 offset, red, green, blue);
4236 DLCALL (cairo_pattern_add_color_stop_rgb, pattern, offset, red, green, blue);
4237 _exit_trace ();
4238 }
4239
4240 void
cairo_pattern_add_color_stop_rgba(cairo_pattern_t * pattern,double offset,double red,double green,double blue,double alpha)4241 cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha)
4242 {
4243 _enter_trace ();
4244 _emit_line_info ();
4245 _emit_pattern_op (pattern,
4246 "%g %g %g %g %g add-color-stop\n",
4247 offset, red, green, blue, alpha);
4248 DLCALL (cairo_pattern_add_color_stop_rgba, pattern, offset, red, green, blue, alpha);
4249 _exit_trace ();
4250 }
4251
4252 void
cairo_pattern_set_matrix(cairo_pattern_t * pattern,const cairo_matrix_t * matrix)4253 cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix)
4254 {
4255 _enter_trace ();
4256 _emit_line_info ();
4257 if (_matrix_is_identity (matrix)) {
4258 _emit_pattern_op (pattern, "identity set-matrix\n");
4259 } else {
4260 _emit_pattern_op (pattern,
4261 "%g %g %g %g %g %g matrix set-matrix\n",
4262 matrix->xx, matrix->yx,
4263 matrix->xy, matrix->yy,
4264 matrix->x0, matrix->y0);
4265 }
4266 DLCALL (cairo_pattern_set_matrix, pattern, matrix);
4267 _exit_trace ();
4268 }
4269
4270 static const char *
_filter_to_string(cairo_filter_t filter)4271 _filter_to_string (cairo_filter_t filter)
4272 {
4273 #define f(name) case CAIRO_FILTER_ ## name: return "FILTER_" #name
4274 switch (filter) {
4275 f(FAST);
4276 f(GOOD);
4277 f(BEST);
4278 f(NEAREST);
4279 f(BILINEAR);
4280 f(GAUSSIAN);
4281 };
4282 #undef f
4283 return "UNKNOWN_FILTER";
4284 }
4285
4286 void
cairo_pattern_set_filter(cairo_pattern_t * pattern,cairo_filter_t filter)4287 cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
4288 {
4289 _enter_trace ();
4290 _emit_line_info ();
4291 _emit_pattern_op (pattern, "//%s set-filter\n", _filter_to_string (filter));
4292 DLCALL (cairo_pattern_set_filter, pattern, filter);
4293 _exit_trace ();
4294 }
4295
4296 static const char *
_extend_to_string(cairo_extend_t extend)4297 _extend_to_string (cairo_extend_t extend)
4298 {
4299 #define f(name) case CAIRO_EXTEND_ ## name: return "EXTEND_" #name
4300 switch (extend) {
4301 f(NONE);
4302 f(REPEAT);
4303 f(REFLECT);
4304 f(PAD);
4305 };
4306 #undef f
4307 return "UNKNOWN_EXTEND";
4308 }
4309
4310 void
cairo_pattern_set_extend(cairo_pattern_t * pattern,cairo_extend_t extend)4311 cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
4312 {
4313 _enter_trace ();
4314 _emit_line_info ();
4315 _emit_pattern_op (pattern, "//%s set-extend\n", _extend_to_string (extend));
4316 DLCALL (cairo_pattern_set_extend, pattern, extend);
4317 _exit_trace ();
4318 }
4319
4320 #if CAIRO_HAS_FT_FONT
4321 #if CAIRO_HAS_FC_FONT
4322 cairo_font_face_t *
cairo_ft_font_face_create_for_pattern(FcPattern * pattern)4323 cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
4324 {
4325 cairo_font_face_t *ret;
4326 long font_face_id;
4327
4328 _enter_trace ();
4329
4330 ret = DLCALL (cairo_ft_font_face_create_for_pattern, pattern);
4331 font_face_id = _create_font_face_id (ret);
4332
4333 _emit_line_info ();
4334 if (pattern != NULL && _write_lock ()) {
4335 Object *obj;
4336
4337 obj = _get_object (FONT_FACE, ret);
4338 if (obj->unknown) {
4339 FcPattern *copy;
4340 FcChar8 *unparsed;
4341
4342 copy = DLCALL (FcPatternDuplicate, pattern);
4343 if (copy)
4344 {
4345 DLCALL (FcPatternDel, copy, FC_LANG);
4346 DLCALL (FcPatternDel, copy, FC_CHARSET);
4347 DLCALL (FcPatternDel, copy, FC_CAPABILITY);
4348 }
4349 else
4350 copy = pattern;
4351
4352 unparsed = DLCALL (FcNameUnparse, copy);
4353 _trace_printf ("dict\n"
4354 " /type 42 set\n"
4355 " /pattern ");
4356 _emit_string_literal ((char *) unparsed, -1);
4357 _trace_printf (" set\n"
4358 " font %% f%ld\n",
4359 font_face_id);
4360 obj->unknown = FALSE;
4361 _push_operand (FONT_FACE, ret);
4362 dump_stack(__func__);
4363
4364 if (copy != pattern)
4365 DLCALL (FcPatternDestroy, copy);
4366 free (unparsed);
4367 }
4368 _write_unlock ();
4369 }
4370
4371 _exit_trace ();
4372 return ret;
4373 }
4374 #endif /* CAIRO_HAS_FC_FONT*/
4375
4376 typedef struct _ft_face_data {
4377 unsigned long index;
4378 unsigned long size;
4379 void *data;
4380 } FtFaceData;
4381
4382 static void
_ft_face_data_destroy(void * arg)4383 _ft_face_data_destroy (void *arg)
4384 {
4385 FtFaceData *data = arg;
4386 free (data->data);
4387 free (data);
4388 }
4389
4390 cairo_font_face_t *
cairo_ft_font_face_create_for_ft_face(FT_Face face,int load_flags)4391 cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags)
4392 {
4393 cairo_font_face_t *ret;
4394 Object *obj;
4395 FtFaceData *data;
4396 long font_face_id;
4397
4398 _enter_trace ();
4399
4400 ret = DLCALL (cairo_ft_font_face_create_for_ft_face, face, load_flags);
4401 font_face_id = _create_font_face_id (ret);
4402
4403 if (face == NULL) {
4404 _exit_trace ();
4405 return ret;
4406 }
4407
4408 obj = _get_object (NONE, face);
4409 data = obj->data;
4410 if (data == NULL) {
4411 _exit_trace ();
4412 return ret;
4413 }
4414
4415 _emit_line_info ();
4416 if (_write_lock ()) {
4417 obj = _get_object (FONT_FACE, ret);
4418 if (obj->operand != -1)
4419 _object_remove (obj);
4420
4421 _trace_printf ("<< /type 42 /source ");
4422 _emit_data (data->data, data->size);
4423 _trace_printf (" /index %lu /flags %d >> font %% f%ld\n",
4424 data->index, load_flags, font_face_id);
4425 _push_operand (FONT_FACE, ret);
4426 dump_stack(__func__);
4427 _write_unlock ();
4428 }
4429
4430 _exit_trace ();
4431 return ret;
4432 }
4433
4434 static cairo_bool_t
_ft_read_file(FtFaceData * data,const char * path)4435 _ft_read_file (FtFaceData *data, const char *path)
4436 {
4437 char buf[8192];
4438 FILE *file;
4439
4440 file = fopen (path, "rb");
4441 if (file != NULL) {
4442 size_t ret;
4443 unsigned long int allocated = sizeof (buf);
4444 data->data = malloc (allocated);
4445 do {
4446 ret = fread (buf, 1, sizeof (buf), file);
4447 if (ret == 0)
4448 break;
4449 memcpy ((char *) data->data + data->size, buf, ret);
4450 data->size += ret;
4451 if (ret != sizeof (buf))
4452 break;
4453
4454 if (data->size == allocated) {
4455 allocated *= 2;
4456 data->data = realloc (data->data, allocated);
4457 }
4458 } while (TRUE);
4459 fclose (file);
4460 }
4461
4462 return file != NULL;
4463 }
4464
4465 FT_Error
FT_New_Face(FT_Library library,const char * pathname,FT_Long index,FT_Face * face)4466 FT_New_Face (FT_Library library, const char *pathname, FT_Long index, FT_Face *face)
4467 {
4468 FT_Error ret;
4469
4470 _enter_trace ();
4471
4472 ret = DLCALL (FT_New_Face, library, pathname, index, face);
4473 if (ret == 0) {
4474 Object *obj = _type_object_create (NONE, *face);
4475 FtFaceData *data = malloc (sizeof (FtFaceData));
4476 data->index = index;
4477 data->size = 0;
4478 data->data = NULL;
4479 _ft_read_file (data, pathname);
4480 obj->data = data;
4481 obj->destroy = _ft_face_data_destroy;
4482 }
4483
4484 _exit_trace ();
4485 return ret;
4486 }
4487
4488 FT_Error
FT_New_Memory_Face(FT_Library library,const FT_Byte * mem,FT_Long size,FT_Long index,FT_Face * face)4489 FT_New_Memory_Face (FT_Library library, const FT_Byte *mem, FT_Long size, FT_Long index, FT_Face *face)
4490 {
4491 FT_Error ret;
4492
4493 _enter_trace ();
4494
4495 ret = DLCALL (FT_New_Memory_Face, library, mem, size, index, face);
4496 if (ret == 0) {
4497 Object *obj = _type_object_create (NONE, *face);
4498 FtFaceData *data = malloc (sizeof (FtFaceData));
4499 data->index = index;
4500 data->size = size;
4501 data->data = malloc (size);
4502 memcpy (data->data, mem, size);
4503 obj->data = data;
4504 obj->destroy = _ft_face_data_destroy;
4505 }
4506
4507 _exit_trace ();
4508 return ret;
4509 }
4510
4511 /* XXX
4512 * FT_New_Memory_Face() and FT_New_Face() appear to wrap FT_Open_Face() so we
4513 * get a redundant call to FT_Open_Face() from those paths (no PLT hiding
4514 * within FT, naughty library!) but we do not intercept a direct call to
4515 * FT_Open_Face(). So far this has not caused any issues, but it will one
4516 * day...
4517 */
4518 FT_Error
FT_Open_Face(FT_Library library,const FT_Open_Args * args,FT_Long index,FT_Face * face)4519 FT_Open_Face (FT_Library library, const FT_Open_Args *args, FT_Long index, FT_Face *face)
4520 {
4521 FT_Error ret;
4522
4523 _enter_trace ();
4524
4525 ret = DLCALL (FT_Open_Face, library, args, index, face);
4526 if (ret == 0) {
4527 Object *obj = _get_object (NONE, *face);
4528 if (obj == NULL) {
4529 FtFaceData *data;
4530
4531 data = malloc (sizeof (FtFaceData));
4532 data->index = index;
4533 if (args->flags & FT_OPEN_MEMORY) {
4534 data->size = args->memory_size;
4535 data->data = malloc (args->memory_size);
4536 memcpy (data->data, args->memory_base, args->memory_size);
4537 } else if (args->flags & FT_OPEN_STREAM) {
4538 fprintf (stderr, "FT_Open_Face (stream, %ld) = %p\n",
4539 index, *face);
4540 abort ();
4541 } else if (args->flags & FT_OPEN_PATHNAME) {
4542 data->size = 0;
4543 data->data = NULL;
4544 _ft_read_file (data, args->pathname);
4545 }
4546
4547 obj = _type_object_create (NONE, *face);
4548 obj->data = data;
4549 obj->destroy = _ft_face_data_destroy;
4550 }
4551 }
4552
4553 _exit_trace ();
4554 return ret;
4555 }
4556
4557 FT_Error
FT_Done_Face(FT_Face face)4558 FT_Done_Face (FT_Face face)
4559 {
4560 FT_Error ret;
4561 _enter_trace ();
4562
4563 _object_destroy (_get_object (NONE, face));
4564
4565 ret = DLCALL (FT_Done_Face, face);
4566 _exit_trace ();
4567 return ret;
4568 }
4569 #endif
4570
4571 static void
_surface_object_set_size(cairo_surface_t * surface,int width,int height)4572 _surface_object_set_size (cairo_surface_t *surface, int width, int height)
4573 {
4574 Object *obj;
4575
4576 obj = _get_object (SURFACE, surface);
4577 obj->width = width;
4578 obj->height = height;
4579 }
4580
4581 static void
_surface_object_set_size_from_surface(cairo_surface_t * surface)4582 _surface_object_set_size_from_surface (cairo_surface_t *surface)
4583 {
4584 _surface_object_set_size (surface,
4585 DLCALL (cairo_image_surface_get_width, surface),
4586 DLCALL (cairo_image_surface_get_height, surface));
4587 }
4588
4589 #if CAIRO_HAS_PS_SURFACE
4590 #include<cairo-ps.h>
4591
4592 cairo_surface_t *
cairo_ps_surface_create(const char * filename,double width_in_points,double height_in_points)4593 cairo_ps_surface_create (const char *filename, double width_in_points, double height_in_points)
4594 {
4595 cairo_surface_t *ret;
4596
4597 _enter_trace ();
4598
4599 ret = DLCALL (cairo_ps_surface_create, filename, width_in_points, height_in_points);
4600
4601 _emit_line_info ();
4602 if (_write_lock ()) {
4603 Object *obj = _create_surface (ret);
4604
4605 _trace_printf ("dict\n"
4606 " /type /PS set\n"
4607 " /filename ");
4608 _emit_string_literal (filename, -1);
4609 _trace_printf (" set\n"
4610 " /width %g set\n"
4611 " /height %g set\n"
4612 " surface %% s%ld\n",
4613 width_in_points,
4614 height_in_points,
4615 obj->token);
4616 obj->width = width_in_points;
4617 obj->height = height_in_points;
4618 _push_object (obj);
4619 dump_stack(__func__);
4620 _write_unlock ();
4621 }
4622
4623 _exit_trace ();
4624 return ret;
4625 }
4626
4627 cairo_surface_t *
cairo_ps_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width_in_points,double height_in_points)4628 cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points)
4629 {
4630 cairo_surface_t *ret;
4631
4632 _enter_trace ();
4633
4634 ret = DLCALL (cairo_ps_surface_create_for_stream, write_func, closure, width_in_points, height_in_points);
4635
4636 _emit_line_info ();
4637 if (_write_lock ()) {
4638 Object *obj = _create_surface (ret);
4639
4640 _trace_printf ("dict\n"
4641 " /type /PS set\n"
4642 " /width %g set\n"
4643 " /height %g set\n"
4644 " surface %% s%ld\n",
4645 width_in_points,
4646 height_in_points,
4647 obj->token);
4648 obj->width = width_in_points;
4649 obj->height = height_in_points;
4650 _push_object (obj);
4651 dump_stack(__func__);
4652 _write_unlock ();
4653 }
4654
4655 _exit_trace ();
4656 return ret;
4657 }
4658
4659 void
cairo_ps_surface_set_size(cairo_surface_t * surface,double width_in_points,double height_in_points)4660 cairo_ps_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points)
4661 {
4662 _enter_trace ();
4663 _emit_line_info ();
4664 DLCALL (cairo_ps_surface_set_size, surface, width_in_points, height_in_points);
4665 _exit_trace ();
4666 }
4667
4668 #endif
4669
4670 #if CAIRO_HAS_PDF_SURFACE
4671 #include <cairo-pdf.h>
4672
4673 cairo_surface_t *
cairo_pdf_surface_create(const char * filename,double width_in_points,double height_in_points)4674 cairo_pdf_surface_create (const char *filename, double width_in_points, double height_in_points)
4675 {
4676 cairo_surface_t *ret;
4677
4678 _enter_trace ();
4679
4680 ret = DLCALL (cairo_pdf_surface_create, filename, width_in_points, height_in_points);
4681
4682 _emit_line_info ();
4683 if (_write_lock ()) {
4684 Object *obj = _create_surface (ret);
4685
4686 _trace_printf ("dict\n"
4687 " /type /PDF set\n"
4688 " /filename ");
4689 _emit_string_literal (filename, -1);
4690 _trace_printf (" set\n"
4691 " /width %g set\n"
4692 " /height %g set\n"
4693 " surface %% s%ld\n",
4694 width_in_points,
4695 height_in_points,
4696 obj->token);
4697 obj->width = width_in_points;
4698 obj->height = height_in_points;
4699 _push_object (obj);
4700 dump_stack(__func__);
4701 _write_unlock ();
4702 }
4703
4704 _exit_trace ();
4705 return ret;
4706 }
4707
4708 cairo_surface_t *
cairo_pdf_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width_in_points,double height_in_points)4709 cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points)
4710 {
4711 cairo_surface_t *ret;
4712
4713 _enter_trace ();
4714
4715 ret = DLCALL (cairo_pdf_surface_create_for_stream, write_func, closure, width_in_points, height_in_points);
4716
4717 _emit_line_info ();
4718 if (_write_lock ()) {
4719 Object *obj = _create_surface (ret);
4720
4721 _trace_printf ("dict\n"
4722 " /type /PDF set\n"
4723 " /width %g set\n"
4724 " /height %g set\n"
4725 " surface %% s%ld\n",
4726 width_in_points,
4727 height_in_points,
4728 obj->token);
4729 obj->width = width_in_points;
4730 obj->height = height_in_points;
4731 _push_object (obj);
4732 dump_stack(__func__);
4733 _write_unlock ();
4734 }
4735 _exit_trace ();
4736 return ret;
4737 }
4738
4739 void
cairo_pdf_surface_set_size(cairo_surface_t * surface,double width_in_points,double height_in_points)4740 cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points)
4741 {
4742 _enter_trace ();
4743 _emit_line_info ();
4744 DLCALL (cairo_pdf_surface_set_size, surface, width_in_points, height_in_points);
4745 _exit_trace ();
4746 }
4747 #endif
4748
4749 #if CAIRO_HAS_SVG_SURFACE
4750 #include <cairo-svg.h>
4751
4752 cairo_surface_t *
cairo_svg_surface_create(const char * filename,double width,double height)4753 cairo_svg_surface_create (const char *filename, double width, double height)
4754 {
4755 cairo_surface_t *ret;
4756
4757 _enter_trace ();
4758
4759 ret = DLCALL (cairo_svg_surface_create, filename, width, height);
4760
4761 _emit_line_info ();
4762 if (_write_lock ()) {
4763 Object *obj = _create_surface (ret);
4764
4765 _trace_printf ("dict\n"
4766 " /type /SVG set\n"
4767 " /filename ");
4768 _emit_string_literal (filename, -1);
4769 _trace_printf (" set\n"
4770 " /width %g set\n"
4771 " /height %g set\n"
4772 " surface %% s%ld\n",
4773 width,
4774 height,
4775 obj->token);
4776 obj->width = width;
4777 obj->height = height;
4778 _push_object (obj);
4779 dump_stack(__func__);
4780 _write_unlock ();
4781 }
4782
4783 _exit_trace ();
4784 return ret;
4785 }
4786
4787 cairo_surface_t *
cairo_svg_surface_create_for_stream(cairo_write_func_t write_func,void * closure,double width,double height)4788 cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width, double height)
4789 {
4790 cairo_surface_t *ret;
4791
4792 _enter_trace ();
4793
4794 ret = DLCALL (cairo_svg_surface_create_for_stream, write_func, closure, width, height);
4795
4796 _emit_line_info ();
4797 if (_write_lock ()) {
4798 Object *obj = _create_surface (ret);
4799
4800 _trace_printf ("dict\n"
4801 " /type /SVG set\n"
4802 " /width %g set\n"
4803 " /height %g set\n"
4804 " surface %% s%ld\n",
4805 width,
4806 height,
4807 obj->token);
4808 obj->width = width;
4809 obj->height = height;
4810 _push_object (obj);
4811 dump_stack(__func__);
4812 _write_unlock ();
4813 }
4814
4815 _exit_trace ();
4816 return ret;
4817 }
4818
4819 #endif
4820
4821 #if CAIRO_HAS_PNG_FUNCTIONS
4822 cairo_surface_t *
cairo_image_surface_create_from_png(const char * filename)4823 cairo_image_surface_create_from_png (const char *filename)
4824 {
4825 cairo_surface_t *ret;
4826
4827 _enter_trace ();
4828
4829 ret = DLCALL (cairo_image_surface_create_from_png, filename);
4830
4831 _emit_line_info ();
4832 if (_write_lock ()) {
4833 Object *obj = _create_surface (ret);
4834 char filename_string[4096];
4835
4836 _encode_string_literal (filename_string, sizeof (filename_string),
4837 filename, -1);
4838 _emit_image (ret, " /filename %s set\n", filename_string);
4839 _trace_printf (" dup /s%ld exch def\n", obj->token);
4840 _surface_object_set_size_from_surface (ret);
4841 obj->defined = TRUE;
4842 _push_object (obj);
4843 dump_stack(__func__);
4844 _write_unlock ();
4845 }
4846
4847 _exit_trace ();
4848 return ret;
4849 }
4850
4851 cairo_surface_t *
cairo_image_surface_create_from_png_stream(cairo_read_func_t read_func,void * closure)4852 cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *closure)
4853 {
4854 cairo_surface_t *ret;
4855
4856 _enter_trace ();
4857
4858 ret = DLCALL (cairo_image_surface_create_from_png_stream, read_func, closure);
4859
4860 _emit_line_info ();
4861 if (_write_lock ()) {
4862 Object *obj = _create_surface (ret);
4863
4864 _emit_image (ret, NULL);
4865 _trace_printf (" dup /s%ld exch def\n",
4866 obj->token);
4867
4868 _surface_object_set_size_from_surface (ret);
4869 obj->defined = TRUE;
4870 _push_object (obj);
4871 dump_stack(__func__);
4872 _write_unlock ();
4873 }
4874
4875 _exit_trace ();
4876 return ret;
4877 }
4878 #endif
4879
4880 static const char *
_content_from_surface(cairo_surface_t * surface)4881 _content_from_surface (cairo_surface_t *surface)
4882 {
4883 return _content_to_string (DLCALL (cairo_surface_get_content, surface));
4884 }
4885
4886 #if CAIRO_HAS_TEE_SURFACE
4887 #include <cairo-tee.h>
4888
4889 cairo_surface_t *
cairo_tee_surface_create(cairo_surface_t * master)4890 cairo_tee_surface_create (cairo_surface_t *master)
4891 {
4892 cairo_surface_t *ret;
4893
4894 _enter_trace ();
4895
4896 ret = DLCALL (cairo_tee_surface_create, master);
4897
4898 _emit_line_info ();
4899 if (_write_lock ()) {
4900 Object *obj = _create_surface (ret);
4901
4902 _trace_printf ("dict\n"
4903 " /type /tee set\n"
4904 " /master s%ld set\n"
4905 " surface dup /s%ld exch def\n",
4906 _get_object (SURFACE, master)->token,
4907 obj->token);
4908 obj->defined = TRUE;
4909 _push_object (obj);
4910 dump_stack(__func__);
4911 _write_unlock ();
4912 }
4913
4914 _exit_trace ();
4915 return ret;
4916 }
4917
4918 #endif
4919
4920 #if CAIRO_HAS_XLIB_SURFACE
4921 #include <cairo-xlib.h>
4922
4923 cairo_surface_t *
cairo_xlib_surface_create(Display * dpy,Drawable drawable,Visual * visual,int width,int height)4924 cairo_xlib_surface_create (Display *dpy,
4925 Drawable drawable,
4926 Visual *visual,
4927 int width, int height)
4928 {
4929 cairo_surface_t *ret;
4930
4931 _enter_trace ();
4932
4933 ret = DLCALL (cairo_xlib_surface_create,
4934 dpy, drawable, visual, width, height);
4935
4936 _emit_line_info ();
4937 if (_write_lock ()) {
4938 Object *obj = _create_surface (ret);
4939
4940 _trace_printf ("dict\n"
4941 " /type /xlib set\n"
4942 " /drawable 16!%lx set\n"
4943 " /content //%s set\n"
4944 " /width %d set\n"
4945 " /height %d set\n"
4946 " surface dup /s%ld exch def\n",
4947 drawable,
4948 _content_from_surface (ret),
4949 width, height,
4950 obj->token);
4951 obj->defined = TRUE;
4952 obj->width = width;
4953 obj->height = height;
4954 obj->foreign = TRUE;
4955 _push_object (obj);
4956 dump_stack(__func__);
4957 _write_unlock ();
4958 }
4959
4960 _exit_trace ();
4961 return ret;
4962 }
4963
4964 cairo_surface_t *
cairo_xlib_surface_create_for_bitmap(Display * dpy,Pixmap bitmap,Screen * screen,int width,int height)4965 cairo_xlib_surface_create_for_bitmap (Display *dpy,
4966 Pixmap bitmap,
4967 Screen *screen,
4968 int width, int height)
4969 {
4970 cairo_surface_t *ret;
4971
4972 _enter_trace ();
4973
4974 ret = DLCALL (cairo_xlib_surface_create_for_bitmap,
4975 dpy, bitmap, screen, width, height);
4976
4977 _emit_line_info ();
4978 if (_write_lock ()) {
4979 Object *obj = _create_surface (ret);
4980
4981 _trace_printf ("dict\n"
4982 " /type /xlib set\n"
4983 " /drawable 16!%lx set\n"
4984 " /content //%s set\n"
4985 " /width %d set\n"
4986 " /height %d set\n"
4987 " /depth 1 set\n"
4988 " surface dup /s%ld exch def\n",
4989 bitmap,
4990 _content_from_surface (ret),
4991 width, height,
4992 obj->token);
4993 obj->defined = TRUE;
4994 obj->width = width;
4995 obj->height = height;
4996 obj->foreign = TRUE;
4997 _push_object (obj);
4998 dump_stack(__func__);
4999 _write_unlock ();
5000 }
5001
5002 _exit_trace ();
5003 return ret;
5004 }
5005
5006 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
5007 #include <cairo-xlib-xrender.h>
5008 cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format(Display * dpy,Drawable drawable,Screen * screen,XRenderPictFormat * format,int width,int height)5009 cairo_xlib_surface_create_with_xrender_format (Display *dpy,
5010 Drawable drawable,
5011 Screen *screen,
5012 XRenderPictFormat *format,
5013 int width, int height)
5014 {
5015 cairo_surface_t *ret;
5016
5017 _enter_trace ();
5018
5019 ret = DLCALL (cairo_xlib_surface_create_with_xrender_format,
5020 dpy, drawable, screen, format, width, height);
5021
5022 _emit_line_info ();
5023 if (_write_lock ()) {
5024 Object *obj = _create_surface (ret);
5025
5026 _trace_printf ("dict\n"
5027 " /type /xrender set\n"
5028 " /drawable 16!%lx set\n"
5029 " /content //%s set\n"
5030 " /width %d set\n"
5031 " /height %d set\n"
5032 " /depth %d set\n"
5033 " surface dup /s%ld exch def\n",
5034 drawable,
5035 _content_from_surface (ret),
5036 width, height,
5037 format->depth,
5038 obj->token);
5039 obj->defined = TRUE;
5040 obj->width = width;
5041 obj->height = height;
5042 obj->foreign = TRUE;
5043 _push_object (obj);
5044 dump_stack(__func__);
5045 _write_unlock ();
5046 }
5047
5048 _exit_trace ();
5049 return ret;
5050 }
5051 #endif
5052 #endif
5053
5054 #if CAIRO_HAS_SCRIPT_SURFACE
5055 #include <cairo-script.h>
5056 cairo_surface_t *
cairo_script_surface_create(cairo_device_t * device,cairo_content_t content,double width,double height)5057 cairo_script_surface_create (cairo_device_t *device,
5058 cairo_content_t content,
5059 double width,
5060 double height)
5061 {
5062 cairo_surface_t *ret;
5063
5064 _enter_trace ();
5065
5066 ret = DLCALL (cairo_script_surface_create, device, content, width, height);
5067
5068 _emit_line_info ();
5069 if (_write_lock ()) {
5070 Object *obj = _create_surface (ret);
5071
5072 _trace_printf ("dict\n"
5073 " /type /script set\n"
5074 " /content %s set\n"
5075 " /width %g set\n"
5076 " /height %g set\n"
5077 " surface dup /s%ld exch def\n",
5078 _content_to_string (content),
5079 width, height,
5080 obj->token);
5081 obj->width = width;
5082 obj->height = height;
5083 obj->defined = TRUE;
5084 _push_object (obj);
5085 dump_stack(__func__);
5086 _write_unlock ();
5087 }
5088
5089 _exit_trace ();
5090 return ret;
5091 }
5092
5093 cairo_surface_t *
cairo_script_surface_create_for_target(cairo_device_t * device,cairo_surface_t * target)5094 cairo_script_surface_create_for_target (cairo_device_t *device,
5095 cairo_surface_t *target)
5096 {
5097 cairo_surface_t *ret;
5098
5099 _enter_trace ();
5100
5101 ret = DLCALL (cairo_script_surface_create_for_target, device, target);
5102
5103 _emit_line_info ();
5104 if (_write_lock ()) {
5105 Object *obj = _create_surface (ret);
5106
5107 _trace_printf ("dict\n"
5108 " /type /script set\n"
5109 " surface dup /s%ld exch def\n",
5110 obj->token);
5111 obj->defined = TRUE;
5112 _push_object (obj);
5113 dump_stack(__func__);
5114 _write_unlock ();
5115 }
5116
5117 _exit_trace ();
5118 return ret;
5119 }
5120 #endif
5121
5122 #if CAIRO_HAS_TEST_SURFACES
5123 #include <test-paginated-surface.h>
5124 cairo_surface_t *
_cairo_test_paginated_surface_create(cairo_surface_t * surface)5125 _cairo_test_paginated_surface_create (cairo_surface_t *surface)
5126 {
5127 cairo_surface_t *ret;
5128
5129 _enter_trace ();
5130
5131 ret = DLCALL (_cairo_test_paginated_surface_create, surface);
5132
5133 _emit_line_info ();
5134 if (_write_lock ()) {
5135 Object *obj = _create_surface (ret);
5136
5137 /* XXX store initial data? */
5138 _trace_printf ("dict\n"
5139 " /type /test-paginated set\n"
5140 " /target s%ld set\n"
5141 " surface dup /s%ld exch def\n",
5142 _get_surface_id (surface),
5143 obj->token);
5144 _push_object (obj);
5145 dump_stack(__func__);
5146 _write_unlock ();
5147 }
5148
5149 _exit_trace ();
5150 return ret;
5151 }
5152
5153 #include <test-compositor-surface.h>
5154
5155 cairo_surface_t *
_cairo_test_fallback_compositor_surface_create(cairo_content_t content,int width,int height)5156 _cairo_test_fallback_compositor_surface_create (cairo_content_t content, int width, int height)
5157 {
5158 cairo_surface_t *ret;
5159
5160 _enter_trace ();
5161
5162 ret = DLCALL (_cairo_test_fallback_compositor_surface_create, content, width, height);
5163
5164 _emit_line_info ();
5165 if (_write_lock ()) {
5166 Object *obj = _create_surface (ret);
5167
5168 _trace_printf ("dict\n"
5169 " /type /test-fallback-compositor set\n"
5170 " /content //%s set\n"
5171 " /width %d set\n"
5172 " /height %d set\n"
5173 " surface dup /s%ld exch def\n",
5174 _content_to_string (content),
5175 width, height,
5176 obj->token);
5177 obj->defined = TRUE;
5178 _push_object (obj);
5179 dump_stack(__func__);
5180 _write_unlock ();
5181 }
5182
5183 _exit_trace ();
5184 return ret;
5185 }
5186
5187 cairo_surface_t *
_cairo_test_mask_compositor_surface_create(cairo_content_t content,int width,int height)5188 _cairo_test_mask_compositor_surface_create (cairo_content_t content, int width, int height)
5189 {
5190 cairo_surface_t *ret;
5191
5192 _enter_trace ();
5193
5194 ret = DLCALL (_cairo_test_mask_compositor_surface_create, content, width, height);
5195
5196 _emit_line_info ();
5197 if (_write_lock ()) {
5198 Object *obj = _create_surface (ret);
5199
5200 _trace_printf ("dict\n"
5201 " /type /test-mask-compositor set\n"
5202 " /content //%s set\n"
5203 " /width %d set\n"
5204 " /height %d set\n"
5205 " surface dup /s%ld exch def\n",
5206 _content_to_string (content),
5207 width, height,
5208 obj->token);
5209 obj->defined = TRUE;
5210 _push_object (obj);
5211 dump_stack(__func__);
5212 _write_unlock ();
5213 }
5214
5215 _exit_trace ();
5216 return ret;
5217 }
5218
5219 cairo_surface_t *
_cairo_test_spans_compositor_surface_create(cairo_content_t content,int width,int height)5220 _cairo_test_spans_compositor_surface_create (cairo_content_t content, int width, int height)
5221 {
5222 cairo_surface_t *ret;
5223
5224 _enter_trace ();
5225
5226 ret = DLCALL (_cairo_test_spans_compositor_surface_create, content, width, height);
5227
5228 _emit_line_info ();
5229 if (_write_lock ()) {
5230 Object *obj = _create_surface (ret);
5231
5232 _trace_printf ("dict\n"
5233 " /type /test-spans-compositor set\n"
5234 " /content //%s set\n"
5235 " /width %d set\n"
5236 " /height %d set\n"
5237 " surface dup /s%ld exch def\n",
5238 _content_to_string (content),
5239 width, height,
5240 obj->token);
5241 obj->defined = TRUE;
5242 _push_object (obj);
5243 dump_stack(__func__);
5244 _write_unlock ();
5245 }
5246
5247 _exit_trace ();
5248 return ret;
5249 }
5250
5251 cairo_surface_t *
_cairo_test_traps_compositor_surface_create(cairo_content_t content,int width,int height)5252 _cairo_test_traps_compositor_surface_create (cairo_content_t content, int width, int height)
5253 {
5254 cairo_surface_t *ret;
5255
5256 _enter_trace ();
5257
5258 ret = DLCALL (_cairo_test_traps_compositor_surface_create, content, width, height);
5259
5260 _emit_line_info ();
5261 if (_write_lock ()) {
5262 Object *obj = _create_surface (ret);
5263
5264 _trace_printf ("dict\n"
5265 " /type /test-traps-compositor set\n"
5266 " /content //%s set\n"
5267 " /width %d set\n"
5268 " /height %d set\n"
5269 " surface dup /s%ld exch def\n",
5270 _content_to_string (content),
5271 width, height,
5272 obj->token);
5273 obj->defined = TRUE;
5274 _push_object (obj);
5275 dump_stack(__func__);
5276 _write_unlock ();
5277 }
5278
5279 _exit_trace ();
5280 return ret;
5281 }
5282
5283 #endif
5284
5285 cairo_surface_t *
cairo_recording_surface_create(cairo_content_t content,const cairo_rectangle_t * extents)5286 cairo_recording_surface_create (cairo_content_t content,
5287 const cairo_rectangle_t *extents)
5288 {
5289 cairo_surface_t *ret;
5290
5291 _enter_trace ();
5292
5293 ret = DLCALL (cairo_recording_surface_create, content, extents);
5294
5295 _emit_line_info ();
5296 if (_write_lock ()) {
5297 Object *obj = _create_surface (ret);
5298
5299 if (extents) {
5300 _trace_printf ("//%s [ %f %f %f %f ] record dup /s%ld exch def\n",
5301 _content_to_string (content),
5302 extents->x, extents->y,
5303 extents->width, extents->height,
5304 obj->token);
5305 obj->width = extents->width;
5306 obj->height = extents->height;
5307 } else {
5308 _trace_printf ("//%s [ ] record dup /s%ld exch def\n",
5309 _content_to_string (content),
5310 obj->token);
5311 }
5312 obj->defined = TRUE;
5313 _push_object (obj);
5314 dump_stack(__func__);
5315 _write_unlock ();
5316 }
5317
5318 _exit_trace ();
5319 return ret;
5320 }
5321
5322 #if CAIRO_HAS_VG_SURFACE
5323 #include <cairo-vg.h>
5324 cairo_surface_t *
cairo_vg_surface_create(cairo_vg_context_t * context,cairo_content_t content,int width,int height)5325 cairo_vg_surface_create (cairo_vg_context_t *context,
5326 cairo_content_t content,
5327 int width, int height)
5328 {
5329 cairo_surface_t *ret;
5330
5331 _enter_trace ();
5332
5333 ret = DLCALL (cairo_vg_surface_create, context, content, width, height);
5334
5335 _emit_line_info ();
5336 if (_write_lock ()) {
5337 Object *obj = _create_surface (ret);
5338
5339 _trace_printf ("dict\n"
5340 " /type /vg set\n"
5341 " /content //%s set\n"
5342 " /width %d set\n"
5343 " /height %d set\n"
5344 " surface dup /s%ld exch def\n",
5345 _content_to_string (content),
5346 width, height,
5347 obj->token);
5348 obj->width = width;
5349 obj->height = height;
5350 obj->defined = TRUE;
5351 _push_object (obj);
5352 dump_stack(__func__);
5353 _write_unlock ();
5354 }
5355
5356 _exit_trace ();
5357 return ret;
5358 }
5359
5360 cairo_surface_t *
cairo_vg_surface_create_for_image(cairo_vg_context_t * context,VGImage image,VGImageFormat format,int width,int height)5361 cairo_vg_surface_create_for_image (cairo_vg_context_t *context,
5362 VGImage image,
5363 VGImageFormat format,
5364 int width, int height)
5365 {
5366 cairo_surface_t *ret;
5367
5368 _enter_trace ();
5369
5370 ret = DLCALL (cairo_vg_surface_create_for_image,
5371 context, image, format, width, height);
5372
5373 _emit_line_info ();
5374 if (_write_lock ()) {
5375 Object *obj = _create_surface (ret);
5376 cairo_content_t content;
5377
5378 content = DLCALL (cairo_surface_get_content, ret);
5379 _trace_printf ("dict\n"
5380 " /type /vg set\n"
5381 " /content //%s set\n"
5382 " /width %d set\n"
5383 " /height %d set\n"
5384 " surface dup /s%ld exch def\n",
5385 _content_to_string (content),
5386 width, height,
5387 obj->token);
5388 obj->width = width;
5389 obj->height = height;
5390 obj->defined = TRUE;
5391 _push_object (obj);
5392 dump_stack(__func__);
5393 _write_unlock ();
5394 }
5395
5396 _exit_trace ();
5397 return ret;
5398 }
5399 #endif
5400
5401 #if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE
5402 #include <cairo-gl.h>
5403 cairo_surface_t *
cairo_gl_surface_create(cairo_device_t * abstract_device,cairo_content_t content,int width,int height)5404 cairo_gl_surface_create (cairo_device_t *abstract_device,
5405 cairo_content_t content,
5406 int width,
5407 int height)
5408 {
5409 cairo_surface_t *ret;
5410
5411 _enter_trace ();
5412
5413 ret = DLCALL (cairo_gl_surface_create, abstract_device, content, width, height);
5414
5415 _emit_line_info ();
5416 if (_write_lock ()) {
5417 Object *obj = _create_surface (ret);
5418
5419 _trace_printf ("dict\n"
5420 " /type /gl set\n"
5421 " /content //%s set\n"
5422 " /width %d set\n"
5423 " /height %d set\n"
5424 " surface dup /s%ld exch def\n",
5425 _content_to_string (content),
5426 width, height,
5427 obj->token);
5428 obj->width = width;
5429 obj->height = height;
5430 obj->defined = TRUE;
5431 _push_object (obj);
5432 dump_stack(__func__);
5433 _write_unlock ();
5434 }
5435
5436 _exit_trace ();
5437 return ret;
5438 }
5439
5440 cairo_surface_t *
cairo_gl_surface_create_for_texture(cairo_device_t * abstract_device,cairo_content_t content,unsigned int tex,int width,int height)5441 cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
5442 cairo_content_t content,
5443 unsigned int tex,
5444 int width,
5445 int height)
5446 {
5447 cairo_surface_t *ret;
5448
5449 _enter_trace ();
5450
5451 ret = DLCALL (cairo_gl_surface_create_for_texture, abstract_device, content, tex, width, height);
5452
5453 _emit_line_info ();
5454 if (_write_lock ()) {
5455 Object *obj = _create_surface (ret);
5456
5457 _trace_printf ("dict\n"
5458 " /type /gl set\n"
5459 " /content //%s set\n"
5460 " /width %d set\n"
5461 " /height %d set\n"
5462 " surface dup /s%ld exch def\n",
5463 _content_to_string (content),
5464 width, height,
5465 obj->token);
5466 obj->width = width;
5467 obj->height = height;
5468 obj->defined = TRUE;
5469 _push_object (obj);
5470 dump_stack(__func__);
5471 _write_unlock ();
5472 }
5473
5474 _exit_trace ();
5475 return ret;
5476 }
5477
5478 #if CAIRO_HAS_GLX_FUNCTIONS
5479 cairo_surface_t *
cairo_gl_surface_create_for_window(cairo_device_t * device,Window win,int width,int height)5480 cairo_gl_surface_create_for_window (cairo_device_t *device,
5481 Window win,
5482 int width, int height)
5483 {
5484 cairo_surface_t *ret;
5485
5486 _enter_trace ();
5487
5488 ret = DLCALL (cairo_gl_surface_create_for_window, device, win, width, height);
5489
5490 _emit_line_info ();
5491 if (_write_lock ()) {
5492 Object *obj = _create_surface (ret);
5493
5494 _trace_printf ("dict\n"
5495 " /type /gl set\n"
5496 " /width %d set\n"
5497 " /height %d set\n"
5498 " surface dup /s%ld exch def\n",
5499 width, height,
5500 obj->token);
5501 obj->width = width;
5502 obj->height = height;
5503 obj->defined = TRUE;
5504 _push_object (obj);
5505 dump_stack(__func__);
5506 _write_unlock ();
5507 }
5508
5509 _exit_trace ();
5510 return ret;
5511 }
5512 #endif
5513
5514 #if CAIRO_HAS_WGL_FUNCTIONS
5515 cairo_surface_t *
cairo_gl_surface_create_for_dc(cairo_device_t * device,HDC dc,int width,int height)5516 cairo_gl_surface_create_for_dc (cairo_device_t *device,
5517 HDC dc,
5518 int width,
5519 int height)
5520 {
5521 cairo_surface_t *ret;
5522
5523 _enter_trace ();
5524
5525 ret = DLCALL (cairo_gl_surface_create_for_dc, device, dc, width, height);
5526
5527 _emit_line_info ();
5528 if (_write_lock ()) {
5529 Object *obj = _create_surface (ret);
5530
5531 _trace_printf ("dict\n"
5532 " /type /gl set\n"
5533 " /width %d set\n"
5534 " /height %d set\n"
5535 " surface dup /s%ld exch def\n",
5536 width, height,
5537 obj->token);
5538 obj->width = width;
5539 obj->height = height;
5540 obj->defined = TRUE;
5541 _push_object (obj);
5542 dump_stack(__func__);
5543 _write_unlock ();
5544 }
5545
5546 _exit_trace ();
5547 return ret;
5548 }
5549 #endif
5550
5551 #if CAIRO_HAS_EGL_FUNCTIONS
5552 cairo_surface_t *
cairo_gl_surface_create_for_egl(cairo_device_t * device,EGLSurface egl,int width,int height)5553 cairo_gl_surface_create_for_egl (cairo_device_t *device,
5554 EGLSurface egl,
5555 int width,
5556 int height)
5557 {
5558 cairo_surface_t *ret;
5559
5560 _enter_trace ();
5561
5562 ret = DLCALL (cairo_gl_surface_create_for_egl, device, egl, width, height);
5563
5564 _emit_line_info ();
5565 if (_write_lock ()) {
5566 Object *obj = _create_surface (ret);
5567
5568 _trace_printf ("dict\n"
5569 " /type /gl set\n"
5570 " /width %d set\n"
5571 " /height %d set\n"
5572 " surface dup /s%ld exch def\n",
5573 width, height,
5574 obj->token);
5575 obj->width = width;
5576 obj->height = height;
5577 obj->defined = TRUE;
5578 _push_object (obj);
5579 dump_stack(__func__);
5580 _write_unlock ();
5581 }
5582
5583 _exit_trace ();
5584 return ret;
5585 }
5586 #endif
5587 #endif
5588