Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2005 Red Hat, Inc
4 : * Copyright © 2009 Chris Wilson
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it either under the terms of the GNU Lesser General Public
8 : * License version 2.1 as published by the Free Software Foundation
9 : * (the "LGPL") or, at your option, under the terms of the Mozilla
10 : * Public License Version 1.1 (the "MPL"). If you do not alter this
11 : * notice, a recipient may use your version of this file under either
12 : * the MPL or the LGPL.
13 : *
14 : * You should have received a copy of the LGPL along with this library
15 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 : * You should have received a copy of the MPL along with this library
18 : * in the file COPYING-MPL-1.1
19 : *
20 : * The contents of this file are subject to the Mozilla Public License
21 : * Version 1.1 (the "License"); you may not use this file except in
22 : * compliance with the License. You may obtain a copy of the License at
23 : * http://www.mozilla.org/MPL/
24 : *
25 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 : * the specific language governing rights and limitations.
28 : *
29 : * The Original Code is the cairo graphics library.
30 : *
31 : * The Initial Developer of the Original Code is Red Hat, Inc.
32 : *
33 : * Contributor(s):
34 : * Carl Worth <cworth@cworth.org>
35 : * Chris Wilson <chris@chris-wilson.co.uk>
36 : */
37 :
38 : /* This surface supports redirecting all its input to multiple surfaces.
39 : */
40 :
41 : #include "cairoint.h"
42 :
43 : #include "cairo-tee.h"
44 :
45 : #include "cairo-error-private.h"
46 : #include "cairo-tee-surface-private.h"
47 : #include "cairo-surface-wrapper-private.h"
48 :
49 : typedef struct _cairo_tee_surface {
50 : cairo_surface_t base;
51 :
52 : cairo_surface_wrapper_t master;
53 : cairo_array_t slaves;
54 : } cairo_tee_surface_t;
55 :
56 : slim_hidden_proto (cairo_tee_surface_create);
57 : slim_hidden_proto (cairo_tee_surface_add);
58 :
59 : static cairo_surface_t *
60 0 : _cairo_tee_surface_create_similar (void *abstract_surface,
61 : cairo_content_t content,
62 : int width,
63 : int height)
64 : {
65 :
66 0 : cairo_tee_surface_t *other = abstract_surface;
67 : cairo_surface_t *similar;
68 : cairo_surface_t *surface;
69 : cairo_surface_wrapper_t *slaves;
70 : int n, num_slaves;
71 :
72 0 : similar = _cairo_surface_wrapper_create_similar (&other->master,
73 : content, width, height);
74 0 : surface = cairo_tee_surface_create (similar);
75 0 : cairo_surface_destroy (similar);
76 0 : if (unlikely (surface->status))
77 0 : return surface;
78 :
79 0 : num_slaves = _cairo_array_num_elements (&other->slaves);
80 0 : slaves = _cairo_array_index (&other->slaves, 0);
81 0 : for (n = 0; n < num_slaves; n++) {
82 :
83 0 : similar = _cairo_surface_wrapper_create_similar (&slaves[n],
84 : content,
85 : width, height);
86 0 : cairo_tee_surface_add (surface, similar);
87 0 : cairo_surface_destroy (similar);
88 : }
89 :
90 0 : if (unlikely (surface->status)) {
91 0 : cairo_status_t status = surface->status;
92 0 : cairo_surface_destroy (surface);
93 0 : surface = _cairo_surface_create_in_error (status);
94 : }
95 :
96 0 : return surface;
97 : }
98 :
99 : static cairo_status_t
100 0 : _cairo_tee_surface_finish (void *abstract_surface)
101 : {
102 0 : cairo_tee_surface_t *surface = abstract_surface;
103 : cairo_surface_wrapper_t *slaves;
104 : int n, num_slaves;
105 :
106 0 : _cairo_surface_wrapper_fini (&surface->master);
107 :
108 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
109 0 : slaves = _cairo_array_index (&surface->slaves, 0);
110 0 : for (n = 0; n < num_slaves; n++)
111 0 : _cairo_surface_wrapper_fini (&slaves[n]);
112 :
113 0 : _cairo_array_fini (&surface->slaves);
114 :
115 0 : return CAIRO_STATUS_SUCCESS;
116 : }
117 :
118 : static cairo_status_t
119 0 : _cairo_tee_surface_acquire_source_image (void *abstract_surface,
120 : cairo_image_surface_t **image_out,
121 : void **image_extra)
122 : {
123 0 : cairo_tee_surface_t *surface = abstract_surface;
124 : cairo_surface_wrapper_t *slaves;
125 : int num_slaves, n;
126 :
127 : /* we prefer to use a real image surface if available */
128 0 : if (_cairo_surface_is_image (surface->master.target)) {
129 0 : return _cairo_surface_wrapper_acquire_source_image (&surface->master,
130 : image_out, image_extra);
131 : }
132 :
133 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
134 0 : slaves = _cairo_array_index (&surface->slaves, 0);
135 0 : for (n = 0; n < num_slaves; n++) {
136 0 : if (_cairo_surface_is_image (slaves[n].target)) {
137 0 : return _cairo_surface_wrapper_acquire_source_image (&slaves[n],
138 : image_out,
139 : image_extra);
140 : }
141 : }
142 :
143 0 : return _cairo_surface_wrapper_acquire_source_image (&surface->master,
144 : image_out, image_extra);
145 : }
146 :
147 : static void
148 0 : _cairo_tee_surface_release_source_image (void *abstract_surface,
149 : cairo_image_surface_t *image,
150 : void *image_extra)
151 : {
152 0 : cairo_tee_surface_t *surface = abstract_surface;
153 :
154 0 : _cairo_surface_wrapper_release_source_image (&surface->master,
155 : image, image_extra);
156 0 : }
157 :
158 : static cairo_surface_t *
159 0 : _cairo_tee_surface_snapshot (void *abstract_surface)
160 : {
161 0 : cairo_tee_surface_t *surface = abstract_surface;
162 : cairo_surface_wrapper_t *slaves;
163 : int num_slaves, n;
164 :
165 : /* we prefer to use a recording surface for our snapshots */
166 0 : if (_cairo_surface_is_recording (surface->master.target))
167 0 : return _cairo_surface_wrapper_snapshot (&surface->master);
168 :
169 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
170 0 : slaves = _cairo_array_index (&surface->slaves, 0);
171 0 : for (n = 0; n < num_slaves; n++) {
172 0 : if (_cairo_surface_is_recording (slaves[n].target))
173 0 : return _cairo_surface_wrapper_snapshot (&slaves[n]);
174 : }
175 :
176 0 : return _cairo_surface_wrapper_snapshot (&surface->master);
177 : }
178 :
179 : static cairo_bool_t
180 0 : _cairo_tee_surface_get_extents (void *abstract_surface,
181 : cairo_rectangle_int_t *rectangle)
182 : {
183 0 : cairo_tee_surface_t *surface = abstract_surface;
184 :
185 0 : return _cairo_surface_wrapper_get_extents (&surface->master, rectangle);
186 : }
187 :
188 : static void
189 0 : _cairo_tee_surface_get_font_options (void *abstract_surface,
190 : cairo_font_options_t *options)
191 : {
192 0 : cairo_tee_surface_t *surface = abstract_surface;
193 :
194 0 : _cairo_surface_wrapper_get_font_options (&surface->master, options);
195 0 : }
196 :
197 : static const cairo_pattern_t *
198 0 : _cairo_tee_surface_match_source (cairo_tee_surface_t *surface,
199 : const cairo_pattern_t *source,
200 : int index,
201 : cairo_surface_wrapper_t *dest,
202 : cairo_surface_pattern_t *temp)
203 : {
204 : cairo_surface_t *s;
205 0 : cairo_status_t status = cairo_pattern_get_surface ((cairo_pattern_t *)source, &s);
206 0 : if (status == CAIRO_STATUS_SUCCESS &&
207 0 : cairo_surface_get_type (s) == CAIRO_SURFACE_TYPE_TEE) {
208 0 : cairo_surface_t *tee_surf = cairo_tee_surface_index (s, index);
209 0 : if (tee_surf->status == CAIRO_STATUS_SUCCESS &&
210 0 : tee_surf->backend == dest->target->backend) {
211 0 : status = _cairo_pattern_init_copy (&temp->base, source);
212 0 : if (status == CAIRO_STATUS_SUCCESS) {
213 0 : cairo_surface_destroy (temp->surface);
214 0 : temp->surface = tee_surf;
215 0 : cairo_surface_reference (temp->surface);
216 0 : return &temp->base;
217 : }
218 : }
219 : }
220 :
221 0 : return source;
222 : }
223 :
224 : static cairo_int_status_t
225 0 : _cairo_tee_surface_paint (void *abstract_surface,
226 : cairo_operator_t op,
227 : const cairo_pattern_t *source,
228 : cairo_clip_t *clip)
229 : {
230 0 : cairo_tee_surface_t *surface = abstract_surface;
231 : cairo_surface_wrapper_t *slaves;
232 : int n, num_slaves;
233 : cairo_status_t status;
234 : const cairo_pattern_t *matched_source;
235 : cairo_surface_pattern_t temp;
236 :
237 0 : matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp);
238 0 : status = _cairo_surface_wrapper_paint (&surface->master, op, matched_source, clip);
239 0 : if (matched_source == &temp.base) {
240 0 : _cairo_pattern_fini (&temp.base);
241 : }
242 0 : if (unlikely (status))
243 0 : return status;
244 :
245 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
246 0 : slaves = _cairo_array_index (&surface->slaves, 0);
247 0 : for (n = 0; n < num_slaves; n++) {
248 0 : matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp);
249 0 : status = _cairo_surface_wrapper_paint (&slaves[n], op, matched_source, clip);
250 0 : if (matched_source == &temp.base) {
251 0 : _cairo_pattern_fini (&temp.base);
252 : }
253 0 : if (unlikely (status))
254 0 : return status;
255 : }
256 :
257 0 : return CAIRO_STATUS_SUCCESS;
258 : }
259 :
260 : static cairo_int_status_t
261 0 : _cairo_tee_surface_mask (void *abstract_surface,
262 : cairo_operator_t op,
263 : const cairo_pattern_t *source,
264 : const cairo_pattern_t *mask,
265 : cairo_clip_t *clip)
266 : {
267 0 : cairo_tee_surface_t *surface = abstract_surface;
268 : cairo_surface_wrapper_t *slaves;
269 : int n, num_slaves;
270 : cairo_status_t status;
271 : const cairo_pattern_t *matched_source;
272 : cairo_surface_pattern_t temp;
273 :
274 0 : matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp);
275 0 : status = _cairo_surface_wrapper_mask (&surface->master,
276 : op, matched_source, mask, clip);
277 0 : if (matched_source == &temp.base) {
278 0 : _cairo_pattern_fini (&temp.base);
279 : }
280 0 : if (unlikely (status))
281 0 : return status;
282 :
283 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
284 0 : slaves = _cairo_array_index (&surface->slaves, 0);
285 0 : for (n = 0; n < num_slaves; n++) {
286 0 : matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp);
287 0 : status = _cairo_surface_wrapper_mask (&slaves[n],
288 : op, matched_source, mask, clip);
289 0 : if (matched_source == &temp.base) {
290 0 : _cairo_pattern_fini (&temp.base);
291 : }
292 0 : if (unlikely (status))
293 0 : return status;
294 : }
295 :
296 0 : return CAIRO_STATUS_SUCCESS;
297 : }
298 :
299 : static cairo_int_status_t
300 0 : _cairo_tee_surface_stroke (void *abstract_surface,
301 : cairo_operator_t op,
302 : const cairo_pattern_t *source,
303 : cairo_path_fixed_t *path,
304 : const cairo_stroke_style_t *style,
305 : const cairo_matrix_t *ctm,
306 : const cairo_matrix_t *ctm_inverse,
307 : double tolerance,
308 : cairo_antialias_t antialias,
309 : cairo_clip_t *clip)
310 : {
311 0 : cairo_tee_surface_t *surface = abstract_surface;
312 : cairo_surface_wrapper_t *slaves;
313 : int n, num_slaves;
314 : cairo_status_t status;
315 : const cairo_pattern_t *matched_source;
316 : cairo_surface_pattern_t temp;
317 :
318 0 : matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp);
319 0 : status = _cairo_surface_wrapper_stroke (&surface->master,
320 : op, matched_source,
321 : path, style,
322 : ctm, ctm_inverse,
323 : tolerance, antialias,
324 : clip);
325 0 : if (matched_source == &temp.base) {
326 0 : _cairo_pattern_fini (&temp.base);
327 : }
328 0 : if (unlikely (status))
329 0 : return status;
330 :
331 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
332 0 : slaves = _cairo_array_index (&surface->slaves, 0);
333 0 : for (n = 0; n < num_slaves; n++) {
334 0 : matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp);
335 0 : status = _cairo_surface_wrapper_stroke (&slaves[n],
336 : op, matched_source,
337 : path, style,
338 : ctm, ctm_inverse,
339 : tolerance, antialias,
340 : clip);
341 0 : if (matched_source == &temp.base) {
342 0 : _cairo_pattern_fini (&temp.base);
343 : }
344 0 : if (unlikely (status))
345 0 : return status;
346 : }
347 :
348 0 : return CAIRO_STATUS_SUCCESS;
349 : }
350 :
351 : static cairo_int_status_t
352 0 : _cairo_tee_surface_fill (void *abstract_surface,
353 : cairo_operator_t op,
354 : const cairo_pattern_t *source,
355 : cairo_path_fixed_t *path,
356 : cairo_fill_rule_t fill_rule,
357 : double tolerance,
358 : cairo_antialias_t antialias,
359 : cairo_clip_t *clip)
360 : {
361 0 : cairo_tee_surface_t *surface = abstract_surface;
362 : cairo_surface_wrapper_t *slaves;
363 : int n, num_slaves;
364 : cairo_status_t status;
365 : const cairo_pattern_t *matched_source;
366 : cairo_surface_pattern_t temp;
367 :
368 0 : matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp);
369 0 : status = _cairo_surface_wrapper_fill (&surface->master,
370 : op, matched_source,
371 : path, fill_rule,
372 : tolerance, antialias,
373 : clip);
374 0 : if (matched_source == &temp.base) {
375 0 : _cairo_pattern_fini (&temp.base);
376 : }
377 0 : if (unlikely (status))
378 0 : return status;
379 :
380 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
381 0 : slaves = _cairo_array_index (&surface->slaves, 0);
382 0 : for (n = 0; n < num_slaves; n++) {
383 0 : matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp);
384 0 : status = _cairo_surface_wrapper_fill (&slaves[n],
385 : op, matched_source,
386 : path, fill_rule,
387 : tolerance, antialias,
388 : clip);
389 0 : if (matched_source == &temp.base) {
390 0 : _cairo_pattern_fini (&temp.base);
391 : }
392 0 : if (unlikely (status))
393 0 : return status;
394 : }
395 :
396 0 : return CAIRO_STATUS_SUCCESS;
397 : }
398 :
399 : static cairo_bool_t
400 0 : _cairo_tee_surface_has_show_text_glyphs (void *abstract_surface)
401 : {
402 0 : return TRUE;
403 : }
404 :
405 : static cairo_int_status_t
406 0 : _cairo_tee_surface_show_text_glyphs (void *abstract_surface,
407 : cairo_operator_t op,
408 : const cairo_pattern_t *source,
409 : const char *utf8,
410 : int utf8_len,
411 : cairo_glyph_t *glyphs,
412 : int num_glyphs,
413 : const cairo_text_cluster_t *clusters,
414 : int num_clusters,
415 : cairo_text_cluster_flags_t cluster_flags,
416 : cairo_scaled_font_t *scaled_font,
417 : cairo_clip_t *clip)
418 : {
419 0 : cairo_tee_surface_t *surface = abstract_surface;
420 : cairo_surface_wrapper_t *slaves;
421 : int n, num_slaves;
422 : cairo_status_t status;
423 : cairo_glyph_t *glyphs_copy;
424 : const cairo_pattern_t *matched_source;
425 : cairo_surface_pattern_t temp;
426 :
427 : /* XXX: This copying is ugly. */
428 0 : glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
429 0 : if (unlikely (glyphs_copy == NULL))
430 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
431 :
432 0 : memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
433 0 : matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp);
434 0 : status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op,
435 : matched_source,
436 : utf8, utf8_len,
437 : glyphs_copy, num_glyphs,
438 : clusters, num_clusters,
439 : cluster_flags,
440 : scaled_font,
441 : clip);
442 0 : if (matched_source == &temp.base) {
443 0 : _cairo_pattern_fini (&temp.base);
444 : }
445 0 : if (unlikely (status))
446 0 : goto CLEANUP;
447 :
448 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
449 0 : slaves = _cairo_array_index (&surface->slaves, 0);
450 0 : for (n = 0; n < num_slaves; n++) {
451 0 : memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
452 0 : matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp);
453 0 : status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op,
454 : matched_source,
455 : utf8, utf8_len,
456 : glyphs_copy, num_glyphs,
457 : clusters, num_clusters,
458 : cluster_flags,
459 : scaled_font,
460 : clip);
461 0 : if (matched_source == &temp.base) {
462 0 : _cairo_pattern_fini (&temp.base);
463 : }
464 0 : if (unlikely (status))
465 0 : goto CLEANUP;
466 : }
467 :
468 : CLEANUP:
469 0 : free (glyphs_copy);
470 0 : return status;
471 : }
472 :
473 : static cairo_status_t
474 0 : _cairo_tee_surface_flush (void *abstract_surface)
475 : {
476 0 : cairo_tee_surface_t *surface = abstract_surface;
477 : cairo_surface_wrapper_t *slaves;
478 : int n, num_slaves;
479 : cairo_status_t status;
480 :
481 0 : status = _cairo_surface_wrapper_flush(&surface->master);
482 0 : if (unlikely (status))
483 0 : return status;
484 :
485 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
486 0 : slaves = _cairo_array_index (&surface->slaves, 0);
487 0 : for (n = 0; n < num_slaves; n++) {
488 0 : status = _cairo_surface_wrapper_flush(&slaves[n]);
489 0 : if (unlikely (status))
490 0 : return status;
491 : }
492 :
493 0 : return CAIRO_STATUS_SUCCESS;
494 : }
495 :
496 : static const cairo_surface_backend_t cairo_tee_surface_backend = {
497 : CAIRO_SURFACE_TYPE_TEE,
498 : _cairo_tee_surface_create_similar,
499 : _cairo_tee_surface_finish,
500 : _cairo_tee_surface_acquire_source_image,
501 : _cairo_tee_surface_release_source_image,
502 : NULL, NULL, /* dest_image */
503 : NULL, /* clone_similar */
504 : NULL, /* composite */
505 : NULL, /* fill_rectangles */
506 : NULL, /* composite_trapezoids */
507 : NULL, /* create_span_renderer */
508 : NULL, /* check_span_renderer */
509 : NULL, /* copy_page */
510 : NULL, /* show_page */
511 : _cairo_tee_surface_get_extents,
512 : NULL, /* old_show_glyphs */
513 : _cairo_tee_surface_get_font_options,
514 : _cairo_tee_surface_flush,
515 : NULL, /* mark_dirty_rectangle */
516 : NULL, /* scaled_font_fini */
517 : NULL, /* scaled_glyph_fini */
518 :
519 : _cairo_tee_surface_paint,
520 : _cairo_tee_surface_mask,
521 : _cairo_tee_surface_stroke,
522 : _cairo_tee_surface_fill,
523 : NULL, /* replaced by show_text_glyphs */
524 :
525 : _cairo_tee_surface_snapshot,
526 : NULL, /* is_similar */
527 : NULL, /* fill_stroke */
528 : NULL, /* create_solid_pattern_surface */
529 : NULL, /* can_repaint_solid_pattern_surface */
530 :
531 : _cairo_tee_surface_has_show_text_glyphs,
532 : _cairo_tee_surface_show_text_glyphs
533 : };
534 :
535 : cairo_surface_t *
536 0 : cairo_tee_surface_create (cairo_surface_t *master)
537 : {
538 : cairo_tee_surface_t *surface;
539 :
540 0 : if (unlikely (master->status))
541 0 : return _cairo_surface_create_in_error (master->status);
542 :
543 0 : surface = malloc (sizeof (cairo_tee_surface_t));
544 0 : if (unlikely (surface == NULL))
545 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
546 :
547 0 : _cairo_surface_init (&surface->base,
548 : &cairo_tee_surface_backend,
549 : master->device,
550 : master->content);
551 :
552 0 : _cairo_surface_wrapper_init (&surface->master, master);
553 : /* we trust that these are already set and remain constant */
554 0 : surface->base.device_transform = master->device_transform;
555 0 : surface->base.device_transform_inverse = master->device_transform_inverse;
556 :
557 0 : _cairo_array_init (&surface->slaves, sizeof (cairo_surface_wrapper_t));
558 :
559 0 : return &surface->base;
560 : }
561 : slim_hidden_def (cairo_tee_surface_create);
562 :
563 : void
564 0 : cairo_tee_surface_add (cairo_surface_t *abstract_surface,
565 : cairo_surface_t *target)
566 : {
567 : cairo_tee_surface_t *surface;
568 : cairo_surface_wrapper_t slave;
569 : cairo_status_t status;
570 :
571 0 : if (unlikely (abstract_surface->status))
572 0 : return;
573 0 : if (unlikely (abstract_surface->finished)) {
574 0 : status = _cairo_surface_set_error (abstract_surface,
575 : _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
576 0 : return;
577 : }
578 :
579 0 : if (abstract_surface->backend != &cairo_tee_surface_backend) {
580 0 : status = _cairo_surface_set_error (abstract_surface,
581 : _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
582 0 : return;
583 : }
584 :
585 0 : if (unlikely (target->status)) {
586 0 : status = _cairo_surface_set_error (abstract_surface, target->status);
587 0 : return;
588 : }
589 :
590 0 : surface = (cairo_tee_surface_t *) abstract_surface;
591 :
592 0 : _cairo_surface_wrapper_init (&slave, target);
593 0 : status = _cairo_array_append (&surface->slaves, &slave);
594 0 : if (unlikely (status)) {
595 0 : _cairo_surface_wrapper_fini (&slave);
596 0 : status = _cairo_surface_set_error (&surface->base, status);
597 : }
598 : }
599 : slim_hidden_def (cairo_tee_surface_add);
600 :
601 : void
602 0 : cairo_tee_surface_remove (cairo_surface_t *abstract_surface,
603 : cairo_surface_t *target)
604 : {
605 : cairo_tee_surface_t *surface;
606 : cairo_surface_wrapper_t *slaves;
607 : int n, num_slaves;
608 : cairo_status_t status;
609 :
610 0 : if (unlikely (abstract_surface->status))
611 0 : return;
612 0 : if (unlikely (abstract_surface->finished)) {
613 0 : status = _cairo_surface_set_error (abstract_surface,
614 : _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
615 0 : return;
616 : }
617 :
618 0 : if (abstract_surface->backend != &cairo_tee_surface_backend) {
619 0 : status = _cairo_surface_set_error (abstract_surface,
620 : _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
621 0 : return;
622 : }
623 :
624 0 : surface = (cairo_tee_surface_t *) abstract_surface;
625 0 : if (target == surface->master.target) {
626 0 : status = _cairo_surface_set_error (abstract_surface,
627 : _cairo_error (CAIRO_STATUS_INVALID_INDEX));
628 0 : return;
629 : }
630 :
631 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
632 0 : slaves = _cairo_array_index (&surface->slaves, 0);
633 0 : for (n = 0; n < num_slaves; n++) {
634 0 : if (slaves[n].target == target)
635 0 : break;
636 : }
637 :
638 0 : if (n == num_slaves) {
639 0 : status = _cairo_surface_set_error (abstract_surface,
640 : _cairo_error (CAIRO_STATUS_INVALID_INDEX));
641 0 : return;
642 : }
643 :
644 0 : _cairo_surface_wrapper_fini (&slaves[n]);
645 0 : for (n++; n < num_slaves; n++)
646 0 : slaves[n-1] = slaves[n];
647 0 : surface->slaves.num_elements--; /* XXX: cairo_array_remove()? */
648 : }
649 :
650 : cairo_surface_t *
651 0 : cairo_tee_surface_index (cairo_surface_t *abstract_surface,
652 : int index)
653 : {
654 : cairo_tee_surface_t *surface;
655 :
656 0 : if (unlikely (abstract_surface->status))
657 0 : return _cairo_surface_create_in_error (abstract_surface->status);
658 0 : if (unlikely (abstract_surface->finished))
659 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
660 :
661 0 : if (abstract_surface->backend != &cairo_tee_surface_backend)
662 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
663 :
664 0 : surface = (cairo_tee_surface_t *) abstract_surface;
665 0 : if (index == 0) {
666 0 : return surface->master.target;
667 : } else {
668 : cairo_surface_wrapper_t *slave;
669 :
670 0 : index--;
671 :
672 0 : if (index >= _cairo_array_num_elements (&surface->slaves))
673 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX));
674 :
675 0 : slave = _cairo_array_index (&surface->slaves, index);
676 0 : return slave->target;
677 : }
678 : }
679 :
680 : cairo_surface_t *
681 0 : _cairo_tee_surface_find_match (void *abstract_surface,
682 : const cairo_surface_backend_t *backend,
683 : cairo_content_t content)
684 : {
685 0 : cairo_tee_surface_t *surface = abstract_surface;
686 : cairo_surface_wrapper_t *slaves;
687 : int num_slaves, n;
688 :
689 : /* exact match first */
690 0 : if (surface->master.target->backend == backend &&
691 0 : surface->master.target->content == content)
692 : {
693 0 : return surface->master.target;
694 : }
695 :
696 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
697 0 : slaves = _cairo_array_index (&surface->slaves, 0);
698 0 : for (n = 0; n < num_slaves; n++) {
699 0 : if (slaves[n].target->backend == backend &&
700 0 : slaves[n].target->content == content)
701 : {
702 0 : return slaves[n].target;
703 : }
704 : }
705 :
706 : /* matching backend? */
707 0 : if (surface->master.target->backend == backend)
708 0 : return surface->master.target;
709 :
710 0 : num_slaves = _cairo_array_num_elements (&surface->slaves);
711 0 : slaves = _cairo_array_index (&surface->slaves, 0);
712 0 : for (n = 0; n < num_slaves; n++) {
713 0 : if (slaves[n].target->backend == backend)
714 0 : return slaves[n].target;
715 : }
716 :
717 0 : return NULL;
718 : }
|