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