tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-recording-surface.c
1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2005 Red Hat, Inc
5  * Copyright © 2007 Adrian Johnson
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it either under the terms of the GNU Lesser General Public
9  * License version 2.1 as published by the Free Software Foundation
10  * (the "LGPL") or, at your option, under the terms of the Mozilla
11  * Public License Version 1.1 (the "MPL"). If you do not alter this
12  * notice, a recipient may use your version of this file under either
13  * the MPL or the LGPL.
14  *
15  * You should have received a copy of the LGPL along with this library
16  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18  * You should have received a copy of the MPL along with this library
19  * in the file COPYING-MPL-1.1
20  *
21  * The contents of this file are subject to the Mozilla Public License
22  * Version 1.1 (the "License"); you may not use this file except in
23  * compliance with the License. You may obtain a copy of the License at
24  * http://www.mozilla.org/MPL/
25  *
26  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28  * the specific language governing rights and limitations.
29  *
30  * The Original Code is the cairo graphics library.
31  *
32  * The Initial Developer of the Original Code is Red Hat, Inc.
33  *
34  * Contributor(s):
35  *      Kristian Høgsberg <krh@redhat.com>
36  *      Carl Worth <cworth@cworth.org>
37  *      Adrian Johnson <ajohnson@redneon.com>
38  */
39
40 /**
41  * SECTION:cairo-recording
42  * @Title: Recording Surfaces
43  * @Short_Description: Records all drawing operations
44  * @See_Also: #cairo_surface_t
45  *
46  * A recording surface is a surface that records all drawing operations at
47  * the highest level of the surface backend interface, (that is, the
48  * level of paint, mask, stroke, fill, and show_text_glyphs). The recording
49  * surface can then be "replayed" against any target surface by using it
50  * as a source surface.
51  *
52  * If you want to replay a surface so that the results in target will be
53  * identical to the results that would have been obtained if the original
54  * operations applied to the recording surface had instead been applied to the
55  * target surface, you can use code like this:
56  * <informalexample><programlisting>
57  * cairo_t *cr;
58  *
59  * cr = cairo_create (target);
60  * cairo_set_source_surface (cr, recording_surface, 0.0, 0.0);
61  * cairo_paint (cr);
62  * cairo_destroy (cr);
63  * </programlisting></informalexample>
64  *
65  * A recording surface is logically unbounded, i.e. it has no implicit constraint
66  * on the size of the drawing surface. However, in practice this is rarely
67  * useful as you wish to replay against a particular target surface with
68  * known bounds. For this case, it is more efficient to specify the target
69  * extents to the recording surface upon creation.
70  *
71  * The recording phase of the recording surface is careful to snapshot all
72  * necessary objects (paths, patterns, etc.), in order to achieve
73  * accurate replay. The efficiency of the recording surface could be
74  * improved by improving the implementation of snapshot for the
75  * various objects. For example, it would be nice to have a
76  * copy-on-write implementation for _cairo_surface_snapshot.
77  **/
78
79 #include "cairoint.h"
80
81 #include "cairo-array-private.h"
82 #include "cairo-analysis-surface-private.h"
83 #include "cairo-clip-private.h"
84 #include "cairo-combsort-inline.h"
85 #include "cairo-composite-rectangles-private.h"
86 #include "cairo-default-context-private.h"
87 #include "cairo-error-private.h"
88 #include "cairo-image-surface-private.h"
89 #include "cairo-recording-surface-inline.h"
90 #include "cairo-surface-wrapper-private.h"
91 #include "cairo-traps-private.h"
92
93 typedef enum {
94     CAIRO_RECORDING_REPLAY,
95     CAIRO_RECORDING_CREATE_REGIONS
96 } cairo_recording_replay_type_t;
97
98 static const cairo_surface_backend_t cairo_recording_surface_backend;
99
100 /**
101  * CAIRO_HAS_RECORDING_SURFACE:
102  *
103  * Defined if the recording surface backend is available.
104  * The recording surface backend is always built in.
105  * This macro was added for completeness in cairo 1.10.
106  *
107  * Since: 1.10
108  **/
109
110 /* Currently all recording surfaces do have a size which should be passed
111  * in as the maximum size of any target surface against which the
112  * recording-surface will ever be replayed.
113  *
114  * XXX: The naming of "pixels" in the size here is a misnomer. It's
115  * actually a size in whatever device-space units are desired (again,
116  * according to the intended replay target).
117  */
118
119 static int bbtree_left_or_right (struct bbtree *bbt,
120                                  const cairo_box_t *box)
121 {
122     int left, right;
123
124     if (bbt->left) {
125         cairo_box_t *e = &bbt->left->extents;
126         cairo_box_t b;
127
128         b.p1.x = MIN (e->p1.x, box->p1.x);
129         b.p1.y = MIN (e->p1.y, box->p1.y);
130         b.p2.x = MAX (e->p2.x, box->p2.x);
131         b.p2.y = MAX (e->p2.y, box->p2.y);
132
133         left = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y);
134         left -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y);
135     } else
136         left = 0;
137
138     if (bbt->right) {
139         cairo_box_t *e = &bbt->right->extents;
140         cairo_box_t b;
141
142         b.p1.x = MIN (e->p1.x, box->p1.x);
143         b.p1.y = MIN (e->p1.y, box->p1.y);
144         b.p2.x = MAX (e->p2.x, box->p2.x);
145         b.p2.y = MAX (e->p2.y, box->p2.y);
146
147         right = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y);
148         right -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y);
149     } else
150         right = 0;
151
152     return left <= right;
153 }
154
155 #define INVALID_CHAIN ((cairo_command_header_t *)-1)
156
157 static struct bbtree *
158 bbtree_new (const cairo_box_t *box, cairo_command_header_t *chain)
159 {
160     struct bbtree *bbt = malloc (sizeof (*bbt));
161     if (bbt == NULL)
162         return NULL;
163     bbt->extents = *box;
164     bbt->left = bbt->right = NULL;
165     bbt->chain = chain;
166     return bbt;
167 }
168
169 static void
170 bbtree_init (struct bbtree *bbt, cairo_command_header_t *header)
171 {
172     _cairo_box_from_rectangle (&bbt->extents, &header->extents);
173     bbt->chain = header;
174 }
175
176 static cairo_status_t
177 bbtree_add (struct bbtree *bbt,
178             cairo_command_header_t *header,
179             const cairo_box_t *box)
180 {
181     if (box->p1.x < bbt->extents.p1.x || box->p1.y < bbt->extents.p1.y ||
182         box->p2.x > bbt->extents.p2.x || box->p2.y > bbt->extents.p2.y)
183     {
184         if (bbt->chain) {
185             if (bbtree_left_or_right (bbt, &bbt->extents)) {
186                 if (bbt->left == NULL) {
187                     bbt->left = bbtree_new (&bbt->extents, bbt->chain);
188                     if (unlikely (bbt->left == NULL))
189                         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
190                 } else
191                     bbtree_add (bbt->left, bbt->chain, &bbt->extents);
192             } else {
193                 if (bbt->right == NULL) {
194                     bbt->right = bbtree_new (&bbt->extents, bbt->chain);
195                     if (unlikely (bbt->right == NULL))
196                         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
197                 } else
198                     bbtree_add (bbt->right, bbt->chain, &bbt->extents);
199             }
200
201             bbt->chain = NULL;
202         }
203
204         bbt->extents.p1.x = MIN (bbt->extents.p1.x, box->p1.x);
205         bbt->extents.p1.y = MIN (bbt->extents.p1.y, box->p1.y);
206         bbt->extents.p2.x = MAX (bbt->extents.p2.x, box->p2.x);
207         bbt->extents.p2.y = MAX (bbt->extents.p2.y, box->p2.y);
208     }
209
210     if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y &&
211         box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y)
212     {
213         cairo_command_header_t *last = header;
214         while (last->chain) /* expected to be infrequent */
215             last = last->chain;
216         last->chain = bbt->chain;
217         bbt->chain = header;
218         return CAIRO_STATUS_SUCCESS;
219     }
220
221     if (bbtree_left_or_right (bbt, box)) {
222         if (bbt->left == NULL) {
223             bbt->left = bbtree_new (box, header);
224             if (unlikely (bbt->left == NULL))
225                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
226         } else
227             return bbtree_add (bbt->left, header, box);
228     } else {
229         if (bbt->right == NULL) {
230             bbt->right = bbtree_new (box, header);
231             if (unlikely (bbt->right == NULL))
232                 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
233         } else
234             return bbtree_add (bbt->right, header, box);
235     }
236
237     return CAIRO_STATUS_SUCCESS;
238 }
239
240 static void bbtree_del (struct bbtree *bbt)
241 {
242     if (bbt->left)
243         bbtree_del (bbt->left);
244     if (bbt->right)
245         bbtree_del (bbt->right);
246
247     free (bbt);
248 }
249
250 static cairo_bool_t box_outside (const cairo_box_t *a, const cairo_box_t *b)
251 {
252     return
253         a->p1.x >= b->p2.x || a->p1.y >= b->p2.y ||
254         a->p2.x <= b->p1.x || a->p2.y <= b->p1.y;
255 }
256
257 static void
258 bbtree_foreach_mark_visible (struct bbtree *bbt,
259                              const cairo_box_t *box,
260                              int **indices)
261 {
262     cairo_command_header_t *chain;
263
264     for (chain = bbt->chain; chain; chain = chain->chain)
265         *(*indices)++ = chain->index;
266
267     if (bbt->left && ! box_outside (box, &bbt->left->extents))
268         bbtree_foreach_mark_visible (bbt->left, box, indices);
269     if (bbt->right && ! box_outside (box, &bbt->right->extents))
270         bbtree_foreach_mark_visible (bbt->right, box, indices);
271 }
272
273 static inline int intcmp (const int a, const int b)
274 {
275     return a - b;
276 }
277 CAIRO_COMBSORT_DECLARE (sort_indices, int, intcmp)
278
279 static inline int sizecmp (int a, int b, cairo_command_header_t **elements)
280 {
281     const cairo_rectangle_int_t *r;
282
283     r = &elements[a]->extents;
284     a = r->width * r->height;
285
286     r = &elements[b]->extents;
287     b = r->width * r->height;
288
289     return b - a;
290 }
291 CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, int, sizecmp)
292
293 static void
294 _cairo_recording_surface_destroy_bbtree (cairo_recording_surface_t *surface)
295 {
296     cairo_command_t **elements;
297     int i, num_elements;
298
299     if (surface->bbtree.chain == INVALID_CHAIN)
300         return;
301
302     if (surface->bbtree.left) {
303         bbtree_del (surface->bbtree.left);
304         surface->bbtree.left = NULL;
305     }
306     if (surface->bbtree.right) {
307         bbtree_del (surface->bbtree.right);
308         surface->bbtree.right = NULL;
309     }
310
311     elements = _cairo_array_index (&surface->commands, 0);
312     num_elements = surface->commands.num_elements;
313     for (i = 0; i < num_elements; i++)
314         elements[i]->header.chain = NULL;
315
316     surface->bbtree.chain = INVALID_CHAIN;
317 }
318
319 static cairo_status_t
320 _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface)
321 {
322     cairo_command_t **elements = _cairo_array_index (&surface->commands, 0);
323     if (unlikely (elements == NULL))
324         return _cairo_error (CAIRO_STATUS_NULL_POINTER);
325
326     cairo_status_t status;
327     int i, count;
328     int *indices;
329
330     count = surface->commands.num_elements;
331     if (count > surface->num_indices) {
332         free (surface->indices);
333         surface->indices = _cairo_malloc_ab (count, sizeof (int));
334         if (unlikely (surface->indices == NULL))
335             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
336
337         surface->num_indices = count;
338     }
339
340     indices = surface->indices;
341     for (i = 0; i < count; i++)
342         indices[i] = i;
343
344     sort_commands (indices, count, elements);
345
346     bbtree_init (&surface->bbtree, &elements[indices[0]]->header);
347     for (i = 1; i < count; i++) {
348         cairo_command_header_t *header = &elements[indices[i]]->header;
349         cairo_box_t box;
350
351         _cairo_box_from_rectangle (&box, &header->extents);
352         status = bbtree_add (&surface->bbtree, header, &box);
353         if (unlikely (status))
354             goto cleanup;
355     }
356
357     return CAIRO_STATUS_SUCCESS;
358
359 cleanup:
360     bbtree_del (&surface->bbtree);
361     return status;
362 }
363
364 /**
365  * cairo_recording_surface_create:
366  * @content: the content of the recording surface
367  * @extents: the extents to record in pixels, can be %NULL to record
368  *           unbounded operations.
369  *
370  * Creates a recording-surface which can be used to record all drawing operations
371  * at the highest level (that is, the level of paint, mask, stroke, fill
372  * and show_text_glyphs). The recording surface can then be "replayed" against
373  * any target surface by using it as a source to drawing operations.
374  *
375  * The recording phase of the recording surface is careful to snapshot all
376  * necessary objects (paths, patterns, etc.), in order to achieve
377  * accurate replay.
378  *
379  * Return value: a pointer to the newly created surface. The caller
380  * owns the surface and should call cairo_surface_destroy() when done
381  * with it.
382  *
383  * Since: 1.10
384  **/
385 cairo_surface_t *
386 cairo_recording_surface_create (cairo_content_t          content,
387                                 const cairo_rectangle_t *extents)
388 {
389     cairo_recording_surface_t *surface;
390
391     surface = malloc (sizeof (cairo_recording_surface_t));
392     if (unlikely (surface == NULL))
393         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
394
395     _cairo_surface_init (&surface->base,
396                          &cairo_recording_surface_backend,
397                          NULL, /* device */
398                          content);
399
400
401     surface->unbounded = TRUE;
402
403     /* unbounded -> 'infinite' extents */
404     if (extents != NULL) {
405         surface->extents_pixels = *extents;
406
407         /* XXX check for overflow */
408         surface->extents.x = floor (extents->x);
409         surface->extents.y = floor (extents->y);
410         surface->extents.width = ceil (extents->x + extents->width) - surface->extents.x;
411         surface->extents.height = ceil (extents->y + extents->height) - surface->extents.y;
412
413         surface->unbounded = FALSE;
414     }
415
416     _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
417
418     surface->base.is_clear = TRUE;
419
420     surface->bbtree.left = surface->bbtree.right = NULL;
421     surface->bbtree.chain = INVALID_CHAIN;
422
423     surface->indices = NULL;
424     surface->num_indices = 0;
425     surface->optimize_clears = TRUE;
426
427     return &surface->base;
428 }
429 slim_hidden_def (cairo_recording_surface_create);
430
431 static cairo_surface_t *
432 _cairo_recording_surface_create_similar (void                  *abstract_surface,
433                                          cairo_content_t        content,
434                                          int                    width,
435                                          int                    height)
436 {
437     cairo_rectangle_t extents;
438     extents.x = extents.y = 0;
439     extents.width = width;
440     extents.height = height;
441     return cairo_recording_surface_create (content, &extents);
442 }
443
444 static cairo_status_t
445 _cairo_recording_surface_finish (void *abstract_surface)
446 {
447     cairo_recording_surface_t *surface = abstract_surface;
448     cairo_command_t **elements;
449     int i, num_elements;
450
451     num_elements = surface->commands.num_elements;
452     elements = _cairo_array_index (&surface->commands, 0);
453     for (i = 0; i < num_elements; i++) {
454         cairo_command_t *command = elements[i];
455
456         switch (command->header.type) {
457         case CAIRO_COMMAND_PAINT:
458             _cairo_pattern_fini (&command->paint.source.base);
459             break;
460
461         case CAIRO_COMMAND_MASK:
462             _cairo_pattern_fini (&command->mask.source.base);
463             _cairo_pattern_fini (&command->mask.mask.base);
464             break;
465
466         case CAIRO_COMMAND_STROKE:
467             _cairo_pattern_fini (&command->stroke.source.base);
468             _cairo_path_fixed_fini (&command->stroke.path);
469             _cairo_stroke_style_fini (&command->stroke.style);
470             break;
471
472         case CAIRO_COMMAND_FILL:
473             _cairo_pattern_fini (&command->fill.source.base);
474             _cairo_path_fixed_fini (&command->fill.path);
475             break;
476
477         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
478             _cairo_pattern_fini (&command->show_text_glyphs.source.base);
479             free (command->show_text_glyphs.utf8);
480             free (command->show_text_glyphs.glyphs);
481             free (command->show_text_glyphs.clusters);
482             cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
483             break;
484
485         default:
486             ASSERT_NOT_REACHED;
487         }
488
489         _cairo_clip_destroy (command->header.clip);
490         free (command);
491     }
492
493     _cairo_array_fini (&surface->commands);
494
495     if (surface->bbtree.left)
496         bbtree_del (surface->bbtree.left);
497     if (surface->bbtree.right)
498         bbtree_del (surface->bbtree.right);
499
500     free (surface->indices);
501
502     return CAIRO_STATUS_SUCCESS;
503 }
504
505 struct proxy {
506     cairo_surface_t base;
507     cairo_surface_t *image;
508 };
509
510 static cairo_status_t
511 proxy_acquire_source_image (void                         *abstract_surface,
512                             cairo_image_surface_t       **image_out,
513                             void                        **image_extra)
514 {
515     struct proxy *proxy = abstract_surface;
516     return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
517 }
518
519 static void
520 proxy_release_source_image (void                        *abstract_surface,
521                             cairo_image_surface_t       *image,
522                             void                        *image_extra)
523 {
524     struct proxy *proxy = abstract_surface;
525     _cairo_surface_release_source_image (proxy->image, image, image_extra);
526 }
527
528 static cairo_status_t
529 proxy_finish (void *abstract_surface)
530 {
531     return CAIRO_STATUS_SUCCESS;
532 }
533
534 static const cairo_surface_backend_t proxy_backend  = {
535     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
536     proxy_finish,
537     NULL,
538
539     NULL, /* create similar */
540     NULL, /* create similar image */
541     NULL, /* map to image */
542     NULL, /* unmap image */
543
544     _cairo_surface_default_source,
545     proxy_acquire_source_image,
546     proxy_release_source_image,
547 };
548
549 static cairo_surface_t *
550 attach_proxy (cairo_surface_t *source,
551               cairo_surface_t *image)
552 {
553     struct proxy *proxy;
554
555     proxy = malloc (sizeof (*proxy));
556     if (unlikely (proxy == NULL))
557         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
558
559     _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content);
560
561     proxy->image = image;
562     _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
563
564     return &proxy->base;
565 }
566
567 static void
568 detach_proxy (cairo_surface_t *source,
569               cairo_surface_t *proxy)
570 {
571     cairo_surface_finish (proxy);
572     cairo_surface_destroy (proxy);
573 }
574
575 static cairo_surface_t *
576 get_proxy (cairo_surface_t *proxy)
577 {
578     return ((struct proxy *)proxy)->image;
579 }
580
581 static cairo_status_t
582 _cairo_recording_surface_acquire_source_image (void                      *abstract_surface,
583                                                cairo_image_surface_t    **image_out,
584                                                void                     **image_extra)
585 {
586     cairo_recording_surface_t *surface = abstract_surface;
587     cairo_surface_t *image, *proxy;
588     cairo_status_t status;
589
590     proxy = _cairo_surface_has_snapshot (abstract_surface, &proxy_backend);
591     if (proxy != NULL) {
592         *image_out = (cairo_image_surface_t *)
593             cairo_surface_reference (get_proxy (proxy));
594         *image_extra = NULL;
595         return CAIRO_STATUS_SUCCESS;
596     }
597
598     assert (! surface->unbounded);
599     image = _cairo_image_surface_create_with_content (surface->base.content,
600                                                       surface->extents.width,
601                                                       surface->extents.height);
602     if (unlikely (image->status)) {
603         status = image->status;
604         cairo_surface_destroy (image);
605         return status;
606     }
607
608     /* Handle recursion by returning future reads from the current image */
609     proxy = attach_proxy (abstract_surface, image);
610     status = _cairo_recording_surface_replay (&surface->base, image);
611     detach_proxy (abstract_surface, proxy);
612
613     if (unlikely (status)) {
614         cairo_surface_destroy (image);
615         return status;
616     }
617
618     *image_out = (cairo_image_surface_t *) image;
619     *image_extra = NULL;
620     return CAIRO_STATUS_SUCCESS;
621 }
622
623 static void
624 _cairo_recording_surface_release_source_image (void                     *abstract_surface,
625                                                cairo_image_surface_t    *image,
626                                                void                     *image_extra)
627 {
628     cairo_surface_destroy (&image->base);
629 }
630
631 static cairo_status_t
632 _command_init (cairo_recording_surface_t *surface,
633                cairo_command_header_t *command,
634                cairo_command_type_t type,
635                cairo_operator_t op,
636                cairo_composite_rectangles_t *composite)
637 {
638     cairo_status_t status = CAIRO_STATUS_SUCCESS;
639
640     command->type = type;
641     command->op = op;
642     command->region = CAIRO_RECORDING_REGION_ALL;
643
644     command->extents = composite->unbounded;
645     command->chain = NULL;
646     command->index = surface->commands.num_elements;
647
648     /* steal the clip */
649     command->clip = NULL;
650     if (! _cairo_composite_rectangles_can_reduce_clip (composite,
651                                                        composite->clip))
652     {
653         command->clip = composite->clip;
654         composite->clip = NULL;
655     }
656
657     return status;
658 }
659
660 static void
661 _cairo_recording_surface_break_self_copy_loop (cairo_recording_surface_t *surface)
662 {
663     cairo_surface_flush (&surface->base);
664 }
665
666 static cairo_status_t
667 _cairo_recording_surface_commit (cairo_recording_surface_t *surface,
668                                  cairo_command_header_t *command)
669 {
670     _cairo_recording_surface_break_self_copy_loop (surface);
671     return _cairo_array_append (&surface->commands, &command);
672 }
673
674 static void
675 _cairo_recording_surface_reset (cairo_recording_surface_t *surface)
676 {
677     /* Reset the commands and temporaries */
678     _cairo_recording_surface_finish (surface);
679
680     surface->bbtree.left = surface->bbtree.right = NULL;
681     surface->bbtree.chain = INVALID_CHAIN;
682
683     surface->indices = NULL;
684     surface->num_indices = 0;
685
686     _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
687 }
688
689 static cairo_bool_t
690 is_identity_recording_pattern (const cairo_pattern_t *pattern)
691 {
692     cairo_surface_t *surface;
693
694     if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
695         return FALSE;
696
697     if (!_cairo_matrix_is_identity(&pattern->matrix))
698         return FALSE;
699
700     surface = ((cairo_surface_pattern_t *)pattern)->surface;
701     return surface->backend->type == CAIRO_SURFACE_TYPE_RECORDING;
702 }
703
704 static cairo_int_status_t
705 _cairo_recording_surface_paint (void                      *abstract_surface,
706                                 cairo_operator_t           op,
707                                 const cairo_pattern_t     *source,
708                                 const cairo_clip_t        *clip)
709 {
710     cairo_status_t status;
711     cairo_recording_surface_t *surface = abstract_surface;
712     cairo_command_paint_t *command;
713     cairo_composite_rectangles_t composite;
714
715     TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));
716
717     if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
718         if (surface->optimize_clears) {
719             _cairo_recording_surface_reset (surface);
720             return CAIRO_STATUS_SUCCESS;
721         }
722     }
723
724     if (clip == NULL && surface->optimize_clears &&
725         (op == CAIRO_OPERATOR_SOURCE ||
726          (op == CAIRO_OPERATOR_OVER &&
727           (surface->base.is_clear || _cairo_pattern_is_opaque_solid (source)))))
728     {
729         _cairo_recording_surface_reset (surface);
730         if (is_identity_recording_pattern (source)) {
731             cairo_surface_t *src = ((cairo_surface_pattern_t *)source)->surface;
732             return _cairo_recording_surface_replay (src, &surface->base);
733         }
734     }
735
736     status = _cairo_composite_rectangles_init_for_paint (&composite,
737                                                          &surface->base,
738                                                          op, source,
739                                                          clip);
740     if (unlikely (status))
741         return status;
742
743     command = malloc (sizeof (cairo_command_paint_t));
744     if (unlikely (command == NULL)) {
745         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
746         goto CLEANUP_COMPOSITE;
747     }
748
749     status = _command_init (surface,
750                             &command->header, CAIRO_COMMAND_PAINT, op,
751                             &composite);
752     if (unlikely (status))
753         goto CLEANUP_COMMAND;
754
755     status = _cairo_pattern_init_snapshot (&command->source.base, source);
756     if (unlikely (status))
757         goto CLEANUP_COMMAND;
758
759     status = _cairo_recording_surface_commit (surface, &command->header);
760     if (unlikely (status))
761         goto CLEANUP_SOURCE;
762
763     _cairo_recording_surface_destroy_bbtree (surface);
764
765     _cairo_composite_rectangles_fini (&composite);
766     return CAIRO_STATUS_SUCCESS;
767
768   CLEANUP_SOURCE:
769     _cairo_pattern_fini (&command->source.base);
770   CLEANUP_COMMAND:
771     _cairo_clip_destroy (command->header.clip);
772     free (command);
773 CLEANUP_COMPOSITE:
774     _cairo_composite_rectangles_fini (&composite);
775     return status;
776 }
777
778 static cairo_int_status_t
779 _cairo_recording_surface_mask (void                     *abstract_surface,
780                                cairo_operator_t          op,
781                                const cairo_pattern_t    *source,
782                                const cairo_pattern_t    *mask,
783                                const cairo_clip_t       *clip)
784 {
785     cairo_status_t status;
786     cairo_recording_surface_t *surface = abstract_surface;
787     cairo_command_mask_t *command;
788     cairo_composite_rectangles_t composite;
789
790     TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));
791
792     status = _cairo_composite_rectangles_init_for_mask (&composite,
793                                                         &surface->base,
794                                                         op, source, mask,
795                                                         clip);
796     if (unlikely (status))
797         return status;
798
799     command = malloc (sizeof (cairo_command_mask_t));
800     if (unlikely (command == NULL)) {
801         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
802         goto CLEANUP_COMPOSITE;
803     }
804
805     status = _command_init (surface,
806                             &command->header, CAIRO_COMMAND_MASK, op,
807                             &composite);
808     if (unlikely (status))
809         goto CLEANUP_COMMAND;
810
811     status = _cairo_pattern_init_snapshot (&command->source.base, source);
812     if (unlikely (status))
813         goto CLEANUP_COMMAND;
814
815     status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
816     if (unlikely (status))
817         goto CLEANUP_SOURCE;
818
819     status = _cairo_recording_surface_commit (surface, &command->header);
820     if (unlikely (status))
821         goto CLEANUP_MASK;
822
823     _cairo_recording_surface_destroy_bbtree (surface);
824
825     _cairo_composite_rectangles_fini (&composite);
826     return CAIRO_STATUS_SUCCESS;
827
828   CLEANUP_MASK:
829     _cairo_pattern_fini (&command->mask.base);
830   CLEANUP_SOURCE:
831     _cairo_pattern_fini (&command->source.base);
832   CLEANUP_COMMAND:
833     _cairo_clip_destroy (command->header.clip);
834     free (command);
835 CLEANUP_COMPOSITE:
836     _cairo_composite_rectangles_fini (&composite);
837     return status;
838 }
839
840 static cairo_int_status_t
841 _cairo_recording_surface_stroke (void                   *abstract_surface,
842                                  cairo_operator_t        op,
843                                  const cairo_pattern_t  *source,
844                                  const cairo_path_fixed_t       *path,
845                                  const cairo_stroke_style_t     *style,
846                                  const cairo_matrix_t           *ctm,
847                                  const cairo_matrix_t           *ctm_inverse,
848                                  double                  tolerance,
849                                  cairo_antialias_t       antialias,
850                                  const cairo_clip_t     *clip)
851 {
852     cairo_status_t status;
853     cairo_recording_surface_t *surface = abstract_surface;
854     cairo_command_stroke_t *command;
855     cairo_composite_rectangles_t composite;
856
857     TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));
858
859     status = _cairo_composite_rectangles_init_for_stroke (&composite,
860                                                           &surface->base,
861                                                           op, source,
862                                                           path, style, ctm,
863                                                           clip);
864     if (unlikely (status))
865         return status;
866
867     command = malloc (sizeof (cairo_command_stroke_t));
868     if (unlikely (command == NULL)) {
869         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
870         goto CLEANUP_COMPOSITE;
871     }
872
873     status = _command_init (surface,
874                             &command->header, CAIRO_COMMAND_STROKE, op,
875                             &composite);
876     if (unlikely (status))
877         goto CLEANUP_COMMAND;
878
879     status = _cairo_pattern_init_snapshot (&command->source.base, source);
880     if (unlikely (status))
881         goto CLEANUP_COMMAND;
882
883     status = _cairo_path_fixed_init_copy (&command->path, path);
884     if (unlikely (status))
885         goto CLEANUP_SOURCE;
886
887     status = _cairo_stroke_style_init_copy (&command->style, style);
888     if (unlikely (status))
889         goto CLEANUP_PATH;
890
891     command->ctm = *ctm;
892     command->ctm_inverse = *ctm_inverse;
893     command->tolerance = tolerance;
894     command->antialias = antialias;
895
896     status = _cairo_recording_surface_commit (surface, &command->header);
897     if (unlikely (status))
898         goto CLEANUP_STYLE;
899
900     _cairo_recording_surface_destroy_bbtree (surface);
901
902     _cairo_composite_rectangles_fini (&composite);
903     return CAIRO_STATUS_SUCCESS;
904
905   CLEANUP_STYLE:
906     _cairo_stroke_style_fini (&command->style);
907   CLEANUP_PATH:
908     _cairo_path_fixed_fini (&command->path);
909   CLEANUP_SOURCE:
910     _cairo_pattern_fini (&command->source.base);
911   CLEANUP_COMMAND:
912     _cairo_clip_destroy (command->header.clip);
913     free (command);
914 CLEANUP_COMPOSITE:
915     _cairo_composite_rectangles_fini (&composite);
916     return status;
917 }
918
919 static cairo_int_status_t
920 _cairo_recording_surface_fill (void                     *abstract_surface,
921                                cairo_operator_t          op,
922                                const cairo_pattern_t    *source,
923                                const cairo_path_fixed_t *path,
924                                cairo_fill_rule_t         fill_rule,
925                                double                    tolerance,
926                                cairo_antialias_t         antialias,
927                                const cairo_clip_t       *clip)
928 {
929     cairo_status_t status;
930     cairo_recording_surface_t *surface = abstract_surface;
931     cairo_command_fill_t *command;
932     cairo_composite_rectangles_t composite;
933
934     TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));
935
936     status = _cairo_composite_rectangles_init_for_fill (&composite,
937                                                         &surface->base,
938                                                         op, source, path,
939                                                         clip);
940     if (unlikely (status))
941         return status;
942
943     command = malloc (sizeof (cairo_command_fill_t));
944     if (unlikely (command == NULL)) {
945         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
946         goto CLEANUP_COMPOSITE;
947     }
948
949     status =_command_init (surface,
950                            &command->header, CAIRO_COMMAND_FILL, op,
951                            &composite);
952     if (unlikely (status))
953         goto CLEANUP_COMMAND;
954
955     status = _cairo_pattern_init_snapshot (&command->source.base, source);
956     if (unlikely (status))
957         goto CLEANUP_COMMAND;
958
959     status = _cairo_path_fixed_init_copy (&command->path, path);
960     if (unlikely (status))
961         goto CLEANUP_SOURCE;
962
963     command->fill_rule = fill_rule;
964     command->tolerance = tolerance;
965     command->antialias = antialias;
966
967     status = _cairo_recording_surface_commit (surface, &command->header);
968     if (unlikely (status))
969         goto CLEANUP_PATH;
970
971     _cairo_recording_surface_destroy_bbtree (surface);
972
973     _cairo_composite_rectangles_fini (&composite);
974     return CAIRO_STATUS_SUCCESS;
975
976   CLEANUP_PATH:
977     _cairo_path_fixed_fini (&command->path);
978   CLEANUP_SOURCE:
979     _cairo_pattern_fini (&command->source.base);
980   CLEANUP_COMMAND:
981     _cairo_clip_destroy (command->header.clip);
982     free (command);
983 CLEANUP_COMPOSITE:
984     _cairo_composite_rectangles_fini (&composite);
985     return status;
986 }
987
988 static cairo_bool_t
989 _cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
990 {
991     return TRUE;
992 }
993
994 static cairo_int_status_t
995 _cairo_recording_surface_show_text_glyphs (void                         *abstract_surface,
996                                            cairo_operator_t              op,
997                                            const cairo_pattern_t        *source,
998                                            const char                   *utf8,
999                                            int                           utf8_len,
1000                                            cairo_glyph_t                *glyphs,
1001                                            int                           num_glyphs,
1002                                            const cairo_text_cluster_t   *clusters,
1003                                            int                           num_clusters,
1004                                            cairo_text_cluster_flags_t    cluster_flags,
1005                                            cairo_scaled_font_t          *scaled_font,
1006                                            const cairo_clip_t           *clip)
1007 {
1008     cairo_status_t status;
1009     cairo_recording_surface_t *surface = abstract_surface;
1010     cairo_command_show_text_glyphs_t *command;
1011     cairo_composite_rectangles_t composite;
1012
1013     TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));
1014
1015     status = _cairo_composite_rectangles_init_for_glyphs (&composite,
1016                                                           &surface->base,
1017                                                           op, source,
1018                                                           scaled_font,
1019                                                           glyphs, num_glyphs,
1020                                                           clip,
1021                                                           NULL);
1022     if (unlikely (status))
1023         return status;
1024
1025     command = malloc (sizeof (cairo_command_show_text_glyphs_t));
1026     if (unlikely (command == NULL)) {
1027         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1028         goto CLEANUP_COMPOSITE;
1029     }
1030
1031     status = _command_init (surface,
1032                             &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
1033                             op, &composite);
1034     if (unlikely (status))
1035         goto CLEANUP_COMMAND;
1036
1037     status = _cairo_pattern_init_snapshot (&command->source.base, source);
1038     if (unlikely (status))
1039         goto CLEANUP_COMMAND;
1040
1041     command->utf8 = NULL;
1042     command->utf8_len = utf8_len;
1043     command->glyphs = NULL;
1044     command->num_glyphs = num_glyphs;
1045     command->clusters = NULL;
1046     command->num_clusters = num_clusters;
1047
1048     if (utf8_len) {
1049         command->utf8 = malloc (utf8_len);
1050         if (unlikely (command->utf8 == NULL)) {
1051             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1052             goto CLEANUP_ARRAYS;
1053         }
1054         memcpy (command->utf8, utf8, utf8_len);
1055     }
1056     if (num_glyphs) {
1057         command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
1058         if (unlikely (command->glyphs == NULL)) {
1059             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1060             goto CLEANUP_ARRAYS;
1061         }
1062         memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
1063     }
1064     if (num_clusters) {
1065         command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
1066         if (unlikely (command->clusters == NULL)) {
1067             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1068             goto CLEANUP_ARRAYS;
1069         }
1070         memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
1071     }
1072
1073     command->cluster_flags = cluster_flags;
1074
1075     command->scaled_font = cairo_scaled_font_reference (scaled_font);
1076
1077     status = _cairo_recording_surface_commit (surface, &command->header);
1078     if (unlikely (status))
1079         goto CLEANUP_SCALED_FONT;
1080
1081     _cairo_composite_rectangles_fini (&composite);
1082     return CAIRO_STATUS_SUCCESS;
1083
1084   CLEANUP_SCALED_FONT:
1085     cairo_scaled_font_destroy (command->scaled_font);
1086   CLEANUP_ARRAYS:
1087     free (command->utf8);
1088     free (command->glyphs);
1089     free (command->clusters);
1090
1091     _cairo_pattern_fini (&command->source.base);
1092   CLEANUP_COMMAND:
1093     _cairo_clip_destroy (command->header.clip);
1094     free (command);
1095 CLEANUP_COMPOSITE:
1096     _cairo_composite_rectangles_fini (&composite);
1097     return status;
1098 }
1099
1100 static void
1101 _command_init_copy (cairo_recording_surface_t *surface,
1102                     cairo_command_header_t *dst,
1103                     const cairo_command_header_t *src)
1104 {
1105     dst->type = src->type;
1106     dst->op = src->op;
1107     dst->region = CAIRO_RECORDING_REGION_ALL;
1108
1109     dst->extents = src->extents;
1110     dst->chain = NULL;
1111     dst->index = surface->commands.num_elements;
1112
1113     dst->clip = _cairo_clip_copy (src->clip);
1114 }
1115
1116 static cairo_status_t
1117 _cairo_recording_surface_copy__paint (cairo_recording_surface_t *surface,
1118                                       const cairo_command_t *src)
1119 {
1120     cairo_command_paint_t *command;
1121     cairo_status_t status;
1122
1123     command = malloc (sizeof (*command));
1124     if (unlikely (command == NULL)) {
1125         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1126         goto err;
1127     }
1128
1129     _command_init_copy (surface, &command->header, &src->header);
1130
1131     status = _cairo_pattern_init_copy (&command->source.base,
1132                                        &src->paint.source.base);
1133     if (unlikely (status))
1134         goto err_command;
1135
1136     status = _cairo_recording_surface_commit (surface, &command->header);
1137     if (unlikely (status))
1138         goto err_source;
1139
1140     return CAIRO_STATUS_SUCCESS;
1141
1142 err_source:
1143     _cairo_pattern_fini (&command->source.base);
1144 err_command:
1145     free(command);
1146 err:
1147     return status;
1148 }
1149
1150 static cairo_status_t
1151 _cairo_recording_surface_copy__mask (cairo_recording_surface_t *surface,
1152                                      const cairo_command_t *src)
1153 {
1154     cairo_command_mask_t *command;
1155     cairo_status_t status;
1156
1157     command = malloc (sizeof (*command));
1158     if (unlikely (command == NULL)) {
1159         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1160         goto err;
1161     }
1162
1163     _command_init_copy (surface, &command->header, &src->header);
1164
1165     status = _cairo_pattern_init_copy (&command->source.base,
1166                                        &src->mask.source.base);
1167     if (unlikely (status))
1168         goto err_command;
1169
1170     status = _cairo_pattern_init_copy (&command->mask.base,
1171                                        &src->mask.source.base);
1172     if (unlikely (status))
1173         goto err_source;
1174
1175     status = _cairo_recording_surface_commit (surface, &command->header);
1176     if (unlikely (status))
1177         goto err_mask;
1178
1179     return CAIRO_STATUS_SUCCESS;
1180
1181 err_mask:
1182     _cairo_pattern_fini (&command->mask.base);
1183 err_source:
1184     _cairo_pattern_fini (&command->source.base);
1185 err_command:
1186     free(command);
1187 err:
1188     return status;
1189 }
1190
1191 static cairo_status_t
1192 _cairo_recording_surface_copy__stroke (cairo_recording_surface_t *surface,
1193                                      const cairo_command_t *src)
1194 {
1195     cairo_command_stroke_t *command;
1196     cairo_status_t status;
1197
1198     command = malloc (sizeof (*command));
1199     if (unlikely (command == NULL)) {
1200         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1201         goto err;
1202     }
1203
1204     _command_init_copy (surface, &command->header, &src->header);
1205
1206     status = _cairo_pattern_init_copy (&command->source.base,
1207                                        &src->stroke.source.base);
1208     if (unlikely (status))
1209         goto err_command;
1210
1211     status = _cairo_path_fixed_init_copy (&command->path, &src->stroke.path);
1212     if (unlikely (status))
1213         goto err_source;
1214
1215     status = _cairo_stroke_style_init_copy (&command->style,
1216                                             &src->stroke.style);
1217     if (unlikely (status))
1218         goto err_path;
1219
1220     command->ctm = src->stroke.ctm;
1221     command->ctm_inverse = src->stroke.ctm_inverse;
1222     command->tolerance = src->stroke.tolerance;
1223     command->antialias = src->stroke.antialias;
1224
1225     status = _cairo_recording_surface_commit (surface, &command->header);
1226     if (unlikely (status))
1227         goto err_style;
1228
1229     return CAIRO_STATUS_SUCCESS;
1230
1231 err_style:
1232     _cairo_stroke_style_fini (&command->style);
1233 err_path:
1234     _cairo_path_fixed_fini (&command->path);
1235 err_source:
1236     _cairo_pattern_fini (&command->source.base);
1237 err_command:
1238     free(command);
1239 err:
1240     return status;
1241 }
1242
1243 static cairo_status_t
1244 _cairo_recording_surface_copy__fill (cairo_recording_surface_t *surface,
1245                                      const cairo_command_t *src)
1246 {
1247     cairo_command_fill_t *command;
1248     cairo_status_t status;
1249
1250     command = malloc (sizeof (*command));
1251     if (unlikely (command == NULL)) {
1252         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1253         goto err;
1254     }
1255
1256     _command_init_copy (surface, &command->header, &src->header);
1257
1258     status = _cairo_pattern_init_copy (&command->source.base,
1259                                        &src->fill.source.base);
1260     if (unlikely (status))
1261         goto err_command;
1262
1263     status = _cairo_path_fixed_init_copy (&command->path, &src->fill.path);
1264     if (unlikely (status))
1265         goto err_source;
1266
1267     command->fill_rule = src->fill.fill_rule;
1268     command->tolerance = src->fill.tolerance;
1269     command->antialias = src->fill.antialias;
1270
1271     status = _cairo_recording_surface_commit (surface, &command->header);
1272     if (unlikely (status))
1273         goto err_path;
1274
1275     return CAIRO_STATUS_SUCCESS;
1276
1277 err_path:
1278     _cairo_path_fixed_fini (&command->path);
1279 err_source:
1280     _cairo_pattern_fini (&command->source.base);
1281 err_command:
1282     free(command);
1283 err:
1284     return status;
1285 }
1286
1287 static cairo_status_t
1288 _cairo_recording_surface_copy__glyphs (cairo_recording_surface_t *surface,
1289                                        const cairo_command_t *src)
1290 {
1291     cairo_command_show_text_glyphs_t *command;
1292     cairo_status_t status;
1293
1294     command = malloc (sizeof (*command));
1295     if (unlikely (command == NULL)) {
1296         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1297         goto err;
1298     }
1299
1300     _command_init_copy (surface, &command->header, &src->header);
1301
1302     status = _cairo_pattern_init_copy (&command->source.base,
1303                                        &src->show_text_glyphs.source.base);
1304     if (unlikely (status))
1305         goto err_command;
1306
1307     command->utf8 = NULL;
1308     command->utf8_len = src->show_text_glyphs.utf8_len;
1309     command->glyphs = NULL;
1310     command->num_glyphs = src->show_text_glyphs.num_glyphs;
1311     command->clusters = NULL;
1312     command->num_clusters = src->show_text_glyphs.num_clusters;
1313
1314     if (command->utf8_len) {
1315         command->utf8 = malloc (command->utf8_len);
1316         if (unlikely (command->utf8 == NULL)) {
1317             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1318             goto err_arrays;
1319         }
1320         memcpy (command->utf8, src->show_text_glyphs.utf8, command->utf8_len);
1321     }
1322     if (command->num_glyphs) {
1323         command->glyphs = _cairo_malloc_ab (command->num_glyphs,
1324                                             sizeof (command->glyphs[0]));
1325         if (unlikely (command->glyphs == NULL)) {
1326             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1327             goto err_arrays;
1328         }
1329         memcpy (command->glyphs, src->show_text_glyphs.glyphs,
1330                 sizeof (command->glyphs[0]) * command->num_glyphs);
1331     }
1332     if (command->num_clusters) {
1333         command->clusters = _cairo_malloc_ab (command->num_clusters,
1334                                               sizeof (command->clusters[0]));
1335         if (unlikely (command->clusters == NULL)) {
1336             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1337             goto err_arrays;
1338         }
1339         memcpy (command->clusters, src->show_text_glyphs.clusters,
1340                 sizeof (command->clusters[0]) * command->num_clusters);
1341     }
1342
1343     command->cluster_flags = src->show_text_glyphs.cluster_flags;
1344
1345     command->scaled_font =
1346         cairo_scaled_font_reference (src->show_text_glyphs.scaled_font);
1347
1348     status = _cairo_recording_surface_commit (surface, &command->header);
1349     if (unlikely (status))
1350         goto err_arrays;
1351
1352     return CAIRO_STATUS_SUCCESS;
1353
1354 err_arrays:
1355     free (command->utf8);
1356     free (command->glyphs);
1357     free (command->clusters);
1358     _cairo_pattern_fini (&command->source.base);
1359 err_command:
1360     free(command);
1361 err:
1362     return status;
1363 }
1364
1365 static cairo_status_t
1366 _cairo_recording_surface_copy (cairo_recording_surface_t *dst,
1367                                cairo_recording_surface_t *src)
1368 {
1369     cairo_command_t **elements;
1370     int i, num_elements;
1371     cairo_status_t status;
1372
1373     elements = _cairo_array_index (&src->commands, 0);
1374     num_elements = src->commands.num_elements;
1375     for (i = 0; i < num_elements; i++) {
1376         const cairo_command_t *command = elements[i];
1377
1378         switch (command->header.type) {
1379         case CAIRO_COMMAND_PAINT:
1380             status = _cairo_recording_surface_copy__paint (dst, command);
1381             break;
1382
1383         case CAIRO_COMMAND_MASK:
1384             status = _cairo_recording_surface_copy__mask (dst, command);
1385             break;
1386
1387         case CAIRO_COMMAND_STROKE:
1388             status = _cairo_recording_surface_copy__stroke (dst, command);
1389             break;
1390
1391         case CAIRO_COMMAND_FILL:
1392             status = _cairo_recording_surface_copy__fill (dst, command);
1393             break;
1394
1395         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
1396             status = _cairo_recording_surface_copy__glyphs (dst, command);
1397             break;
1398
1399         default:
1400             ASSERT_NOT_REACHED;
1401         }
1402
1403         if (unlikely (status))
1404             return status;
1405     }
1406
1407     return CAIRO_STATUS_SUCCESS;
1408 }
1409
1410 /**
1411  * _cairo_recording_surface_snapshot:
1412  * @surface: a #cairo_surface_t which must be a recording surface
1413  *
1414  * Make an immutable copy of @surface. It is an error to call a
1415  * surface-modifying function on the result of this function.
1416  *
1417  * The caller owns the return value and should call
1418  * cairo_surface_destroy() when finished with it. This function will not
1419  * return %NULL, but will return a nil surface instead.
1420  *
1421  * Return value: The snapshot surface.
1422  **/
1423 static cairo_surface_t *
1424 _cairo_recording_surface_snapshot (void *abstract_other)
1425 {
1426     cairo_recording_surface_t *other = abstract_other;
1427     cairo_recording_surface_t *surface;
1428     cairo_status_t status;
1429
1430     surface = malloc (sizeof (cairo_recording_surface_t));
1431     if (unlikely (surface == NULL))
1432         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1433
1434     _cairo_surface_init (&surface->base,
1435                          &cairo_recording_surface_backend,
1436                          NULL, /* device */
1437                          other->base.content);
1438
1439     surface->extents_pixels = other->extents_pixels;
1440     surface->extents = other->extents;
1441     surface->unbounded = other->unbounded;
1442
1443     surface->base.is_clear = other->base.is_clear;
1444
1445     surface->bbtree.left = surface->bbtree.right = NULL;
1446     surface->bbtree.chain = INVALID_CHAIN;
1447
1448     surface->indices = NULL;
1449     surface->num_indices = 0;
1450     surface->optimize_clears = TRUE;
1451
1452     _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
1453     status = _cairo_recording_surface_copy (surface, other);
1454     if (unlikely (status)) {
1455         cairo_surface_destroy (&surface->base);
1456         return _cairo_surface_create_in_error (status);
1457     }
1458
1459     return &surface->base;
1460 }
1461
1462 static cairo_bool_t
1463 _cairo_recording_surface_get_extents (void                  *abstract_surface,
1464                                       cairo_rectangle_int_t *rectangle)
1465 {
1466     cairo_recording_surface_t *surface = abstract_surface;
1467
1468     if (surface->unbounded)
1469         return FALSE;
1470
1471     *rectangle = surface->extents;
1472     return TRUE;
1473 }
1474
1475 static const cairo_surface_backend_t cairo_recording_surface_backend = {
1476     CAIRO_SURFACE_TYPE_RECORDING,
1477     _cairo_recording_surface_finish,
1478
1479     _cairo_default_context_create,
1480
1481     _cairo_recording_surface_create_similar,
1482     NULL, /* create similar image */
1483     NULL, /* map to image */
1484     NULL, /* unmap image */
1485
1486     _cairo_surface_default_source,
1487     _cairo_recording_surface_acquire_source_image,
1488     _cairo_recording_surface_release_source_image,
1489     _cairo_recording_surface_snapshot,
1490
1491     NULL, /* copy_page */
1492     NULL, /* show_page */
1493
1494     _cairo_recording_surface_get_extents,
1495     NULL, /* get_font_options */
1496
1497     NULL, /* flush */
1498     NULL, /* mark_dirty_rectangle */
1499
1500     /* Here are the 5 basic drawing operations, (which are in some
1501      * sense the only things that cairo_recording_surface should need to
1502      * implement).  However, we implement the more generic show_text_glyphs
1503      * instead of show_glyphs.  One or the other is eough. */
1504
1505     _cairo_recording_surface_paint,
1506     _cairo_recording_surface_mask,
1507     _cairo_recording_surface_stroke,
1508     _cairo_recording_surface_fill,
1509     NULL, /* fill-stroke */
1510     NULL,
1511     _cairo_recording_surface_has_show_text_glyphs,
1512     _cairo_recording_surface_show_text_glyphs,
1513 };
1514
1515 cairo_int_status_t
1516 _cairo_recording_surface_get_path (cairo_surface_t    *abstract_surface,
1517                                    cairo_path_fixed_t *path)
1518 {
1519     cairo_recording_surface_t *surface;
1520     cairo_command_t **elements;
1521     int i, num_elements;
1522     cairo_int_status_t status;
1523
1524     if (unlikely (abstract_surface->status))
1525         return abstract_surface->status;
1526
1527     surface = (cairo_recording_surface_t *) abstract_surface;
1528     status = CAIRO_STATUS_SUCCESS;
1529
1530     num_elements = surface->commands.num_elements;
1531     elements = _cairo_array_index (&surface->commands, 0);
1532     for (i = 0; i < num_elements; i++) {
1533         cairo_command_t *command = elements[i];
1534
1535         switch (command->header.type) {
1536         case CAIRO_COMMAND_PAINT:
1537         case CAIRO_COMMAND_MASK:
1538             status = CAIRO_INT_STATUS_UNSUPPORTED;
1539             break;
1540
1541         case CAIRO_COMMAND_STROKE:
1542         {
1543             cairo_traps_t traps;
1544
1545             _cairo_traps_init (&traps);
1546
1547             /* XXX call cairo_stroke_to_path() when that is implemented */
1548             status = _cairo_path_fixed_stroke_polygon_to_traps (&command->stroke.path,
1549                                                                 &command->stroke.style,
1550                                                                 &command->stroke.ctm,
1551                                                                 &command->stroke.ctm_inverse,
1552                                                                 command->stroke.tolerance,
1553                                                                 &traps);
1554
1555             if (status == CAIRO_INT_STATUS_SUCCESS)
1556                 status = _cairo_traps_path (&traps, path);
1557
1558             _cairo_traps_fini (&traps);
1559             break;
1560         }
1561         case CAIRO_COMMAND_FILL:
1562         {
1563             status = _cairo_path_fixed_append (path,
1564                                                &command->fill.path,
1565                                                0, 0);
1566             break;
1567         }
1568         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
1569         {
1570             status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
1571                                                     command->show_text_glyphs.glyphs,
1572                                                     command->show_text_glyphs.num_glyphs,
1573                                                     path);
1574             break;
1575         }
1576
1577         default:
1578             ASSERT_NOT_REACHED;
1579         }
1580
1581         if (unlikely (status))
1582             break;
1583     }
1584
1585     return status;
1586 }
1587
1588 static int
1589 _cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surface,
1590                                                const cairo_rectangle_int_t *extents)
1591 {
1592     int num_visible, *indices;
1593     cairo_box_t box;
1594
1595     _cairo_box_from_rectangle (&box, extents);
1596
1597     if (surface->bbtree.chain == INVALID_CHAIN)
1598         _cairo_recording_surface_create_bbtree (surface);
1599
1600     indices = surface->indices;
1601     bbtree_foreach_mark_visible (&surface->bbtree, &box, &indices);
1602     num_visible = indices - surface->indices;
1603     if (num_visible > 1)
1604         sort_indices (surface->indices, num_visible);
1605
1606     return num_visible;
1607 }
1608
1609 static cairo_status_t
1610 _cairo_recording_surface_replay_internal (cairo_recording_surface_t     *surface,
1611                                           const cairo_rectangle_int_t *surface_extents,
1612                                           const cairo_matrix_t *surface_transform,
1613                                           cairo_surface_t            *target,
1614                                           const cairo_clip_t *target_clip,
1615                                           cairo_recording_replay_type_t type,
1616                                           cairo_recording_region_type_t region)
1617 {
1618     cairo_surface_wrapper_t wrapper;
1619     cairo_command_t **elements;
1620     cairo_bool_t replay_all =
1621         type == CAIRO_RECORDING_REPLAY &&
1622         region == CAIRO_RECORDING_REGION_ALL;
1623     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
1624     cairo_rectangle_int_t extents;
1625     cairo_bool_t use_indices = FALSE;
1626     const cairo_rectangle_int_t *r;
1627     int i, num_elements;
1628
1629     if (unlikely (surface->base.status))
1630         return surface->base.status;
1631
1632     if (unlikely (target->status))
1633         return target->status;
1634
1635     if (unlikely (surface->base.finished))
1636         return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
1637
1638     if (surface->base.is_clear)
1639         return CAIRO_STATUS_SUCCESS;
1640
1641     assert (_cairo_surface_is_recording (&surface->base));
1642
1643     _cairo_surface_wrapper_init (&wrapper, target);
1644     if (surface_extents)
1645         _cairo_surface_wrapper_intersect_extents (&wrapper, surface_extents);
1646     r = &_cairo_unbounded_rectangle;
1647     if (! surface->unbounded) {
1648         _cairo_surface_wrapper_intersect_extents (&wrapper, &surface->extents);
1649         r = &surface->extents;
1650     }
1651     _cairo_surface_wrapper_set_inverse_transform (&wrapper, surface_transform);
1652     _cairo_surface_wrapper_set_clip (&wrapper, target_clip);
1653
1654     /* Compute the extents of the target clip in recorded device space */
1655     if (! _cairo_surface_wrapper_get_target_extents (&wrapper, &extents))
1656         goto done;
1657
1658     num_elements = surface->commands.num_elements;
1659     elements = _cairo_array_index (&surface->commands, 0);
1660     if (elements == NULL) {
1661         status = CAIRO_STATUS_NULL_POINTER;
1662         goto done;
1663     }
1664
1665     if (extents.width < r->width || extents.height < r->height) {
1666         num_elements =
1667             _cairo_recording_surface_get_visible_commands (surface, &extents);
1668         use_indices = TRUE;
1669     }
1670
1671     for (i = 0; i < num_elements; i++) {
1672         cairo_command_t *command = elements[use_indices ? surface->indices[i] : i];
1673
1674         if (! replay_all && command->header.region != region)
1675             continue;
1676
1677         if (! _cairo_rectangle_intersects (&extents, &command->header.extents))
1678             continue;
1679
1680         switch (command->header.type) {
1681         case CAIRO_COMMAND_PAINT:
1682             status = _cairo_surface_wrapper_paint (&wrapper,
1683                                                    command->header.op,
1684                                                    &command->paint.source.base,
1685                                                    command->header.clip);
1686             break;
1687
1688         case CAIRO_COMMAND_MASK:
1689             status = _cairo_surface_wrapper_mask (&wrapper,
1690                                                   command->header.op,
1691                                                   &command->mask.source.base,
1692                                                   &command->mask.mask.base,
1693                                                   command->header.clip);
1694             break;
1695
1696         case CAIRO_COMMAND_STROKE:
1697             status = _cairo_surface_wrapper_stroke (&wrapper,
1698                                                     command->header.op,
1699                                                     &command->stroke.source.base,
1700                                                     &command->stroke.path,
1701                                                     &command->stroke.style,
1702                                                     &command->stroke.ctm,
1703                                                     &command->stroke.ctm_inverse,
1704                                                     command->stroke.tolerance,
1705                                                     command->stroke.antialias,
1706                                                     command->header.clip);
1707             break;
1708
1709         case CAIRO_COMMAND_FILL:
1710             status = CAIRO_INT_STATUS_UNSUPPORTED;
1711             if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) {
1712                 cairo_command_t *stroke_command;
1713
1714                 stroke_command = NULL;
1715                 if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
1716                     stroke_command = elements[i + 1];
1717
1718                 if (stroke_command != NULL &&
1719                     type == CAIRO_RECORDING_REPLAY &&
1720                     region != CAIRO_RECORDING_REGION_ALL)
1721                 {
1722                     if (stroke_command->header.region != region)
1723                         stroke_command = NULL;
1724                 }
1725
1726                 if (stroke_command != NULL &&
1727                     stroke_command->header.type == CAIRO_COMMAND_STROKE &&
1728                     _cairo_path_fixed_equal (&command->fill.path,
1729                                              &stroke_command->stroke.path) &&
1730                     _cairo_clip_equal (command->header.clip,
1731                                        stroke_command->header.clip))
1732                 {
1733                     status = _cairo_surface_wrapper_fill_stroke (&wrapper,
1734                                                                  command->header.op,
1735                                                                  &command->fill.source.base,
1736                                                                  command->fill.fill_rule,
1737                                                                  command->fill.tolerance,
1738                                                                  command->fill.antialias,
1739                                                                  &command->fill.path,
1740                                                                  stroke_command->header.op,
1741                                                                  &stroke_command->stroke.source.base,
1742                                                                  &stroke_command->stroke.style,
1743                                                                  &stroke_command->stroke.ctm,
1744                                                                  &stroke_command->stroke.ctm_inverse,
1745                                                                  stroke_command->stroke.tolerance,
1746                                                                  stroke_command->stroke.antialias,
1747                                                                  command->header.clip);
1748                     i++;
1749                 }
1750             }
1751             if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1752                 status = _cairo_surface_wrapper_fill (&wrapper,
1753                                                       command->header.op,
1754                                                       &command->fill.source.base,
1755                                                       &command->fill.path,
1756                                                       command->fill.fill_rule,
1757                                                       command->fill.tolerance,
1758                                                       command->fill.antialias,
1759                                                       command->header.clip);
1760             }
1761             break;
1762
1763         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
1764             status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
1765                                                               command->header.op,
1766                                                               &command->show_text_glyphs.source.base,
1767                                                               command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
1768                                                               command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs,
1769                                                               command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
1770                                                               command->show_text_glyphs.cluster_flags,
1771                                                               command->show_text_glyphs.scaled_font,
1772                                                               command->header.clip);
1773             break;
1774
1775         default:
1776             ASSERT_NOT_REACHED;
1777         }
1778
1779         if (type == CAIRO_RECORDING_CREATE_REGIONS) {
1780             if (status == CAIRO_INT_STATUS_SUCCESS) {
1781                 command->header.region = CAIRO_RECORDING_REGION_NATIVE;
1782             } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
1783                 command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
1784                 status = CAIRO_INT_STATUS_SUCCESS;
1785             } else {
1786                 assert (_cairo_int_status_is_error (status));
1787             }
1788         }
1789
1790         if (unlikely (status))
1791             break;
1792     }
1793
1794 done:
1795     _cairo_surface_wrapper_fini (&wrapper);
1796     return _cairo_surface_set_error (&surface->base, status);
1797 }
1798
1799 cairo_status_t
1800 _cairo_recording_surface_replay_one (cairo_recording_surface_t  *surface,
1801                                      long unsigned index,
1802                                      cairo_surface_t         *target)
1803 {
1804     cairo_surface_wrapper_t wrapper;
1805     cairo_command_t **elements, *command;
1806     cairo_int_status_t status;
1807
1808     if (unlikely (surface->base.status))
1809         return surface->base.status;
1810
1811     if (unlikely (target->status))
1812         return target->status;
1813
1814     if (unlikely (surface->base.finished))
1815         return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
1816
1817     assert (_cairo_surface_is_recording (&surface->base));
1818
1819     /* XXX
1820      * Use a surface wrapper because we may want to do transformed
1821      * replay in the future.
1822      */
1823     _cairo_surface_wrapper_init (&wrapper, target);
1824
1825     if (index > surface->commands.num_elements)
1826         return _cairo_error (CAIRO_STATUS_READ_ERROR);
1827
1828     elements = _cairo_array_index (&surface->commands, 0);
1829     if (elements == NULL)
1830         return _cairo_error (CAIRO_STATUS_NULL_POINTER);
1831
1832     command = elements[index];
1833     switch (command->header.type) {
1834     case CAIRO_COMMAND_PAINT:
1835         status = _cairo_surface_wrapper_paint (&wrapper,
1836                                                command->header.op,
1837                                                &command->paint.source.base,
1838                                                command->header.clip);
1839         break;
1840
1841     case CAIRO_COMMAND_MASK:
1842         status = _cairo_surface_wrapper_mask (&wrapper,
1843                                               command->header.op,
1844                                               &command->mask.source.base,
1845                                               &command->mask.mask.base,
1846                                               command->header.clip);
1847         break;
1848
1849     case CAIRO_COMMAND_STROKE:
1850         status = _cairo_surface_wrapper_stroke (&wrapper,
1851                                                 command->header.op,
1852                                                 &command->stroke.source.base,
1853                                                 &command->stroke.path,
1854                                                 &command->stroke.style,
1855                                                 &command->stroke.ctm,
1856                                                 &command->stroke.ctm_inverse,
1857                                                 command->stroke.tolerance,
1858                                                 command->stroke.antialias,
1859                                                 command->header.clip);
1860         break;
1861
1862     case CAIRO_COMMAND_FILL:
1863         status = _cairo_surface_wrapper_fill (&wrapper,
1864                                               command->header.op,
1865                                               &command->fill.source.base,
1866                                               &command->fill.path,
1867                                               command->fill.fill_rule,
1868                                               command->fill.tolerance,
1869                                               command->fill.antialias,
1870                                               command->header.clip);
1871         break;
1872
1873     case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
1874         status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
1875                                                           command->header.op,
1876                                                           &command->show_text_glyphs.source.base,
1877                                                           command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
1878                                                           command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs,
1879                                                           command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
1880                                                           command->show_text_glyphs.cluster_flags,
1881                                                           command->show_text_glyphs.scaled_font,
1882                                                           command->header.clip);
1883         break;
1884
1885     default:
1886         ASSERT_NOT_REACHED;
1887     }
1888
1889     _cairo_surface_wrapper_fini (&wrapper);
1890     return _cairo_surface_set_error (&surface->base, status);
1891 }
1892 /**
1893  * _cairo_recording_surface_replay:
1894  * @surface: the #cairo_recording_surface_t
1895  * @target: a target #cairo_surface_t onto which to replay the operations
1896  * @width_pixels: width of the surface, in pixels
1897  * @height_pixels: height of the surface, in pixels
1898  *
1899  * A recording surface can be "replayed" against any target surface,
1900  * after which the results in target will be identical to the results
1901  * that would have been obtained if the original operations applied to
1902  * the recording surface had instead been applied to the target surface.
1903  **/
1904 cairo_status_t
1905 _cairo_recording_surface_replay (cairo_surface_t *surface,
1906                                  cairo_surface_t *target)
1907 {
1908     return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, NULL,
1909                                                      target, NULL,
1910                                                      CAIRO_RECORDING_REPLAY,
1911                                                      CAIRO_RECORDING_REGION_ALL);
1912 }
1913
1914 cairo_status_t
1915 _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
1916                                            const cairo_matrix_t *surface_transform,
1917                                            cairo_surface_t *target,
1918                                            const cairo_clip_t *target_clip)
1919 {
1920     return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, surface_transform,
1921                                                      target, target_clip,
1922                                                      CAIRO_RECORDING_REPLAY,
1923                                                      CAIRO_RECORDING_REGION_ALL);
1924 }
1925
1926 /* Replay recording to surface. When the return status of each operation is
1927  * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
1928  * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
1929  * will be stored in the recording surface. Any other status will abort the
1930  * replay and return the status.
1931  */
1932 cairo_status_t
1933 _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
1934                                                     cairo_surface_t *target)
1935 {
1936     return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, NULL, NULL,
1937                                                      target, NULL,
1938                                                      CAIRO_RECORDING_CREATE_REGIONS,
1939                                                      CAIRO_RECORDING_REGION_ALL);
1940 }
1941
1942 cairo_status_t
1943 _cairo_recording_surface_replay_region (cairo_surface_t          *surface,
1944                                         const cairo_rectangle_int_t *surface_extents,
1945                                         cairo_surface_t          *target,
1946                                         cairo_recording_region_type_t  region)
1947 {
1948     return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface,
1949                                                      surface_extents, NULL,
1950                                                      target, NULL,
1951                                                      CAIRO_RECORDING_REPLAY,
1952                                                      region);
1953 }
1954
1955 static cairo_status_t
1956 _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
1957                                  cairo_box_t *bbox,
1958                                  const cairo_matrix_t *transform)
1959 {
1960     cairo_surface_t *null_surface;
1961     cairo_surface_t *analysis_surface;
1962     cairo_status_t status;
1963
1964     null_surface = _cairo_null_surface_create (surface->base.content);
1965     analysis_surface = _cairo_analysis_surface_create (null_surface);
1966     cairo_surface_destroy (null_surface);
1967
1968     status = analysis_surface->status;
1969     if (unlikely (status)) {
1970         cairo_surface_destroy (analysis_surface);
1971         return status;
1972     }
1973
1974     if (transform != NULL)
1975         _cairo_analysis_surface_set_ctm (analysis_surface, transform);
1976
1977     status = _cairo_recording_surface_replay (&surface->base, analysis_surface);
1978     _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
1979     cairo_surface_destroy (analysis_surface);
1980
1981     return status;
1982 }
1983
1984 /**
1985  * cairo_recording_surface_ink_extents:
1986  * @surface: a #cairo_recording_surface_t
1987  * @x0: the x-coordinate of the top-left of the ink bounding box
1988  * @y0: the y-coordinate of the top-left of the ink bounding box
1989  * @width: the width of the ink bounding box
1990  * @height: the height of the ink bounding box
1991  *
1992  * Measures the extents of the operations stored within the recording-surface.
1993  * This is useful to compute the required size of an image surface (or
1994  * equivalent) into which to replay the full sequence of drawing operations.
1995  *
1996  * Since: 1.10
1997  **/
1998 void
1999 cairo_recording_surface_ink_extents (cairo_surface_t *surface,
2000                                      double *x0,
2001                                      double *y0,
2002                                      double *width,
2003                                      double *height)
2004 {
2005     cairo_status_t status;
2006     cairo_box_t bbox;
2007
2008     memset (&bbox, 0, sizeof (bbox));
2009
2010     if (surface->status || ! _cairo_surface_is_recording (surface)) {
2011         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2012         goto DONE;
2013     }
2014
2015     status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface,
2016                                          &bbox,
2017                                          NULL);
2018     if (unlikely (status))
2019         status = _cairo_surface_set_error (surface, status);
2020
2021 DONE:
2022     if (x0)
2023         *x0 = _cairo_fixed_to_double (bbox.p1.x);
2024     if (y0)
2025         *y0 = _cairo_fixed_to_double (bbox.p1.y);
2026     if (width)
2027         *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
2028     if (height)
2029         *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
2030 }
2031
2032 cairo_status_t
2033 _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
2034                                    cairo_box_t *bbox,
2035                                    const cairo_matrix_t *transform)
2036 {
2037     if (! surface->unbounded) {
2038         _cairo_box_from_rectangle (bbox, &surface->extents);
2039         if (transform != NULL)
2040             _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
2041
2042         return CAIRO_STATUS_SUCCESS;
2043     }
2044
2045     return _recording_surface_get_ink_bbox (surface, bbox, transform);
2046 }
2047
2048 cairo_status_t
2049 _cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
2050                                        cairo_box_t *bbox,
2051                                        const cairo_matrix_t *transform)
2052 {
2053     return _recording_surface_get_ink_bbox (surface, bbox, transform);
2054 }
2055
2056 /**
2057  * cairo_recording_surface_get_extents:
2058  * @surface: a #cairo_recording_surface_t
2059  * @extents: the #cairo_rectangle_t to be assigned the extents
2060  *
2061  * Get the extents of the recording-surface.
2062  *
2063  * Return value: %TRUE if the surface is bounded, of recording type, and
2064  * not in an error state, otherwise %FALSE
2065  *
2066  * Since: 1.12
2067  **/
2068 cairo_bool_t
2069 cairo_recording_surface_get_extents (cairo_surface_t *surface,
2070                                      cairo_rectangle_t *extents)
2071 {
2072     cairo_recording_surface_t *record;
2073
2074     if (surface->status || ! _cairo_surface_is_recording (surface)) {
2075         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
2076         return FALSE;
2077     }
2078
2079     record = (cairo_recording_surface_t *)surface;
2080     if (record->unbounded)
2081         return FALSE;
2082
2083     *extents = record->extents_pixels;
2084     return TRUE;
2085 }