cairo-recording-surface.c 34.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
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 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
/* A recording surface is a surface that records all drawing operations at
41
 * the highest level of the surface backend interface, (that is, the
42
 * level of paint, mask, stroke, fill, and show_text_glyphs). The recording
43
44
 * surface can then be "replayed" against any target surface by using it
 * as a source surface.
45
 *
46
47
 * 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
48
 * operations applied to the recording surface had instead been applied to the
49
 * target surface, you can use code like this:
Chris Wilson's avatar
Chris Wilson committed
50
 * <informalexample><programlisting>
51
 *      cairo_t *cr;
52
 *
53
 *	cr = cairo_create (target);
54
 *	cairo_set_source_surface (cr, recording_surface, 0.0, 0.0);
55
56
57
 *	cairo_paint (cr);
 *	cairo_destroy (cr);
 * </programlisting></informalexample>
58
 *
59
 * A recording surface is logically unbounded, i.e. it has no implicit constraint
60
61
62
 * 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
63
 * extents to the recording surface upon creation.
64
 *
65
 * The recording phase of the recording surface is careful to snapshot all
Behdad Esfahbod's avatar
Behdad Esfahbod committed
66
 * necessary objects (paths, patterns, etc.), in order to achieve
67
 * accurate replay. The efficiency of the recording surface could be
68
69
70
71
72
 * 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.
 */

73
74
/* XXX Rename to recording surface */

75
#include "cairoint.h"
Chris Wilson's avatar
Chris Wilson committed
76
#include "cairo-analysis-surface-private.h"
77
#include "cairo-clip-private.h"
78
79
#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
80
#include "cairo-surface-wrapper-private.h"
81

82
typedef enum {
83
84
85
    CAIRO_RECORDING_REPLAY,
    CAIRO_RECORDING_CREATE_REGIONS
} cairo_recording_replay_type_t;
86

87
static const cairo_surface_backend_t cairo_recording_surface_backend;
88

89
/* Currently all recording surfaces do have a size which should be passed
90
 * in as the maximum size of any target surface against which the
91
 * recording-surface will ever be replayed.
92
93
94
 *
 * 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
95
 * according to the intended replay target).
96
 */
Chris Wilson's avatar
Chris Wilson committed
97
98

/**
99
100
 * cairo_recording_surface_create:
 * @content: the content of the recording surface
101
102
 * @extents_pixels: the extents to record in pixels, can be %NULL to record
 *                  unbounded operations.
Chris Wilson's avatar
Chris Wilson committed
103
 *
104
 * Creates a recording-surface which can be used to record all drawing operations
Chris Wilson's avatar
Chris Wilson committed
105
 * at the highest level (that is, the level of paint, mask, stroke, fill
106
 * and show_text_glyphs). The recording surface can then be "replayed" against
107
 * any target surface by using it as a source to drawing operations.
Chris Wilson's avatar
Chris Wilson committed
108
 *
109
 * The recording phase of the recording surface is careful to snapshot all
Chris Wilson's avatar
Chris Wilson committed
110
111
112
113
114
 * necessary objects (paths, patterns, etc.), in order to achieve
 * accurate replay.
 *
 * Since 1.10
 **/
115
cairo_surface_t *
116
117
cairo_recording_surface_create (cairo_content_t		 content,
				const cairo_rectangle_t	*extents)
118
{
119
    cairo_recording_surface_t *recording_surface;
120
    cairo_status_t status;
121

122
123
    recording_surface = malloc (sizeof (cairo_recording_surface_t));
    if (unlikely (recording_surface == NULL))
124
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
125

Chris Wilson's avatar
Chris Wilson committed
126
127
128
129
    _cairo_surface_init (&recording_surface->base,
			 &cairo_recording_surface_backend,
			 NULL, /* device */
			 content);
130

131
    recording_surface->content = content;
132

Chris Wilson's avatar
Chris Wilson committed
133
    /* unbounded -> 'infinite' extents */
134
    if (extents != NULL) {
135
	recording_surface->extents_pixels = *extents;
Chris Wilson's avatar
Chris Wilson committed
136

137
	/* XXX check for overflow */
138
139
140
141
	recording_surface->extents.x = floor (extents->x);
	recording_surface->extents.y = floor (extents->y);
	recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x;
	recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y;
142

143
	status = _cairo_clip_init_rectangle (&recording_surface->clip, &recording_surface->extents);
144
	if (unlikely (status)) {
145
	    free (recording_surface);
146
147
148
	    return _cairo_surface_create_in_error (status);
	}

149
	recording_surface->unbounded = FALSE;
Chris Wilson's avatar
Chris Wilson committed
150
    } else {
151
152
	recording_surface->unbounded = TRUE;
	_cairo_clip_init (&recording_surface->clip);
Chris Wilson's avatar
Chris Wilson committed
153
154
    }

155
156
    _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
    recording_surface->commands_owner = NULL;
157

158
    recording_surface->replay_start_idx = 0;
159

160
    return &recording_surface->base;
161
}
162
slim_hidden_def (cairo_recording_surface_create);
163
164

static cairo_surface_t *
165
166
167
168
_cairo_recording_surface_create_similar (void		       *abstract_surface,
					 cairo_content_t	content,
					 int			width,
					 int			height)
169
{
170
171
172
173
    cairo_rectangle_t extents;
    extents.x = extents.y = 0;
    extents.width = width;
    extents.height = height;
174
    return cairo_recording_surface_create (content, &extents);
175
176
177
}

static cairo_status_t
178
_cairo_recording_surface_finish (void *abstract_surface)
179
{
180
    cairo_recording_surface_t *recording_surface = abstract_surface;
181
182
183
    cairo_command_t **elements;
    int i, num_elements;

184
185
    if (recording_surface->commands_owner) {
	cairo_surface_destroy (recording_surface->commands_owner);
186
187
188
	return CAIRO_STATUS_SUCCESS;
    }

189
190
    num_elements = recording_surface->commands.num_elements;
    elements = _cairo_array_index (&recording_surface->commands, 0);
191
    for (i = 0; i < num_elements; i++) {
192
	cairo_command_t *command = elements[i];
193

194
	_cairo_clip_reset (&command->header.clip);
195

196
	switch (command->header.type) {
197
	case CAIRO_COMMAND_PAINT:
198
	    _cairo_pattern_fini_snapshot (&command->paint.source.base);
199
200
201
202
	    free (command);
	    break;

	case CAIRO_COMMAND_MASK:
203
204
	    _cairo_pattern_fini_snapshot (&command->mask.source.base);
	    _cairo_pattern_fini_snapshot (&command->mask.mask.base);
205
206
	    free (command);
	    break;
207

208
	case CAIRO_COMMAND_STROKE:
209
	    _cairo_pattern_fini_snapshot (&command->stroke.source.base);
210
211
212
213
214
215
	    _cairo_path_fixed_fini (&command->stroke.path);
	    _cairo_stroke_style_fini (&command->stroke.style);
	    free (command);
	    break;

	case CAIRO_COMMAND_FILL:
216
	    _cairo_pattern_fini_snapshot (&command->fill.source.base);
217
218
219
220
	    _cairo_path_fixed_fini (&command->fill.path);
	    free (command);
	    break;

221
	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
222
	    _cairo_pattern_fini_snapshot (&command->show_text_glyphs.source.base);
223
224
225
226
	    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);
227
228
229
	    free (command);
	    break;

230
231
232
233
234
	default:
	    ASSERT_NOT_REACHED;
	}
    }

235
236
    _cairo_array_fini (&recording_surface->commands);
    _cairo_clip_reset (&recording_surface->clip);
237
238
239
240

    return CAIRO_STATUS_SUCCESS;
}

241
static cairo_status_t
242
243
244
_cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
					       cairo_image_surface_t	**image_out,
					       void			**image_extra)
245
246
{
    cairo_status_t status;
247
    cairo_recording_surface_t *surface = abstract_surface;
248
249
    cairo_surface_t *image;

250
    image = _cairo_surface_has_snapshot (&surface->base,
251
					 &_cairo_image_surface_backend);
252
253
254
255
256
257
    if (image != NULL) {
	*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
	*image_extra = NULL;
	return CAIRO_STATUS_SUCCESS;
    }

258
    image = _cairo_image_surface_create_with_content (surface->content,
259
260
						      surface->extents.width,
						      surface->extents.height);
Chris Wilson's avatar
Chris Wilson committed
261
262
    if (unlikely (image->status))
	return image->status;
263
264
265
266

    cairo_surface_set_device_offset (image,
				     -surface->extents.x,
				     -surface->extents.y);
267

268
    status = _cairo_recording_surface_replay (&surface->base, image);
269
    if (unlikely (status)) {
270
271
272
273
	cairo_surface_destroy (image);
	return status;
    }

274
275
276
277
278
279
    status = _cairo_surface_attach_snapshot (&surface->base, image, NULL);
    if (unlikely (status)) {
	cairo_surface_destroy (image);
	return status;
    }

280
281
    *image_out = (cairo_image_surface_t *) image;
    *image_extra = NULL;
282
    return CAIRO_STATUS_SUCCESS;
283
284
285
}

static void
286
287
288
_cairo_recording_surface_release_source_image (void			*abstract_surface,
					       cairo_image_surface_t	*image,
					       void			*image_extra)
289
290
291
292
{
    cairo_surface_destroy (&image->base);
}

293
static cairo_status_t
294
_command_init (cairo_recording_surface_t *recording_surface,
295
296
297
298
	       cairo_command_header_t *command,
	       cairo_command_type_t type,
	       cairo_operator_t op,
	       cairo_clip_t *clip)
Chris Wilson's avatar
Chris Wilson committed
299
{
300
301
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

Chris Wilson's avatar
Chris Wilson committed
302
    command->type = type;
303
    command->op = op;
304
    command->region = CAIRO_RECORDING_REGION_ALL;
305
    _cairo_clip_init_copy (&command->clip, clip);
306
307
    if (recording_surface->clip.path != NULL)
	status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip);
308
309

    return status;
Chris Wilson's avatar
Chris Wilson committed
310
311
}

312
static cairo_int_status_t
313
314
315
316
_cairo_recording_surface_paint (void			  *abstract_surface,
				cairo_operator_t	   op,
				const cairo_pattern_t	  *source,
				cairo_clip_t		  *clip)
317
318
{
    cairo_status_t status;
319
    cairo_recording_surface_t *recording_surface = abstract_surface;
320
321
322
    cairo_command_paint_t *command;

    command = malloc (sizeof (cairo_command_paint_t));
323
    if (unlikely (command == NULL))
324
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
325

326
    status = _command_init (recording_surface,
327
328
329
			    &command->header, CAIRO_COMMAND_PAINT, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;
330

331
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
332
    if (unlikely (status))
333
	goto CLEANUP_COMMAND;
334

335
    status = _cairo_array_append (&recording_surface->commands, &command);
336
    if (unlikely (status))
337
338
	goto CLEANUP_SOURCE;

339
340
341
    /* An optimisation that takes care to not replay what was done
     * before surface is cleared. We don't erase recorded commands
     * since we may have earlier snapshots of this surface. */
342
    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
343
	recording_surface->replay_start_idx = recording_surface->commands.num_elements;
344

345
346
347
    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SOURCE:
348
    _cairo_pattern_fini_snapshot (&command->source.base);
349
  CLEANUP_COMMAND:
350
    _cairo_clip_fini (&command->header.clip);
351
352
353
354
355
    free (command);
    return status;
}

static cairo_int_status_t
356
357
358
359
360
_cairo_recording_surface_mask (void			*abstract_surface,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
			       const cairo_pattern_t	*mask,
			       cairo_clip_t		*clip)
361
362
{
    cairo_status_t status;
363
    cairo_recording_surface_t *recording_surface = abstract_surface;
364
365
366
    cairo_command_mask_t *command;

    command = malloc (sizeof (cairo_command_mask_t));
367
    if (unlikely (command == NULL))
368
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
369

370
    status = _command_init (recording_surface,
371
372
373
			    &command->header, CAIRO_COMMAND_MASK, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;
374

375
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
376
    if (unlikely (status))
377
378
	goto CLEANUP_COMMAND;

379
    status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
380
    if (unlikely (status))
381
	goto CLEANUP_SOURCE;
382

383
    status = _cairo_array_append (&recording_surface->commands, &command);
384
    if (unlikely (status))
385
386
387
388
389
	goto CLEANUP_MASK;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_MASK:
390
    _cairo_pattern_fini_snapshot (&command->mask.base);
391
  CLEANUP_SOURCE:
392
    _cairo_pattern_fini_snapshot (&command->source.base);
393
  CLEANUP_COMMAND:
394
    _cairo_clip_fini (&command->header.clip);
395
396
397
398
399
    free (command);
    return status;
}

static cairo_int_status_t
400
401
402
403
_cairo_recording_surface_stroke (void			*abstract_surface,
				 cairo_operator_t	 op,
				 const cairo_pattern_t	*source,
				 cairo_path_fixed_t	*path,
404
405
406
				 const cairo_stroke_style_t	*style,
				 const cairo_matrix_t		*ctm,
				 const cairo_matrix_t		*ctm_inverse,
407
408
409
				 double			 tolerance,
				 cairo_antialias_t	 antialias,
				 cairo_clip_t		*clip)
410
411
{
    cairo_status_t status;
412
    cairo_recording_surface_t *recording_surface = abstract_surface;
413
    cairo_command_stroke_t *command;
414

415
    command = malloc (sizeof (cairo_command_stroke_t));
416
    if (unlikely (command == NULL))
417
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
418

419
    status = _command_init (recording_surface,
420
421
422
			    &command->header, CAIRO_COMMAND_STROKE, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;
423

424
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
425
    if (unlikely (status))
426
427
428
	goto CLEANUP_COMMAND;

    status = _cairo_path_fixed_init_copy (&command->path, path);
429
    if (unlikely (status))
430
431
432
	goto CLEANUP_SOURCE;

    status = _cairo_stroke_style_init_copy (&command->style, style);
433
    if (unlikely (status))
434
435
436
437
438
439
440
	goto CLEANUP_PATH;

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

441
    status = _cairo_array_append (&recording_surface->commands, &command);
442
    if (unlikely (status))
443
444
445
446
447
448
449
450
451
	goto CLEANUP_STYLE;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_STYLE:
    _cairo_stroke_style_fini (&command->style);
  CLEANUP_PATH:
    _cairo_path_fixed_fini (&command->path);
  CLEANUP_SOURCE:
452
    _cairo_pattern_fini_snapshot (&command->source.base);
453
  CLEANUP_COMMAND:
454
    _cairo_clip_fini (&command->header.clip);
455
456
457
458
459
    free (command);
    return status;
}

static cairo_int_status_t
460
461
462
463
464
465
466
467
_cairo_recording_surface_fill (void			*abstract_surface,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
			       cairo_path_fixed_t	*path,
			       cairo_fill_rule_t	 fill_rule,
			       double			 tolerance,
			       cairo_antialias_t	 antialias,
			       cairo_clip_t		*clip)
468
469
{
    cairo_status_t status;
470
    cairo_recording_surface_t *recording_surface = abstract_surface;
471
472
473
    cairo_command_fill_t *command;

    command = malloc (sizeof (cairo_command_fill_t));
474
    if (unlikely (command == NULL))
475
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
476

477
    status =_command_init (recording_surface,
478
479
480
			   &command->header, CAIRO_COMMAND_FILL, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;
481

482
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
483
    if (unlikely (status))
484
485
486
	goto CLEANUP_COMMAND;

    status = _cairo_path_fixed_init_copy (&command->path, path);
487
    if (unlikely (status))
488
489
490
491
492
493
	goto CLEANUP_SOURCE;

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

494
    status = _cairo_array_append (&recording_surface->commands, &command);
495
    if (unlikely (status))
496
497
498
499
500
501
502
	goto CLEANUP_PATH;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_PATH:
    _cairo_path_fixed_fini (&command->path);
  CLEANUP_SOURCE:
503
    _cairo_pattern_fini_snapshot (&command->source.base);
504
  CLEANUP_COMMAND:
505
    _cairo_clip_fini (&command->header.clip);
506
507
508
509
    free (command);
    return status;
}

510
static cairo_bool_t
511
_cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
512
513
514
515
{
    return TRUE;
}

516
static cairo_int_status_t
517
518
519
520
521
522
523
524
525
526
527
528
_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,
					   cairo_clip_t			*clip)
529
530
{
    cairo_status_t status;
531
    cairo_recording_surface_t *recording_surface = abstract_surface;
532
    cairo_command_show_text_glyphs_t *command;
533

534
    command = malloc (sizeof (cairo_command_show_text_glyphs_t));
535
    if (unlikely (command == NULL))
536
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
537

538
    status = _command_init (recording_surface,
539
540
541
542
			    &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
			    op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;
543

544
    status = _cairo_pattern_init_snapshot (&command->source.base, source);
545
    if (unlikely (status))
546
547
	goto CLEANUP_COMMAND;

548
549
550
551
552
553
554
555
556
    command->utf8 = NULL;
    command->utf8_len = utf8_len;
    command->glyphs = NULL;
    command->num_glyphs = num_glyphs;
    command->clusters = NULL;
    command->num_clusters = num_clusters;

    if (utf8_len) {
	command->utf8 = malloc (utf8_len);
557
	if (unlikely (command->utf8 == NULL)) {
558
559
560
561
562
563
564
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->utf8, utf8, utf8_len);
    }
    if (num_glyphs) {
	command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
565
	if (unlikely (command->glyphs == NULL)) {
566
567
568
569
570
571
572
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
    }
    if (num_clusters) {
	command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
573
	if (unlikely (command->clusters == NULL)) {
574
575
576
577
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
578
579
    }

580
    command->cluster_flags = cluster_flags;
581
582
583

    command->scaled_font = cairo_scaled_font_reference (scaled_font);

584
    status = _cairo_array_append (&recording_surface->commands, &command);
585
    if (unlikely (status))
586
587
588
589
590
591
	goto CLEANUP_SCALED_FONT;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SCALED_FONT:
    cairo_scaled_font_destroy (command->scaled_font);
592
593
  CLEANUP_ARRAYS:
    free (command->utf8);
594
    free (command->glyphs);
595
596
    free (command->clusters);

597
    _cairo_pattern_fini_snapshot (&command->source.base);
598
  CLEANUP_COMMAND:
599
    _cairo_clip_fini (&command->header.clip);
600
    free (command);
601
    return status;
602
603
}

604
/**
605
606
 * _cairo_recording_surface_snapshot
 * @surface: a #cairo_surface_t which must be a recording surface
607
608
609
610
611
 *
 * Make an immutable copy of @surface. It is an error to call a
 * surface-modifying function on the result of this function.
 *
 * The caller owns the return value and should call
612
 * cairo_surface_destroy() when finished with it. This function will not
613
 * return %NULL, but will return a nil surface instead.
614
615
616
617
 *
 * Return value: The snapshot surface.
 **/
static cairo_surface_t *
618
_cairo_recording_surface_snapshot (void *abstract_other)
619
{
620
621
    cairo_recording_surface_t *other = abstract_other;
    cairo_recording_surface_t *recording_surface;
622

623
624
    recording_surface = malloc (sizeof (cairo_recording_surface_t));
    if (unlikely (recording_surface == NULL))
625
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
626

Chris Wilson's avatar
Chris Wilson committed
627
628
629
    _cairo_surface_init (&recording_surface->base,
			 &cairo_recording_surface_backend,
			 NULL, /* device */
630
			 other->base.content);
631

632
633
634
635
636
    recording_surface->extents_pixels = other->extents_pixels;
    recording_surface->extents = other->extents;
    recording_surface->unbounded = other->unbounded;
    recording_surface->replay_start_idx = other->replay_start_idx;
    recording_surface->content = other->content;
637

638
639
    _cairo_array_init_snapshot (&recording_surface->commands, &other->commands);
    recording_surface->commands_owner = cairo_surface_reference (&other->base);
640

641
    _cairo_clip_init_copy (&recording_surface->clip, &other->clip);
642

643
    return &recording_surface->base;
644
645
}

646
static cairo_bool_t
647
648
_cairo_recording_surface_get_extents (void		    *abstract_surface,
				      cairo_rectangle_int_t *rectangle)
649
{
650
    cairo_recording_surface_t *surface = abstract_surface;
651

652
653
    if (surface->unbounded)
	return FALSE;
654

655
656
    *rectangle = surface->extents;
    return TRUE;
657
658
}

659
/**
660
 * _cairo_surface_is_recording:
661
 * @surface: a #cairo_surface_t
662
 *
663
 * Checks if a surface is a #cairo_recording_surface_t
664
 *
665
 * Return value: %TRUE if the surface is a recording surface
666
667
 **/
cairo_bool_t
668
_cairo_surface_is_recording (const cairo_surface_t *surface)
669
{
670
    return surface->backend == &cairo_recording_surface_backend;
671
672
}

673
674
675
676
677
678
static const cairo_surface_backend_t cairo_recording_surface_backend = {
    CAIRO_SURFACE_TYPE_RECORDING,
    _cairo_recording_surface_create_similar,
    _cairo_recording_surface_finish,
    _cairo_recording_surface_acquire_source_image,
    _cairo_recording_surface_release_source_image,
679
680
681
    NULL, /* acquire_dest_image */
    NULL, /* release_dest_image */
    NULL, /* clone_similar */
682
683
684
    NULL, /* composite */
    NULL, /* fill_rectangles */
    NULL, /* composite_trapezoids */
685
686
    NULL, /* create_span_renderer */
    NULL, /* check_span_renderer */
687
688
    NULL, /* copy_page */
    NULL, /* show_page */
689
    _cairo_recording_surface_get_extents,
690
    NULL, /* old_show_glyphs */
691
692
693
694
695
696
    NULL, /* get_font_options */
    NULL, /* flush */
    NULL, /* mark_dirty_rectangle */
    NULL, /* scaled_font_fini */
    NULL, /* scaled_glyph_fini */

697
    /* Here are the 5 basic drawing operations, (which are in some
698
     * sense the only things that cairo_recording_surface should need to
699
700
     * implement).  However, we implement the more generic show_text_glyphs
     * instead of show_glyphs.  One or the other is eough. */
701

702
703
704
705
    _cairo_recording_surface_paint,
    _cairo_recording_surface_mask,
    _cairo_recording_surface_stroke,
    _cairo_recording_surface_fill,
706
707
    NULL,

708
    _cairo_recording_surface_snapshot,
709

710
711
712
    NULL, /* is_similar */
    NULL, /* fill_stroke */
    NULL, /* create_solid_pattern_surface */
713
    NULL, /* can_repaint_solid_pattern_surface */
714

715
716
    _cairo_recording_surface_has_show_text_glyphs,
    _cairo_recording_surface_show_text_glyphs
717
718
};

719
cairo_int_status_t
720
721
_cairo_recording_surface_get_path (cairo_surface_t    *surface,
				   cairo_path_fixed_t *path)
722
{
723
    cairo_recording_surface_t *recording_surface;
724
    cairo_command_t **elements;
725
726
727
728
729
730
    int i, num_elements;
    cairo_int_status_t status;

    if (surface->status)
	return surface->status;

731
    recording_surface = (cairo_recording_surface_t *) surface;
732
733
    status = CAIRO_STATUS_SUCCESS;

734
735
736
    num_elements = recording_surface->commands.num_elements;
    elements = _cairo_array_index (&recording_surface->commands, 0);
    for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
737
	cairo_command_t *command = elements[i];
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766

	switch (command->header.type) {
	case CAIRO_COMMAND_PAINT:
	case CAIRO_COMMAND_MASK:
	    status = CAIRO_INT_STATUS_UNSUPPORTED;
	    break;

	case CAIRO_COMMAND_STROKE:
	{
	    cairo_traps_t traps;

	    _cairo_traps_init (&traps);

	    /* XXX call cairo_stroke_to_path() when that is implemented */
	    status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
							&command->stroke.style,
							&command->stroke.ctm,
							&command->stroke.ctm_inverse,
							command->stroke.tolerance,
							&traps);

	    if (status == CAIRO_STATUS_SUCCESS)
		status = _cairo_traps_path (&traps, path);

	    _cairo_traps_fini (&traps);
	    break;
	}
	case CAIRO_COMMAND_FILL:
	{
767
768
769
	    status = _cairo_path_fixed_append (path,
					       &command->fill.path, CAIRO_DIRECTION_FORWARD,
					       0, 0);
770
771
	    break;
	}
772
	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
773
	{
774
775
776
	    status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
						    command->show_text_glyphs.glyphs,
						    command->show_text_glyphs.num_glyphs,
777
778
779
						    path);
	    break;
	}
780

781
782
783
784
	default:
	    ASSERT_NOT_REACHED;
	}

785
	if (unlikely (status))
786
787
788
789
790
791
	    break;
    }

    return _cairo_surface_set_error (surface, status);
}

792
#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
793
static cairo_status_t
794
795
796
797
_cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
					  cairo_surface_t	     *target,
					  cairo_recording_replay_type_t type,
					  cairo_recording_region_type_t region)
798
{
799
    cairo_recording_surface_t *recording_surface;
800
    cairo_command_t **elements;
801
    int i, num_elements;
802
803
    cairo_int_status_t status;
    cairo_surface_wrapper_t wrapper;
804

805
    if (unlikely (surface->status))
806
807
	return surface->status;

808
    if (unlikely (target->status))
809
810
	return _cairo_surface_set_error (surface, target->status);

811
812
    _cairo_surface_wrapper_init (&wrapper, target);

813
    recording_surface = (cairo_recording_surface_t *) surface;
814
    status = CAIRO_STATUS_SUCCESS;
815

816
817
818
    num_elements = recording_surface->commands.num_elements;
    elements = _cairo_array_index (&recording_surface->commands, 0);
    for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
819
	cairo_command_t *command = elements[i];
820

821
	if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
822
823
824
825
826
	    if (command->header.region != region)
		continue;
        }

	switch (command->header.type) {
827
	case CAIRO_COMMAND_PAINT:
828
829
830
831
	    status = _cairo_surface_wrapper_paint (&wrapper,
						   command->header.op,
						   &command->paint.source.base,
						   _clip (command));
832
	    break;
833

834
	case CAIRO_COMMAND_MASK:
835
836
837
838
839
	    status = _cairo_surface_wrapper_mask (&wrapper,
						  command->header.op,
						  &command->mask.source.base,
						  &command->mask.mask.base,
						  _clip (command));
840
	    break;
841

842
	case CAIRO_COMMAND_STROKE:
843
	{
844
845
846
847
848
849
850
851
852
853
	    status = _cairo_surface_wrapper_stroke (&wrapper,
						    command->header.op,
						    &command->stroke.source.base,
						    &command->stroke.path,
						    &command->stroke.style,
						    &command->stroke.ctm,
						    &command->stroke.ctm_inverse,
						    command->stroke.tolerance,
						    command->stroke.antialias,
						    _clip (command));
854
	    break;
855
	}
856
	case CAIRO_COMMAND_FILL:
857
858
859
	{
	    cairo_command_t *stroke_command;

860
	    stroke_command = NULL;
861
	    if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
862
		stroke_command = elements[i + 1];
863

Adrian Johnson's avatar
Adrian Johnson committed
864
	    if (stroke_command != NULL &&
865
866
		type == CAIRO_RECORDING_REPLAY &&
		region != CAIRO_RECORDING_REGION_ALL)
Adrian Johnson's avatar
Adrian Johnson committed
867
868
869
870
	    {
		if (stroke_command->header.region != region)
		    stroke_command = NULL;
	    }
871

872
873
	    if (stroke_command != NULL &&
		stroke_command->header.type == CAIRO_COMMAND_STROKE &&
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
		_cairo_path_fixed_is_equal (&command->fill.path,
					    &stroke_command->stroke.path))
	    {
		status = _cairo_surface_wrapper_fill_stroke (&wrapper,
							     command->header.op,
							     &command->fill.source.base,
							     command->fill.fill_rule,
							     command->fill.tolerance,
							     command->fill.antialias,
							     &command->fill.path,
							     stroke_command->header.op,
							     &stroke_command->stroke.source.base,
							     &stroke_command->stroke.style,
							     &stroke_command->stroke.ctm,
							     &stroke_command->stroke.ctm_inverse,
							     stroke_command->stroke.tolerance,
							     stroke_command->stroke.antialias,
							     _clip (command));
892
		i++;
893
894
895
896
897
898
899
900
901
902
903
904
	    }
	    else
	    {
		status = _cairo_surface_wrapper_fill (&wrapper,
						      command->header.op,
						      &command->fill.source.base,
						      &command->fill.path,
						      command->fill.fill_rule,
						      command->fill.tolerance,
						      command->fill.antialias,
						      _clip (command));
	    }
905
	    break;
906
	}
907
	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
908
	{
909
	    cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
910
911
	    cairo_glyph_t *glyphs_copy;
	    int num_glyphs = command->show_text_glyphs.num_glyphs;
912

913
            /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
914
915
916
	     * to modify the glyph array that's passed in.  We must always
	     * copy the array before handing it to the backend.
	     */
917
918
	    glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (glyphs_copy == NULL)) {
919
920
921
922
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		break;
	    }

923
924
925
926
927
928
929
930
931
932
933
934
	    memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);

	    status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
							      command->header.op,
							      &command->show_text_glyphs.source.base,
							      command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
							      glyphs_copy, num_glyphs,
							      command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
							      command->show_text_glyphs.cluster_flags,
							      command->show_text_glyphs.scaled_font,
							      _clip (command));
	    free (glyphs_copy);
935
	    break;
936
	}
937
938
939
940
	default:
	    ASSERT_NOT_REACHED;
	}

941
	if (type == CAIRO_RECORDING_CREATE_REGIONS) {
942
	    if (status == CAIRO_STATUS_SUCCESS) {
943
		command->header.region = CAIRO_RECORDING_REGION_NATIVE;
944
	    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
945
		command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;