cairo-recording-surface.c 69.4 KB
Newer Older
1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
3
4
/* cairo - a vector graphics library with display and print output
 *
 * Copyright © 2005 Red Hat, Inc
5
 * Copyright © 2007 Adrian Johnson
6
7
8
9
10
11
12
13
14
15
16
 *
 * This library is free software; you can redistribute it and/or
 * modify it either under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * (the "LGPL") or, at your option, under the terms of the Mozilla
 * Public License Version 1.1 (the "MPL"). If you do not alter this
 * notice, a recipient may use your version of this file under either
 * the MPL or the LGPL.
 *
 * You should have received a copy of the LGPL along with this library
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
Andrea Canciani's avatar
Andrea Canciani committed
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * You should have received a copy of the MPL along with this library
 * in the file COPYING-MPL-1.1
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
 * the specific language governing rights and limitations.
 *
 * The Original Code is the cairo graphics library.
 *
 * The Initial Developer of the Original Code is Red Hat, Inc.
 *
 * Contributor(s):
 *	Kristian Høgsberg <krh@redhat.com>
36
 *	Carl Worth <cworth@cworth.org>
37
 *	Adrian Johnson <ajohnson@redneon.com>
38
39
 */

40
41
42
43
44
45
46
/**
 * SECTION:cairo-recording
 * @Title: Recording Surfaces
 * @Short_Description: Records all drawing operations
 * @See_Also: #cairo_surface_t
 *
 * 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
50
 * surface can then be "replayed" against any target surface by using it
 * as a source surface.
51
 *
52
53
 * If you want to replay a surface so that the results in target will be
 * 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:
Chris Wilson's avatar
Chris Wilson committed
56
 * <informalexample><programlisting>
57
 * cairo_t *cr;
58
 *
59
60
61
62
 * cr = cairo_create (target);
 * cairo_set_source_surface (cr, recording_surface, 0.0, 0.0);
 * cairo_paint (cr);
 * cairo_destroy (cr);
63
 * </programlisting></informalexample>
64
 *
65
 * A recording surface is logically unbounded, i.e. it has no implicit constraint
66
67
68
 * on the size of the drawing surface. However, in practice this is rarely
 * useful as you wish to replay against a particular target surface with
 * 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
Behdad Esfahbod's avatar
Behdad Esfahbod committed
72
 * necessary objects (paths, patterns, etc.), in order to achieve
73
 * accurate replay. The efficiency of the recording surface could be
74
75
76
 * improved by improving the implementation of snapshot for the
 * various objects. For example, it would be nice to have a
 * copy-on-write implementation for _cairo_surface_snapshot.
77
 **/
78

79
#include "cairoint.h"
80
81

#include "cairo-array-private.h"
Chris Wilson's avatar
Chris Wilson committed
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"
Chris Wilson's avatar
Chris Wilson committed
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
96
97
    CAIRO_RECORDING_REPLAY,
    CAIRO_RECORDING_CREATE_REGIONS
} cairo_recording_replay_type_t;
98

99
static const cairo_surface_backend_t cairo_recording_surface_backend;
100

101
102
103
104
105
106
107
108
/**
 * CAIRO_HAS_RECORDING_SURFACE:
 *
 * Defined if the recording surface backend is available.
 * The recording surface backend is always built in.
 * This macro was added for completeness in cairo 1.10.
 *
 * 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
116
 *
 * XXX: The naming of "pixels" in the size here is a misnomer. It's
 * actually a size in whatever device-space units are desired (again,
Chris Wilson's avatar
Chris Wilson committed
117
 * according to the intended replay target).
118
 */
Chris Wilson's avatar
Chris Wilson committed
119

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
static int bbtree_left_or_right (struct bbtree *bbt,
				 const cairo_box_t *box)
{
    int left, right;

    if (bbt->left) {
	cairo_box_t *e = &bbt->left->extents;
	cairo_box_t b;

	b.p1.x = MIN (e->p1.x, box->p1.x);
	b.p1.y = MIN (e->p1.y, box->p1.y);
	b.p2.x = MAX (e->p2.x, box->p2.x);
	b.p2.y = MAX (e->p2.y, box->p2.y);

	left = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y);
	left -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y);
    } else
	left = 0;

    if (bbt->right) {
	cairo_box_t *e = &bbt->right->extents;
	cairo_box_t b;

	b.p1.x = MIN (e->p1.x, box->p1.x);
	b.p1.y = MIN (e->p1.y, box->p1.y);
	b.p2.x = MAX (e->p2.x, box->p2.x);
	b.p2.y = MAX (e->p2.y, box->p2.y);

	right = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y);
	right -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y);
    } else
	right = 0;

    return left <= right;
}

#define INVALID_CHAIN ((cairo_command_header_t *)-1)

static struct bbtree *
bbtree_new (const cairo_box_t *box, cairo_command_header_t *chain)
{
161
    struct bbtree *bbt = _cairo_malloc (sizeof (*bbt));
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    if (bbt == NULL)
	return NULL;
    bbt->extents = *box;
    bbt->left = bbt->right = NULL;
    bbt->chain = chain;
    return bbt;
}

static void
bbtree_init (struct bbtree *bbt, cairo_command_header_t *header)
{
    _cairo_box_from_rectangle (&bbt->extents, &header->extents);
    bbt->chain = header;
}

static cairo_status_t
bbtree_add (struct bbtree *bbt,
	    cairo_command_header_t *header,
	    const cairo_box_t *box)
{
    if (box->p1.x < bbt->extents.p1.x || box->p1.y < bbt->extents.p1.y ||
	box->p2.x > bbt->extents.p2.x || box->p2.y > bbt->extents.p2.y)
    {
	if (bbt->chain) {
	    if (bbtree_left_or_right (bbt, &bbt->extents)) {
		if (bbt->left == NULL) {
		    bbt->left = bbtree_new (&bbt->extents, bbt->chain);
		    if (unlikely (bbt->left == NULL))
			return _cairo_error (CAIRO_STATUS_NO_MEMORY);
		} else
		    bbtree_add (bbt->left, bbt->chain, &bbt->extents);
	    } else {
		if (bbt->right == NULL) {
		    bbt->right = bbtree_new (&bbt->extents, bbt->chain);
		    if (unlikely (bbt->right == NULL))
			return _cairo_error (CAIRO_STATUS_NO_MEMORY);
		} else
		    bbtree_add (bbt->right, bbt->chain, &bbt->extents);
	    }

	    bbt->chain = NULL;
	}

	bbt->extents.p1.x = MIN (bbt->extents.p1.x, box->p1.x);
	bbt->extents.p1.y = MIN (bbt->extents.p1.y, box->p1.y);
	bbt->extents.p2.x = MAX (bbt->extents.p2.x, box->p2.x);
	bbt->extents.p2.y = MAX (bbt->extents.p2.y, box->p2.y);
    }

    if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y &&
	box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y)
    {
214
215
216
217
	cairo_command_header_t *last = header;
	while (last->chain) /* expected to be infrequent */
	    last = last->chain;
	last->chain = bbt->chain;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
	bbt->chain = header;
	return CAIRO_STATUS_SUCCESS;
    }

    if (bbtree_left_or_right (bbt, box)) {
	if (bbt->left == NULL) {
	    bbt->left = bbtree_new (box, header);
	    if (unlikely (bbt->left == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	} else
	    return bbtree_add (bbt->left, header, box);
    } else {
	if (bbt->right == NULL) {
	    bbt->right = bbtree_new (box, header);
	    if (unlikely (bbt->right == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	} else
	    return bbtree_add (bbt->right, header, box);
    }

    return CAIRO_STATUS_SUCCESS;
}

static void bbtree_del (struct bbtree *bbt)
{
    if (bbt->left)
	bbtree_del (bbt->left);
    if (bbt->right)
	bbtree_del (bbt->right);

    free (bbt);
}

static cairo_bool_t box_outside (const cairo_box_t *a, const cairo_box_t *b)
{
    return
	a->p1.x >= b->p2.x || a->p1.y >= b->p2.y ||
	a->p2.x <= b->p1.x || a->p2.y <= b->p1.y;
}

static void
bbtree_foreach_mark_visible (struct bbtree *bbt,
			     const cairo_box_t *box,
261
			     unsigned int **indices)
262
263
264
265
266
267
268
269
270
271
272
273
{
    cairo_command_header_t *chain;

    for (chain = bbt->chain; chain; chain = chain->chain)
	*(*indices)++ = chain->index;

    if (bbt->left && ! box_outside (box, &bbt->left->extents))
	bbtree_foreach_mark_visible (bbt->left, box, indices);
    if (bbt->right && ! box_outside (box, &bbt->right->extents))
	bbtree_foreach_mark_visible (bbt->right, box, indices);
}

274
static inline int intcmp (const unsigned int a, const unsigned int b)
275
276
277
{
    return a - b;
}
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
283
284
285
286
287
288
289
290
291
{
    const cairo_rectangle_int_t *r;

    r = &elements[a]->extents;
    a = r->width * r->height;

    r = &elements[b]->extents;
    b = r->width * r->height;

    return b - a;
}
292
CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, unsigned int, sizecmp)
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313

static void
_cairo_recording_surface_destroy_bbtree (cairo_recording_surface_t *surface)
{
    cairo_command_t **elements;
    int i, num_elements;

    if (surface->bbtree.chain == INVALID_CHAIN)
	return;

    if (surface->bbtree.left) {
	bbtree_del (surface->bbtree.left);
	surface->bbtree.left = NULL;
    }
    if (surface->bbtree.right) {
	bbtree_del (surface->bbtree.right);
	surface->bbtree.right = NULL;
    }

    elements = _cairo_array_index (&surface->commands, 0);
    num_elements = surface->commands.num_elements;
314
    for (i = 0; i < num_elements; i++)
315
316
317
318
319
320
321
322
323
	elements[i]->header.chain = NULL;

    surface->bbtree.chain = INVALID_CHAIN;
}

static cairo_status_t
_cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface)
{
    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
330
331
332
333
334
335
336
337
338
339
    if (count > surface->num_indices) {
	free (surface->indices);
	surface->indices = _cairo_malloc_ab (count, sizeof (int));
	if (unlikely (surface->indices == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	surface->num_indices = count;
    }

    indices = surface->indices;
    for (i = 0; i < count; i++)
340
	indices[i] = i;
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361

    sort_commands (indices, count, elements);

    bbtree_init (&surface->bbtree, &elements[indices[0]]->header);
    for (i = 1; i < count; i++) {
	cairo_command_header_t *header = &elements[indices[i]]->header;
	cairo_box_t box;

	_cairo_box_from_rectangle (&box, &header->extents);
	status = bbtree_add (&surface->bbtree, header, &box);
	if (unlikely (status))
	    goto cleanup;
    }

    return CAIRO_STATUS_SUCCESS;

cleanup:
    bbtree_del (&surface->bbtree);
    return status;
}

Chris Wilson's avatar
Chris Wilson committed
362
/**
363
364
 * cairo_recording_surface_create:
 * @content: the content of the recording surface
365
366
 * @extents: the extents to record in pixels, can be %NULL to record
 *           unbounded operations.
Chris Wilson's avatar
Chris Wilson committed
367
 *
368
 * Creates a recording-surface which can be used to record all drawing operations
Chris Wilson's avatar
Chris Wilson committed
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.
Chris Wilson's avatar
Chris Wilson committed
372
 *
373
 * The recording phase of the recording surface is careful to snapshot all
Chris Wilson's avatar
Chris Wilson committed
374
375
376
 * necessary objects (paths, patterns, etc.), in order to achieve
 * accurate replay.
 *
377
378
379
380
381
 * Return value: a pointer to the newly created surface. The caller
 * owns the surface and should call cairo_surface_destroy() when done
 * with it.
 *
 * Since: 1.10
Chris Wilson's avatar
Chris Wilson committed
382
 **/
383
cairo_surface_t *
384
385
cairo_recording_surface_create (cairo_content_t		 content,
				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,
Chris Wilson's avatar
Chris Wilson committed
394
395
			 &cairo_recording_surface_backend,
			 NULL, /* device */
396
397
			 content,
			 TRUE); /* is_vector */
398
399


400
    surface->unbounded = TRUE;
401

Chris Wilson's avatar
Chris Wilson committed
402
    /* unbounded -> 'infinite' extents */
403
    if (extents != NULL) {
404
	surface->extents_pixels = *extents;
Chris Wilson's avatar
Chris Wilson committed
405

406
	/* XXX check for overflow */
407
408
409
410
	surface->extents.x = floor (extents->x);
	surface->extents.y = floor (extents->y);
	surface->extents.width = ceil (extents->x + extents->width) - surface->extents.x;
	surface->extents.height = ceil (extents->y + extents->height) - surface->extents.y;
411

412
	surface->unbounded = FALSE;
Chris Wilson's avatar
Chris Wilson committed
413
414
    }

415
    _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
416

417
    surface->base.is_clear = TRUE;
418

419
420
421
422
423
    surface->bbtree.left = surface->bbtree.right = NULL;
    surface->bbtree.chain = INVALID_CHAIN;

    surface->indices = NULL;
    surface->num_indices = 0;
424
    surface->optimize_clears = TRUE;
425
426
    surface->has_bilevel_alpha = FALSE;
    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 *
433
434
435
436
_cairo_recording_surface_create_similar (void		       *abstract_surface,
					 cairo_content_t	content,
					 int			width,
					 int			height)
437
{
438
439
440
441
    cairo_rectangle_t extents;
    extents.x = extents.y = 0;
    extents.width = width;
    extents.height = height;
442
    return cairo_recording_surface_create (content, &extents);
443
444
445
}

static cairo_status_t
446
_cairo_recording_surface_finish (void *abstract_surface)
447
{
448
    cairo_recording_surface_t *surface = abstract_surface;
449
450
451
    cairo_command_t **elements;
    int i, num_elements;

452
453
    num_elements = surface->commands.num_elements;
    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
461
462
	    break;

	case CAIRO_COMMAND_MASK:
463
464
	    _cairo_pattern_fini (&command->mask.source.base);
	    _cairo_pattern_fini (&command->mask.mask.base);
465
	    break;
466

467
	case CAIRO_COMMAND_STROKE:
468
	    _cairo_pattern_fini (&command->stroke.source.base);
469
470
471
472
473
	    _cairo_path_fixed_fini (&command->stroke.path);
	    _cairo_stroke_style_fini (&command->stroke.style);
	    break;

	case CAIRO_COMMAND_FILL:
474
	    _cairo_pattern_fini (&command->fill.source.base);
475
476
477
	    _cairo_path_fixed_fini (&command->fill.path);
	    break;

478
	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
479
	    _cairo_pattern_fini (&command->show_text_glyphs.source.base);
480
481
482
483
	    free (command->show_text_glyphs.utf8);
	    free (command->show_text_glyphs.glyphs);
	    free (command->show_text_glyphs.clusters);
	    cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
484
485
	    break;

486
487
488
489
490
491
492
493
494
495
	case CAIRO_COMMAND_TAG:
	    free (command->tag.tag_name);
	    if (command->tag.begin) {
		free (command->tag.attributes);
		_cairo_pattern_fini (&command->tag.source.base);
		_cairo_stroke_style_fini (&command->tag.style);
	    }
	    break;

	    default:
496
497
	    ASSERT_NOT_REACHED;
	}
Chris Wilson's avatar
Chris Wilson committed
498

499
	_cairo_clip_destroy (command->header.clip);
Chris Wilson's avatar
Chris Wilson committed
500
	free (command);
501
502
    }

503
    _cairo_array_fini (&surface->commands);
504

505
506
507
508
509
510
511
    if (surface->bbtree.left)
	bbtree_del (surface->bbtree.left);
    if (surface->bbtree.right)
	bbtree_del (surface->bbtree.right);

    free (surface->indices);

512
513
514
    return CAIRO_STATUS_SUCCESS;
}

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
struct proxy {
    cairo_surface_t base;
    cairo_surface_t *image;
};

static cairo_status_t
proxy_acquire_source_image (void			 *abstract_surface,
			    cairo_image_surface_t	**image_out,
			    void			**image_extra)
{
    struct proxy *proxy = abstract_surface;
    return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra);
}

static void
proxy_release_source_image (void			*abstract_surface,
			    cairo_image_surface_t	*image,
			    void			*image_extra)
{
    struct proxy *proxy = abstract_surface;
    _cairo_surface_release_source_image (proxy->image, image, image_extra);
}

static cairo_status_t
proxy_finish (void *abstract_surface)
{
    return CAIRO_STATUS_SUCCESS;
}

static const cairo_surface_backend_t proxy_backend  = {
    CAIRO_INTERNAL_SURFACE_TYPE_NULL,
    proxy_finish,
    NULL,

    NULL, /* create similar */
    NULL, /* create similar image */
    NULL, /* map to image */
    NULL, /* unmap image */

554
    _cairo_surface_default_source,
555
556
557
558
559
560
561
562
563
564
    proxy_acquire_source_image,
    proxy_release_source_image,
};

static cairo_surface_t *
attach_proxy (cairo_surface_t *source,
	      cairo_surface_t *image)
{
    struct proxy *proxy;

565
    proxy = _cairo_malloc (sizeof (*proxy));
566
567
568
    if (unlikely (proxy == NULL))
	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);

569
    _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content, FALSE);
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590

    proxy->image = image;
    _cairo_surface_attach_snapshot (source, &proxy->base, NULL);

    return &proxy->base;
}

static void
detach_proxy (cairo_surface_t *source,
	      cairo_surface_t *proxy)
{
    cairo_surface_finish (proxy);
    cairo_surface_destroy (proxy);
}

static cairo_surface_t *
get_proxy (cairo_surface_t *proxy)
{
    return ((struct proxy *)proxy)->image;
}

Adrian Johnson's avatar
Adrian Johnson committed
591
592
593
594
595
static cairo_status_t
_cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
					       cairo_image_surface_t	**image_out,
					       void			**image_extra)
{
596
597
    cairo_recording_surface_t *surface = abstract_surface;
    cairo_surface_t *image, *proxy;
598
599
    cairo_status_t status;

600
601
602
603
    proxy = _cairo_surface_has_snapshot (abstract_surface, &proxy_backend);
    if (proxy != NULL) {
	*image_out = (cairo_image_surface_t *)
	    cairo_surface_reference (get_proxy (proxy));
604
605
606
	*image_extra = NULL;
	return CAIRO_STATUS_SUCCESS;
    }
Adrian Johnson's avatar
Adrian Johnson committed
607

608
609
610
611
612
613
    assert (! surface->unbounded);
    image = _cairo_image_surface_create_with_content (surface->base.content,
						      surface->extents.width,
						      surface->extents.height);
    if (unlikely (image->status))
	return image->status;
Adrian Johnson's avatar
Adrian Johnson committed
614

615
616
617
618
619
620
621
    /* Handle recursion by returning future reads from the current image */
    proxy = attach_proxy (abstract_surface, image);
    status = _cairo_recording_surface_replay (&surface->base, image);
    detach_proxy (abstract_surface, proxy);

    if (unlikely (status)) {
	cairo_surface_destroy (image);
622
	return status;
623
    }
624

625
626
    *image_out = (cairo_image_surface_t *) image;
    *image_extra = NULL;
627
    return CAIRO_STATUS_SUCCESS;
Adrian Johnson's avatar
Adrian Johnson committed
628
629
}

630
static void
631
632
633
_cairo_recording_surface_release_source_image (void			*abstract_surface,
					       cairo_image_surface_t	*image,
					       void			*image_extra)
634
635
636
637
{
    cairo_surface_destroy (&image->base);
}

638
static cairo_status_t
639
_command_init (cairo_recording_surface_t *surface,
640
641
642
	       cairo_command_header_t *command,
	       cairo_command_type_t type,
	       cairo_operator_t op,
643
	       cairo_composite_rectangles_t *composite)
Chris Wilson's avatar
Chris Wilson committed
644
{
645
646
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

Chris Wilson's avatar
Chris Wilson committed
647
    command->type = type;
648
    command->op = op;
649
    command->region = CAIRO_RECORDING_REGION_ALL;
650
651

    command->extents = composite->unbounded;
652
653
    command->chain = NULL;
    command->index = surface->commands.num_elements;
654
655

    /* steal the clip */
Chris Wilson's avatar
Chris Wilson committed
656
    command->clip = NULL;
657
658
    if (! _cairo_composite_rectangles_can_reduce_clip (composite,
						       composite->clip))
Chris Wilson's avatar
Chris Wilson committed
659
660
661
662
    {
	command->clip = composite->clip;
	composite->clip = NULL;
    }
663
664

    return status;
Chris Wilson's avatar
Chris Wilson committed
665
666
}

Chris Wilson's avatar
Chris Wilson committed
667
668
669
670
671
672
673
674
675
676
677
678
679
680
static void
_cairo_recording_surface_break_self_copy_loop (cairo_recording_surface_t *surface)
{
    cairo_surface_flush (&surface->base);
}

static cairo_status_t
_cairo_recording_surface_commit (cairo_recording_surface_t *surface,
				 cairo_command_header_t *command)
{
    _cairo_recording_surface_break_self_copy_loop (surface);
    return _cairo_array_append (&surface->commands, &command);
}

681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
static void
_cairo_recording_surface_reset (cairo_recording_surface_t *surface)
{
    /* Reset the commands and temporaries */
    _cairo_recording_surface_finish (surface);

    surface->bbtree.left = surface->bbtree.right = NULL;
    surface->bbtree.chain = INVALID_CHAIN;

    surface->indices = NULL;
    surface->num_indices = 0;

    _cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
}

696
static cairo_int_status_t
697
698
699
_cairo_recording_surface_paint (void			  *abstract_surface,
				cairo_operator_t	   op,
				const cairo_pattern_t	  *source,
700
				const cairo_clip_t	  *clip)
701
702
{
    cairo_status_t status;
703
    cairo_recording_surface_t *surface = abstract_surface;
704
    cairo_command_paint_t *command;
705
706
    cairo_composite_rectangles_t composite;

707
708
    TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));

709
    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
710
	if (surface->optimize_clears) {
711
	    _cairo_recording_surface_reset (surface);
712
713
	    return CAIRO_STATUS_SUCCESS;
	}
714
715
    }

716
717
718
719
720
721
722
723
    if (clip == NULL && surface->optimize_clears &&
	(op == CAIRO_OPERATOR_SOURCE ||
	 (op == CAIRO_OPERATOR_OVER &&
	  (surface->base.is_clear || _cairo_pattern_is_opaque_solid (source)))))
    {
	_cairo_recording_surface_reset (surface);
    }

724
725
    status = _cairo_composite_rectangles_init_for_paint (&composite,
							 &surface->base,
726
727
728
729
							 op, source,
							 clip);
    if (unlikely (status))
	return status;
730

731
    command = _cairo_malloc (sizeof (cairo_command_paint_t));
732
733
734
735
    if (unlikely (command == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_COMPOSITE;
    }
736

737
738
739
    status = _command_init (surface,
			    &command->header, CAIRO_COMMAND_PAINT, op,
			    &composite);
740
741
    if (unlikely (status))
	goto CLEANUP_COMMAND;
742

743
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
744
    if (unlikely (status))
745
	goto CLEANUP_COMMAND;
746

Chris Wilson's avatar
Chris Wilson committed
747
    status = _cairo_recording_surface_commit (surface, &command->header);
748
    if (unlikely (status))
749
750
	goto CLEANUP_SOURCE;

751
752
    _cairo_recording_surface_destroy_bbtree (surface);

753
    _cairo_composite_rectangles_fini (&composite);
754
755
756
    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SOURCE:
757
    _cairo_pattern_fini (&command->source.base);
758
  CLEANUP_COMMAND:
759
    _cairo_clip_destroy (command->header.clip);
760
    free (command);
761
762
CLEANUP_COMPOSITE:
    _cairo_composite_rectangles_fini (&composite);
763
764
765
766
    return status;
}

static cairo_int_status_t
767
768
769
770
_cairo_recording_surface_mask (void			*abstract_surface,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
			       const cairo_pattern_t	*mask,
771
			       const cairo_clip_t	*clip)
772
773
{
    cairo_status_t status;
774
    cairo_recording_surface_t *surface = abstract_surface;
775
    cairo_command_mask_t *command;
776
777
    cairo_composite_rectangles_t composite;

778
779
    TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));

780
781
    status = _cairo_composite_rectangles_init_for_mask (&composite,
							&surface->base,
782
783
784
785
							op, source, mask,
							clip);
    if (unlikely (status))
	return status;
786

787
    command = _cairo_malloc (sizeof (cairo_command_mask_t));
788
789
790
791
    if (unlikely (command == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_COMPOSITE;
    }
792

793
794
795
    status = _command_init (surface,
			    &command->header, CAIRO_COMMAND_MASK, op,
			    &composite);
796
797
    if (unlikely (status))
	goto CLEANUP_COMMAND;
798

799
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
800
    if (unlikely (status))
801
802
	goto CLEANUP_COMMAND;

803
    status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
804
    if (unlikely (status))
805
	goto CLEANUP_SOURCE;
806

Chris Wilson's avatar
Chris Wilson committed
807
    status = _cairo_recording_surface_commit (surface, &command->header);
808
    if (unlikely (status))
809
810
	goto CLEANUP_MASK;

811
812
    _cairo_recording_surface_destroy_bbtree (surface);

813
    _cairo_composite_rectangles_fini (&composite);
814
815
816
    return CAIRO_STATUS_SUCCESS;

  CLEANUP_MASK:
817
    _cairo_pattern_fini (&command->mask.base);
818
  CLEANUP_SOURCE:
819
    _cairo_pattern_fini (&command->source.base);
820
  CLEANUP_COMMAND:
821
    _cairo_clip_destroy (command->header.clip);
822
    free (command);
823
824
CLEANUP_COMPOSITE:
    _cairo_composite_rectangles_fini (&composite);
825
826
827
828
    return status;
}

static cairo_int_status_t
829
830
831
_cairo_recording_surface_stroke (void			*abstract_surface,
				 cairo_operator_t	 op,
				 const cairo_pattern_t	*source,
832
				 const cairo_path_fixed_t	*path,
833
834
835
				 const cairo_stroke_style_t	*style,
				 const cairo_matrix_t		*ctm,
				 const cairo_matrix_t		*ctm_inverse,
836
837
				 double			 tolerance,
				 cairo_antialias_t	 antialias,
838
				 const cairo_clip_t	*clip)
839
840
{
    cairo_status_t status;
841
    cairo_recording_surface_t *surface = abstract_surface;
842
    cairo_command_stroke_t *command;
843
844
    cairo_composite_rectangles_t composite;

845
846
    TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));

847
848
    status = _cairo_composite_rectangles_init_for_stroke (&composite,
							  &surface->base,
849
850
851
852
853
							  op, source,
							  path, style, ctm,
							  clip);
    if (unlikely (status))
	return status;
854

855
    command = _cairo_malloc (sizeof (cairo_command_stroke_t));
856
857
858
859
    if (unlikely (command == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_COMPOSITE;
    }
860

861
862
863
    status = _command_init (surface,
			    &command->header, CAIRO_COMMAND_STROKE, op,
			    &composite);
864
865
    if (unlikely (status))
	goto CLEANUP_COMMAND;
866

867
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
868
    if (unlikely (status))
869
870
871
	goto CLEANUP_COMMAND;

    status = _cairo_path_fixed_init_copy (&command->path, path);
872
    if (unlikely (status))
873
874
875
	goto CLEANUP_SOURCE;

    status = _cairo_stroke_style_init_copy (&command->style, style);
876
    if (unlikely (status))
877
878
879
880
881
882
883
	goto CLEANUP_PATH;

    command->ctm = *ctm;
    command->ctm_inverse = *ctm_inverse;
    command->tolerance = tolerance;
    command->antialias = antialias;

Chris Wilson's avatar
Chris Wilson committed
884
    status = _cairo_recording_surface_commit (surface, &command->header);
885
    if (unlikely (status))
886
887
	goto CLEANUP_STYLE;

888
889
    _cairo_recording_surface_destroy_bbtree (surface);

890
    _cairo_composite_rectangles_fini (&composite);
891
892
893
894
895
896
897
    return CAIRO_STATUS_SUCCESS;

  CLEANUP_STYLE:
    _cairo_stroke_style_fini (&command->style);
  CLEANUP_PATH:
    _cairo_path_fixed_fini (&command->path);
  CLEANUP_SOURCE:
898
    _cairo_pattern_fini (&command->source.base);
899
  CLEANUP_COMMAND:
900
    _cairo_clip_destroy (command->header.clip);
901
    free (command);
902
903
CLEANUP_COMPOSITE:
    _cairo_composite_rectangles_fini (&composite);
904
905
906
907
    return status;
}

static cairo_int_status_t
908
909
910
_cairo_recording_surface_fill (void			*abstract_surface,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
911
			       const cairo_path_fixed_t	*path,
912
913
914
			       cairo_fill_rule_t	 fill_rule,
			       double			 tolerance,
			       cairo_antialias_t	 antialias,
915
			       const cairo_clip_t	*clip)
916
917
{
    cairo_status_t status;
918
    cairo_recording_surface_t *surface = abstract_surface;
919
    cairo_command_fill_t *command;
920
921
    cairo_composite_rectangles_t composite;

922
923
    TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));

924
925
    status = _cairo_composite_rectangles_init_for_fill (&composite,
							&surface->base,
926
927
928
929
							op, source, path,
							clip);
    if (unlikely (status))
	return status;
930

931
    command = _cairo_malloc (sizeof (cairo_command_fill_t));
932
933
934
935
    if (unlikely (command == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_COMPOSITE;
    }
936

937
938
939
    status =_command_init (surface,
			   &command->header, CAIRO_COMMAND_FILL, op,
			   &composite);
940
941
    if (unlikely (status))
	goto CLEANUP_COMMAND;
942

943
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
944
    if (unlikely (status))
945
946
947
	goto CLEANUP_COMMAND;

    status = _cairo_path_fixed_init_copy (&command->path, path);
948
    if (unlikely (status))
949
950
951
952
953
954
	goto CLEANUP_SOURCE;

    command->fill_rule = fill_rule;
    command->tolerance = tolerance;
    command->antialias = antialias;

Chris Wilson's avatar
Chris Wilson committed
955
    status = _cairo_recording_surface_commit (surface, &command->header);
956
    if (unlikely (status))
957
958
	goto CLEANUP_PATH;

959
960
    _cairo_recording_surface_destroy_bbtree (surface);

961
    _cairo_composite_rectangles_fini (&composite);
962
963
964
965
966
    return CAIRO_STATUS_SUCCESS;

  CLEANUP_PATH:
    _cairo_path_fixed_fini (&command->path);
  CLEANUP_SOURCE:
967
    _cairo_pattern_fini (&command->source.base);
968
  CLEANUP_COMMAND:
969
    _cairo_clip_destroy (command->header.clip);
970
    free (command);
971
972
CLEANUP_COMPOSITE:
    _cairo_composite_rectangles_fini (&composite);
973
974
975
    return status;
}

976
static cairo_bool_t
977
_cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
978
979
980
981
{
    return TRUE;
}

982
static cairo_int_status_t
983
984
985
986
987
988
989
990
991
992
993
_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,
994
					   const cairo_clip_t		*clip)
995
996
{
    cairo_status_t status;
997
    cairo_recording_surface_t *surface = abstract_surface;
998
    cairo_command_show_text_glyphs_t *command;
999
1000
    cairo_composite_rectangles_t composite;

1001
1002
    TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id));

1003
1004
    status = _cairo_composite_rectangles_init_for_glyphs (&composite,
							  &surface->base,
1005
1006
1007
1008
1009
1010
1011
							  op, source,
							  scaled_font,
							  glyphs, num_glyphs,
							  clip,
							  NULL);
    if (unlikely (status))
	return status;
1012

1013
    command = _cairo_malloc (sizeof (cairo_command_show_text_glyphs_t));
1014
1015
1016
1017
    if (unlikely (command == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_COMPOSITE;
    }
1018

1019
    status = _command_init (surface,
1020
			    &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
1021
			    op, &composite);
1022
1023
    if (unlikely (status))
	goto CLEANUP_COMMAND;
1024

1025
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
1026
    if (unlikely (status))
1027
1028
	goto CLEANUP_COMMAND;