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