/src/cairo/src/cairo-recording-surface.c
Line | Count | Source |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2005 Red Hat, Inc |
5 | | * Copyright © 2007 Adrian Johnson |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it either under the terms of the GNU Lesser General Public |
9 | | * License version 2.1 as published by the Free Software Foundation |
10 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
11 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
12 | | * notice, a recipient may use your version of this file under either |
13 | | * the MPL or the LGPL. |
14 | | * |
15 | | * You should have received a copy of the LGPL along with this library |
16 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
17 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
18 | | * You should have received a copy of the MPL along with this library |
19 | | * in the file COPYING-MPL-1.1 |
20 | | * |
21 | | * The contents of this file are subject to the Mozilla Public License |
22 | | * Version 1.1 (the "License"); you may not use this file except in |
23 | | * compliance with the License. You may obtain a copy of the License at |
24 | | * http://www.mozilla.org/MPL/ |
25 | | * |
26 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
27 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
28 | | * the specific language governing rights and limitations. |
29 | | * |
30 | | * The Original Code is the cairo graphics library. |
31 | | * |
32 | | * The Initial Developer of the Original Code is Red Hat, Inc. |
33 | | * |
34 | | * Contributor(s): |
35 | | * Kristian Høgsberg <krh@redhat.com> |
36 | | * Carl Worth <cworth@cworth.org> |
37 | | * Adrian Johnson <ajohnson@redneon.com> |
38 | | */ |
39 | | |
40 | | /** |
41 | | * SECTION:cairo-recording |
42 | | * @Title: Recording Surfaces |
43 | | * @Short_Description: Records all drawing operations |
44 | | * @See_Also: #cairo_surface_t |
45 | | * |
46 | | * A recording surface is a surface that records all drawing operations at |
47 | | * the highest level of the surface backend interface, (that is, the |
48 | | * level of paint, mask, stroke, fill, and show_text_glyphs). The recording |
49 | | * surface can then be "replayed" against any target surface by using it |
50 | | * as a source surface. |
51 | | * |
52 | | * If you want to replay a surface so that the results in target will be |
53 | | * identical to the results that would have been obtained if the original |
54 | | * operations applied to the recording surface had instead been applied to the |
55 | | * target surface, you can use code like this: |
56 | | * <informalexample><programlisting> |
57 | | * cairo_t *cr; |
58 | | * |
59 | | * cr = cairo_create (target); |
60 | | * cairo_set_source_surface (cr, recording_surface, 0.0, 0.0); |
61 | | * cairo_paint (cr); |
62 | | * cairo_destroy (cr); |
63 | | * </programlisting></informalexample> |
64 | | * |
65 | | * A recording surface is logically unbounded, i.e. it has no implicit constraint |
66 | | * on the size of the drawing surface. However, in practice this is rarely |
67 | | * useful as you wish to replay against a particular target surface with |
68 | | * known bounds. For this case, it is more efficient to specify the target |
69 | | * extents to the recording surface upon creation. |
70 | | * |
71 | | * The recording phase of the recording surface is careful to snapshot all |
72 | | * necessary objects (paths, patterns, etc.), in order to achieve |
73 | | * accurate replay. The efficiency of the recording surface could be |
74 | | * improved by improving the implementation of snapshot for the |
75 | | * various objects. For example, it would be nice to have a |
76 | | * copy-on-write implementation for _cairo_surface_snapshot. |
77 | | **/ |
78 | | |
79 | | #include "cairoint.h" |
80 | | |
81 | | #include "cairo-array-private.h" |
82 | | #include "cairo-analysis-surface-private.h" |
83 | | #include "cairo-clip-private.h" |
84 | | #include "cairo-combsort-inline.h" |
85 | | #include "cairo-composite-rectangles-private.h" |
86 | | #include "cairo-default-context-private.h" |
87 | | #include "cairo-error-private.h" |
88 | | #include "cairo-image-surface-private.h" |
89 | | #include "cairo-list-inline.h" |
90 | | #include "cairo-recording-surface-inline.h" |
91 | | #include "cairo-surface-snapshot-inline.h" |
92 | | #include "cairo-surface-wrapper-private.h" |
93 | | #include "cairo-traps-private.h" |
94 | | |
95 | | typedef struct _cairo_recording_surface_replay_params { |
96 | | const cairo_rectangle_int_t *surface_extents; |
97 | | const cairo_matrix_t *surface_transform; |
98 | | cairo_surface_t *target; |
99 | | const cairo_clip_t *target_clip; |
100 | | cairo_bool_t surface_is_unbounded; |
101 | | cairo_recording_replay_type_t type; |
102 | | cairo_recording_region_type_t region; |
103 | | unsigned int regions_id; |
104 | | const cairo_color_t *foreground_color; |
105 | | cairo_bool_t foreground_used; |
106 | | cairo_bool_t replay_all; |
107 | | } cairo_recording_surface_replay_params_t; |
108 | | |
109 | | static const cairo_surface_backend_t cairo_recording_surface_backend; |
110 | | |
111 | | /** |
112 | | * CAIRO_HAS_RECORDING_SURFACE: |
113 | | * |
114 | | * Defined if the recording surface backend is available. |
115 | | * The recording surface backend is always built in. |
116 | | * This macro was added for completeness in cairo 1.10. |
117 | | * |
118 | | * Since: 1.10 |
119 | | **/ |
120 | | |
121 | | /* Currently all recording surfaces do have a size which should be passed |
122 | | * in as the maximum size of any target surface against which the |
123 | | * recording-surface will ever be replayed. |
124 | | * |
125 | | * XXX: The naming of "pixels" in the size here is a misnomer. It's |
126 | | * actually a size in whatever device-space units are desired (again, |
127 | | * according to the intended replay target). |
128 | | */ |
129 | | |
130 | | static int bbtree_left_or_right (struct bbtree *bbt, |
131 | | const cairo_box_t *box) |
132 | 0 | { |
133 | 0 | int left, right; |
134 | |
|
135 | 0 | if (bbt->left) { |
136 | 0 | cairo_box_t *e = &bbt->left->extents; |
137 | 0 | cairo_box_t b; |
138 | |
|
139 | 0 | b.p1.x = MIN (e->p1.x, box->p1.x); |
140 | 0 | b.p1.y = MIN (e->p1.y, box->p1.y); |
141 | 0 | b.p2.x = MAX (e->p2.x, box->p2.x); |
142 | 0 | b.p2.y = MAX (e->p2.y, box->p2.y); |
143 | |
|
144 | 0 | left = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y); |
145 | 0 | left -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y); |
146 | 0 | } else |
147 | 0 | left = 0; |
148 | |
|
149 | 0 | if (bbt->right) { |
150 | 0 | cairo_box_t *e = &bbt->right->extents; |
151 | 0 | cairo_box_t b; |
152 | |
|
153 | 0 | b.p1.x = MIN (e->p1.x, box->p1.x); |
154 | 0 | b.p1.y = MIN (e->p1.y, box->p1.y); |
155 | 0 | b.p2.x = MAX (e->p2.x, box->p2.x); |
156 | 0 | b.p2.y = MAX (e->p2.y, box->p2.y); |
157 | |
|
158 | 0 | right = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y); |
159 | 0 | right -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y); |
160 | 0 | } else |
161 | 0 | right = 0; |
162 | |
|
163 | 0 | return left <= right; |
164 | 0 | } |
165 | | |
166 | 76.2k | #define INVALID_CHAIN ((cairo_command_header_t *)-1) |
167 | | |
168 | | static struct bbtree * |
169 | | bbtree_new (const cairo_box_t *box, cairo_command_header_t *chain) |
170 | 0 | { |
171 | 0 | struct bbtree *bbt = _cairo_calloc (sizeof (*bbt)); |
172 | 0 | if (bbt == NULL) |
173 | 0 | return NULL; |
174 | 0 | bbt->extents = *box; |
175 | 0 | bbt->left = bbt->right = NULL; |
176 | 0 | bbt->chain = chain; |
177 | 0 | return bbt; |
178 | 0 | } |
179 | | |
180 | | static void |
181 | | bbtree_init (struct bbtree *bbt, cairo_command_header_t *header) |
182 | 454 | { |
183 | 454 | _cairo_box_from_rectangle (&bbt->extents, &header->extents); |
184 | 454 | bbt->chain = header; |
185 | 454 | } |
186 | | |
187 | | static cairo_status_t |
188 | | bbtree_add (struct bbtree *bbt, |
189 | | cairo_command_header_t *header, |
190 | | const cairo_box_t *box) |
191 | 0 | { |
192 | 0 | if (box->p1.x < bbt->extents.p1.x || box->p1.y < bbt->extents.p1.y || |
193 | 0 | box->p2.x > bbt->extents.p2.x || box->p2.y > bbt->extents.p2.y) |
194 | 0 | { |
195 | 0 | if (bbt->chain) { |
196 | 0 | if (bbtree_left_or_right (bbt, &bbt->extents)) { |
197 | 0 | if (bbt->left == NULL) { |
198 | 0 | bbt->left = bbtree_new (&bbt->extents, bbt->chain); |
199 | 0 | if (unlikely (bbt->left == NULL)) |
200 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
201 | 0 | } else |
202 | 0 | bbtree_add (bbt->left, bbt->chain, &bbt->extents); |
203 | 0 | } else { |
204 | 0 | if (bbt->right == NULL) { |
205 | 0 | bbt->right = bbtree_new (&bbt->extents, bbt->chain); |
206 | 0 | if (unlikely (bbt->right == NULL)) |
207 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
208 | 0 | } else |
209 | 0 | bbtree_add (bbt->right, bbt->chain, &bbt->extents); |
210 | 0 | } |
211 | | |
212 | 0 | bbt->chain = NULL; |
213 | 0 | } |
214 | | |
215 | 0 | bbt->extents.p1.x = MIN (bbt->extents.p1.x, box->p1.x); |
216 | 0 | bbt->extents.p1.y = MIN (bbt->extents.p1.y, box->p1.y); |
217 | 0 | bbt->extents.p2.x = MAX (bbt->extents.p2.x, box->p2.x); |
218 | 0 | bbt->extents.p2.y = MAX (bbt->extents.p2.y, box->p2.y); |
219 | 0 | } |
220 | | |
221 | 0 | if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y && |
222 | 0 | box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y) |
223 | 0 | { |
224 | 0 | cairo_command_header_t *last = header; |
225 | 0 | while (last->chain) /* expected to be infrequent */ |
226 | 0 | last = last->chain; |
227 | 0 | last->chain = bbt->chain; |
228 | 0 | bbt->chain = header; |
229 | 0 | return CAIRO_STATUS_SUCCESS; |
230 | 0 | } |
231 | | |
232 | 0 | if (bbtree_left_or_right (bbt, box)) { |
233 | 0 | if (bbt->left == NULL) { |
234 | 0 | bbt->left = bbtree_new (box, header); |
235 | 0 | if (unlikely (bbt->left == NULL)) |
236 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
237 | 0 | } else |
238 | 0 | return bbtree_add (bbt->left, header, box); |
239 | 0 | } else { |
240 | 0 | if (bbt->right == NULL) { |
241 | 0 | bbt->right = bbtree_new (box, header); |
242 | 0 | if (unlikely (bbt->right == NULL)) |
243 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
244 | 0 | } else |
245 | 0 | return bbtree_add (bbt->right, header, box); |
246 | 0 | } |
247 | | |
248 | 0 | return CAIRO_STATUS_SUCCESS; |
249 | 0 | } |
250 | | |
251 | | static void bbtree_del (struct bbtree *bbt) |
252 | 0 | { |
253 | 0 | if (bbt->left) |
254 | 0 | bbtree_del (bbt->left); |
255 | 0 | if (bbt->right) |
256 | 0 | bbtree_del (bbt->right); |
257 | |
|
258 | 0 | free (bbt); |
259 | 0 | } |
260 | | |
261 | | static cairo_bool_t box_outside (const cairo_box_t *a, const cairo_box_t *b) |
262 | 0 | { |
263 | 0 | return |
264 | 0 | a->p1.x >= b->p2.x || a->p1.y >= b->p2.y || |
265 | 0 | a->p2.x <= b->p1.x || a->p2.y <= b->p1.y; |
266 | 0 | } |
267 | | |
268 | | static void |
269 | | bbtree_foreach_mark_visible (struct bbtree *bbt, |
270 | | const cairo_box_t *box, |
271 | | unsigned int **indices) |
272 | 454 | { |
273 | 454 | cairo_command_header_t *chain; |
274 | | |
275 | 908 | for (chain = bbt->chain; chain; chain = chain->chain) |
276 | 454 | *(*indices)++ = chain->index; |
277 | | |
278 | 454 | if (bbt->left && ! box_outside (box, &bbt->left->extents)) |
279 | 0 | bbtree_foreach_mark_visible (bbt->left, box, indices); |
280 | 454 | if (bbt->right && ! box_outside (box, &bbt->right->extents)) |
281 | 0 | bbtree_foreach_mark_visible (bbt->right, box, indices); |
282 | 454 | } |
283 | | |
284 | | static inline int intcmp (const unsigned int a, const unsigned int b) |
285 | 0 | { |
286 | 0 | return a - b; |
287 | 0 | } |
288 | | CAIRO_COMBSORT_DECLARE (sort_indices, unsigned int, intcmp) |
289 | | |
290 | | static inline int sizecmp (unsigned int a, unsigned int b, cairo_command_header_t **elements) |
291 | 0 | { |
292 | 0 | const cairo_rectangle_int_t *r; |
293 | |
|
294 | 0 | r = &elements[a]->extents; |
295 | 0 | a = r->width * r->height; |
296 | |
|
297 | 0 | r = &elements[b]->extents; |
298 | 0 | b = r->width * r->height; |
299 | |
|
300 | 0 | return b - a; |
301 | 0 | } |
302 | | CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, unsigned int, sizecmp) |
303 | | |
304 | | static void |
305 | | _cairo_recording_surface_destroy_bbtree (cairo_recording_surface_t *surface) |
306 | 60.5k | { |
307 | 60.5k | cairo_command_t **elements; |
308 | 60.5k | int i, num_elements; |
309 | | |
310 | 60.5k | if (surface->bbtree.chain == INVALID_CHAIN) |
311 | 60.5k | return; |
312 | | |
313 | 0 | if (surface->bbtree.left) { |
314 | 0 | bbtree_del (surface->bbtree.left); |
315 | 0 | surface->bbtree.left = NULL; |
316 | 0 | } |
317 | 0 | if (surface->bbtree.right) { |
318 | 0 | bbtree_del (surface->bbtree.right); |
319 | 0 | surface->bbtree.right = NULL; |
320 | 0 | } |
321 | |
|
322 | 0 | elements = _cairo_array_index (&surface->commands, 0); |
323 | 0 | num_elements = surface->commands.num_elements; |
324 | 0 | for (i = 0; i < num_elements; i++) |
325 | 0 | elements[i]->header.chain = NULL; |
326 | |
|
327 | 0 | surface->bbtree.chain = INVALID_CHAIN; |
328 | 0 | } |
329 | | |
330 | | static cairo_status_t |
331 | | _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface) |
332 | 454 | { |
333 | 454 | cairo_command_t **elements = _cairo_array_index (&surface->commands, 0); |
334 | 454 | unsigned int *indices; |
335 | 454 | cairo_status_t status; |
336 | 454 | unsigned int i, count; |
337 | | |
338 | 454 | count = surface->commands.num_elements; |
339 | 454 | if (count > surface->num_indices) { |
340 | 454 | free (surface->indices); |
341 | 454 | surface->indices = _cairo_malloc_ab (count, sizeof (int)); |
342 | 454 | if (unlikely (surface->indices == NULL)) |
343 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
344 | | |
345 | 454 | surface->num_indices = count; |
346 | 454 | } |
347 | | |
348 | 454 | indices = surface->indices; |
349 | 908 | for (i = 0; i < count; i++) |
350 | 454 | indices[i] = i; |
351 | | |
352 | 454 | sort_commands (indices, count, elements); |
353 | | |
354 | 454 | bbtree_init (&surface->bbtree, &elements[indices[0]]->header); |
355 | 454 | for (i = 1; i < count; i++) { |
356 | 0 | cairo_command_header_t *header = &elements[indices[i]]->header; |
357 | 0 | cairo_box_t box; |
358 | |
|
359 | 0 | _cairo_box_from_rectangle (&box, &header->extents); |
360 | 0 | status = bbtree_add (&surface->bbtree, header, &box); |
361 | 0 | if (unlikely (status)) |
362 | 0 | goto cleanup; |
363 | 0 | } |
364 | | |
365 | 454 | return CAIRO_STATUS_SUCCESS; |
366 | | |
367 | 0 | cleanup: |
368 | 0 | if (surface->bbtree.left) |
369 | 0 | bbtree_del (surface->bbtree.left); |
370 | 0 | if (surface->bbtree.right) |
371 | 0 | bbtree_del (surface->bbtree.right); |
372 | 0 | return status; |
373 | 454 | } |
374 | | |
375 | | /** |
376 | | * cairo_recording_surface_create: |
377 | | * @content: the content of the recording surface |
378 | | * @extents: the extents to record in pixels, can be %NULL to record |
379 | | * unbounded operations. |
380 | | * |
381 | | * Creates a recording-surface which can be used to record all drawing operations |
382 | | * at the highest level (that is, the level of paint, mask, stroke, fill |
383 | | * and show_text_glyphs). The recording surface can then be "replayed" against |
384 | | * any target surface by using it as a source to drawing operations. |
385 | | * |
386 | | * The recording phase of the recording surface is careful to snapshot all |
387 | | * necessary objects (paths, patterns, etc.), in order to achieve |
388 | | * accurate replay. |
389 | | * |
390 | | * Return value: a pointer to the newly created surface. The caller |
391 | | * owns the surface and should call cairo_surface_destroy() when done |
392 | | * with it. |
393 | | * |
394 | | * Since: 1.10 |
395 | | **/ |
396 | | cairo_surface_t * |
397 | | cairo_recording_surface_create (cairo_content_t content, |
398 | | const cairo_rectangle_t *extents) |
399 | 6.60k | { |
400 | 6.60k | cairo_recording_surface_t *surface; |
401 | | |
402 | 6.60k | surface = _cairo_calloc (sizeof (cairo_recording_surface_t)); |
403 | 6.60k | if (unlikely (surface == NULL)) |
404 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
405 | | |
406 | 6.60k | _cairo_surface_init (&surface->base, |
407 | 6.60k | &cairo_recording_surface_backend, |
408 | 6.60k | NULL, /* device */ |
409 | 6.60k | content, |
410 | 6.60k | TRUE); /* is_vector */ |
411 | | |
412 | | |
413 | 6.60k | surface->unbounded = TRUE; |
414 | | |
415 | | /* unbounded -> 'infinite' extents */ |
416 | 6.60k | if (extents != NULL) { |
417 | 5.13k | surface->extents_pixels = *extents; |
418 | | |
419 | | /* XXX check for overflow */ |
420 | 5.13k | surface->extents.x = floor (extents->x); |
421 | 5.13k | surface->extents.y = floor (extents->y); |
422 | 5.13k | surface->extents.width = ceil (extents->x + extents->width) - surface->extents.x; |
423 | 5.13k | surface->extents.height = ceil (extents->y + extents->height) - surface->extents.y; |
424 | | |
425 | 5.13k | surface->unbounded = FALSE; |
426 | 5.13k | } |
427 | | |
428 | 6.60k | _cairo_array_init (&surface->commands, sizeof (cairo_command_t *)); |
429 | | |
430 | 6.60k | surface->base.is_clear = TRUE; |
431 | | |
432 | 6.60k | surface->bbtree.left = surface->bbtree.right = NULL; |
433 | 6.60k | surface->bbtree.chain = INVALID_CHAIN; |
434 | | |
435 | 6.60k | surface->indices = NULL; |
436 | 6.60k | surface->num_indices = 0; |
437 | 6.60k | surface->optimize_clears = TRUE; |
438 | 6.60k | surface->has_bilevel_alpha = FALSE; |
439 | 6.60k | surface->has_only_op_over = FALSE; |
440 | 6.60k | surface->has_tags = FALSE; |
441 | | |
442 | 6.60k | CAIRO_MUTEX_INIT (surface->mutex); |
443 | | |
444 | 6.60k | cairo_list_init (&surface->region_array_list); |
445 | | |
446 | 6.60k | return &surface->base; |
447 | 6.60k | } |
448 | | |
449 | | static cairo_surface_t * |
450 | | _cairo_recording_surface_create_similar (void *abstract_surface, |
451 | | cairo_content_t content, |
452 | | int width, |
453 | | int height) |
454 | 73 | { |
455 | 73 | cairo_rectangle_t extents; |
456 | 73 | extents.x = extents.y = 0; |
457 | 73 | extents.width = width; |
458 | 73 | extents.height = height; |
459 | 73 | return cairo_recording_surface_create (content, &extents); |
460 | 73 | } |
461 | | |
462 | | static void |
463 | | destroy_pattern_region_array (const cairo_pattern_t *pattern, |
464 | | unsigned int region_id) |
465 | 797k | { |
466 | 797k | if (region_id != 0) { |
467 | 1.57k | if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { |
468 | 1.04k | cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; |
469 | 1.04k | if (_cairo_surface_is_recording (surface_pattern->surface)) |
470 | 0 | _cairo_recording_surface_region_array_remove (surface_pattern->surface, region_id); |
471 | 1.04k | } |
472 | 1.57k | } |
473 | 797k | } |
474 | | |
475 | | static void |
476 | | _cairo_recording_surface_region_array_destroy (cairo_recording_surface_t *surface, |
477 | | cairo_recording_regions_array_t *region_array) |
478 | 2.66k | { |
479 | 2.66k | cairo_command_t **elements; |
480 | 2.66k | cairo_recording_region_element_t *region_elements; |
481 | 2.66k | int i, num_elements; |
482 | | |
483 | 2.66k | num_elements = MIN(surface->commands.num_elements, _cairo_array_num_elements(®ion_array->regions)); |
484 | 2.66k | elements = _cairo_array_index (&surface->commands, 0); |
485 | 2.66k | region_elements = _cairo_array_index (®ion_array->regions, 0); |
486 | 798k | for (i = 0; i < num_elements; i++) { |
487 | 795k | cairo_command_t *command = elements[i]; |
488 | 795k | cairo_recording_region_element_t *region_element = ®ion_elements[i]; |
489 | | |
490 | 795k | switch (command->header.type) { |
491 | 1.82k | case CAIRO_COMMAND_PAINT: |
492 | 1.82k | destroy_pattern_region_array (&command->paint.source.base, region_element->source_id); |
493 | 1.82k | break; |
494 | | |
495 | 1.73k | case CAIRO_COMMAND_MASK: |
496 | 1.73k | destroy_pattern_region_array (&command->mask.source.base, region_element->source_id); |
497 | 1.73k | destroy_pattern_region_array (&command->mask.mask.base, region_element->mask_id); |
498 | 1.73k | break; |
499 | | |
500 | 35.9k | case CAIRO_COMMAND_STROKE: |
501 | 35.9k | destroy_pattern_region_array (&command->stroke.source.base, region_element->source_id); |
502 | 35.9k | break; |
503 | | |
504 | 19.0k | case CAIRO_COMMAND_FILL: |
505 | 19.0k | destroy_pattern_region_array (&command->fill.source.base, region_element->source_id); |
506 | 19.0k | break; |
507 | | |
508 | 736k | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
509 | 736k | destroy_pattern_region_array (&command->show_text_glyphs.source.base, region_element->source_id); |
510 | 736k | break; |
511 | | |
512 | 0 | case CAIRO_COMMAND_TAG: |
513 | 0 | break; |
514 | | |
515 | 0 | default: |
516 | 0 | ASSERT_NOT_REACHED; |
517 | 795k | } |
518 | 795k | } |
519 | | |
520 | 2.66k | _cairo_array_fini (®ion_array->regions); |
521 | 2.66k | free (region_array); |
522 | 2.66k | } |
523 | | |
524 | | static void |
525 | | _cairo_recording_surface_reset (cairo_recording_surface_t *surface) |
526 | 7.64k | { |
527 | 7.64k | cairo_command_t **elements; |
528 | 7.64k | int i, num_elements; |
529 | 7.64k | cairo_recording_regions_array_t *region_array, *region_next; |
530 | | |
531 | | /* Normally backend surfaces hold a reference to the surface as |
532 | | * well as the region and free the region before the surface. So |
533 | | * the regions should already be freed at this point but just in |
534 | | * case we ensure the regions are freed before destroying the |
535 | | * surface. */ |
536 | 7.64k | cairo_list_foreach_entry_safe (region_array, region_next, |
537 | 7.64k | cairo_recording_regions_array_t, |
538 | 7.64k | &surface->region_array_list, link) |
539 | 1.04k | { |
540 | 1.04k | cairo_list_del (®ion_array->link); |
541 | 1.04k | _cairo_recording_surface_region_array_destroy (surface, region_array); |
542 | 1.04k | } |
543 | | |
544 | 7.64k | num_elements = surface->commands.num_elements; |
545 | 7.64k | elements = _cairo_array_index (&surface->commands, 0); |
546 | 807k | for (i = 0; i < num_elements; i++) { |
547 | 799k | cairo_command_t *command = elements[i]; |
548 | | |
549 | 799k | switch (command->header.type) { |
550 | 1.88k | case CAIRO_COMMAND_PAINT: |
551 | 1.88k | _cairo_pattern_fini (&command->paint.source.base); |
552 | 1.88k | break; |
553 | | |
554 | 3.50k | case CAIRO_COMMAND_MASK: |
555 | 3.50k | _cairo_pattern_fini (&command->mask.source.base); |
556 | 3.50k | _cairo_pattern_fini (&command->mask.mask.base); |
557 | 3.50k | break; |
558 | | |
559 | 36.6k | case CAIRO_COMMAND_STROKE: |
560 | 36.6k | _cairo_pattern_fini (&command->stroke.source.base); |
561 | 36.6k | _cairo_path_fixed_fini (&command->stroke.path); |
562 | 36.6k | _cairo_stroke_style_fini (&command->stroke.style); |
563 | 36.6k | break; |
564 | | |
565 | 20.6k | case CAIRO_COMMAND_FILL: |
566 | 20.6k | _cairo_pattern_fini (&command->fill.source.base); |
567 | 20.6k | _cairo_path_fixed_fini (&command->fill.path); |
568 | 20.6k | break; |
569 | | |
570 | 737k | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
571 | 737k | _cairo_pattern_fini (&command->show_text_glyphs.source.base); |
572 | 737k | free (command->show_text_glyphs.utf8); |
573 | 737k | free (command->show_text_glyphs.glyphs); |
574 | 737k | free (command->show_text_glyphs.clusters); |
575 | 737k | cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font); |
576 | 737k | break; |
577 | | |
578 | 0 | case CAIRO_COMMAND_TAG: |
579 | 0 | free (command->tag.tag_name); |
580 | 0 | if (command->tag.begin) { |
581 | 0 | free (command->tag.attributes); |
582 | 0 | } |
583 | 0 | break; |
584 | | |
585 | 0 | default: |
586 | 0 | ASSERT_NOT_REACHED; |
587 | 799k | } |
588 | | |
589 | 799k | _cairo_clip_destroy (command->header.clip); |
590 | 799k | free (command); |
591 | 799k | } |
592 | | |
593 | 7.64k | _cairo_array_fini (&surface->commands); |
594 | 7.64k | _cairo_array_init (&surface->commands, sizeof (cairo_command_t *)); |
595 | | |
596 | 7.64k | if (surface->bbtree.left) |
597 | 0 | bbtree_del (surface->bbtree.left); |
598 | 7.64k | if (surface->bbtree.right) |
599 | 0 | bbtree_del (surface->bbtree.right); |
600 | 7.64k | surface->bbtree.left = surface->bbtree.right = NULL; |
601 | 7.64k | surface->bbtree.chain = INVALID_CHAIN; |
602 | | |
603 | 7.64k | free (surface->indices); |
604 | 7.64k | surface->indices = NULL; |
605 | 7.64k | surface->num_indices = 0; |
606 | 7.64k | } |
607 | | |
608 | | static cairo_status_t |
609 | | _cairo_recording_surface_finish (void *abstract_surface) |
610 | 7.64k | { |
611 | 7.64k | cairo_recording_surface_t *surface = abstract_surface; |
612 | | |
613 | 7.64k | _cairo_recording_surface_reset (surface); |
614 | 7.64k | CAIRO_MUTEX_FINI (surface->mutex); |
615 | | |
616 | 7.64k | return CAIRO_STATUS_SUCCESS; |
617 | 7.64k | } |
618 | | |
619 | | struct proxy { |
620 | | cairo_surface_t base; |
621 | | cairo_surface_t *image; |
622 | | }; |
623 | | |
624 | | static cairo_status_t |
625 | | proxy_acquire_source_image (void *abstract_surface, |
626 | | cairo_image_surface_t **image_out, |
627 | | void **image_extra) |
628 | 0 | { |
629 | 0 | struct proxy *proxy = abstract_surface; |
630 | 0 | return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra); |
631 | 0 | } |
632 | | |
633 | | static void |
634 | | proxy_release_source_image (void *abstract_surface, |
635 | | cairo_image_surface_t *image, |
636 | | void *image_extra) |
637 | 0 | { |
638 | 0 | struct proxy *proxy = abstract_surface; |
639 | 0 | _cairo_surface_release_source_image (proxy->image, image, image_extra); |
640 | 0 | } |
641 | | |
642 | | static cairo_status_t |
643 | | proxy_finish (void *abstract_surface) |
644 | 0 | { |
645 | 0 | return CAIRO_STATUS_SUCCESS; |
646 | 0 | } |
647 | | |
648 | | static const cairo_surface_backend_t proxy_backend = { |
649 | | CAIRO_INTERNAL_SURFACE_TYPE_NULL, |
650 | | proxy_finish, |
651 | | NULL, |
652 | | |
653 | | NULL, /* create similar */ |
654 | | NULL, /* create similar image */ |
655 | | NULL, /* map to image */ |
656 | | NULL, /* unmap image */ |
657 | | |
658 | | _cairo_surface_default_source, |
659 | | proxy_acquire_source_image, |
660 | | proxy_release_source_image, |
661 | | }; |
662 | | |
663 | | static cairo_surface_t * |
664 | | attach_proxy (cairo_surface_t *source, |
665 | | cairo_surface_t *image) |
666 | 0 | { |
667 | 0 | struct proxy *proxy; |
668 | |
|
669 | 0 | proxy = _cairo_calloc (sizeof (*proxy)); |
670 | 0 | if (unlikely (proxy == NULL)) |
671 | 0 | return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); |
672 | | |
673 | 0 | _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content, FALSE); |
674 | |
|
675 | 0 | proxy->image = image; |
676 | 0 | _cairo_surface_attach_snapshot (source, &proxy->base, NULL); |
677 | |
|
678 | 0 | return &proxy->base; |
679 | 0 | } |
680 | | |
681 | | static void |
682 | | detach_proxy (cairo_surface_t *source, |
683 | | cairo_surface_t *proxy) |
684 | 0 | { |
685 | 0 | cairo_surface_finish (proxy); |
686 | 0 | cairo_surface_destroy (proxy); |
687 | 0 | } |
688 | | |
689 | | static cairo_surface_t * |
690 | | get_proxy (cairo_surface_t *proxy) |
691 | 0 | { |
692 | 0 | return ((struct proxy *)proxy)->image; |
693 | 0 | } |
694 | | |
695 | | static cairo_status_t |
696 | | _cairo_recording_surface_acquire_source_image (void *abstract_surface, |
697 | | cairo_image_surface_t **image_out, |
698 | | void **image_extra) |
699 | 0 | { |
700 | 0 | cairo_recording_surface_t *surface = abstract_surface; |
701 | 0 | cairo_surface_t *image, *proxy; |
702 | 0 | cairo_status_t status; |
703 | |
|
704 | 0 | proxy = _cairo_surface_has_snapshot (abstract_surface, &proxy_backend); |
705 | 0 | if (proxy != NULL) { |
706 | 0 | *image_out = (cairo_image_surface_t *) |
707 | 0 | cairo_surface_reference (get_proxy (proxy)); |
708 | 0 | *image_extra = NULL; |
709 | 0 | return CAIRO_STATUS_SUCCESS; |
710 | 0 | } |
711 | | |
712 | 0 | if (surface->unbounded) |
713 | 0 | return CAIRO_INT_STATUS_UNSUPPORTED; |
714 | 0 | image = _cairo_image_surface_create_with_content (surface->base.content, |
715 | 0 | surface->extents.width, |
716 | 0 | surface->extents.height); |
717 | 0 | cairo_surface_set_device_offset (image, -surface->extents.x, -surface->extents.y); |
718 | 0 | if (unlikely (image->status)) |
719 | 0 | return image->status; |
720 | | |
721 | 0 | cairo_surface_set_device_offset(image, -surface->extents.x, -surface->extents.y); |
722 | | |
723 | | /* Handle recursion by returning future reads from the current image */ |
724 | 0 | proxy = attach_proxy (abstract_surface, image); |
725 | 0 | status = _cairo_recording_surface_replay (&surface->base, image); |
726 | 0 | detach_proxy (abstract_surface, proxy); |
727 | |
|
728 | 0 | if (unlikely (status)) { |
729 | 0 | cairo_surface_destroy (image); |
730 | 0 | return status; |
731 | 0 | } |
732 | | |
733 | 0 | *image_out = (cairo_image_surface_t *) image; |
734 | 0 | *image_extra = NULL; |
735 | 0 | return CAIRO_STATUS_SUCCESS; |
736 | 0 | } |
737 | | |
738 | | static void |
739 | | _cairo_recording_surface_release_source_image (void *abstract_surface, |
740 | | cairo_image_surface_t *image, |
741 | | void *image_extra) |
742 | 0 | { |
743 | 0 | cairo_surface_destroy (&image->base); |
744 | 0 | } |
745 | | |
746 | | static cairo_status_t |
747 | | _command_init (cairo_recording_surface_t *surface, |
748 | | cairo_command_header_t *command, |
749 | | cairo_command_type_t type, |
750 | | cairo_operator_t op, |
751 | | cairo_composite_rectangles_t *composite) |
752 | 797k | { |
753 | 797k | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
754 | | |
755 | 797k | command->type = type; |
756 | 797k | command->op = op; |
757 | | |
758 | 797k | command->extents = composite ? composite->unbounded : _cairo_empty_rectangle; |
759 | 797k | command->chain = NULL; |
760 | 797k | command->index = surface->commands.num_elements; |
761 | | |
762 | | /* steal the clip */ |
763 | 797k | command->clip = NULL; |
764 | 797k | if (composite && ! _cairo_composite_rectangles_can_reduce_clip (composite, |
765 | 797k | composite->clip)) |
766 | 7.53k | { |
767 | 7.53k | command->clip = composite->clip; |
768 | 7.53k | composite->clip = NULL; |
769 | 7.53k | } |
770 | | |
771 | 797k | return status; |
772 | 797k | } |
773 | | |
774 | | static void |
775 | | _cairo_recording_surface_break_self_copy_loop (cairo_recording_surface_t *surface) |
776 | 799k | { |
777 | 799k | cairo_surface_flush (&surface->base); |
778 | 799k | } |
779 | | |
780 | | static cairo_status_t |
781 | | _cairo_recording_surface_commit (cairo_recording_surface_t *surface, |
782 | | cairo_command_header_t *command) |
783 | 799k | { |
784 | 799k | _cairo_recording_surface_break_self_copy_loop (surface); |
785 | 799k | return _cairo_array_append (&surface->commands, &command); |
786 | 799k | } |
787 | | |
788 | | static cairo_int_status_t |
789 | | _cairo_recording_surface_paint (void *abstract_surface, |
790 | | cairo_operator_t op, |
791 | | const cairo_pattern_t *source, |
792 | | const cairo_clip_t *clip) |
793 | 1.87k | { |
794 | 1.87k | cairo_status_t status; |
795 | 1.87k | cairo_recording_surface_t *surface = abstract_surface; |
796 | 1.87k | cairo_command_paint_t *command; |
797 | 1.87k | cairo_composite_rectangles_t composite; |
798 | | |
799 | 1.87k | TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); |
800 | | |
801 | 1.87k | if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) { |
802 | 0 | if (surface->optimize_clears) { |
803 | 0 | _cairo_recording_surface_reset (surface); |
804 | 0 | return CAIRO_STATUS_SUCCESS; |
805 | 0 | } |
806 | 0 | } |
807 | | |
808 | 1.87k | if (clip == NULL && surface->optimize_clears && |
809 | 0 | (op == CAIRO_OPERATOR_SOURCE || |
810 | 0 | (op == CAIRO_OPERATOR_OVER && |
811 | 0 | (surface->base.is_clear || _cairo_pattern_is_opaque_solid (source))))) |
812 | 0 | { |
813 | 0 | _cairo_recording_surface_reset (surface); |
814 | 0 | } |
815 | | |
816 | 1.87k | status = _cairo_composite_rectangles_init_for_paint (&composite, |
817 | 1.87k | &surface->base, |
818 | 1.87k | op, source, |
819 | 1.87k | clip); |
820 | 1.87k | if (unlikely (status)) |
821 | 7 | return status; |
822 | | |
823 | 1.86k | command = _cairo_calloc (sizeof (cairo_command_paint_t)); |
824 | 1.86k | if (unlikely (command == NULL)) { |
825 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
826 | 0 | goto CLEANUP_COMPOSITE; |
827 | 0 | } |
828 | | |
829 | 1.86k | status = _command_init (surface, |
830 | 1.86k | &command->header, CAIRO_COMMAND_PAINT, op, |
831 | 1.86k | &composite); |
832 | 1.86k | if (unlikely (status)) |
833 | 0 | goto CLEANUP_COMMAND; |
834 | | |
835 | 1.86k | status = _cairo_pattern_init_snapshot (&command->source.base, source); |
836 | 1.86k | if (unlikely (status)) |
837 | 0 | goto CLEANUP_COMMAND; |
838 | | |
839 | 1.86k | status = _cairo_recording_surface_commit (surface, &command->header); |
840 | 1.86k | if (unlikely (status)) |
841 | 0 | goto CLEANUP_SOURCE; |
842 | | |
843 | 1.86k | _cairo_recording_surface_destroy_bbtree (surface); |
844 | | |
845 | 1.86k | _cairo_composite_rectangles_fini (&composite); |
846 | 1.86k | return CAIRO_STATUS_SUCCESS; |
847 | | |
848 | 0 | CLEANUP_SOURCE: |
849 | 0 | _cairo_pattern_fini (&command->source.base); |
850 | 0 | CLEANUP_COMMAND: |
851 | 0 | _cairo_clip_destroy (command->header.clip); |
852 | 0 | free (command); |
853 | 0 | CLEANUP_COMPOSITE: |
854 | 0 | _cairo_composite_rectangles_fini (&composite); |
855 | 0 | return status; |
856 | 0 | } |
857 | | |
858 | | static cairo_int_status_t |
859 | | _cairo_recording_surface_mask (void *abstract_surface, |
860 | | cairo_operator_t op, |
861 | | const cairo_pattern_t *source, |
862 | | const cairo_pattern_t *mask, |
863 | | const cairo_clip_t *clip) |
864 | 3.09k | { |
865 | 3.09k | cairo_status_t status; |
866 | 3.09k | cairo_recording_surface_t *surface = abstract_surface; |
867 | 3.09k | cairo_command_mask_t *command; |
868 | 3.09k | cairo_composite_rectangles_t composite; |
869 | | |
870 | 3.09k | TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); |
871 | | |
872 | 3.09k | status = _cairo_composite_rectangles_init_for_mask (&composite, |
873 | 3.09k | &surface->base, |
874 | 3.09k | op, source, mask, |
875 | 3.09k | clip); |
876 | 3.09k | if (unlikely (status)) |
877 | 0 | return status; |
878 | | |
879 | 3.09k | command = _cairo_calloc (sizeof (cairo_command_mask_t)); |
880 | 3.09k | if (unlikely (command == NULL)) { |
881 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
882 | 0 | goto CLEANUP_COMPOSITE; |
883 | 0 | } |
884 | | |
885 | 3.09k | status = _command_init (surface, |
886 | 3.09k | &command->header, CAIRO_COMMAND_MASK, op, |
887 | 3.09k | &composite); |
888 | 3.09k | if (unlikely (status)) |
889 | 0 | goto CLEANUP_COMMAND; |
890 | | |
891 | 3.09k | status = _cairo_pattern_init_snapshot (&command->source.base, source); |
892 | 3.09k | if (unlikely (status)) |
893 | 0 | goto CLEANUP_COMMAND; |
894 | | |
895 | 3.09k | status = _cairo_pattern_init_snapshot (&command->mask.base, mask); |
896 | 3.09k | if (unlikely (status)) |
897 | 0 | goto CLEANUP_SOURCE; |
898 | | |
899 | 3.09k | status = _cairo_recording_surface_commit (surface, &command->header); |
900 | 3.09k | if (unlikely (status)) |
901 | 0 | goto CLEANUP_MASK; |
902 | | |
903 | 3.09k | _cairo_recording_surface_destroy_bbtree (surface); |
904 | | |
905 | 3.09k | _cairo_composite_rectangles_fini (&composite); |
906 | 3.09k | return CAIRO_STATUS_SUCCESS; |
907 | | |
908 | 0 | CLEANUP_MASK: |
909 | 0 | _cairo_pattern_fini (&command->mask.base); |
910 | 0 | CLEANUP_SOURCE: |
911 | 0 | _cairo_pattern_fini (&command->source.base); |
912 | 0 | CLEANUP_COMMAND: |
913 | 0 | _cairo_clip_destroy (command->header.clip); |
914 | 0 | free (command); |
915 | 0 | CLEANUP_COMPOSITE: |
916 | 0 | _cairo_composite_rectangles_fini (&composite); |
917 | 0 | return status; |
918 | 0 | } |
919 | | |
920 | | static cairo_int_status_t |
921 | | _cairo_recording_surface_stroke (void *abstract_surface, |
922 | | cairo_operator_t op, |
923 | | const cairo_pattern_t *source, |
924 | | const cairo_path_fixed_t *path, |
925 | | const cairo_stroke_style_t *style, |
926 | | const cairo_matrix_t *ctm, |
927 | | const cairo_matrix_t *ctm_inverse, |
928 | | double tolerance, |
929 | | cairo_antialias_t antialias, |
930 | | const cairo_clip_t *clip) |
931 | 36.9k | { |
932 | 36.9k | cairo_status_t status; |
933 | 36.9k | cairo_recording_surface_t *surface = abstract_surface; |
934 | 36.9k | cairo_command_stroke_t *command; |
935 | 36.9k | cairo_composite_rectangles_t composite; |
936 | | |
937 | 36.9k | TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); |
938 | | |
939 | 36.9k | status = _cairo_composite_rectangles_init_for_stroke (&composite, |
940 | 36.9k | &surface->base, |
941 | 36.9k | op, source, |
942 | 36.9k | path, style, ctm, |
943 | 36.9k | clip); |
944 | 36.9k | if (unlikely (status)) |
945 | 993 | return status; |
946 | | |
947 | 35.9k | command = _cairo_calloc (sizeof (cairo_command_stroke_t)); |
948 | 35.9k | if (unlikely (command == NULL)) { |
949 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
950 | 0 | goto CLEANUP_COMPOSITE; |
951 | 0 | } |
952 | | |
953 | 35.9k | status = _command_init (surface, |
954 | 35.9k | &command->header, CAIRO_COMMAND_STROKE, op, |
955 | 35.9k | &composite); |
956 | 35.9k | if (unlikely (status)) |
957 | 0 | goto CLEANUP_COMMAND; |
958 | | |
959 | 35.9k | status = _cairo_pattern_init_snapshot (&command->source.base, source); |
960 | 35.9k | if (unlikely (status)) |
961 | 0 | goto CLEANUP_COMMAND; |
962 | | |
963 | 35.9k | status = _cairo_path_fixed_init_copy (&command->path, path); |
964 | 35.9k | if (unlikely (status)) |
965 | 0 | goto CLEANUP_SOURCE; |
966 | | |
967 | 35.9k | status = _cairo_stroke_style_init_copy (&command->style, style); |
968 | 35.9k | if (unlikely (status)) |
969 | 0 | goto CLEANUP_PATH; |
970 | | |
971 | 35.9k | command->ctm = *ctm; |
972 | 35.9k | command->ctm_inverse = *ctm_inverse; |
973 | 35.9k | command->tolerance = tolerance; |
974 | 35.9k | command->antialias = antialias; |
975 | | |
976 | 35.9k | status = _cairo_recording_surface_commit (surface, &command->header); |
977 | 35.9k | if (unlikely (status)) |
978 | 0 | goto CLEANUP_STYLE; |
979 | | |
980 | 35.9k | _cairo_recording_surface_destroy_bbtree (surface); |
981 | | |
982 | 35.9k | _cairo_composite_rectangles_fini (&composite); |
983 | 35.9k | return CAIRO_STATUS_SUCCESS; |
984 | | |
985 | 0 | CLEANUP_STYLE: |
986 | 0 | _cairo_stroke_style_fini (&command->style); |
987 | 0 | CLEANUP_PATH: |
988 | 0 | _cairo_path_fixed_fini (&command->path); |
989 | 0 | CLEANUP_SOURCE: |
990 | 0 | _cairo_pattern_fini (&command->source.base); |
991 | 0 | CLEANUP_COMMAND: |
992 | 0 | _cairo_clip_destroy (command->header.clip); |
993 | 0 | free (command); |
994 | 0 | CLEANUP_COMPOSITE: |
995 | 0 | _cairo_composite_rectangles_fini (&composite); |
996 | 0 | return status; |
997 | 0 | } |
998 | | |
999 | | static cairo_int_status_t |
1000 | | _cairo_recording_surface_fill (void *abstract_surface, |
1001 | | cairo_operator_t op, |
1002 | | const cairo_pattern_t *source, |
1003 | | const cairo_path_fixed_t *path, |
1004 | | cairo_fill_rule_t fill_rule, |
1005 | | double tolerance, |
1006 | | cairo_antialias_t antialias, |
1007 | | const cairo_clip_t *clip) |
1008 | 21.1k | { |
1009 | 21.1k | cairo_status_t status; |
1010 | 21.1k | cairo_recording_surface_t *surface = abstract_surface; |
1011 | 21.1k | cairo_command_fill_t *command; |
1012 | 21.1k | cairo_composite_rectangles_t composite; |
1013 | | |
1014 | 21.1k | TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); |
1015 | | |
1016 | 21.1k | status = _cairo_composite_rectangles_init_for_fill (&composite, |
1017 | 21.1k | &surface->base, |
1018 | 21.1k | op, source, path, |
1019 | 21.1k | clip); |
1020 | 21.1k | if (unlikely (status)) |
1021 | 1.56k | return status; |
1022 | | |
1023 | 19.5k | command = _cairo_calloc (sizeof (cairo_command_fill_t)); |
1024 | 19.5k | if (unlikely (command == NULL)) { |
1025 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1026 | 0 | goto CLEANUP_COMPOSITE; |
1027 | 0 | } |
1028 | | |
1029 | 19.5k | status =_command_init (surface, |
1030 | 19.5k | &command->header, CAIRO_COMMAND_FILL, op, |
1031 | 19.5k | &composite); |
1032 | 19.5k | if (unlikely (status)) |
1033 | 0 | goto CLEANUP_COMMAND; |
1034 | | |
1035 | 19.5k | status = _cairo_pattern_init_snapshot (&command->source.base, source); |
1036 | 19.5k | if (unlikely (status)) |
1037 | 0 | goto CLEANUP_COMMAND; |
1038 | | |
1039 | 19.5k | status = _cairo_path_fixed_init_copy (&command->path, path); |
1040 | 19.5k | if (unlikely (status)) |
1041 | 0 | goto CLEANUP_SOURCE; |
1042 | | |
1043 | 19.5k | command->fill_rule = fill_rule; |
1044 | 19.5k | command->tolerance = tolerance; |
1045 | 19.5k | command->antialias = antialias; |
1046 | | |
1047 | 19.5k | status = _cairo_recording_surface_commit (surface, &command->header); |
1048 | 19.5k | if (unlikely (status)) |
1049 | 0 | goto CLEANUP_PATH; |
1050 | | |
1051 | 19.5k | _cairo_recording_surface_destroy_bbtree (surface); |
1052 | | |
1053 | 19.5k | _cairo_composite_rectangles_fini (&composite); |
1054 | 19.5k | return CAIRO_STATUS_SUCCESS; |
1055 | | |
1056 | 0 | CLEANUP_PATH: |
1057 | 0 | _cairo_path_fixed_fini (&command->path); |
1058 | 0 | CLEANUP_SOURCE: |
1059 | 0 | _cairo_pattern_fini (&command->source.base); |
1060 | 0 | CLEANUP_COMMAND: |
1061 | 0 | _cairo_clip_destroy (command->header.clip); |
1062 | 0 | free (command); |
1063 | 0 | CLEANUP_COMPOSITE: |
1064 | 0 | _cairo_composite_rectangles_fini (&composite); |
1065 | 0 | return status; |
1066 | 0 | } |
1067 | | |
1068 | | static cairo_bool_t |
1069 | | _cairo_recording_surface_has_show_text_glyphs (void *abstract_surface) |
1070 | 549 | { |
1071 | 549 | return TRUE; |
1072 | 549 | } |
1073 | | |
1074 | | static cairo_int_status_t |
1075 | | _cairo_recording_surface_show_text_glyphs (void *abstract_surface, |
1076 | | cairo_operator_t op, |
1077 | | const cairo_pattern_t *source, |
1078 | | const char *utf8, |
1079 | | int utf8_len, |
1080 | | cairo_glyph_t *glyphs, |
1081 | | int num_glyphs, |
1082 | | const cairo_text_cluster_t *clusters, |
1083 | | int num_clusters, |
1084 | | cairo_text_cluster_flags_t cluster_flags, |
1085 | | cairo_scaled_font_t *scaled_font, |
1086 | | const cairo_clip_t *clip) |
1087 | 738k | { |
1088 | 738k | cairo_status_t status; |
1089 | 738k | cairo_recording_surface_t *surface = abstract_surface; |
1090 | 738k | cairo_command_show_text_glyphs_t *command; |
1091 | 738k | cairo_composite_rectangles_t composite; |
1092 | | |
1093 | 738k | TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); |
1094 | | |
1095 | 738k | status = _cairo_composite_rectangles_init_for_glyphs (&composite, |
1096 | 738k | &surface->base, |
1097 | 738k | op, source, |
1098 | 738k | scaled_font, |
1099 | 738k | glyphs, num_glyphs, |
1100 | 738k | clip, |
1101 | 738k | NULL); |
1102 | 738k | if (unlikely (status)) |
1103 | 2.18k | return status; |
1104 | | |
1105 | 736k | command = _cairo_calloc (sizeof (cairo_command_show_text_glyphs_t)); |
1106 | 736k | if (unlikely (command == NULL)) { |
1107 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1108 | 0 | goto CLEANUP_COMPOSITE; |
1109 | 0 | } |
1110 | | |
1111 | 736k | status = _command_init (surface, |
1112 | 736k | &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, |
1113 | 736k | op, &composite); |
1114 | 736k | if (unlikely (status)) |
1115 | 0 | goto CLEANUP_COMMAND; |
1116 | | |
1117 | 736k | status = _cairo_pattern_init_snapshot (&command->source.base, source); |
1118 | 736k | if (unlikely (status)) |
1119 | 0 | goto CLEANUP_COMMAND; |
1120 | | |
1121 | 736k | command->utf8 = NULL; |
1122 | 736k | command->utf8_len = utf8_len; |
1123 | 736k | command->glyphs = NULL; |
1124 | 736k | command->num_glyphs = num_glyphs; |
1125 | 736k | command->clusters = NULL; |
1126 | 736k | command->num_clusters = num_clusters; |
1127 | | |
1128 | 736k | if (utf8_len) { |
1129 | 176k | command->utf8 = _cairo_malloc (utf8_len); |
1130 | 176k | if (unlikely (command->utf8 == NULL)) { |
1131 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1132 | 0 | goto CLEANUP_ARRAYS; |
1133 | 0 | } |
1134 | 176k | memcpy (command->utf8, utf8, utf8_len); |
1135 | 176k | } |
1136 | 736k | if (num_glyphs) { |
1137 | 736k | command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0])); |
1138 | 736k | if (unlikely (command->glyphs == NULL)) { |
1139 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1140 | 0 | goto CLEANUP_ARRAYS; |
1141 | 0 | } |
1142 | 736k | memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs); |
1143 | 736k | } |
1144 | 736k | if (num_clusters) { |
1145 | 176k | command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0])); |
1146 | 176k | if (unlikely (command->clusters == NULL)) { |
1147 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1148 | 0 | goto CLEANUP_ARRAYS; |
1149 | 0 | } |
1150 | 176k | memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters); |
1151 | 176k | } |
1152 | | |
1153 | 736k | command->cluster_flags = cluster_flags; |
1154 | | |
1155 | 736k | status = scaled_font->status; |
1156 | 736k | if (unlikely (status)) |
1157 | 0 | goto CLEANUP_ARRAYS; |
1158 | | |
1159 | 736k | command->scaled_font = cairo_scaled_font_reference (scaled_font); |
1160 | | |
1161 | 736k | status = _cairo_recording_surface_commit (surface, &command->header); |
1162 | 736k | if (unlikely (status)) |
1163 | 0 | goto CLEANUP_SCALED_FONT; |
1164 | | |
1165 | 736k | _cairo_composite_rectangles_fini (&composite); |
1166 | 736k | return CAIRO_STATUS_SUCCESS; |
1167 | | |
1168 | 0 | CLEANUP_SCALED_FONT: |
1169 | 0 | cairo_scaled_font_destroy (command->scaled_font); |
1170 | 0 | CLEANUP_ARRAYS: |
1171 | 0 | free (command->utf8); |
1172 | 0 | free (command->glyphs); |
1173 | 0 | free (command->clusters); |
1174 | |
|
1175 | 0 | _cairo_pattern_fini (&command->source.base); |
1176 | 0 | CLEANUP_COMMAND: |
1177 | 0 | _cairo_clip_destroy (command->header.clip); |
1178 | 0 | free (command); |
1179 | 0 | CLEANUP_COMPOSITE: |
1180 | 0 | _cairo_composite_rectangles_fini (&composite); |
1181 | 0 | return status; |
1182 | 0 | } |
1183 | | |
1184 | | static cairo_int_status_t |
1185 | | _cairo_recording_surface_tag (void *abstract_surface, |
1186 | | cairo_bool_t begin, |
1187 | | const char *tag_name, |
1188 | | const char *attributes) |
1189 | 0 | { |
1190 | 0 | cairo_status_t status; |
1191 | 0 | cairo_recording_surface_t *surface = abstract_surface; |
1192 | 0 | cairo_command_tag_t *command; |
1193 | |
|
1194 | 0 | TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); |
1195 | |
|
1196 | 0 | surface->has_tags = TRUE; |
1197 | |
|
1198 | 0 | command = _cairo_calloc (sizeof (cairo_command_tag_t)); |
1199 | 0 | if (unlikely (command == NULL)) { |
1200 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1201 | 0 | } |
1202 | | |
1203 | 0 | status = _command_init (surface, |
1204 | 0 | &command->header, CAIRO_COMMAND_TAG, CAIRO_OPERATOR_SOURCE, |
1205 | 0 | NULL); |
1206 | 0 | if (unlikely (status)) |
1207 | 0 | goto CLEANUP_COMMAND; |
1208 | | |
1209 | 0 | command->begin = begin; |
1210 | 0 | command->tag_name = strdup (tag_name); |
1211 | 0 | if (unlikely (command->tag_name == NULL)) { |
1212 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1213 | 0 | goto CLEANUP_COMMAND; |
1214 | 0 | } |
1215 | 0 | if (begin) { |
1216 | 0 | if (attributes) { |
1217 | 0 | command->attributes = strdup (attributes); |
1218 | 0 | if (unlikely (command->attributes == NULL)) { |
1219 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1220 | 0 | goto CLEANUP_STRINGS; |
1221 | 0 | } |
1222 | 0 | } |
1223 | 0 | } |
1224 | | |
1225 | 0 | status = _cairo_recording_surface_commit (surface, &command->header); |
1226 | 0 | if (unlikely (status)) |
1227 | 0 | goto CLEANUP_STRINGS; |
1228 | | |
1229 | 0 | _cairo_recording_surface_destroy_bbtree (surface); |
1230 | |
|
1231 | 0 | return CAIRO_STATUS_SUCCESS; |
1232 | | |
1233 | 0 | CLEANUP_STRINGS: |
1234 | 0 | free (command->tag_name); |
1235 | 0 | free (command->attributes); |
1236 | 0 | CLEANUP_COMMAND: |
1237 | 0 | _cairo_clip_destroy (command->header.clip); |
1238 | 0 | free (command); |
1239 | 0 | return status; |
1240 | 0 | } |
1241 | | |
1242 | | static cairo_bool_t |
1243 | | _cairo_recording_surface_supports_color_glyph (void *abstract_surface, |
1244 | | cairo_scaled_font_t *scaled_font, |
1245 | | unsigned long glyph_index) |
1246 | 0 | { |
1247 | 0 | return TRUE; |
1248 | 0 | } |
1249 | | |
1250 | | static void |
1251 | | _command_init_copy (cairo_recording_surface_t *surface, |
1252 | | cairo_command_header_t *dst, |
1253 | | const cairo_command_header_t *src) |
1254 | 2.68k | { |
1255 | 2.68k | dst->type = src->type; |
1256 | 2.68k | dst->op = src->op; |
1257 | | |
1258 | 2.68k | dst->extents = src->extents; |
1259 | 2.68k | dst->chain = NULL; |
1260 | 2.68k | dst->index = surface->commands.num_elements; |
1261 | | |
1262 | 2.68k | dst->clip = _cairo_clip_copy (src->clip); |
1263 | 2.68k | } |
1264 | | |
1265 | | static cairo_status_t |
1266 | | _cairo_recording_surface_copy__paint (cairo_recording_surface_t *surface, |
1267 | | const cairo_command_t *src) |
1268 | 18 | { |
1269 | 18 | cairo_command_paint_t *command; |
1270 | 18 | cairo_status_t status; |
1271 | | |
1272 | 18 | command = _cairo_calloc (sizeof (*command)); |
1273 | 18 | if (unlikely (command == NULL)) { |
1274 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1275 | 0 | goto err; |
1276 | 0 | } |
1277 | | |
1278 | 18 | _command_init_copy (surface, &command->header, &src->header); |
1279 | | |
1280 | 18 | status = _cairo_pattern_init_copy (&command->source.base, |
1281 | 18 | &src->paint.source.base); |
1282 | 18 | if (unlikely (status)) |
1283 | 0 | goto err_command; |
1284 | | |
1285 | 18 | status = _cairo_recording_surface_commit (surface, &command->header); |
1286 | 18 | if (unlikely (status)) |
1287 | 0 | goto err_source; |
1288 | | |
1289 | 18 | return CAIRO_STATUS_SUCCESS; |
1290 | | |
1291 | 0 | err_source: |
1292 | 0 | _cairo_pattern_fini (&command->source.base); |
1293 | 0 | err_command: |
1294 | 0 | free(command); |
1295 | 0 | err: |
1296 | 0 | return status; |
1297 | 0 | } |
1298 | | |
1299 | | static cairo_status_t |
1300 | | _cairo_recording_surface_copy__mask (cairo_recording_surface_t *surface, |
1301 | | const cairo_command_t *src) |
1302 | 407 | { |
1303 | 407 | cairo_command_mask_t *command; |
1304 | 407 | cairo_status_t status; |
1305 | | |
1306 | 407 | command = _cairo_calloc (sizeof (*command)); |
1307 | 407 | if (unlikely (command == NULL)) { |
1308 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1309 | 0 | goto err; |
1310 | 0 | } |
1311 | | |
1312 | 407 | _command_init_copy (surface, &command->header, &src->header); |
1313 | | |
1314 | 407 | status = _cairo_pattern_init_copy (&command->source.base, |
1315 | 407 | &src->mask.source.base); |
1316 | 407 | if (unlikely (status)) |
1317 | 0 | goto err_command; |
1318 | | |
1319 | 407 | status = _cairo_pattern_init_copy (&command->mask.base, |
1320 | 407 | &src->mask.mask.base); |
1321 | 407 | if (unlikely (status)) |
1322 | 0 | goto err_source; |
1323 | | |
1324 | 407 | status = _cairo_recording_surface_commit (surface, &command->header); |
1325 | 407 | if (unlikely (status)) |
1326 | 0 | goto err_mask; |
1327 | | |
1328 | 407 | return CAIRO_STATUS_SUCCESS; |
1329 | | |
1330 | 0 | err_mask: |
1331 | 0 | _cairo_pattern_fini (&command->mask.base); |
1332 | 0 | err_source: |
1333 | 0 | _cairo_pattern_fini (&command->source.base); |
1334 | 0 | err_command: |
1335 | 0 | free(command); |
1336 | 0 | err: |
1337 | 0 | return status; |
1338 | 0 | } |
1339 | | |
1340 | | static cairo_status_t |
1341 | | _cairo_recording_surface_copy__stroke (cairo_recording_surface_t *surface, |
1342 | | const cairo_command_t *src) |
1343 | 646 | { |
1344 | 646 | cairo_command_stroke_t *command; |
1345 | 646 | cairo_status_t status; |
1346 | | |
1347 | 646 | command = _cairo_calloc (sizeof (*command)); |
1348 | 646 | if (unlikely (command == NULL)) { |
1349 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1350 | 0 | goto err; |
1351 | 0 | } |
1352 | | |
1353 | 646 | _command_init_copy (surface, &command->header, &src->header); |
1354 | | |
1355 | 646 | status = _cairo_pattern_init_copy (&command->source.base, |
1356 | 646 | &src->stroke.source.base); |
1357 | 646 | if (unlikely (status)) |
1358 | 0 | goto err_command; |
1359 | | |
1360 | 646 | status = _cairo_path_fixed_init_copy (&command->path, &src->stroke.path); |
1361 | 646 | if (unlikely (status)) |
1362 | 0 | goto err_source; |
1363 | | |
1364 | 646 | status = _cairo_stroke_style_init_copy (&command->style, |
1365 | 646 | &src->stroke.style); |
1366 | 646 | if (unlikely (status)) |
1367 | 0 | goto err_path; |
1368 | | |
1369 | 646 | command->ctm = src->stroke.ctm; |
1370 | 646 | command->ctm_inverse = src->stroke.ctm_inverse; |
1371 | 646 | command->tolerance = src->stroke.tolerance; |
1372 | 646 | command->antialias = src->stroke.antialias; |
1373 | | |
1374 | 646 | status = _cairo_recording_surface_commit (surface, &command->header); |
1375 | 646 | if (unlikely (status)) |
1376 | 0 | goto err_style; |
1377 | | |
1378 | 646 | return CAIRO_STATUS_SUCCESS; |
1379 | | |
1380 | 0 | err_style: |
1381 | 0 | _cairo_stroke_style_fini (&command->style); |
1382 | 0 | err_path: |
1383 | 0 | _cairo_path_fixed_fini (&command->path); |
1384 | 0 | err_source: |
1385 | 0 | _cairo_pattern_fini (&command->source.base); |
1386 | 0 | err_command: |
1387 | 0 | free(command); |
1388 | 0 | err: |
1389 | 0 | return status; |
1390 | 0 | } |
1391 | | |
1392 | | static cairo_status_t |
1393 | | _cairo_recording_surface_copy__fill (cairo_recording_surface_t *surface, |
1394 | | const cairo_command_t *src) |
1395 | 1.06k | { |
1396 | 1.06k | cairo_command_fill_t *command; |
1397 | 1.06k | cairo_status_t status; |
1398 | | |
1399 | 1.06k | command = _cairo_calloc (sizeof (*command)); |
1400 | 1.06k | if (unlikely (command == NULL)) { |
1401 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1402 | 0 | goto err; |
1403 | 0 | } |
1404 | | |
1405 | 1.06k | _command_init_copy (surface, &command->header, &src->header); |
1406 | | |
1407 | 1.06k | status = _cairo_pattern_init_copy (&command->source.base, |
1408 | 1.06k | &src->fill.source.base); |
1409 | 1.06k | if (unlikely (status)) |
1410 | 0 | goto err_command; |
1411 | | |
1412 | 1.06k | status = _cairo_path_fixed_init_copy (&command->path, &src->fill.path); |
1413 | 1.06k | if (unlikely (status)) |
1414 | 0 | goto err_source; |
1415 | | |
1416 | 1.06k | command->fill_rule = src->fill.fill_rule; |
1417 | 1.06k | command->tolerance = src->fill.tolerance; |
1418 | 1.06k | command->antialias = src->fill.antialias; |
1419 | | |
1420 | 1.06k | status = _cairo_recording_surface_commit (surface, &command->header); |
1421 | 1.06k | if (unlikely (status)) |
1422 | 0 | goto err_path; |
1423 | | |
1424 | 1.06k | return CAIRO_STATUS_SUCCESS; |
1425 | | |
1426 | 0 | err_path: |
1427 | 0 | _cairo_path_fixed_fini (&command->path); |
1428 | 0 | err_source: |
1429 | 0 | _cairo_pattern_fini (&command->source.base); |
1430 | 0 | err_command: |
1431 | 0 | free(command); |
1432 | 0 | err: |
1433 | 0 | return status; |
1434 | 0 | } |
1435 | | |
1436 | | static cairo_status_t |
1437 | | _cairo_recording_surface_copy__glyphs (cairo_recording_surface_t *surface, |
1438 | | const cairo_command_t *src) |
1439 | 546 | { |
1440 | 546 | cairo_command_show_text_glyphs_t *command; |
1441 | 546 | cairo_status_t status; |
1442 | | |
1443 | 546 | command = _cairo_calloc (sizeof (*command)); |
1444 | 546 | if (unlikely (command == NULL)) { |
1445 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1446 | 0 | goto err; |
1447 | 0 | } |
1448 | | |
1449 | 546 | _command_init_copy (surface, &command->header, &src->header); |
1450 | | |
1451 | 546 | status = _cairo_pattern_init_copy (&command->source.base, |
1452 | 546 | &src->show_text_glyphs.source.base); |
1453 | 546 | if (unlikely (status)) |
1454 | 0 | goto err_command; |
1455 | | |
1456 | 546 | command->utf8 = NULL; |
1457 | 546 | command->utf8_len = src->show_text_glyphs.utf8_len; |
1458 | 546 | command->glyphs = NULL; |
1459 | 546 | command->num_glyphs = src->show_text_glyphs.num_glyphs; |
1460 | 546 | command->clusters = NULL; |
1461 | 546 | command->num_clusters = src->show_text_glyphs.num_clusters; |
1462 | | |
1463 | 546 | if (command->utf8_len) { |
1464 | 545 | command->utf8 = _cairo_malloc (command->utf8_len); |
1465 | 545 | if (unlikely (command->utf8 == NULL)) { |
1466 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1467 | 0 | goto err_arrays; |
1468 | 0 | } |
1469 | 545 | memcpy (command->utf8, src->show_text_glyphs.utf8, command->utf8_len); |
1470 | 545 | } |
1471 | 546 | if (command->num_glyphs) { |
1472 | 546 | command->glyphs = _cairo_malloc_ab (command->num_glyphs, |
1473 | 546 | sizeof (command->glyphs[0])); |
1474 | 546 | if (unlikely (command->glyphs == NULL)) { |
1475 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1476 | 0 | goto err_arrays; |
1477 | 0 | } |
1478 | 546 | memcpy (command->glyphs, src->show_text_glyphs.glyphs, |
1479 | 546 | sizeof (command->glyphs[0]) * command->num_glyphs); |
1480 | 546 | } |
1481 | 546 | if (command->num_clusters) { |
1482 | 545 | command->clusters = _cairo_malloc_ab (command->num_clusters, |
1483 | 545 | sizeof (command->clusters[0])); |
1484 | 545 | if (unlikely (command->clusters == NULL)) { |
1485 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1486 | 0 | goto err_arrays; |
1487 | 0 | } |
1488 | 545 | memcpy (command->clusters, src->show_text_glyphs.clusters, |
1489 | 545 | sizeof (command->clusters[0]) * command->num_clusters); |
1490 | 545 | } |
1491 | | |
1492 | 546 | command->cluster_flags = src->show_text_glyphs.cluster_flags; |
1493 | | |
1494 | 546 | command->scaled_font = |
1495 | 546 | cairo_scaled_font_reference (src->show_text_glyphs.scaled_font); |
1496 | | |
1497 | 546 | status = _cairo_recording_surface_commit (surface, &command->header); |
1498 | 546 | if (unlikely (status)) |
1499 | 0 | goto err_arrays; |
1500 | | |
1501 | 546 | return CAIRO_STATUS_SUCCESS; |
1502 | | |
1503 | 0 | err_arrays: |
1504 | 0 | free (command->utf8); |
1505 | 0 | free (command->glyphs); |
1506 | 0 | free (command->clusters); |
1507 | 0 | _cairo_pattern_fini (&command->source.base); |
1508 | 0 | err_command: |
1509 | 0 | free(command); |
1510 | 0 | err: |
1511 | 0 | return status; |
1512 | 0 | } |
1513 | | |
1514 | | static cairo_status_t |
1515 | | _cairo_recording_surface_copy__tag (cairo_recording_surface_t *surface, |
1516 | | const cairo_command_t *src) |
1517 | 0 | { |
1518 | 0 | cairo_command_tag_t *command; |
1519 | 0 | cairo_status_t status; |
1520 | |
|
1521 | 0 | command = _cairo_calloc (sizeof (*command)); |
1522 | 0 | if (unlikely (command == NULL)) { |
1523 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1524 | 0 | goto err; |
1525 | 0 | } |
1526 | | |
1527 | 0 | _command_init_copy (surface, &command->header, &src->header); |
1528 | |
|
1529 | 0 | command->begin = src->tag.begin; |
1530 | 0 | command->tag_name = strdup (src->tag.tag_name); |
1531 | 0 | if (unlikely (command->tag_name == NULL)) { |
1532 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1533 | 0 | goto err_command; |
1534 | 0 | } |
1535 | 0 | if (src->tag.begin) { |
1536 | 0 | if (src->tag.attributes) { |
1537 | 0 | command->attributes = strdup (src->tag.attributes); |
1538 | 0 | if (unlikely (command->attributes == NULL)) { |
1539 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1540 | 0 | goto err_command; |
1541 | 0 | } |
1542 | 0 | } |
1543 | 0 | } |
1544 | | |
1545 | 0 | status = _cairo_recording_surface_commit (surface, &command->header); |
1546 | 0 | if (unlikely (status)) |
1547 | 0 | goto err_command; |
1548 | | |
1549 | 0 | return CAIRO_STATUS_SUCCESS; |
1550 | | |
1551 | 0 | err_command: |
1552 | 0 | free(command->tag_name); |
1553 | 0 | free(command->attributes); |
1554 | 0 | free(command); |
1555 | 0 | err: |
1556 | 0 | return status; |
1557 | 0 | } |
1558 | | |
1559 | | static cairo_status_t |
1560 | | _cairo_recording_surface_copy (cairo_recording_surface_t *dst, |
1561 | | cairo_recording_surface_t *src) |
1562 | 1.03k | { |
1563 | 1.03k | cairo_command_t **elements; |
1564 | 1.03k | int i, num_elements; |
1565 | 1.03k | cairo_status_t status; |
1566 | | |
1567 | 1.03k | elements = _cairo_array_index (&src->commands, 0); |
1568 | 1.03k | num_elements = src->commands.num_elements; |
1569 | 3.72k | for (i = 0; i < num_elements; i++) { |
1570 | 2.68k | const cairo_command_t *command = elements[i]; |
1571 | | |
1572 | 2.68k | switch (command->header.type) { |
1573 | 18 | case CAIRO_COMMAND_PAINT: |
1574 | 18 | status = _cairo_recording_surface_copy__paint (dst, command); |
1575 | 18 | break; |
1576 | | |
1577 | 407 | case CAIRO_COMMAND_MASK: |
1578 | 407 | status = _cairo_recording_surface_copy__mask (dst, command); |
1579 | 407 | break; |
1580 | | |
1581 | 646 | case CAIRO_COMMAND_STROKE: |
1582 | 646 | status = _cairo_recording_surface_copy__stroke (dst, command); |
1583 | 646 | break; |
1584 | | |
1585 | 1.06k | case CAIRO_COMMAND_FILL: |
1586 | 1.06k | status = _cairo_recording_surface_copy__fill (dst, command); |
1587 | 1.06k | break; |
1588 | | |
1589 | 546 | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
1590 | 546 | status = _cairo_recording_surface_copy__glyphs (dst, command); |
1591 | 546 | break; |
1592 | | |
1593 | 0 | case CAIRO_COMMAND_TAG: |
1594 | 0 | status = _cairo_recording_surface_copy__tag (dst, command); |
1595 | 0 | break; |
1596 | | |
1597 | 0 | default: |
1598 | 0 | ASSERT_NOT_REACHED; |
1599 | 2.68k | } |
1600 | | |
1601 | 2.68k | if (unlikely (status)) |
1602 | 0 | return status; |
1603 | 2.68k | } |
1604 | | |
1605 | 1.03k | return CAIRO_STATUS_SUCCESS; |
1606 | 1.03k | } |
1607 | | |
1608 | | /** |
1609 | | * _cairo_recording_surface_snapshot: |
1610 | | * @surface: a #cairo_surface_t which must be a recording surface |
1611 | | * |
1612 | | * Make an immutable copy of @surface. It is an error to call a |
1613 | | * surface-modifying function on the result of this function. |
1614 | | * |
1615 | | * The caller owns the return value and should call |
1616 | | * cairo_surface_destroy() when finished with it. This function will not |
1617 | | * return %NULL, but will return a nil surface instead. |
1618 | | * |
1619 | | * Return value: The snapshot surface. |
1620 | | **/ |
1621 | | static cairo_surface_t * |
1622 | | _cairo_recording_surface_snapshot (void *abstract_other) |
1623 | 1.03k | { |
1624 | 1.03k | cairo_recording_surface_t *other = abstract_other; |
1625 | 1.03k | cairo_recording_surface_t *surface; |
1626 | 1.03k | cairo_status_t status; |
1627 | | |
1628 | 1.03k | surface = _cairo_calloc (sizeof (cairo_recording_surface_t)); |
1629 | 1.03k | if (unlikely (surface == NULL)) |
1630 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
1631 | | |
1632 | 1.03k | _cairo_surface_init (&surface->base, |
1633 | 1.03k | &cairo_recording_surface_backend, |
1634 | 1.03k | NULL, /* device */ |
1635 | 1.03k | other->base.content, |
1636 | 1.03k | other->base.is_vector); |
1637 | | |
1638 | 1.03k | surface->extents_pixels = other->extents_pixels; |
1639 | 1.03k | surface->extents = other->extents; |
1640 | 1.03k | surface->unbounded = other->unbounded; |
1641 | 1.03k | surface->has_bilevel_alpha = other->has_bilevel_alpha; |
1642 | 1.03k | surface->has_only_op_over = other->has_only_op_over; |
1643 | 1.03k | surface->has_tags = other->has_tags; |
1644 | | |
1645 | 1.03k | surface->base.is_clear = other->base.is_clear; |
1646 | | |
1647 | 1.03k | surface->bbtree.left = surface->bbtree.right = NULL; |
1648 | 1.03k | surface->bbtree.chain = INVALID_CHAIN; |
1649 | | |
1650 | 1.03k | surface->indices = NULL; |
1651 | 1.03k | surface->num_indices = 0; |
1652 | 1.03k | surface->optimize_clears = TRUE; |
1653 | | |
1654 | 1.03k | CAIRO_MUTEX_INIT (surface->mutex); |
1655 | | |
1656 | 1.03k | cairo_list_init (&surface->region_array_list); |
1657 | | |
1658 | 1.03k | _cairo_array_init (&surface->commands, sizeof (cairo_command_t *)); |
1659 | 1.03k | status = _cairo_recording_surface_copy (surface, other); |
1660 | 1.03k | if (unlikely (status)) { |
1661 | 0 | cairo_surface_destroy (&surface->base); |
1662 | 0 | return _cairo_surface_create_in_error (status); |
1663 | 0 | } |
1664 | | |
1665 | 1.03k | return &surface->base; |
1666 | 1.03k | } |
1667 | | |
1668 | | static cairo_bool_t |
1669 | | _cairo_recording_surface_get_extents (void *abstract_surface, |
1670 | | cairo_rectangle_int_t *rectangle) |
1671 | 815k | { |
1672 | 815k | cairo_recording_surface_t *surface = abstract_surface; |
1673 | | |
1674 | 815k | if (surface->unbounded) |
1675 | 1.36k | return FALSE; |
1676 | | |
1677 | 813k | *rectangle = surface->extents; |
1678 | 813k | return TRUE; |
1679 | 815k | } |
1680 | | |
1681 | | static const cairo_surface_backend_t cairo_recording_surface_backend = { |
1682 | | CAIRO_SURFACE_TYPE_RECORDING, |
1683 | | _cairo_recording_surface_finish, |
1684 | | |
1685 | | _cairo_default_context_create, |
1686 | | |
1687 | | _cairo_recording_surface_create_similar, |
1688 | | NULL, /* create similar image */ |
1689 | | NULL, /* map to image */ |
1690 | | NULL, /* unmap image */ |
1691 | | |
1692 | | _cairo_surface_default_source, |
1693 | | _cairo_recording_surface_acquire_source_image, |
1694 | | _cairo_recording_surface_release_source_image, |
1695 | | _cairo_recording_surface_snapshot, |
1696 | | |
1697 | | NULL, /* copy_page */ |
1698 | | NULL, /* show_page */ |
1699 | | |
1700 | | _cairo_recording_surface_get_extents, |
1701 | | NULL, /* get_font_options */ |
1702 | | |
1703 | | NULL, /* flush */ |
1704 | | NULL, /* mark_dirty_rectangle */ |
1705 | | |
1706 | | /* Here are the 5 basic drawing operations, (which are in some |
1707 | | * sense the only things that cairo_recording_surface should need to |
1708 | | * implement). However, we implement the more generic show_text_glyphs |
1709 | | * instead of show_glyphs. One or the other is eough. */ |
1710 | | |
1711 | | _cairo_recording_surface_paint, |
1712 | | _cairo_recording_surface_mask, |
1713 | | _cairo_recording_surface_stroke, |
1714 | | _cairo_recording_surface_fill, |
1715 | | NULL, /* fill-stroke */ |
1716 | | NULL, |
1717 | | _cairo_recording_surface_has_show_text_glyphs, |
1718 | | _cairo_recording_surface_show_text_glyphs, |
1719 | | NULL, /* get_supported_mime_types */ |
1720 | | _cairo_recording_surface_tag, |
1721 | | _cairo_recording_surface_supports_color_glyph, |
1722 | | NULL, /* analyze_recording_surface */ |
1723 | | NULL, /* command_id */ |
1724 | | }; |
1725 | | |
1726 | | static unsigned int |
1727 | | _cairo_recording_surface_regions_allocate_unique_id (void) |
1728 | 2.66k | { |
1729 | 2.66k | static cairo_atomic_int_t unique_id; |
1730 | | |
1731 | | #if CAIRO_NO_MUTEX |
1732 | | if (++unique_id == 0) |
1733 | | unique_id = 1; |
1734 | | return unique_id; |
1735 | | #else |
1736 | 2.66k | int old, id; |
1737 | | |
1738 | 2.66k | do { |
1739 | 2.66k | old = _cairo_atomic_uint_get (&unique_id); |
1740 | 2.66k | id = old + 1; |
1741 | 2.66k | if (id == 0) |
1742 | 0 | id = 1; |
1743 | 2.66k | } while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id)); |
1744 | | |
1745 | 2.66k | return id; |
1746 | 2.66k | #endif |
1747 | 2.66k | } |
1748 | | |
1749 | | static cairo_recording_regions_array_t * |
1750 | | _cairo_recording_surface_region_array_find (cairo_recording_surface_t *surface, |
1751 | | unsigned int id) |
1752 | 5.85k | { |
1753 | 5.85k | cairo_recording_regions_array_t *regions; |
1754 | | |
1755 | 5.85k | cairo_list_foreach_entry (regions, cairo_recording_regions_array_t, |
1756 | 5.85k | &surface->region_array_list, link) |
1757 | 5.85k | { |
1758 | 5.85k | if (regions->id == id) |
1759 | 5.85k | return regions; |
1760 | 5.85k | } |
1761 | | |
1762 | 0 | return NULL; |
1763 | 5.85k | } |
1764 | | |
1765 | | /* Create and initialize a new #cairo_recording_regions_array_t. Attach |
1766 | | * it to the recording surface and return its id |
1767 | | */ |
1768 | | cairo_status_t |
1769 | | _cairo_recording_surface_region_array_attach (cairo_surface_t *abstract_surface, |
1770 | | unsigned int *id) |
1771 | 2.66k | { |
1772 | 2.66k | cairo_recording_regions_array_t *region_array; |
1773 | 2.66k | cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface; |
1774 | | |
1775 | 2.66k | assert (_cairo_surface_is_recording (abstract_surface)); |
1776 | | |
1777 | 2.66k | region_array = _cairo_calloc (sizeof (cairo_recording_regions_array_t)); |
1778 | 2.66k | if (region_array == NULL) { |
1779 | 0 | *id = 0; |
1780 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1781 | 0 | } |
1782 | | |
1783 | 2.66k | region_array->id = _cairo_recording_surface_regions_allocate_unique_id (); |
1784 | | |
1785 | 2.66k | CAIRO_REFERENCE_COUNT_INIT (®ion_array->ref_count, 1); |
1786 | | |
1787 | 2.66k | _cairo_array_init (®ion_array->regions, sizeof (cairo_recording_region_element_t)); |
1788 | | |
1789 | 2.66k | CAIRO_MUTEX_LOCK (surface->mutex); |
1790 | 2.66k | cairo_list_add (®ion_array->link, &surface->region_array_list); |
1791 | 2.66k | CAIRO_MUTEX_UNLOCK (surface->mutex); |
1792 | | |
1793 | 2.66k | *id = region_array->id; |
1794 | | |
1795 | 2.66k | return CAIRO_STATUS_SUCCESS; |
1796 | 2.66k | } |
1797 | | |
1798 | | void |
1799 | | _cairo_recording_surface_region_array_remove (cairo_surface_t *abstract_surface, |
1800 | | unsigned int id) |
1801 | 1.61k | { |
1802 | 1.61k | cairo_recording_regions_array_t *region_array; |
1803 | 1.61k | cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface; |
1804 | | |
1805 | 1.61k | if (id == 0) |
1806 | 0 | return; |
1807 | | |
1808 | 1.61k | assert (_cairo_surface_is_recording (abstract_surface)); |
1809 | | |
1810 | 1.61k | CAIRO_MUTEX_LOCK (surface->mutex); |
1811 | 1.61k | region_array = _cairo_recording_surface_region_array_find (surface, id); |
1812 | 1.61k | if (region_array) { |
1813 | 1.61k | if (_cairo_reference_count_dec_and_test (®ion_array->ref_count)) |
1814 | 1.61k | cairo_list_del (®ion_array->link); |
1815 | 0 | else |
1816 | 0 | region_array = NULL; |
1817 | 1.61k | } |
1818 | | |
1819 | 1.61k | CAIRO_MUTEX_UNLOCK (surface->mutex); |
1820 | | |
1821 | 1.61k | if (region_array) |
1822 | 1.61k | _cairo_recording_surface_region_array_destroy (surface, region_array); |
1823 | 1.61k | } |
1824 | | |
1825 | | void |
1826 | | _cairo_recording_surface_region_array_reference (cairo_surface_t *abstract_surface, |
1827 | | unsigned int id) |
1828 | 0 | { |
1829 | 0 | cairo_recording_regions_array_t *region_array; |
1830 | 0 | cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface; |
1831 | |
|
1832 | 0 | assert (_cairo_surface_is_recording (abstract_surface)); |
1833 | |
|
1834 | 0 | CAIRO_MUTEX_LOCK (surface->mutex); |
1835 | 0 | region_array = _cairo_recording_surface_region_array_find (surface, id); |
1836 | 0 | if (region_array) { |
1837 | 0 | _cairo_reference_count_inc (®ion_array->ref_count); |
1838 | 0 | } |
1839 | |
|
1840 | 0 | CAIRO_MUTEX_UNLOCK (surface->mutex); |
1841 | 0 | } |
1842 | | |
1843 | | cairo_int_status_t |
1844 | | _cairo_recording_surface_get_path (cairo_surface_t *abstract_surface, |
1845 | | cairo_path_fixed_t *path) |
1846 | 239 | { |
1847 | 239 | cairo_recording_surface_t *surface; |
1848 | 239 | cairo_command_t **elements; |
1849 | 239 | int i, num_elements; |
1850 | 239 | cairo_int_status_t status; |
1851 | | |
1852 | 239 | if (unlikely (abstract_surface->status)) |
1853 | 0 | return abstract_surface->status; |
1854 | | |
1855 | 239 | surface = (cairo_recording_surface_t *) abstract_surface; |
1856 | 239 | status = CAIRO_STATUS_SUCCESS; |
1857 | | |
1858 | 239 | num_elements = surface->commands.num_elements; |
1859 | 239 | elements = _cairo_array_index (&surface->commands, 0); |
1860 | 239 | for (i = 0; i < num_elements; i++) { |
1861 | 227 | cairo_command_t *command = elements[i]; |
1862 | | |
1863 | 227 | switch (command->header.type) { |
1864 | 0 | case CAIRO_COMMAND_PAINT: |
1865 | 227 | case CAIRO_COMMAND_MASK: |
1866 | 227 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
1867 | 227 | break; |
1868 | | |
1869 | 0 | case CAIRO_COMMAND_STROKE: |
1870 | 0 | { |
1871 | 0 | cairo_traps_t traps; |
1872 | |
|
1873 | 0 | _cairo_traps_init (&traps); |
1874 | | |
1875 | | /* XXX call cairo_stroke_to_path() when that is implemented */ |
1876 | 0 | status = _cairo_path_fixed_stroke_polygon_to_traps (&command->stroke.path, |
1877 | 0 | &command->stroke.style, |
1878 | 0 | &command->stroke.ctm, |
1879 | 0 | &command->stroke.ctm_inverse, |
1880 | 0 | command->stroke.tolerance, |
1881 | 0 | &traps); |
1882 | |
|
1883 | 0 | if (status == CAIRO_INT_STATUS_SUCCESS) |
1884 | 0 | status = _cairo_traps_path (&traps, path); |
1885 | |
|
1886 | 0 | _cairo_traps_fini (&traps); |
1887 | 0 | break; |
1888 | 0 | } |
1889 | 0 | case CAIRO_COMMAND_FILL: |
1890 | 0 | { |
1891 | 0 | status = _cairo_path_fixed_append (path, |
1892 | 0 | &command->fill.path, |
1893 | 0 | 0, 0); |
1894 | 0 | break; |
1895 | 0 | } |
1896 | 0 | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
1897 | 0 | { |
1898 | 0 | status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font, |
1899 | 0 | command->show_text_glyphs.glyphs, |
1900 | 0 | command->show_text_glyphs.num_glyphs, |
1901 | 0 | path); |
1902 | 0 | break; |
1903 | 0 | } |
1904 | | |
1905 | 0 | case CAIRO_COMMAND_TAG: |
1906 | 0 | break; |
1907 | | |
1908 | 0 | default: |
1909 | 0 | ASSERT_NOT_REACHED; |
1910 | 227 | } |
1911 | | |
1912 | 227 | if (unlikely (status)) |
1913 | 227 | break; |
1914 | 227 | } |
1915 | | |
1916 | 239 | return status; |
1917 | 239 | } |
1918 | | |
1919 | | static int |
1920 | | _cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surface, |
1921 | | const cairo_rectangle_int_t *extents) |
1922 | 454 | { |
1923 | 454 | unsigned int num_visible, *indices; |
1924 | 454 | cairo_box_t box; |
1925 | | |
1926 | 454 | if (surface->commands.num_elements == 0) |
1927 | 0 | return 0; |
1928 | | |
1929 | 454 | _cairo_box_from_rectangle (&box, extents); |
1930 | | |
1931 | 454 | if (surface->bbtree.chain == INVALID_CHAIN) |
1932 | 454 | _cairo_recording_surface_create_bbtree (surface); |
1933 | | |
1934 | 454 | indices = surface->indices; |
1935 | 454 | bbtree_foreach_mark_visible (&surface->bbtree, &box, &indices); |
1936 | 454 | num_visible = indices - surface->indices; |
1937 | 454 | if (num_visible > 1) |
1938 | 0 | sort_indices (surface->indices, num_visible); |
1939 | | |
1940 | 454 | return num_visible; |
1941 | 454 | } |
1942 | | |
1943 | | static void |
1944 | | _cairo_recording_surface_merge_source_attributes (cairo_recording_surface_t *surface, |
1945 | | cairo_operator_t op, |
1946 | | const cairo_pattern_t *source) |
1947 | 797k | { |
1948 | 797k | if (op != CAIRO_OPERATOR_OVER) |
1949 | 1.33k | surface->has_only_op_over = FALSE; |
1950 | | |
1951 | 797k | if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { |
1952 | 4.66k | cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) source; |
1953 | 4.66k | cairo_surface_t *surf = surf_pat->surface; |
1954 | 4.66k | cairo_surface_t *free_me = NULL; |
1955 | | |
1956 | 4.66k | if (_cairo_surface_is_snapshot (surf)) |
1957 | 4.66k | free_me = surf = _cairo_surface_snapshot_get_target (surf); |
1958 | | |
1959 | 4.66k | if (unlikely (surf->status)) |
1960 | | // There was some kind of error and the surface could be a nil error |
1961 | | // surface with various "problems" (e.g. ->backend == NULL). |
1962 | 0 | return; |
1963 | | |
1964 | 4.66k | if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) { |
1965 | 1.04k | cairo_recording_surface_t *rec_surf = (cairo_recording_surface_t *) surf; |
1966 | | |
1967 | 1.04k | if (! _cairo_recording_surface_has_only_bilevel_alpha (rec_surf)) |
1968 | 21 | surface->has_bilevel_alpha = FALSE; |
1969 | | |
1970 | 1.04k | if (! _cairo_recording_surface_has_only_op_over (rec_surf)) |
1971 | 13 | surface->has_only_op_over = FALSE; |
1972 | | |
1973 | 3.61k | } else if (surf->type == CAIRO_SURFACE_TYPE_IMAGE) { |
1974 | 3.61k | cairo_image_surface_t *img_surf = (cairo_image_surface_t *) surf; |
1975 | | |
1976 | 3.61k | if (_cairo_image_analyze_transparency (img_surf) == CAIRO_IMAGE_HAS_ALPHA) |
1977 | 523 | surface->has_bilevel_alpha = FALSE; |
1978 | | |
1979 | 3.61k | } else { |
1980 | 0 | if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL)) |
1981 | 0 | surface->has_bilevel_alpha = FALSE; |
1982 | 0 | } |
1983 | | |
1984 | 4.66k | cairo_surface_destroy (free_me); |
1985 | 4.66k | return; |
1986 | | |
1987 | 792k | } else if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { |
1988 | 0 | cairo_surface_t *image; |
1989 | 0 | cairo_surface_t *raster; |
1990 | |
|
1991 | 0 | image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); |
1992 | 0 | raster = _cairo_raster_source_pattern_acquire (source, image, NULL); |
1993 | 0 | cairo_surface_destroy (image); |
1994 | 0 | if (raster) { |
1995 | 0 | if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) { |
1996 | 0 | if (_cairo_image_analyze_transparency ((cairo_image_surface_t *)raster) == CAIRO_IMAGE_HAS_ALPHA) |
1997 | 0 | surface->has_bilevel_alpha = FALSE; |
1998 | 0 | } |
1999 | |
|
2000 | 0 | _cairo_raster_source_pattern_release (source, raster); |
2001 | 0 | if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) |
2002 | 0 | return; |
2003 | 0 | } |
2004 | 0 | } |
2005 | | |
2006 | 792k | if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL)) |
2007 | 2.26k | surface->has_bilevel_alpha = FALSE; |
2008 | 792k | } |
2009 | | |
2010 | | static cairo_status_t |
2011 | | _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, |
2012 | | cairo_recording_surface_replay_params_t *params) |
2013 | 6.03k | { |
2014 | 6.03k | cairo_surface_wrapper_t wrapper; |
2015 | 6.03k | cairo_command_t **elements; |
2016 | 6.03k | cairo_recording_regions_array_t *regions_array = NULL; |
2017 | 6.03k | cairo_recording_region_element_t *region_elements = NULL; |
2018 | 6.03k | cairo_int_status_t status = CAIRO_STATUS_SUCCESS; |
2019 | 6.03k | cairo_rectangle_int_t extents; |
2020 | 6.03k | cairo_bool_t use_indices = FALSE; |
2021 | 6.03k | const cairo_rectangle_int_t *r; |
2022 | 6.03k | unsigned int i, num_elements; |
2023 | | |
2024 | 6.03k | if (unlikely (surface->base.status)) |
2025 | 0 | return surface->base.status; |
2026 | | |
2027 | 6.03k | if (unlikely (params->target->status)) |
2028 | 0 | return params->target->status; |
2029 | | |
2030 | 6.03k | if (unlikely (surface->base.finished)) |
2031 | 0 | return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); |
2032 | | |
2033 | 6.03k | if (surface->base.is_clear) |
2034 | 433 | return CAIRO_STATUS_SUCCESS; |
2035 | | |
2036 | 6.03k | assert (_cairo_surface_is_recording (&surface->base)); |
2037 | | |
2038 | 5.59k | if (params->regions_id != 0) { |
2039 | 4.23k | regions_array = _cairo_recording_surface_region_array_find (surface, params->regions_id); |
2040 | 4.23k | assert (regions_array != NULL); |
2041 | 4.23k | } |
2042 | | |
2043 | 5.59k | _cairo_surface_wrapper_init (&wrapper, params->target); |
2044 | 5.59k | if (params->surface_extents) |
2045 | 0 | _cairo_surface_wrapper_intersect_extents (&wrapper, params->surface_extents); |
2046 | 5.59k | r = &_cairo_unbounded_rectangle; |
2047 | 5.59k | if (! surface->unbounded && !params->surface_is_unbounded) { |
2048 | 4.57k | _cairo_surface_wrapper_intersect_extents (&wrapper, &surface->extents); |
2049 | 4.57k | r = &surface->extents; |
2050 | 4.57k | } |
2051 | 5.59k | _cairo_surface_wrapper_set_inverse_transform (&wrapper, params->surface_transform); |
2052 | 5.59k | _cairo_surface_wrapper_set_clip (&wrapper, params->target_clip); |
2053 | | |
2054 | 5.59k | if (params->foreground_color) { |
2055 | 0 | params->target->foreground_source = _cairo_pattern_create_solid (params->foreground_color); |
2056 | 0 | params->target->foreground_used = FALSE; |
2057 | 0 | } |
2058 | | |
2059 | | /* Compute the extents of the target clip in recorded device space */ |
2060 | 5.59k | if (! _cairo_surface_wrapper_get_target_extents (&wrapper, params->surface_is_unbounded, &extents)) |
2061 | 0 | goto done; |
2062 | | |
2063 | 5.59k | surface->has_bilevel_alpha = TRUE; |
2064 | 5.59k | surface->has_only_op_over = TRUE; |
2065 | | |
2066 | 5.59k | num_elements = surface->commands.num_elements; |
2067 | 5.59k | if (regions_array) { |
2068 | 4.23k | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2069 | | /* Re-running create regions with the same region id is not supported. */ |
2070 | 2.27k | assert (_cairo_array_num_elements (®ions_array->regions) == 0); |
2071 | 2.27k | void *array_elems; |
2072 | 2.27k | status = _cairo_array_allocate (®ions_array->regions, num_elements, &array_elems); |
2073 | 2.27k | if (unlikely (status)) |
2074 | 0 | return status; |
2075 | | |
2076 | | /* Set regions to CAIRO_RECORDING_REGION_ALL and ids to 0 */ |
2077 | 2.27k | memset (array_elems, 0, num_elements * sizeof (cairo_recording_region_element_t)); |
2078 | 2.27k | } else { |
2079 | 1.96k | assert (_cairo_array_num_elements (®ions_array->regions) == num_elements); |
2080 | 1.96k | } |
2081 | 4.23k | } |
2082 | | |
2083 | 5.59k | elements = _cairo_array_index (&surface->commands, 0); |
2084 | 5.59k | if (regions_array) |
2085 | 4.23k | region_elements = _cairo_array_index (®ions_array->regions, 0); |
2086 | | |
2087 | 5.59k | if (!params->replay_all && (extents.width < r->width || extents.height < r->height)) { |
2088 | 454 | num_elements = |
2089 | 454 | _cairo_recording_surface_get_visible_commands (surface, &extents); |
2090 | 454 | use_indices = num_elements != surface->commands.num_elements; |
2091 | 454 | } |
2092 | | |
2093 | 5.59k | cairo_bool_t target_is_analysis = _cairo_surface_is_analysis (params->target); |
2094 | | |
2095 | 1.59M | for (i = 0; i < num_elements; i++) { |
2096 | 1.58M | cairo_command_t *command = elements[use_indices ? surface->indices[i] : i]; |
2097 | 1.58M | cairo_recording_region_element_t *region_element = NULL; |
2098 | 1.58M | unsigned int source_region_id = 0; |
2099 | 1.58M | unsigned int mask_region_id = 0; |
2100 | | |
2101 | 1.58M | if (region_elements) |
2102 | 1.58M | region_element = ®ion_elements[use_indices ? surface->indices[i] : i]; |
2103 | | |
2104 | 1.58M | if (region_element && params->type == CAIRO_RECORDING_REPLAY_REGION && |
2105 | 789k | region_element->region != params->region) |
2106 | 0 | { |
2107 | 0 | continue; |
2108 | 0 | } |
2109 | | |
2110 | 1.58M | if (! _cairo_rectangle_intersects (&extents, &command->header.extents)) { |
2111 | 0 | if (command->header.type != CAIRO_COMMAND_TAG) |
2112 | 0 | continue; |
2113 | 0 | } |
2114 | | |
2115 | | |
2116 | 1.58M | if (params->target->backend->command_id) { |
2117 | 1.58M | status = params->target->backend->command_id (params->target, params->regions_id, i); |
2118 | 1.58M | if (unlikely (status)) |
2119 | 0 | return status; |
2120 | 1.58M | } |
2121 | | |
2122 | 1.58M | switch (command->header.type) { |
2123 | 3.69k | case CAIRO_COMMAND_PAINT: |
2124 | 3.69k | if (region_element) |
2125 | 3.64k | source_region_id = region_element->source_id; |
2126 | | |
2127 | 3.69k | status = _cairo_surface_wrapper_paint (&wrapper, |
2128 | 3.69k | command->header.op, |
2129 | 3.69k | &command->paint.source.base, |
2130 | 3.69k | source_region_id, |
2131 | 3.69k | command->header.clip); |
2132 | 3.69k | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2133 | 1.82k | _cairo_recording_surface_merge_source_attributes (surface, |
2134 | 1.82k | command->header.op, |
2135 | 1.82k | &command->paint.source.base); |
2136 | 1.82k | if (region_element && target_is_analysis) |
2137 | 1.82k | region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); |
2138 | 1.82k | } |
2139 | 3.69k | break; |
2140 | | |
2141 | 4.21k | case CAIRO_COMMAND_MASK: |
2142 | 4.21k | if (region_element) { |
2143 | 3.44k | source_region_id = region_element->source_id; |
2144 | 3.44k | mask_region_id = region_element->mask_id; |
2145 | 3.44k | } |
2146 | | |
2147 | 4.21k | status = _cairo_surface_wrapper_mask (&wrapper, |
2148 | 4.21k | command->header.op, |
2149 | 4.21k | &command->mask.source.base, |
2150 | 4.21k | source_region_id, |
2151 | 4.21k | &command->mask.mask.base, |
2152 | 4.21k | mask_region_id, |
2153 | 4.21k | command->header.clip); |
2154 | 4.21k | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2155 | 1.73k | _cairo_recording_surface_merge_source_attributes (surface, |
2156 | 1.73k | command->header.op, |
2157 | 1.73k | &command->mask.source.base); |
2158 | 1.73k | _cairo_recording_surface_merge_source_attributes (surface, |
2159 | 1.73k | command->header.op, |
2160 | 1.73k | &command->mask.mask.base); |
2161 | 1.73k | if (region_element && target_is_analysis) { |
2162 | 1.73k | region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); |
2163 | 1.73k | region_element->mask_id = _cairo_analysis_surface_get_mask_region_id (params->target); |
2164 | 1.73k | } |
2165 | 1.73k | } |
2166 | 4.21k | break; |
2167 | | |
2168 | 68.9k | case CAIRO_COMMAND_STROKE: |
2169 | 68.9k | if (region_element) |
2170 | 68.3k | source_region_id = region_element->source_id; |
2171 | | |
2172 | 68.9k | status = _cairo_surface_wrapper_stroke (&wrapper, |
2173 | 68.9k | command->header.op, |
2174 | 68.9k | &command->stroke.source.base, |
2175 | 68.9k | source_region_id, |
2176 | 68.9k | &command->stroke.path, |
2177 | 68.9k | &command->stroke.style, |
2178 | 68.9k | &command->stroke.ctm, |
2179 | 68.9k | &command->stroke.ctm_inverse, |
2180 | 68.9k | command->stroke.tolerance, |
2181 | 68.9k | command->stroke.antialias, |
2182 | 68.9k | command->header.clip); |
2183 | 68.9k | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2184 | 35.9k | _cairo_recording_surface_merge_source_attributes (surface, |
2185 | 35.9k | command->header.op, |
2186 | 35.9k | &command->stroke.source.base); |
2187 | 35.9k | if (region_element && target_is_analysis) |
2188 | 35.9k | region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); |
2189 | 35.9k | } |
2190 | 68.9k | break; |
2191 | | |
2192 | 38.7k | case CAIRO_COMMAND_FILL: |
2193 | 38.7k | status = CAIRO_INT_STATUS_UNSUPPORTED; |
2194 | 38.7k | if (region_element) |
2195 | 38.0k | source_region_id = region_element->source_id; |
2196 | | |
2197 | 38.7k | if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) { |
2198 | 19.0k | cairo_command_t *stroke_command = NULL; |
2199 | 19.0k | cairo_recording_region_element_t *stroke_region_element = NULL; |
2200 | 19.0k | unsigned stroke_region_id = 0; |
2201 | | |
2202 | | /* The analysis surface does not implement |
2203 | | * fill_stroke. When creating regions the fill and |
2204 | | * stroke commands are tested separately. |
2205 | | */ |
2206 | 19.0k | if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) { |
2207 | 18.8k | stroke_command = elements[i + 1]; |
2208 | 18.8k | if (region_elements) |
2209 | 18.8k | stroke_region_element = ®ion_elements[i + 1]; |
2210 | 18.8k | } |
2211 | | |
2212 | 19.0k | if (stroke_region_element) |
2213 | 18.8k | stroke_region_id = stroke_region_element->source_id; |
2214 | | |
2215 | 19.0k | if (stroke_command && stroke_region_element && |
2216 | 18.8k | params->type == CAIRO_RECORDING_REPLAY_REGION && |
2217 | 18.8k | params->region != CAIRO_RECORDING_REGION_ALL) |
2218 | 18.8k | { |
2219 | 18.8k | if (stroke_region_element->region != params->region) |
2220 | 0 | stroke_command = NULL; |
2221 | 18.8k | } |
2222 | | |
2223 | 19.0k | if (stroke_command != NULL && |
2224 | 18.8k | stroke_command->header.type == CAIRO_COMMAND_STROKE && |
2225 | 6.76k | _cairo_path_fixed_equal (&command->fill.path, |
2226 | 6.76k | &stroke_command->stroke.path) && |
2227 | 3.61k | _cairo_clip_equal (command->header.clip, |
2228 | 3.61k | stroke_command->header.clip)) |
2229 | 3.09k | { |
2230 | 3.09k | status = _cairo_surface_wrapper_fill_stroke (&wrapper, |
2231 | 3.09k | command->header.op, |
2232 | 3.09k | &command->fill.source.base, |
2233 | 3.09k | source_region_id, |
2234 | 3.09k | command->fill.fill_rule, |
2235 | 3.09k | command->fill.tolerance, |
2236 | 3.09k | command->fill.antialias, |
2237 | 3.09k | &command->fill.path, |
2238 | 3.09k | stroke_command->header.op, |
2239 | 3.09k | &stroke_command->stroke.source.base, |
2240 | 3.09k | stroke_region_id, |
2241 | 3.09k | &stroke_command->stroke.style, |
2242 | 3.09k | &stroke_command->stroke.ctm, |
2243 | 3.09k | &stroke_command->stroke.ctm_inverse, |
2244 | 3.09k | stroke_command->stroke.tolerance, |
2245 | 3.09k | stroke_command->stroke.antialias, |
2246 | 3.09k | command->header.clip); |
2247 | 3.09k | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2248 | 0 | _cairo_recording_surface_merge_source_attributes (surface, |
2249 | 0 | command->header.op, |
2250 | 0 | &command->fill.source.base); |
2251 | 0 | _cairo_recording_surface_merge_source_attributes (surface, |
2252 | 0 | command->header.op, |
2253 | 0 | &command->stroke.source.base); |
2254 | 0 | } |
2255 | 3.09k | i++; |
2256 | 3.09k | } |
2257 | 19.0k | } |
2258 | 38.7k | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
2259 | 35.6k | status = _cairo_surface_wrapper_fill (&wrapper, |
2260 | 35.6k | command->header.op, |
2261 | 35.6k | &command->fill.source.base, |
2262 | 35.6k | source_region_id, |
2263 | 35.6k | &command->fill.path, |
2264 | 35.6k | command->fill.fill_rule, |
2265 | 35.6k | command->fill.tolerance, |
2266 | 35.6k | command->fill.antialias, |
2267 | 35.6k | command->header.clip); |
2268 | 35.6k | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2269 | 19.0k | _cairo_recording_surface_merge_source_attributes (surface, |
2270 | 19.0k | command->header.op, |
2271 | 19.0k | &command->fill.source.base); |
2272 | 19.0k | if (region_element && target_is_analysis) |
2273 | 19.0k | region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); |
2274 | 19.0k | } |
2275 | 35.6k | } |
2276 | 38.7k | break; |
2277 | | |
2278 | 1.47M | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
2279 | 1.47M | if (region_element) |
2280 | 1.47M | source_region_id = region_element->source_id; |
2281 | | |
2282 | 1.47M | status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, |
2283 | 1.47M | command->header.op, |
2284 | 1.47M | &command->show_text_glyphs.source.base, |
2285 | 1.47M | source_region_id, |
2286 | 1.47M | command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, |
2287 | 1.47M | command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs, |
2288 | 1.47M | command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, |
2289 | 1.47M | command->show_text_glyphs.cluster_flags, |
2290 | 1.47M | command->show_text_glyphs.scaled_font, |
2291 | 1.47M | command->header.clip); |
2292 | 1.47M | if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { |
2293 | 736k | _cairo_recording_surface_merge_source_attributes (surface, |
2294 | 736k | command->header.op, |
2295 | 736k | &command->show_text_glyphs.source.base); |
2296 | 736k | if (region_element && target_is_analysis) |
2297 | 736k | region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); |
2298 | | |
2299 | 736k | } |
2300 | 1.47M | break; |
2301 | | |
2302 | 0 | case CAIRO_COMMAND_TAG: |
2303 | 0 | status = _cairo_surface_wrapper_tag (&wrapper, |
2304 | 0 | command->tag.begin, |
2305 | 0 | command->tag.tag_name, |
2306 | 0 | command->tag.attributes); |
2307 | 0 | break; |
2308 | | |
2309 | 0 | default: |
2310 | 0 | ASSERT_NOT_REACHED; |
2311 | 1.58M | } |
2312 | | |
2313 | | /* It's possible that a degenerate clip caused the command to end up doing nothing when replayed. */ |
2314 | 1.58M | if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) |
2315 | 0 | status = CAIRO_INT_STATUS_SUCCESS; |
2316 | | |
2317 | 1.58M | if (params->type == CAIRO_RECORDING_CREATE_REGIONS && region_element) { |
2318 | 795k | if (status == CAIRO_INT_STATUS_SUCCESS) { |
2319 | 795k | region_element->region = CAIRO_RECORDING_REGION_NATIVE; |
2320 | 795k | } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { |
2321 | 0 | region_element->region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK; |
2322 | 0 | status = CAIRO_INT_STATUS_SUCCESS; |
2323 | 0 | } else { |
2324 | 0 | assert (_cairo_int_status_is_error (status)); |
2325 | 0 | } |
2326 | 795k | } |
2327 | | |
2328 | 1.58M | if (unlikely (status)) |
2329 | 5 | break; |
2330 | 1.58M | } |
2331 | | |
2332 | 5.59k | done: |
2333 | 5.59k | if (params->foreground_color) { |
2334 | 0 | cairo_pattern_destroy (params->target->foreground_source); |
2335 | 0 | params->target->foreground_source = NULL; |
2336 | 0 | params->foreground_used = params->target->foreground_used; |
2337 | 0 | } |
2338 | | |
2339 | 5.59k | _cairo_surface_wrapper_fini (&wrapper); |
2340 | 5.59k | return _cairo_surface_set_error (&surface->base, status); |
2341 | 5.59k | } |
2342 | | |
2343 | | cairo_status_t |
2344 | | _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface, |
2345 | | long unsigned index, |
2346 | | cairo_surface_t *target) |
2347 | 0 | { |
2348 | 0 | cairo_surface_wrapper_t wrapper; |
2349 | 0 | cairo_command_t **elements, *command; |
2350 | 0 | cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; |
2351 | |
|
2352 | 0 | if (unlikely (surface->base.status)) |
2353 | 0 | return surface->base.status; |
2354 | | |
2355 | 0 | if (unlikely (target->status)) |
2356 | 0 | return target->status; |
2357 | | |
2358 | 0 | if (unlikely (surface->base.finished)) |
2359 | 0 | return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); |
2360 | | |
2361 | 0 | assert (_cairo_surface_is_recording (&surface->base)); |
2362 | | |
2363 | | /* XXX |
2364 | | * Use a surface wrapper because we may want to do transformed |
2365 | | * replay in the future. |
2366 | | */ |
2367 | 0 | _cairo_surface_wrapper_init (&wrapper, target); |
2368 | |
|
2369 | 0 | if (index > surface->commands.num_elements) |
2370 | 0 | return _cairo_error (CAIRO_STATUS_READ_ERROR); |
2371 | | |
2372 | 0 | elements = _cairo_array_index (&surface->commands, 0); |
2373 | 0 | command = elements[index]; |
2374 | 0 | switch (command->header.type) { |
2375 | 0 | case CAIRO_COMMAND_PAINT: |
2376 | 0 | status = _cairo_surface_wrapper_paint (&wrapper, |
2377 | 0 | command->header.op, |
2378 | 0 | &command->paint.source.base, |
2379 | 0 | 0, |
2380 | 0 | command->header.clip); |
2381 | 0 | break; |
2382 | | |
2383 | 0 | case CAIRO_COMMAND_MASK: |
2384 | 0 | status = _cairo_surface_wrapper_mask (&wrapper, |
2385 | 0 | command->header.op, |
2386 | 0 | &command->mask.source.base, |
2387 | 0 | 0, |
2388 | 0 | &command->mask.mask.base, |
2389 | 0 | 0, |
2390 | 0 | command->header.clip); |
2391 | 0 | break; |
2392 | | |
2393 | 0 | case CAIRO_COMMAND_STROKE: |
2394 | 0 | status = _cairo_surface_wrapper_stroke (&wrapper, |
2395 | 0 | command->header.op, |
2396 | 0 | &command->stroke.source.base, |
2397 | 0 | 0, |
2398 | 0 | &command->stroke.path, |
2399 | 0 | &command->stroke.style, |
2400 | 0 | &command->stroke.ctm, |
2401 | 0 | &command->stroke.ctm_inverse, |
2402 | 0 | command->stroke.tolerance, |
2403 | 0 | command->stroke.antialias, |
2404 | 0 | command->header.clip); |
2405 | 0 | break; |
2406 | | |
2407 | 0 | case CAIRO_COMMAND_FILL: |
2408 | 0 | status = _cairo_surface_wrapper_fill (&wrapper, |
2409 | 0 | command->header.op, |
2410 | 0 | &command->fill.source.base, |
2411 | 0 | 0, |
2412 | 0 | &command->fill.path, |
2413 | 0 | command->fill.fill_rule, |
2414 | 0 | command->fill.tolerance, |
2415 | 0 | command->fill.antialias, |
2416 | 0 | command->header.clip); |
2417 | 0 | break; |
2418 | | |
2419 | 0 | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
2420 | 0 | status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, |
2421 | 0 | command->header.op, |
2422 | 0 | &command->show_text_glyphs.source.base, |
2423 | 0 | 0, |
2424 | 0 | command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, |
2425 | 0 | command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs, |
2426 | 0 | command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, |
2427 | 0 | command->show_text_glyphs.cluster_flags, |
2428 | 0 | command->show_text_glyphs.scaled_font, |
2429 | 0 | command->header.clip); |
2430 | 0 | break; |
2431 | | |
2432 | 0 | case CAIRO_COMMAND_TAG: |
2433 | 0 | status = _cairo_surface_wrapper_tag (&wrapper, |
2434 | 0 | command->tag.begin, |
2435 | 0 | command->tag.tag_name, |
2436 | 0 | command->tag.attributes); |
2437 | 0 | break; |
2438 | | |
2439 | 0 | default: |
2440 | 0 | ASSERT_NOT_REACHED; |
2441 | 0 | } |
2442 | | |
2443 | 0 | _cairo_surface_wrapper_fini (&wrapper); |
2444 | 0 | return _cairo_surface_set_error (&surface->base, status); |
2445 | 0 | } |
2446 | | /** |
2447 | | * _cairo_recording_surface_replay: |
2448 | | * @surface: the #cairo_recording_surface_t |
2449 | | * @target: a target #cairo_surface_t onto which to replay the operations |
2450 | | * @width_pixels: width of the surface, in pixels |
2451 | | * @height_pixels: height of the surface, in pixels |
2452 | | * |
2453 | | * A recording surface can be "replayed" against any target surface, |
2454 | | * after which the results in target will be identical to the results |
2455 | | * that would have been obtained if the original operations applied to |
2456 | | * the recording surface had instead been applied to the target surface. |
2457 | | **/ |
2458 | | cairo_status_t |
2459 | | _cairo_recording_surface_replay (cairo_surface_t *surface, |
2460 | | cairo_surface_t *target) |
2461 | 1.29k | { |
2462 | 1.29k | cairo_recording_surface_replay_params_t params; |
2463 | | |
2464 | 1.29k | params.surface_extents = NULL; |
2465 | 1.29k | params.surface_transform = NULL; |
2466 | 1.29k | params.target = target; |
2467 | 1.29k | params.target_clip = NULL; |
2468 | 1.29k | params.surface_is_unbounded = FALSE; |
2469 | 1.29k | params.type = CAIRO_RECORDING_REPLAY; |
2470 | 1.29k | params.region = CAIRO_RECORDING_REGION_ALL; |
2471 | 1.29k | params.regions_id = 0; |
2472 | 1.29k | params.foreground_color = NULL; |
2473 | 1.29k | params.replay_all = FALSE; |
2474 | | |
2475 | 1.29k | return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); |
2476 | 1.29k | } |
2477 | | |
2478 | | cairo_status_t |
2479 | | _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface, |
2480 | | cairo_surface_t *target, |
2481 | | const cairo_color_t *foreground_color, |
2482 | | cairo_bool_t *foreground_used) |
2483 | 3 | { |
2484 | 3 | cairo_recording_surface_replay_params_t params; |
2485 | 3 | cairo_status_t status; |
2486 | | |
2487 | 3 | params.surface_extents = NULL; |
2488 | 3 | params.surface_transform = NULL; |
2489 | 3 | params.target = target; |
2490 | 3 | params.target_clip = NULL; |
2491 | 3 | params.surface_is_unbounded = FALSE; |
2492 | 3 | params.type = CAIRO_RECORDING_REPLAY; |
2493 | 3 | params.region = CAIRO_RECORDING_REGION_ALL; |
2494 | 3 | params.regions_id = 0; |
2495 | 3 | params.foreground_color = foreground_color; |
2496 | 3 | params.foreground_used = FALSE; |
2497 | 3 | params.replay_all = FALSE; |
2498 | | |
2499 | 3 | status = _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); |
2500 | 3 | *foreground_used = params.foreground_used; |
2501 | | |
2502 | 3 | return status; |
2503 | 3 | } |
2504 | | |
2505 | | cairo_status_t |
2506 | | _cairo_recording_surface_replay_with_transform (cairo_surface_t *surface, |
2507 | | const cairo_matrix_t *surface_transform, |
2508 | | cairo_surface_t *target, |
2509 | | cairo_bool_t surface_is_unbounded, |
2510 | | cairo_bool_t replay_all) |
2511 | 25 | { |
2512 | 25 | cairo_recording_surface_replay_params_t params; |
2513 | | |
2514 | 25 | params.surface_extents = NULL; |
2515 | 25 | params.surface_transform = surface_transform; |
2516 | 25 | params.target = target; |
2517 | 25 | params.target_clip = NULL; |
2518 | 25 | params.surface_is_unbounded = surface_is_unbounded; |
2519 | 25 | params.type = CAIRO_RECORDING_REPLAY; |
2520 | 25 | params.region = CAIRO_RECORDING_REGION_ALL; |
2521 | 25 | params.regions_id = 0; |
2522 | 25 | params.foreground_color = NULL; |
2523 | 25 | params.replay_all = replay_all; |
2524 | | |
2525 | 25 | return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); |
2526 | 25 | } |
2527 | | |
2528 | | cairo_status_t |
2529 | | _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface, |
2530 | | const cairo_matrix_t *surface_transform, |
2531 | | cairo_surface_t *target, |
2532 | | const cairo_clip_t *target_clip) |
2533 | 80 | { |
2534 | 80 | cairo_recording_surface_replay_params_t params; |
2535 | | |
2536 | 80 | params.surface_extents = NULL; |
2537 | 80 | params.surface_transform = surface_transform; |
2538 | 80 | params.target = target; |
2539 | 80 | params.target_clip = target_clip; |
2540 | 80 | params.surface_is_unbounded = FALSE; |
2541 | 80 | params.type = CAIRO_RECORDING_REPLAY; |
2542 | 80 | params.region = CAIRO_RECORDING_REGION_ALL; |
2543 | 80 | params.regions_id = 0; |
2544 | 80 | params.foreground_color = NULL; |
2545 | 80 | params.replay_all = FALSE; |
2546 | | |
2547 | 80 | return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); |
2548 | 80 | } |
2549 | | |
2550 | | /* Replay recording to surface. When the return status of each operation is |
2551 | | * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or |
2552 | | * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation |
2553 | | * will be stored in the recording surface. Any other status will abort the |
2554 | | * replay and return the status. |
2555 | | */ |
2556 | | cairo_status_t |
2557 | | _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface, |
2558 | | unsigned int regions_id, |
2559 | | const cairo_matrix_t *surface_transform, |
2560 | | cairo_surface_t *target, |
2561 | | cairo_bool_t surface_is_unbounded, |
2562 | | cairo_bool_t replay_all) |
2563 | 2.66k | { |
2564 | 2.66k | cairo_recording_surface_replay_params_t params; |
2565 | | |
2566 | 2.66k | params.surface_extents = NULL; |
2567 | 2.66k | params.surface_transform = surface_transform; |
2568 | 2.66k | params.target = target; |
2569 | 2.66k | params.target_clip = NULL; |
2570 | 2.66k | params.surface_is_unbounded = surface_is_unbounded; |
2571 | 2.66k | params.type = CAIRO_RECORDING_CREATE_REGIONS; |
2572 | 2.66k | params.region = CAIRO_RECORDING_REGION_ALL; |
2573 | 2.66k | params.regions_id = regions_id; |
2574 | 2.66k | params.foreground_color = NULL; |
2575 | 2.66k | params.replay_all = replay_all; |
2576 | | |
2577 | 2.66k | return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); |
2578 | 2.66k | } |
2579 | | |
2580 | | cairo_status_t |
2581 | | _cairo_recording_surface_replay_region (cairo_surface_t *surface, |
2582 | | unsigned int regions_id, |
2583 | | const cairo_rectangle_int_t *surface_extents, |
2584 | | cairo_surface_t *target, |
2585 | | cairo_recording_region_type_t region) |
2586 | 1.96k | { |
2587 | 1.96k | cairo_recording_surface_replay_params_t params; |
2588 | | |
2589 | 1.96k | params.surface_extents = surface_extents; |
2590 | 1.96k | params.surface_transform = NULL; |
2591 | 1.96k | params.target = target; |
2592 | 1.96k | params.target_clip = NULL; |
2593 | 1.96k | params.surface_is_unbounded = FALSE; |
2594 | 1.96k | params.type = CAIRO_RECORDING_REPLAY_REGION; |
2595 | 1.96k | params.region = region; |
2596 | 1.96k | params.regions_id = regions_id; |
2597 | 1.96k | params.foreground_color = NULL; |
2598 | 1.96k | params.replay_all = FALSE; |
2599 | | |
2600 | 1.96k | return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); |
2601 | 1.96k | } |
2602 | | |
2603 | | static cairo_status_t |
2604 | | _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, |
2605 | | cairo_box_t *bbox, |
2606 | | const cairo_matrix_t *transform) |
2607 | 579 | { |
2608 | 579 | cairo_surface_t *null_surface; |
2609 | 579 | cairo_surface_t *analysis_surface; |
2610 | 579 | cairo_status_t status; |
2611 | | |
2612 | 579 | null_surface = _cairo_null_surface_create (surface->base.content); |
2613 | 579 | analysis_surface = _cairo_analysis_surface_create (null_surface, FALSE); |
2614 | 579 | cairo_surface_destroy (null_surface); |
2615 | | |
2616 | 579 | status = analysis_surface->status; |
2617 | 579 | if (unlikely (status)) |
2618 | 0 | return status; |
2619 | | |
2620 | 579 | if (transform != NULL) |
2621 | 579 | _cairo_analysis_surface_set_ctm (analysis_surface, transform); |
2622 | | |
2623 | 579 | status = _cairo_recording_surface_replay (&surface->base, analysis_surface); |
2624 | 579 | _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox); |
2625 | 579 | cairo_surface_destroy (analysis_surface); |
2626 | | |
2627 | 579 | return status; |
2628 | 579 | } |
2629 | | |
2630 | | /** |
2631 | | * cairo_recording_surface_ink_extents: |
2632 | | * @surface: a #cairo_recording_surface_t |
2633 | | * @x0: the x-coordinate of the top-left of the ink bounding box |
2634 | | * @y0: the y-coordinate of the top-left of the ink bounding box |
2635 | | * @width: the width of the ink bounding box |
2636 | | * @height: the height of the ink bounding box |
2637 | | * |
2638 | | * Measures the extents of the operations stored within the recording-surface. |
2639 | | * This is useful to compute the required size of an image surface (or |
2640 | | * equivalent) into which to replay the full sequence of drawing operations. |
2641 | | * |
2642 | | * Since: 1.10 |
2643 | | **/ |
2644 | | void |
2645 | | cairo_recording_surface_ink_extents (cairo_surface_t *surface, |
2646 | | double *x0, |
2647 | | double *y0, |
2648 | | double *width, |
2649 | | double *height) |
2650 | 0 | { |
2651 | 0 | cairo_status_t status; |
2652 | 0 | cairo_box_t bbox; |
2653 | |
|
2654 | 0 | memset (&bbox, 0, sizeof (bbox)); |
2655 | |
|
2656 | 0 | if (surface->status || ! _cairo_surface_is_recording (surface)) { |
2657 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
2658 | 0 | goto DONE; |
2659 | 0 | } |
2660 | | |
2661 | 0 | status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface, |
2662 | 0 | &bbox, |
2663 | 0 | NULL); |
2664 | 0 | if (unlikely (status)) |
2665 | 0 | status = _cairo_surface_set_error (surface, status); |
2666 | |
|
2667 | 0 | DONE: |
2668 | 0 | if (x0) |
2669 | 0 | *x0 = _cairo_fixed_to_double (bbox.p1.x); |
2670 | 0 | if (y0) |
2671 | 0 | *y0 = _cairo_fixed_to_double (bbox.p1.y); |
2672 | 0 | if (width) |
2673 | 0 | *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x); |
2674 | 0 | if (height) |
2675 | 0 | *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); |
2676 | 0 | } |
2677 | | |
2678 | | cairo_status_t |
2679 | | _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface, |
2680 | | cairo_box_t *bbox, |
2681 | | const cairo_matrix_t *transform) |
2682 | 3 | { |
2683 | 3 | if (! surface->unbounded) { |
2684 | 0 | _cairo_box_from_rectangle (bbox, &surface->extents); |
2685 | 0 | if (transform != NULL) |
2686 | 0 | _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL); |
2687 | |
|
2688 | 0 | return CAIRO_STATUS_SUCCESS; |
2689 | 0 | } |
2690 | | |
2691 | 3 | return _recording_surface_get_ink_bbox (surface, bbox, transform); |
2692 | 3 | } |
2693 | | |
2694 | | cairo_status_t |
2695 | | _cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, |
2696 | | cairo_box_t *bbox, |
2697 | | const cairo_matrix_t *transform) |
2698 | 576 | { |
2699 | 576 | return _recording_surface_get_ink_bbox (surface, bbox, transform); |
2700 | 576 | } |
2701 | | |
2702 | | /** |
2703 | | * cairo_recording_surface_get_extents: |
2704 | | * @surface: a #cairo_recording_surface_t |
2705 | | * @extents: the #cairo_rectangle_t to be assigned the extents |
2706 | | * |
2707 | | * Get the extents of the recording-surface. |
2708 | | * |
2709 | | * Return value: %TRUE if the surface is bounded, of recording type, and |
2710 | | * not in an error state, otherwise %FALSE |
2711 | | * |
2712 | | * Since: 1.12 |
2713 | | **/ |
2714 | | cairo_bool_t |
2715 | | cairo_recording_surface_get_extents (cairo_surface_t *surface, |
2716 | | cairo_rectangle_t *extents) |
2717 | 0 | { |
2718 | 0 | cairo_recording_surface_t *record; |
2719 | |
|
2720 | 0 | if (surface->status || ! _cairo_surface_is_recording (surface)) { |
2721 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
2722 | 0 | return FALSE; |
2723 | 0 | } |
2724 | | |
2725 | 0 | record = (cairo_recording_surface_t *)surface; |
2726 | 0 | if (record->unbounded) |
2727 | 0 | return FALSE; |
2728 | | |
2729 | 0 | *extents = record->extents_pixels; |
2730 | 0 | return TRUE; |
2731 | 0 | } |
2732 | | |
2733 | | cairo_bool_t |
2734 | | _cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface) |
2735 | 1.52k | { |
2736 | 1.52k | return surface->has_bilevel_alpha; |
2737 | 1.52k | } |
2738 | | |
2739 | | cairo_bool_t |
2740 | | _cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface) |
2741 | 1.52k | { |
2742 | 1.52k | return surface->has_only_op_over; |
2743 | 1.52k | } |
2744 | | |
2745 | | cairo_bool_t |
2746 | | _cairo_recording_surface_has_tags (cairo_surface_t *surface) |
2747 | 2.72k | { |
2748 | 2.72k | cairo_recording_surface_t *record; |
2749 | | |
2750 | 2.72k | if (surface->status || ! _cairo_surface_is_recording (surface)) { |
2751 | 0 | _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); |
2752 | 0 | return FALSE; |
2753 | 0 | } |
2754 | | |
2755 | 2.72k | record = (cairo_recording_surface_t *)surface; |
2756 | | |
2757 | 2.72k | return record->has_tags; |
2758 | 2.72k | } |
2759 | | |
2760 | | static void |
2761 | | print_indent (FILE *file, int indent) |
2762 | 0 | { |
2763 | 0 | fprintf (file, "%*s", indent * 2, ""); |
2764 | 0 | } |
2765 | | |
2766 | | static void |
2767 | | print_pattern (FILE *file, |
2768 | | const cairo_pattern_t *pattern, |
2769 | | unsigned int region_id, |
2770 | | int indent, |
2771 | | cairo_bool_t recurse) |
2772 | 0 | { |
2773 | 0 | switch (pattern->type) { |
2774 | 0 | case CAIRO_PATTERN_TYPE_SOLID: { |
2775 | 0 | cairo_solid_pattern_t *p = (cairo_solid_pattern_t *) pattern; |
2776 | 0 | if (pattern->is_foreground_marker) { |
2777 | 0 | fprintf (file, "solid foreground\n"); |
2778 | 0 | } else { |
2779 | 0 | fprintf (file, "solid rgba: %f %f %f %f\n", |
2780 | 0 | p->color.red, |
2781 | 0 | p->color.green, |
2782 | 0 | p->color.blue, |
2783 | 0 | p->color.alpha); |
2784 | 0 | } |
2785 | 0 | } break; |
2786 | 0 | case CAIRO_PATTERN_TYPE_SURFACE: { |
2787 | 0 | cairo_surface_pattern_t *p = (cairo_surface_pattern_t *) pattern; |
2788 | 0 | fprintf (file, "surface "); |
2789 | 0 | if (p->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { |
2790 | 0 | fprintf (file, "recording id: %d\n", p->surface->unique_id); |
2791 | 0 | if (recurse) { |
2792 | 0 | _cairo_debug_print_recording_surface (file, p->surface, |
2793 | 0 | region_id, |
2794 | 0 | indent + 1, recurse); |
2795 | 0 | } |
2796 | 0 | } else if (p->surface->type == CAIRO_SURFACE_TYPE_IMAGE) { |
2797 | 0 | cairo_image_surface_t *image = (cairo_image_surface_t *)p->surface; |
2798 | 0 | fprintf (file, "image format: "); |
2799 | 0 | switch (image->format) { |
2800 | 0 | case CAIRO_FORMAT_INVALID: fputs ("INVALID", file); break; |
2801 | 0 | case CAIRO_FORMAT_ARGB32: fputs ("ARGB32", file); break; |
2802 | 0 | case CAIRO_FORMAT_RGB24: fputs ("RGB24", file); break; |
2803 | 0 | case CAIRO_FORMAT_A8: fputs ("A8", file); break; |
2804 | 0 | case CAIRO_FORMAT_A1: fputs ("A1", file); break; |
2805 | 0 | case CAIRO_FORMAT_RGB16_565: fputs ("RGB16_565", file); break; |
2806 | 0 | case CAIRO_FORMAT_RGB30: fputs ("RGB30", file); break; |
2807 | 0 | case CAIRO_FORMAT_RGB96F: fputs ("RGB96F", file); break; |
2808 | 0 | case CAIRO_FORMAT_RGBA128F: fputs ("RGBA128F", file); break; |
2809 | 0 | } |
2810 | 0 | fprintf (file, " width: %d height: %d\n", image->width, image->height); |
2811 | 0 | } else { |
2812 | 0 | fprintf (file, "type %d\n", p->surface->type); |
2813 | 0 | } |
2814 | 0 | } break; |
2815 | 0 | case CAIRO_PATTERN_TYPE_LINEAR: |
2816 | 0 | fprintf (file, "linear\n"); |
2817 | 0 | break; |
2818 | 0 | case CAIRO_PATTERN_TYPE_RADIAL: |
2819 | 0 | fprintf (file, "radial\n"); |
2820 | 0 | break; |
2821 | 0 | case CAIRO_PATTERN_TYPE_MESH: |
2822 | 0 | fprintf (file, "mesh\n"); |
2823 | 0 | break; |
2824 | 0 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
2825 | 0 | fprintf (file, "raster\n"); |
2826 | 0 | break; |
2827 | 0 | } |
2828 | 0 | } |
2829 | | |
2830 | | void |
2831 | | _cairo_debug_print_recording_surface (FILE *file, |
2832 | | cairo_surface_t *surface, |
2833 | | unsigned int regions_id, |
2834 | | int indent, |
2835 | | cairo_bool_t recurse) |
2836 | 0 | { |
2837 | 0 | cairo_command_t **elements; |
2838 | 0 | cairo_recording_region_element_t *region_elements = NULL; |
2839 | 0 | unsigned int i, num_elements; |
2840 | 0 | cairo_recording_surface_t *recording_surface; |
2841 | 0 | cairo_surface_t *free_me = NULL; |
2842 | 0 | char common[100]; |
2843 | |
|
2844 | 0 | if (_cairo_surface_is_snapshot (surface)) |
2845 | 0 | free_me = surface = _cairo_surface_snapshot_get_target (surface); |
2846 | |
|
2847 | 0 | assert (_cairo_surface_is_recording (surface)); |
2848 | 0 | recording_surface = (cairo_recording_surface_t *)surface; |
2849 | |
|
2850 | 0 | print_indent (file, indent); |
2851 | 0 | indent++; |
2852 | 0 | fprintf(file, "recording surface id: %d regions id: %d\n", recording_surface->base.unique_id, regions_id); |
2853 | 0 | num_elements = recording_surface->commands.num_elements; |
2854 | 0 | elements = _cairo_array_index (&recording_surface->commands, 0); |
2855 | |
|
2856 | 0 | if (regions_id != 0) { |
2857 | 0 | cairo_recording_regions_array_t *regions_array; |
2858 | 0 | regions_array = _cairo_recording_surface_region_array_find (recording_surface, regions_id); |
2859 | 0 | assert (regions_array != NULL); |
2860 | 0 | assert (_cairo_array_num_elements (®ions_array->regions) == num_elements); |
2861 | 0 | region_elements = _cairo_array_index (®ions_array->regions, 0); |
2862 | 0 | } |
2863 | |
|
2864 | 0 | for (i = 0; i < num_elements; i++) { |
2865 | 0 | cairo_command_t *command = elements[i]; |
2866 | 0 | unsigned int source_region_id = 0; |
2867 | 0 | unsigned int mask_region_id = 0; |
2868 | |
|
2869 | 0 | common[0] = 0; |
2870 | 0 | if (region_elements) { |
2871 | 0 | cairo_recording_region_element_t *region_element = ®ion_elements[i]; |
2872 | 0 | strcpy (common, "region: "); |
2873 | 0 | switch (region_element->region) { |
2874 | 0 | case CAIRO_RECORDING_REGION_ALL: strcat (common, "all"); break; |
2875 | 0 | case CAIRO_RECORDING_REGION_NATIVE: strcat (common, "native"); break; |
2876 | 0 | case CAIRO_RECORDING_REGION_IMAGE_FALLBACK: strcat (common, "fallback"); break; |
2877 | 0 | } |
2878 | 0 | source_region_id = region_element->source_id; |
2879 | 0 | mask_region_id = region_element->mask_id; |
2880 | 0 | } |
2881 | 0 | sprintf (common + strlen(common), " op: %s", _cairo_debug_operator_to_string (command->header.op)); |
2882 | |
|
2883 | 0 | switch (command->header.type) { |
2884 | 0 | case CAIRO_COMMAND_PAINT: |
2885 | 0 | print_indent (file, indent); |
2886 | 0 | fprintf(file, "%d PAINT %s source: ", i, common); |
2887 | 0 | print_pattern (file, &command->paint.source.base, source_region_id, indent + 1, recurse); |
2888 | 0 | break; |
2889 | | |
2890 | 0 | case CAIRO_COMMAND_MASK: |
2891 | 0 | print_indent (file, indent); |
2892 | 0 | fprintf(file, "%d MASK %s\n", i, common); |
2893 | 0 | print_indent (file, indent + 1); |
2894 | 0 | fprintf(file, "source: "); |
2895 | 0 | print_pattern (file, &command->mask.source.base, source_region_id, indent + 1, recurse); |
2896 | 0 | print_indent (file, indent + 1); |
2897 | 0 | fprintf(file, "mask: "); |
2898 | 0 | print_pattern (file, &command->mask.mask.base, mask_region_id, indent + 1, recurse); |
2899 | 0 | break; |
2900 | | |
2901 | 0 | case CAIRO_COMMAND_STROKE: |
2902 | 0 | print_indent (file, indent); |
2903 | 0 | fprintf(file, "%d STROKE %s source:", i, common); |
2904 | 0 | print_pattern (file, &command->stroke.source.base, source_region_id, indent + 1, recurse); |
2905 | 0 | break; |
2906 | | |
2907 | 0 | case CAIRO_COMMAND_FILL: |
2908 | 0 | print_indent (file, indent); |
2909 | 0 | fprintf(file, "%d FILL %s source: ", i, common); |
2910 | 0 | print_pattern (file, &command->fill.source.base, source_region_id, indent + 1, recurse); |
2911 | 0 | break; |
2912 | | |
2913 | 0 | case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: |
2914 | 0 | print_indent (file, indent); |
2915 | 0 | fprintf(file, "%d SHOW_TEXT_GLYPHS %s font_type: ", i, common); |
2916 | 0 | switch (command->show_text_glyphs.scaled_font->backend->type) { |
2917 | 0 | case CAIRO_FONT_TYPE_TOY: fputs ("toy", file); break; |
2918 | 0 | case CAIRO_FONT_TYPE_FT: fputs ("ft", file); break; |
2919 | 0 | case CAIRO_FONT_TYPE_WIN32: fputs ("win32", file); break; |
2920 | 0 | case CAIRO_FONT_TYPE_QUARTZ: fputs ("quartz", file); break; |
2921 | 0 | case CAIRO_FONT_TYPE_USER: fputs ("user", file); break; |
2922 | 0 | case CAIRO_FONT_TYPE_DWRITE: fputs ("dwrite", file); break; |
2923 | 0 | } |
2924 | 0 | fprintf (file, " glyphs:"); |
2925 | 0 | for (unsigned j = 0; j < command->show_text_glyphs.num_glyphs; j++) |
2926 | 0 | fprintf (file, " %ld", command->show_text_glyphs.glyphs[j].index); |
2927 | 0 | fprintf (file, " source:"); |
2928 | 0 | print_pattern (file, &command->show_text_glyphs.source.base, source_region_id, indent + 1, recurse); |
2929 | 0 | break; |
2930 | | |
2931 | 0 | case CAIRO_COMMAND_TAG: |
2932 | 0 | print_indent (file, indent); |
2933 | 0 | fprintf(file, "%d %s %s '%s'\n", |
2934 | 0 | i, |
2935 | 0 | command->tag.begin ? "BEGIN TAG" : "END TAG", |
2936 | 0 | command->tag.tag_name, command->tag.attributes); |
2937 | 0 | break; |
2938 | | |
2939 | 0 | default: |
2940 | 0 | ASSERT_NOT_REACHED; |
2941 | 0 | } |
2942 | 0 | } |
2943 | 0 | cairo_surface_destroy (free_me); |
2944 | 0 | } |