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