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