Line data Source code
1 : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 : /* cairo - a vector graphics library with display and print output
3 : *
4 : * Copyright © 2005 Red Hat, Inc
5 : * Copyright © 2007 Adrian Johnson
6 : *
7 : * This library is free software; you can redistribute it and/or
8 : * modify it either under the terms of the GNU Lesser General Public
9 : * License version 2.1 as published by the Free Software Foundation
10 : * (the "LGPL") or, at your option, under the terms of the Mozilla
11 : * Public License Version 1.1 (the "MPL"). If you do not alter this
12 : * notice, a recipient may use your version of this file under either
13 : * the MPL or the LGPL.
14 : *
15 : * You should have received a copy of the LGPL along with this library
16 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 : * You should have received a copy of the MPL along with this library
19 : * in the file COPYING-MPL-1.1
20 : *
21 : * The contents of this file are subject to the Mozilla Public License
22 : * Version 1.1 (the "License"); you may not use this file except in
23 : * compliance with the License. You may obtain a copy of the License at
24 : * http://www.mozilla.org/MPL/
25 : *
26 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 : * the specific language governing rights and limitations.
29 : *
30 : * The Original Code is the cairo graphics library.
31 : *
32 : * The Initial Developer of the Original Code is Red Hat, Inc.
33 : *
34 : * Contributor(s):
35 : * Kristian Høgsberg <krh@redhat.com>
36 : * Carl Worth <cworth@cworth.org>
37 : * Adrian Johnson <ajohnson@redneon.com>
38 : */
39 :
40 : /**
41 : * SECTION:cairo-recording
42 : * @Title: Recording Surfaces
43 : * @Short_Description: Records all drawing operations
44 : * @See_Also: #cairo_surface_t
45 : *
46 : * A recording surface is a surface that records all drawing operations at
47 : * the highest level of the surface backend interface, (that is, the
48 : * level of paint, mask, stroke, fill, and show_text_glyphs). The recording
49 : * surface can then be "replayed" against any target surface by using it
50 : * as a source surface.
51 : *
52 : * If you want to replay a surface so that the results in target will be
53 : * identical to the results that would have been obtained if the original
54 : * operations applied to the recording surface had instead been applied to the
55 : * target surface, you can use code like this:
56 : * <informalexample><programlisting>
57 : * cairo_t *cr;
58 : *
59 : * cr = cairo_create (target);
60 : * cairo_set_source_surface (cr, recording_surface, 0.0, 0.0);
61 : * cairo_paint (cr);
62 : * cairo_destroy (cr);
63 : * </programlisting></informalexample>
64 : *
65 : * A recording surface is logically unbounded, i.e. it has no implicit constraint
66 : * on the size of the drawing surface. However, in practice this is rarely
67 : * useful as you wish to replay against a particular target surface with
68 : * known bounds. For this case, it is more efficient to specify the target
69 : * extents to the recording surface upon creation.
70 : *
71 : * The recording phase of the recording surface is careful to snapshot all
72 : * necessary objects (paths, patterns, etc.), in order to achieve
73 : * accurate replay. The efficiency of the recording surface could be
74 : * improved by improving the implementation of snapshot for the
75 : * various objects. For example, it would be nice to have a
76 : * copy-on-write implementation for _cairo_surface_snapshot.
77 : */
78 :
79 : #include "cairoint.h"
80 : #include "cairo-analysis-surface-private.h"
81 : #include "cairo-clip-private.h"
82 : #include "cairo-error-private.h"
83 : #include "cairo-recording-surface-private.h"
84 : #include "cairo-surface-wrapper-private.h"
85 :
86 : typedef enum {
87 : CAIRO_RECORDING_REPLAY,
88 : CAIRO_RECORDING_CREATE_REGIONS
89 : } cairo_recording_replay_type_t;
90 :
91 : static const cairo_surface_backend_t cairo_recording_surface_backend;
92 :
93 : /**
94 : * CAIRO_HAS_RECORDING_SURFACE:
95 : *
96 : * Defined if the recording surface backend is available.
97 : * The recording surface backend is always built in.
98 : * This macro was added for completeness in cairo 1.10.
99 : *
100 : * Since: 1.10
101 : */
102 :
103 : /* Currently all recording surfaces do have a size which should be passed
104 : * in as the maximum size of any target surface against which the
105 : * recording-surface will ever be replayed.
106 : *
107 : * XXX: The naming of "pixels" in the size here is a misnomer. It's
108 : * actually a size in whatever device-space units are desired (again,
109 : * according to the intended replay target).
110 : */
111 :
112 : /**
113 : * cairo_recording_surface_create:
114 : * @content: the content of the recording surface
115 : * @extents: the extents to record in pixels, can be %NULL to record
116 : * unbounded operations.
117 : *
118 : * Creates a recording-surface which can be used to record all drawing operations
119 : * at the highest level (that is, the level of paint, mask, stroke, fill
120 : * and show_text_glyphs). The recording surface can then be "replayed" against
121 : * any target surface by using it as a source to drawing operations.
122 : *
123 : * The recording phase of the recording surface is careful to snapshot all
124 : * necessary objects (paths, patterns, etc.), in order to achieve
125 : * accurate replay.
126 : *
127 : * Return value: a pointer to the newly created surface. The caller
128 : * owns the surface and should call cairo_surface_destroy() when done
129 : * with it.
130 : *
131 : * Since: 1.10
132 : **/
133 : cairo_surface_t *
134 0 : cairo_recording_surface_create (cairo_content_t content,
135 : const cairo_rectangle_t *extents)
136 : {
137 : cairo_recording_surface_t *recording_surface;
138 : cairo_status_t status;
139 :
140 0 : recording_surface = malloc (sizeof (cairo_recording_surface_t));
141 0 : if (unlikely (recording_surface == NULL))
142 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
143 :
144 0 : _cairo_surface_init (&recording_surface->base,
145 : &cairo_recording_surface_backend,
146 : NULL, /* device */
147 : content);
148 :
149 0 : recording_surface->content = content;
150 :
151 0 : recording_surface->unbounded = TRUE;
152 0 : _cairo_clip_init (&recording_surface->clip);
153 :
154 : /* unbounded -> 'infinite' extents */
155 0 : if (extents != NULL) {
156 0 : recording_surface->extents_pixels = *extents;
157 :
158 : /* XXX check for overflow */
159 0 : recording_surface->extents.x = floor (extents->x);
160 0 : recording_surface->extents.y = floor (extents->y);
161 0 : recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x;
162 0 : recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y;
163 :
164 0 : status = _cairo_clip_rectangle (&recording_surface->clip,
165 0 : &recording_surface->extents);
166 0 : if (unlikely (status)) {
167 0 : free (recording_surface);
168 0 : return _cairo_surface_create_in_error (status);
169 : }
170 :
171 0 : recording_surface->unbounded = FALSE;
172 : }
173 :
174 0 : _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
175 :
176 0 : recording_surface->replay_start_idx = 0;
177 0 : recording_surface->base.is_clear = TRUE;
178 :
179 0 : return &recording_surface->base;
180 : }
181 : slim_hidden_def (cairo_recording_surface_create);
182 :
183 : static cairo_surface_t *
184 0 : _cairo_recording_surface_create_similar (void *abstract_surface,
185 : cairo_content_t content,
186 : int width,
187 : int height)
188 : {
189 : cairo_rectangle_t extents;
190 0 : extents.x = extents.y = 0;
191 0 : extents.width = width;
192 0 : extents.height = height;
193 0 : return cairo_recording_surface_create (content, &extents);
194 : }
195 :
196 : static cairo_status_t
197 0 : _cairo_recording_surface_finish (void *abstract_surface)
198 : {
199 0 : cairo_recording_surface_t *recording_surface = abstract_surface;
200 : cairo_command_t **elements;
201 : int i, num_elements;
202 :
203 0 : num_elements = recording_surface->commands.num_elements;
204 0 : elements = _cairo_array_index (&recording_surface->commands, 0);
205 0 : for (i = 0; i < num_elements; i++) {
206 0 : cairo_command_t *command = elements[i];
207 :
208 0 : switch (command->header.type) {
209 : case CAIRO_COMMAND_PAINT:
210 0 : _cairo_pattern_fini (&command->paint.source.base);
211 0 : break;
212 :
213 : case CAIRO_COMMAND_MASK:
214 0 : _cairo_pattern_fini (&command->mask.source.base);
215 0 : _cairo_pattern_fini (&command->mask.mask.base);
216 0 : break;
217 :
218 : case CAIRO_COMMAND_STROKE:
219 0 : _cairo_pattern_fini (&command->stroke.source.base);
220 0 : _cairo_path_fixed_fini (&command->stroke.path);
221 0 : _cairo_stroke_style_fini (&command->stroke.style);
222 0 : break;
223 :
224 : case CAIRO_COMMAND_FILL:
225 0 : _cairo_pattern_fini (&command->fill.source.base);
226 0 : _cairo_path_fixed_fini (&command->fill.path);
227 0 : break;
228 :
229 : case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
230 0 : _cairo_pattern_fini (&command->show_text_glyphs.source.base);
231 0 : free (command->show_text_glyphs.utf8);
232 0 : free (command->show_text_glyphs.glyphs);
233 0 : free (command->show_text_glyphs.clusters);
234 0 : cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
235 0 : break;
236 :
237 : default:
238 0 : ASSERT_NOT_REACHED;
239 : }
240 :
241 0 : _cairo_clip_fini (&command->header.clip);
242 0 : free (command);
243 : }
244 :
245 0 : _cairo_array_fini (&recording_surface->commands);
246 0 : _cairo_clip_fini (&recording_surface->clip);
247 :
248 0 : return CAIRO_STATUS_SUCCESS;
249 : }
250 :
251 : static cairo_status_t
252 0 : _cairo_recording_surface_acquire_source_image (void *abstract_surface,
253 : cairo_image_surface_t **image_out,
254 : void **image_extra)
255 : {
256 : cairo_status_t status;
257 0 : cairo_recording_surface_t *surface = abstract_surface;
258 : cairo_surface_t *image;
259 :
260 0 : image = _cairo_surface_has_snapshot (&surface->base,
261 : &_cairo_image_surface_backend);
262 0 : if (image != NULL) {
263 0 : *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
264 0 : *image_extra = NULL;
265 0 : return CAIRO_STATUS_SUCCESS;
266 : }
267 :
268 0 : image = _cairo_image_surface_create_with_content (surface->content,
269 : surface->extents.width,
270 : surface->extents.height);
271 0 : if (unlikely (image->status))
272 0 : return image->status;
273 :
274 0 : cairo_surface_set_device_offset (image,
275 0 : -surface->extents.x,
276 0 : -surface->extents.y);
277 :
278 0 : status = _cairo_recording_surface_replay (&surface->base, image);
279 0 : if (unlikely (status)) {
280 0 : cairo_surface_destroy (image);
281 0 : return status;
282 : }
283 :
284 0 : cairo_surface_attach_snapshot (&surface->base, image, NULL);
285 :
286 0 : *image_out = (cairo_image_surface_t *) image;
287 0 : *image_extra = NULL;
288 0 : return CAIRO_STATUS_SUCCESS;
289 : }
290 :
291 : static void
292 0 : _cairo_recording_surface_release_source_image (void *abstract_surface,
293 : cairo_image_surface_t *image,
294 : void *image_extra)
295 : {
296 0 : cairo_surface_destroy (&image->base);
297 0 : }
298 :
299 : static cairo_status_t
300 0 : _command_init (cairo_recording_surface_t *recording_surface,
301 : cairo_command_header_t *command,
302 : cairo_command_type_t type,
303 : cairo_operator_t op,
304 : cairo_clip_t *clip)
305 : {
306 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
307 :
308 0 : command->type = type;
309 0 : command->op = op;
310 0 : command->region = CAIRO_RECORDING_REGION_ALL;
311 0 : _cairo_clip_init_copy (&command->clip, clip);
312 0 : if (recording_surface->clip.path != NULL)
313 0 : status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip);
314 :
315 0 : return status;
316 : }
317 :
318 : static cairo_int_status_t
319 0 : _cairo_recording_surface_paint (void *abstract_surface,
320 : cairo_operator_t op,
321 : const cairo_pattern_t *source,
322 : cairo_clip_t *clip)
323 : {
324 : cairo_status_t status;
325 0 : cairo_recording_surface_t *recording_surface = abstract_surface;
326 : cairo_command_paint_t *command;
327 :
328 0 : command = malloc (sizeof (cairo_command_paint_t));
329 0 : if (unlikely (command == NULL))
330 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
331 :
332 0 : status = _command_init (recording_surface,
333 0 : &command->header, CAIRO_COMMAND_PAINT, op, clip);
334 0 : if (unlikely (status))
335 0 : goto CLEANUP_COMMAND;
336 :
337 0 : status = _cairo_pattern_init_snapshot (&command->source.base, source);
338 0 : if (unlikely (status))
339 0 : goto CLEANUP_COMMAND;
340 :
341 0 : status = _cairo_array_append (&recording_surface->commands, &command);
342 0 : if (unlikely (status))
343 0 : goto CLEANUP_SOURCE;
344 :
345 : /* An optimisation that takes care to not replay what was done
346 : * before surface is cleared. We don't erase recorded commands
347 : * since we may have earlier snapshots of this surface. */
348 0 : if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
349 0 : recording_surface->replay_start_idx = recording_surface->commands.num_elements;
350 :
351 0 : return CAIRO_STATUS_SUCCESS;
352 :
353 : CLEANUP_SOURCE:
354 0 : _cairo_pattern_fini (&command->source.base);
355 : CLEANUP_COMMAND:
356 0 : _cairo_clip_fini (&command->header.clip);
357 0 : free (command);
358 0 : return status;
359 : }
360 :
361 : static cairo_int_status_t
362 0 : _cairo_recording_surface_mask (void *abstract_surface,
363 : cairo_operator_t op,
364 : const cairo_pattern_t *source,
365 : const cairo_pattern_t *mask,
366 : cairo_clip_t *clip)
367 : {
368 : cairo_status_t status;
369 0 : cairo_recording_surface_t *recording_surface = abstract_surface;
370 : cairo_command_mask_t *command;
371 :
372 0 : command = malloc (sizeof (cairo_command_mask_t));
373 0 : if (unlikely (command == NULL))
374 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
375 :
376 0 : status = _command_init (recording_surface,
377 0 : &command->header, CAIRO_COMMAND_MASK, op, clip);
378 0 : if (unlikely (status))
379 0 : goto CLEANUP_COMMAND;
380 :
381 0 : status = _cairo_pattern_init_snapshot (&command->source.base, source);
382 0 : if (unlikely (status))
383 0 : goto CLEANUP_COMMAND;
384 :
385 0 : status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
386 0 : if (unlikely (status))
387 0 : goto CLEANUP_SOURCE;
388 :
389 0 : status = _cairo_array_append (&recording_surface->commands, &command);
390 0 : if (unlikely (status))
391 0 : goto CLEANUP_MASK;
392 :
393 0 : return CAIRO_STATUS_SUCCESS;
394 :
395 : CLEANUP_MASK:
396 0 : _cairo_pattern_fini (&command->mask.base);
397 : CLEANUP_SOURCE:
398 0 : _cairo_pattern_fini (&command->source.base);
399 : CLEANUP_COMMAND:
400 0 : _cairo_clip_fini (&command->header.clip);
401 0 : free (command);
402 0 : return status;
403 : }
404 :
405 : static cairo_int_status_t
406 0 : _cairo_recording_surface_stroke (void *abstract_surface,
407 : cairo_operator_t op,
408 : const cairo_pattern_t *source,
409 : cairo_path_fixed_t *path,
410 : const cairo_stroke_style_t *style,
411 : const cairo_matrix_t *ctm,
412 : const cairo_matrix_t *ctm_inverse,
413 : double tolerance,
414 : cairo_antialias_t antialias,
415 : cairo_clip_t *clip)
416 : {
417 : cairo_status_t status;
418 0 : cairo_recording_surface_t *recording_surface = abstract_surface;
419 : cairo_command_stroke_t *command;
420 :
421 0 : command = malloc (sizeof (cairo_command_stroke_t));
422 0 : if (unlikely (command == NULL))
423 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
424 :
425 0 : status = _command_init (recording_surface,
426 0 : &command->header, CAIRO_COMMAND_STROKE, op, clip);
427 0 : if (unlikely (status))
428 0 : goto CLEANUP_COMMAND;
429 :
430 0 : status = _cairo_pattern_init_snapshot (&command->source.base, source);
431 0 : if (unlikely (status))
432 0 : goto CLEANUP_COMMAND;
433 :
434 0 : status = _cairo_path_fixed_init_copy (&command->path, path);
435 0 : if (unlikely (status))
436 0 : goto CLEANUP_SOURCE;
437 :
438 0 : status = _cairo_stroke_style_init_copy (&command->style, style);
439 0 : if (unlikely (status))
440 0 : goto CLEANUP_PATH;
441 :
442 0 : command->ctm = *ctm;
443 0 : command->ctm_inverse = *ctm_inverse;
444 0 : command->tolerance = tolerance;
445 0 : command->antialias = antialias;
446 :
447 0 : status = _cairo_array_append (&recording_surface->commands, &command);
448 0 : if (unlikely (status))
449 0 : goto CLEANUP_STYLE;
450 :
451 0 : return CAIRO_STATUS_SUCCESS;
452 :
453 : CLEANUP_STYLE:
454 0 : _cairo_stroke_style_fini (&command->style);
455 : CLEANUP_PATH:
456 0 : _cairo_path_fixed_fini (&command->path);
457 : CLEANUP_SOURCE:
458 0 : _cairo_pattern_fini (&command->source.base);
459 : CLEANUP_COMMAND:
460 0 : _cairo_clip_fini (&command->header.clip);
461 0 : free (command);
462 0 : return status;
463 : }
464 :
465 : static cairo_int_status_t
466 0 : _cairo_recording_surface_fill (void *abstract_surface,
467 : cairo_operator_t op,
468 : const cairo_pattern_t *source,
469 : cairo_path_fixed_t *path,
470 : cairo_fill_rule_t fill_rule,
471 : double tolerance,
472 : cairo_antialias_t antialias,
473 : cairo_clip_t *clip)
474 : {
475 : cairo_status_t status;
476 0 : cairo_recording_surface_t *recording_surface = abstract_surface;
477 : cairo_command_fill_t *command;
478 :
479 0 : command = malloc (sizeof (cairo_command_fill_t));
480 0 : if (unlikely (command == NULL))
481 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
482 :
483 0 : status =_command_init (recording_surface,
484 0 : &command->header, CAIRO_COMMAND_FILL, op, clip);
485 0 : if (unlikely (status))
486 0 : goto CLEANUP_COMMAND;
487 :
488 0 : status = _cairo_pattern_init_snapshot (&command->source.base, source);
489 0 : if (unlikely (status))
490 0 : goto CLEANUP_COMMAND;
491 :
492 0 : status = _cairo_path_fixed_init_copy (&command->path, path);
493 0 : if (unlikely (status))
494 0 : goto CLEANUP_SOURCE;
495 :
496 0 : command->fill_rule = fill_rule;
497 0 : command->tolerance = tolerance;
498 0 : command->antialias = antialias;
499 :
500 0 : status = _cairo_array_append (&recording_surface->commands, &command);
501 0 : if (unlikely (status))
502 0 : goto CLEANUP_PATH;
503 :
504 0 : return CAIRO_STATUS_SUCCESS;
505 :
506 : CLEANUP_PATH:
507 0 : _cairo_path_fixed_fini (&command->path);
508 : CLEANUP_SOURCE:
509 0 : _cairo_pattern_fini (&command->source.base);
510 : CLEANUP_COMMAND:
511 0 : _cairo_clip_fini (&command->header.clip);
512 0 : free (command);
513 0 : return status;
514 : }
515 :
516 : static cairo_bool_t
517 0 : _cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
518 : {
519 0 : return TRUE;
520 : }
521 :
522 : static cairo_int_status_t
523 0 : _cairo_recording_surface_show_text_glyphs (void *abstract_surface,
524 : cairo_operator_t op,
525 : const cairo_pattern_t *source,
526 : const char *utf8,
527 : int utf8_len,
528 : cairo_glyph_t *glyphs,
529 : int num_glyphs,
530 : const cairo_text_cluster_t *clusters,
531 : int num_clusters,
532 : cairo_text_cluster_flags_t cluster_flags,
533 : cairo_scaled_font_t *scaled_font,
534 : cairo_clip_t *clip)
535 : {
536 : cairo_status_t status;
537 0 : cairo_recording_surface_t *recording_surface = abstract_surface;
538 : cairo_command_show_text_glyphs_t *command;
539 :
540 0 : command = malloc (sizeof (cairo_command_show_text_glyphs_t));
541 0 : if (unlikely (command == NULL))
542 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
543 :
544 0 : status = _command_init (recording_surface,
545 0 : &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
546 : op, clip);
547 0 : if (unlikely (status))
548 0 : goto CLEANUP_COMMAND;
549 :
550 0 : status = _cairo_pattern_init_snapshot (&command->source.base, source);
551 0 : if (unlikely (status))
552 0 : goto CLEANUP_COMMAND;
553 :
554 0 : command->utf8 = NULL;
555 0 : command->utf8_len = utf8_len;
556 0 : command->glyphs = NULL;
557 0 : command->num_glyphs = num_glyphs;
558 0 : command->clusters = NULL;
559 0 : command->num_clusters = num_clusters;
560 :
561 0 : if (utf8_len) {
562 0 : command->utf8 = malloc (utf8_len);
563 0 : if (unlikely (command->utf8 == NULL)) {
564 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
565 0 : goto CLEANUP_ARRAYS;
566 : }
567 0 : memcpy (command->utf8, utf8, utf8_len);
568 : }
569 0 : if (num_glyphs) {
570 0 : command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
571 0 : if (unlikely (command->glyphs == NULL)) {
572 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
573 0 : goto CLEANUP_ARRAYS;
574 : }
575 0 : memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
576 : }
577 0 : if (num_clusters) {
578 0 : command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
579 0 : if (unlikely (command->clusters == NULL)) {
580 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
581 0 : goto CLEANUP_ARRAYS;
582 : }
583 0 : memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
584 : }
585 :
586 0 : command->cluster_flags = cluster_flags;
587 :
588 0 : command->scaled_font = cairo_scaled_font_reference (scaled_font);
589 :
590 0 : status = _cairo_array_append (&recording_surface->commands, &command);
591 0 : if (unlikely (status))
592 0 : goto CLEANUP_SCALED_FONT;
593 :
594 0 : return CAIRO_STATUS_SUCCESS;
595 :
596 : CLEANUP_SCALED_FONT:
597 0 : cairo_scaled_font_destroy (command->scaled_font);
598 : CLEANUP_ARRAYS:
599 0 : free (command->utf8);
600 0 : free (command->glyphs);
601 0 : free (command->clusters);
602 :
603 0 : _cairo_pattern_fini (&command->source.base);
604 : CLEANUP_COMMAND:
605 0 : _cairo_clip_fini (&command->header.clip);
606 0 : free (command);
607 0 : return status;
608 : }
609 :
610 : /**
611 : * _cairo_recording_surface_snapshot
612 : * @surface: a #cairo_surface_t which must be a recording surface
613 : *
614 : * Make an immutable copy of @surface. It is an error to call a
615 : * surface-modifying function on the result of this function.
616 : *
617 : * The caller owns the return value and should call
618 : * cairo_surface_destroy() when finished with it. This function will not
619 : * return %NULL, but will return a nil surface instead.
620 : *
621 : * Return value: The snapshot surface.
622 : **/
623 : static cairo_surface_t *
624 0 : _cairo_recording_surface_snapshot (void *abstract_other)
625 : {
626 0 : cairo_recording_surface_t *other = abstract_other;
627 : cairo_recording_surface_t *recording_surface;
628 : cairo_status_t status;
629 :
630 0 : recording_surface = malloc (sizeof (cairo_recording_surface_t));
631 0 : if (unlikely (recording_surface == NULL))
632 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
633 :
634 0 : _cairo_surface_init (&recording_surface->base,
635 : &cairo_recording_surface_backend,
636 : NULL, /* device */
637 : other->base.content);
638 :
639 0 : recording_surface->extents_pixels = other->extents_pixels;
640 0 : recording_surface->extents = other->extents;
641 0 : recording_surface->unbounded = other->unbounded;
642 0 : recording_surface->content = other->content;
643 :
644 0 : _cairo_clip_init_copy (&recording_surface->clip, &other->clip);
645 :
646 : /* XXX We should in theory be able to reuse the original array, but we
647 : * need to handle reference cycles during subsurface and self-copy.
648 : */
649 0 : recording_surface->replay_start_idx = 0;
650 0 : recording_surface->base.is_clear = TRUE;
651 :
652 0 : _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
653 0 : status = _cairo_recording_surface_replay (&other->base, &recording_surface->base);
654 0 : if (unlikely (status)) {
655 0 : cairo_surface_destroy (&recording_surface->base);
656 0 : return _cairo_surface_create_in_error (status);
657 : }
658 :
659 0 : return &recording_surface->base;
660 : }
661 :
662 : static cairo_bool_t
663 0 : _cairo_recording_surface_get_extents (void *abstract_surface,
664 : cairo_rectangle_int_t *rectangle)
665 : {
666 0 : cairo_recording_surface_t *surface = abstract_surface;
667 :
668 0 : if (surface->unbounded)
669 0 : return FALSE;
670 :
671 0 : *rectangle = surface->extents;
672 0 : return TRUE;
673 : }
674 :
675 : /**
676 : * _cairo_surface_is_recording:
677 : * @surface: a #cairo_surface_t
678 : *
679 : * Checks if a surface is a #cairo_recording_surface_t
680 : *
681 : * Return value: %TRUE if the surface is a recording surface
682 : **/
683 : cairo_bool_t
684 0 : _cairo_surface_is_recording (const cairo_surface_t *surface)
685 : {
686 0 : return surface->backend == &cairo_recording_surface_backend;
687 : }
688 :
689 : static const cairo_surface_backend_t cairo_recording_surface_backend = {
690 : CAIRO_SURFACE_TYPE_RECORDING,
691 : _cairo_recording_surface_create_similar,
692 : _cairo_recording_surface_finish,
693 : _cairo_recording_surface_acquire_source_image,
694 : _cairo_recording_surface_release_source_image,
695 : NULL, /* acquire_dest_image */
696 : NULL, /* release_dest_image */
697 : NULL, /* clone_similar */
698 : NULL, /* composite */
699 : NULL, /* fill_rectangles */
700 : NULL, /* composite_trapezoids */
701 : NULL, /* create_span_renderer */
702 : NULL, /* check_span_renderer */
703 : NULL, /* copy_page */
704 : NULL, /* show_page */
705 : _cairo_recording_surface_get_extents,
706 : NULL, /* old_show_glyphs */
707 : NULL, /* get_font_options */
708 : NULL, /* flush */
709 : NULL, /* mark_dirty_rectangle */
710 : NULL, /* scaled_font_fini */
711 : NULL, /* scaled_glyph_fini */
712 :
713 : /* Here are the 5 basic drawing operations, (which are in some
714 : * sense the only things that cairo_recording_surface should need to
715 : * implement). However, we implement the more generic show_text_glyphs
716 : * instead of show_glyphs. One or the other is eough. */
717 :
718 : _cairo_recording_surface_paint,
719 : _cairo_recording_surface_mask,
720 : _cairo_recording_surface_stroke,
721 : _cairo_recording_surface_fill,
722 : NULL,
723 :
724 : _cairo_recording_surface_snapshot,
725 :
726 : NULL, /* is_similar */
727 : NULL, /* fill_stroke */
728 : NULL, /* create_solid_pattern_surface */
729 : NULL, /* can_repaint_solid_pattern_surface */
730 :
731 : _cairo_recording_surface_has_show_text_glyphs,
732 : _cairo_recording_surface_show_text_glyphs
733 : };
734 :
735 : cairo_int_status_t
736 0 : _cairo_recording_surface_get_path (cairo_surface_t *surface,
737 : cairo_path_fixed_t *path)
738 : {
739 : cairo_recording_surface_t *recording_surface;
740 : cairo_command_t **elements;
741 : int i, num_elements;
742 : cairo_int_status_t status;
743 :
744 0 : if (surface->status)
745 0 : return surface->status;
746 :
747 0 : recording_surface = (cairo_recording_surface_t *) surface;
748 0 : status = CAIRO_STATUS_SUCCESS;
749 :
750 0 : num_elements = recording_surface->commands.num_elements;
751 0 : elements = _cairo_array_index (&recording_surface->commands, 0);
752 0 : for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
753 0 : cairo_command_t *command = elements[i];
754 :
755 0 : switch (command->header.type) {
756 : case CAIRO_COMMAND_PAINT:
757 : case CAIRO_COMMAND_MASK:
758 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
759 0 : break;
760 :
761 : case CAIRO_COMMAND_STROKE:
762 : {
763 : cairo_traps_t traps;
764 :
765 0 : _cairo_traps_init (&traps);
766 :
767 : /* XXX call cairo_stroke_to_path() when that is implemented */
768 0 : status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
769 0 : &command->stroke.style,
770 0 : &command->stroke.ctm,
771 0 : &command->stroke.ctm_inverse,
772 : command->stroke.tolerance,
773 : &traps);
774 :
775 0 : if (status == CAIRO_STATUS_SUCCESS)
776 0 : status = _cairo_traps_path (&traps, path);
777 :
778 0 : _cairo_traps_fini (&traps);
779 0 : break;
780 : }
781 : case CAIRO_COMMAND_FILL:
782 : {
783 0 : status = _cairo_path_fixed_append (path,
784 0 : &command->fill.path, CAIRO_DIRECTION_FORWARD,
785 : 0, 0);
786 0 : break;
787 : }
788 : case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
789 : {
790 0 : status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
791 0 : command->show_text_glyphs.glyphs,
792 0 : command->show_text_glyphs.num_glyphs,
793 : path);
794 0 : break;
795 : }
796 :
797 : default:
798 0 : ASSERT_NOT_REACHED;
799 : }
800 :
801 0 : if (unlikely (status))
802 0 : break;
803 : }
804 :
805 0 : return _cairo_surface_set_error (surface, status);
806 : }
807 :
808 : #define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
809 : static cairo_status_t
810 0 : _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
811 : const cairo_rectangle_int_t *surface_extents,
812 : cairo_surface_t *target,
813 : cairo_recording_replay_type_t type,
814 : cairo_recording_region_type_t region)
815 : {
816 : cairo_recording_surface_t *recording_surface;
817 : cairo_command_t **elements;
818 : int i, num_elements;
819 : cairo_int_status_t status;
820 : cairo_surface_wrapper_t wrapper;
821 :
822 0 : if (unlikely (surface->status))
823 0 : return surface->status;
824 :
825 0 : if (unlikely (target->status))
826 0 : return target->status;
827 :
828 0 : if (unlikely (surface->finished))
829 0 : return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
830 :
831 0 : if (surface->is_clear)
832 0 : return CAIRO_STATUS_SUCCESS;
833 :
834 0 : assert (_cairo_surface_is_recording (surface));
835 :
836 0 : _cairo_surface_wrapper_init (&wrapper, target);
837 0 : _cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
838 :
839 0 : recording_surface = (cairo_recording_surface_t *) surface;
840 0 : status = CAIRO_STATUS_SUCCESS;
841 :
842 0 : num_elements = recording_surface->commands.num_elements;
843 0 : elements = _cairo_array_index (&recording_surface->commands, 0);
844 :
845 0 : for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
846 0 : cairo_command_t *command = elements[i];
847 :
848 0 : if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
849 0 : if (command->header.region != region)
850 0 : continue;
851 : }
852 :
853 0 : switch (command->header.type) {
854 : case CAIRO_COMMAND_PAINT:
855 0 : status = _cairo_surface_wrapper_paint (&wrapper,
856 : command->header.op,
857 0 : &command->paint.source.base,
858 0 : _clip (command));
859 0 : break;
860 :
861 : case CAIRO_COMMAND_MASK:
862 0 : status = _cairo_surface_wrapper_mask (&wrapper,
863 : command->header.op,
864 0 : &command->mask.source.base,
865 0 : &command->mask.mask.base,
866 0 : _clip (command));
867 0 : break;
868 :
869 : case CAIRO_COMMAND_STROKE:
870 : {
871 0 : status = _cairo_surface_wrapper_stroke (&wrapper,
872 : command->header.op,
873 0 : &command->stroke.source.base,
874 : &command->stroke.path,
875 0 : &command->stroke.style,
876 0 : &command->stroke.ctm,
877 0 : &command->stroke.ctm_inverse,
878 : command->stroke.tolerance,
879 : command->stroke.antialias,
880 0 : _clip (command));
881 0 : break;
882 : }
883 : case CAIRO_COMMAND_FILL:
884 : {
885 : cairo_command_t *stroke_command;
886 :
887 0 : stroke_command = NULL;
888 0 : if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
889 0 : stroke_command = elements[i + 1];
890 :
891 0 : if (stroke_command != NULL &&
892 0 : type == CAIRO_RECORDING_REPLAY &&
893 : region != CAIRO_RECORDING_REGION_ALL)
894 : {
895 0 : if (stroke_command->header.region != region)
896 0 : stroke_command = NULL;
897 : }
898 :
899 0 : if (stroke_command != NULL &&
900 0 : stroke_command->header.type == CAIRO_COMMAND_STROKE &&
901 0 : _cairo_path_fixed_is_equal (&command->fill.path,
902 0 : &stroke_command->stroke.path))
903 : {
904 0 : status = _cairo_surface_wrapper_fill_stroke (&wrapper,
905 : command->header.op,
906 0 : &command->fill.source.base,
907 : command->fill.fill_rule,
908 : command->fill.tolerance,
909 : command->fill.antialias,
910 : &command->fill.path,
911 : stroke_command->header.op,
912 0 : &stroke_command->stroke.source.base,
913 0 : &stroke_command->stroke.style,
914 0 : &stroke_command->stroke.ctm,
915 0 : &stroke_command->stroke.ctm_inverse,
916 : stroke_command->stroke.tolerance,
917 : stroke_command->stroke.antialias,
918 0 : _clip (command));
919 0 : i++;
920 : }
921 : else
922 : {
923 0 : status = _cairo_surface_wrapper_fill (&wrapper,
924 : command->header.op,
925 0 : &command->fill.source.base,
926 : &command->fill.path,
927 : command->fill.fill_rule,
928 : command->fill.tolerance,
929 : command->fill.antialias,
930 0 : _clip (command));
931 : }
932 0 : break;
933 : }
934 : case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
935 : {
936 0 : cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
937 : cairo_glyph_t *glyphs_copy;
938 0 : int num_glyphs = command->show_text_glyphs.num_glyphs;
939 :
940 : /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
941 : * to modify the glyph array that's passed in. We must always
942 : * copy the array before handing it to the backend.
943 : */
944 0 : glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
945 0 : if (unlikely (glyphs_copy == NULL)) {
946 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
947 0 : break;
948 : }
949 :
950 0 : memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
951 :
952 0 : status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
953 : command->header.op,
954 0 : &command->show_text_glyphs.source.base,
955 0 : command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
956 : glyphs_copy, num_glyphs,
957 0 : command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
958 : command->show_text_glyphs.cluster_flags,
959 : command->show_text_glyphs.scaled_font,
960 0 : _clip (command));
961 0 : free (glyphs_copy);
962 0 : break;
963 : }
964 : default:
965 0 : ASSERT_NOT_REACHED;
966 : }
967 :
968 0 : if (type == CAIRO_RECORDING_CREATE_REGIONS) {
969 0 : if (status == CAIRO_STATUS_SUCCESS) {
970 0 : command->header.region = CAIRO_RECORDING_REGION_NATIVE;
971 0 : } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
972 0 : command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
973 0 : status = CAIRO_STATUS_SUCCESS;
974 : } else {
975 0 : assert (_cairo_status_is_error (status));
976 : }
977 : }
978 :
979 0 : if (unlikely (status))
980 0 : break;
981 : }
982 :
983 : /* free up any caches */
984 0 : for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
985 0 : cairo_command_t *command = elements[i];
986 :
987 0 : _cairo_clip_drop_cache (&command->header.clip);
988 : }
989 :
990 0 : _cairo_surface_wrapper_fini (&wrapper);
991 :
992 0 : return _cairo_surface_set_error (surface, status);
993 : }
994 :
995 : /**
996 : * _cairo_recording_surface_replay:
997 : * @surface: the #cairo_recording_surface_t
998 : * @target: a target #cairo_surface_t onto which to replay the operations
999 : * @width_pixels: width of the surface, in pixels
1000 : * @height_pixels: height of the surface, in pixels
1001 : *
1002 : * A recording surface can be "replayed" against any target surface,
1003 : * after which the results in target will be identical to the results
1004 : * that would have been obtained if the original operations applied to
1005 : * the recording surface had instead been applied to the target surface.
1006 : **/
1007 : cairo_status_t
1008 0 : _cairo_recording_surface_replay (cairo_surface_t *surface,
1009 : cairo_surface_t *target)
1010 : {
1011 0 : return _cairo_recording_surface_replay_internal (surface, NULL,
1012 : target,
1013 : CAIRO_RECORDING_REPLAY,
1014 : CAIRO_RECORDING_REGION_ALL);
1015 : }
1016 :
1017 : /* Replay recording to surface. When the return status of each operation is
1018 : * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
1019 : * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
1020 : * will be stored in the recording surface. Any other status will abort the
1021 : * replay and return the status.
1022 : */
1023 : cairo_status_t
1024 0 : _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
1025 : cairo_surface_t *target)
1026 : {
1027 0 : return _cairo_recording_surface_replay_internal (surface, NULL,
1028 : target,
1029 : CAIRO_RECORDING_CREATE_REGIONS,
1030 : CAIRO_RECORDING_REGION_ALL);
1031 : }
1032 :
1033 : cairo_status_t
1034 0 : _cairo_recording_surface_replay_region (cairo_surface_t *surface,
1035 : const cairo_rectangle_int_t *surface_extents,
1036 : cairo_surface_t *target,
1037 : cairo_recording_region_type_t region)
1038 : {
1039 0 : return _cairo_recording_surface_replay_internal (surface, surface_extents,
1040 : target,
1041 : CAIRO_RECORDING_REPLAY,
1042 : region);
1043 : }
1044 :
1045 : static cairo_status_t
1046 0 : _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
1047 : cairo_box_t *bbox,
1048 : const cairo_matrix_t *transform)
1049 : {
1050 : cairo_surface_t *null_surface;
1051 : cairo_surface_t *analysis_surface;
1052 : cairo_status_t status;
1053 :
1054 0 : null_surface = cairo_null_surface_create (surface->content);
1055 0 : analysis_surface = _cairo_analysis_surface_create (null_surface);
1056 0 : cairo_surface_destroy (null_surface);
1057 :
1058 0 : status = analysis_surface->status;
1059 0 : if (unlikely (status))
1060 0 : return status;
1061 :
1062 0 : if (transform != NULL)
1063 0 : _cairo_analysis_surface_set_ctm (analysis_surface, transform);
1064 :
1065 0 : status = _cairo_recording_surface_replay (&surface->base, analysis_surface);
1066 0 : _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
1067 0 : cairo_surface_destroy (analysis_surface);
1068 :
1069 0 : return status;
1070 : }
1071 :
1072 : /**
1073 : * cairo_recording_surface_ink_extents:
1074 : * @surface: a #cairo_recording_surface_t
1075 : * @x0: the x-coordinate of the top-left of the ink bounding box
1076 : * @y0: the y-coordinate of the top-left of the ink bounding box
1077 : * @width: the width of the ink bounding box
1078 : * @height: the height of the ink bounding box
1079 : *
1080 : * Measures the extents of the operations stored within the recording-surface.
1081 : * This is useful to compute the required size of an image surface (or
1082 : * equivalent) into which to replay the full sequence of drawing operations.
1083 : *
1084 : * Since: 1.10
1085 : **/
1086 : void
1087 0 : cairo_recording_surface_ink_extents (cairo_surface_t *surface,
1088 : double *x0,
1089 : double *y0,
1090 : double *width,
1091 : double *height)
1092 : {
1093 : cairo_status_t status;
1094 : cairo_box_t bbox;
1095 :
1096 0 : memset (&bbox, 0, sizeof (bbox));
1097 :
1098 0 : if (! _cairo_surface_is_recording (surface)) {
1099 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1100 0 : goto DONE;
1101 : }
1102 :
1103 0 : status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface,
1104 : &bbox,
1105 : NULL);
1106 0 : if (unlikely (status))
1107 0 : status = _cairo_surface_set_error (surface, status);
1108 :
1109 : DONE:
1110 0 : if (x0)
1111 0 : *x0 = _cairo_fixed_to_double (bbox.p1.x);
1112 0 : if (y0)
1113 0 : *y0 = _cairo_fixed_to_double (bbox.p1.y);
1114 0 : if (width)
1115 0 : *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
1116 0 : if (height)
1117 0 : *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
1118 0 : }
1119 :
1120 : cairo_status_t
1121 0 : _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
1122 : cairo_box_t *bbox,
1123 : const cairo_matrix_t *transform)
1124 : {
1125 0 : if (! surface->unbounded) {
1126 0 : _cairo_box_from_rectangle (bbox, &surface->extents);
1127 0 : if (transform != NULL)
1128 0 : _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
1129 :
1130 0 : return CAIRO_STATUS_SUCCESS;
1131 : }
1132 :
1133 0 : return _recording_surface_get_ink_bbox (surface, bbox, transform);
1134 : }
|