Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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