1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2005 Red Hat, Inc
4 * Copyright © 2009 Chris Wilson
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.
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
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/
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.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
34 * Carl Worth <cworth@cworth.org>
35 * Chris Wilson <chris@chris-wilson.co.uk>
38 /* This surface supports redirecting all its input to multiple surfaces.
43 #include "cairo-tee.h"
45 #include "cairo-default-context-private.h"
46 #include "cairo-error-private.h"
47 #include "cairo-tee-surface-private.h"
48 #include "cairo-recording-surface-inline.h"
49 #include "cairo-surface-wrapper-private.h"
50 #include "cairo-array-private.h"
51 #include "cairo-image-surface-inline.h"
53 typedef struct _cairo_tee_surface {
56 cairo_surface_wrapper_t master;
58 } cairo_tee_surface_t;
60 slim_hidden_proto (cairo_tee_surface_create);
61 slim_hidden_proto (cairo_tee_surface_add);
63 static cairo_surface_t *
64 _cairo_tee_surface_create_similar (void *abstract_surface,
65 cairo_content_t content,
70 cairo_tee_surface_t *other = abstract_surface;
71 cairo_surface_t *similar;
72 cairo_surface_t *surface;
73 cairo_surface_wrapper_t *slaves;
76 similar = _cairo_surface_wrapper_create_similar (&other->master,
77 content, width, height);
78 surface = cairo_tee_surface_create (similar);
79 cairo_surface_destroy (similar);
80 if (unlikely (surface->status))
83 num_slaves = _cairo_array_num_elements (&other->slaves);
84 slaves = _cairo_array_index (&other->slaves, 0);
85 for (n = 0; n < num_slaves; n++) {
87 similar = _cairo_surface_wrapper_create_similar (&slaves[n],
90 cairo_tee_surface_add (surface, similar);
91 cairo_surface_destroy (similar);
94 if (unlikely (surface->status)) {
95 cairo_status_t status = surface->status;
96 cairo_surface_destroy (surface);
97 surface = _cairo_surface_create_in_error (status);
103 static cairo_status_t
104 _cairo_tee_surface_finish (void *abstract_surface)
106 cairo_tee_surface_t *surface = abstract_surface;
107 cairo_surface_wrapper_t *slaves;
110 _cairo_surface_wrapper_fini (&surface->master);
112 num_slaves = _cairo_array_num_elements (&surface->slaves);
113 slaves = _cairo_array_index (&surface->slaves, 0);
114 for (n = 0; n < num_slaves; n++)
115 _cairo_surface_wrapper_fini (&slaves[n]);
117 _cairo_array_fini (&surface->slaves);
119 return CAIRO_STATUS_SUCCESS;
122 static cairo_surface_t *
123 _cairo_tee_surface_source (void *abstract_surface,
124 cairo_rectangle_int_t *extents)
126 cairo_tee_surface_t *surface = abstract_surface;
127 return _cairo_surface_get_source (surface->master.target, extents);
130 static cairo_status_t
131 _cairo_tee_surface_acquire_source_image (void *abstract_surface,
132 cairo_image_surface_t **image_out,
135 cairo_tee_surface_t *surface = abstract_surface;
136 cairo_surface_wrapper_t *slaves;
139 /* we prefer to use a real image surface if available */
140 if (_cairo_surface_is_image (surface->master.target)) {
141 return _cairo_surface_wrapper_acquire_source_image (&surface->master,
142 image_out, image_extra);
145 num_slaves = _cairo_array_num_elements (&surface->slaves);
146 slaves = _cairo_array_index (&surface->slaves, 0);
147 for (n = 0; n < num_slaves; n++) {
148 if (_cairo_surface_is_image (slaves[n].target)) {
149 return _cairo_surface_wrapper_acquire_source_image (&slaves[n],
155 return _cairo_surface_wrapper_acquire_source_image (&surface->master,
156 image_out, image_extra);
160 _cairo_tee_surface_release_source_image (void *abstract_surface,
161 cairo_image_surface_t *image,
164 cairo_tee_surface_t *surface = abstract_surface;
166 _cairo_surface_wrapper_release_source_image (&surface->master,
170 static cairo_surface_t *
171 _cairo_tee_surface_snapshot (void *abstract_surface)
173 cairo_tee_surface_t *surface = abstract_surface;
174 cairo_surface_wrapper_t *slaves;
177 /* we prefer to use a recording surface for our snapshots */
178 if (_cairo_surface_is_recording (surface->master.target))
179 return _cairo_surface_wrapper_snapshot (&surface->master);
181 num_slaves = _cairo_array_num_elements (&surface->slaves);
182 slaves = _cairo_array_index (&surface->slaves, 0);
183 for (n = 0; n < num_slaves; n++) {
184 if (_cairo_surface_is_recording (slaves[n].target))
185 return _cairo_surface_wrapper_snapshot (&slaves[n]);
188 return _cairo_surface_wrapper_snapshot (&surface->master);
192 _cairo_tee_surface_get_extents (void *abstract_surface,
193 cairo_rectangle_int_t *rectangle)
195 cairo_tee_surface_t *surface = abstract_surface;
197 return _cairo_surface_wrapper_get_extents (&surface->master, rectangle);
201 _cairo_tee_surface_get_font_options (void *abstract_surface,
202 cairo_font_options_t *options)
204 cairo_tee_surface_t *surface = abstract_surface;
206 _cairo_surface_wrapper_get_font_options (&surface->master, options);
209 static cairo_int_status_t
210 _cairo_tee_surface_paint (void *abstract_surface,
212 const cairo_pattern_t *source,
213 const cairo_clip_t *clip)
215 cairo_tee_surface_t *surface = abstract_surface;
216 cairo_surface_wrapper_t *slaves;
218 cairo_int_status_t status;
220 num_slaves = _cairo_array_num_elements (&surface->slaves);
221 slaves = _cairo_array_index (&surface->slaves, 0);
222 for (n = 0; n < num_slaves; n++) {
223 status = _cairo_surface_wrapper_paint (&slaves[n], op, source, clip);
224 if (unlikely (status))
228 return _cairo_surface_wrapper_paint (&surface->master, op, source, clip);
231 static cairo_int_status_t
232 _cairo_tee_surface_mask (void *abstract_surface,
234 const cairo_pattern_t *source,
235 const cairo_pattern_t *mask,
236 const cairo_clip_t *clip)
238 cairo_tee_surface_t *surface = abstract_surface;
239 cairo_surface_wrapper_t *slaves;
240 cairo_int_status_t status;
243 num_slaves = _cairo_array_num_elements (&surface->slaves);
244 slaves = _cairo_array_index (&surface->slaves, 0);
245 for (n = 0; n < num_slaves; n++) {
246 status = _cairo_surface_wrapper_mask (&slaves[n],
247 op, source, mask, clip);
248 if (unlikely (status))
252 return _cairo_surface_wrapper_mask (&surface->master,
253 op, source, mask, clip);
256 static cairo_int_status_t
257 _cairo_tee_surface_stroke (void *abstract_surface,
259 const cairo_pattern_t *source,
260 const cairo_path_fixed_t *path,
261 const cairo_stroke_style_t *style,
262 const cairo_matrix_t *ctm,
263 const cairo_matrix_t *ctm_inverse,
265 cairo_antialias_t antialias,
266 const cairo_clip_t *clip)
268 cairo_tee_surface_t *surface = abstract_surface;
269 cairo_surface_wrapper_t *slaves;
270 cairo_int_status_t status;
273 num_slaves = _cairo_array_num_elements (&surface->slaves);
274 slaves = _cairo_array_index (&surface->slaves, 0);
275 for (n = 0; n < num_slaves; n++) {
276 status = _cairo_surface_wrapper_stroke (&slaves[n],
280 tolerance, antialias,
282 if (unlikely (status))
286 return _cairo_surface_wrapper_stroke (&surface->master,
290 tolerance, antialias,
294 static cairo_int_status_t
295 _cairo_tee_surface_fill (void *abstract_surface,
297 const cairo_pattern_t *source,
298 const cairo_path_fixed_t *path,
299 cairo_fill_rule_t fill_rule,
301 cairo_antialias_t antialias,
302 const cairo_clip_t *clip)
304 cairo_tee_surface_t *surface = abstract_surface;
305 cairo_surface_wrapper_t *slaves;
306 cairo_int_status_t status;
309 num_slaves = _cairo_array_num_elements (&surface->slaves);
310 slaves = _cairo_array_index (&surface->slaves, 0);
311 for (n = 0; n < num_slaves; n++) {
312 status = _cairo_surface_wrapper_fill (&slaves[n],
315 tolerance, antialias,
317 if (unlikely (status))
321 return _cairo_surface_wrapper_fill (&surface->master,
324 tolerance, antialias,
329 _cairo_tee_surface_has_show_text_glyphs (void *abstract_surface)
334 static cairo_int_status_t
335 _cairo_tee_surface_show_text_glyphs (void *abstract_surface,
337 const cairo_pattern_t *source,
340 cairo_glyph_t *glyphs,
342 const cairo_text_cluster_t *clusters,
344 cairo_text_cluster_flags_t cluster_flags,
345 cairo_scaled_font_t *scaled_font,
346 const cairo_clip_t *clip)
348 cairo_tee_surface_t *surface = abstract_surface;
349 cairo_surface_wrapper_t *slaves;
350 cairo_int_status_t status;
352 cairo_glyph_t *glyphs_copy;
354 /* XXX: This copying is ugly. */
355 glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
356 if (unlikely (glyphs_copy == NULL))
357 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
359 num_slaves = _cairo_array_num_elements (&surface->slaves);
360 slaves = _cairo_array_index (&surface->slaves, 0);
361 for (n = 0; n < num_slaves; n++) {
362 memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
363 status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op,
366 glyphs_copy, num_glyphs,
367 clusters, num_clusters,
371 if (unlikely (status))
375 memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
376 status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op,
379 glyphs_copy, num_glyphs,
380 clusters, num_clusters,
389 static const cairo_surface_backend_t cairo_tee_surface_backend = {
390 CAIRO_SURFACE_TYPE_TEE,
391 _cairo_tee_surface_finish,
393 _cairo_default_context_create, /* XXX */
395 _cairo_tee_surface_create_similar,
396 NULL, /* create similar image */
397 NULL, /* map to image */
398 NULL, /* unmap image */
400 _cairo_tee_surface_source,
401 _cairo_tee_surface_acquire_source_image,
402 _cairo_tee_surface_release_source_image,
403 _cairo_tee_surface_snapshot,
404 NULL, /* copy_page */
405 NULL, /* show_page */
406 _cairo_tee_surface_get_extents,
407 _cairo_tee_surface_get_font_options,
409 NULL, /* mark_dirty_rectangle */
411 _cairo_tee_surface_paint,
412 _cairo_tee_surface_mask,
413 _cairo_tee_surface_stroke,
414 _cairo_tee_surface_fill,
415 NULL, /* fill_stroke */
417 NULL, /* show_glyphs */
419 _cairo_tee_surface_has_show_text_glyphs,
420 _cairo_tee_surface_show_text_glyphs
424 cairo_tee_surface_create (cairo_surface_t *master)
426 cairo_tee_surface_t *surface;
428 if (unlikely (master->status))
429 return _cairo_surface_create_in_error (master->status);
431 surface = malloc (sizeof (cairo_tee_surface_t));
432 if (unlikely (surface == NULL))
433 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
435 _cairo_surface_init (&surface->base,
436 &cairo_tee_surface_backend,
440 _cairo_surface_wrapper_init (&surface->master, master);
442 _cairo_array_init (&surface->slaves, sizeof (cairo_surface_wrapper_t));
444 return &surface->base;
446 slim_hidden_def (cairo_tee_surface_create);
449 cairo_tee_surface_add (cairo_surface_t *abstract_surface,
450 cairo_surface_t *target)
452 cairo_tee_surface_t *surface;
453 cairo_surface_wrapper_t slave;
454 cairo_status_t status;
456 if (unlikely (abstract_surface->status))
458 if (unlikely (abstract_surface->finished)) {
459 status = _cairo_surface_set_error (abstract_surface,
460 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
464 if (abstract_surface->backend != &cairo_tee_surface_backend) {
465 status = _cairo_surface_set_error (abstract_surface,
466 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
470 if (unlikely (target->status)) {
471 status = _cairo_surface_set_error (abstract_surface, target->status);
475 surface = (cairo_tee_surface_t *) abstract_surface;
477 _cairo_surface_wrapper_init (&slave, target);
478 status = _cairo_array_append (&surface->slaves, &slave);
479 if (unlikely (status)) {
480 _cairo_surface_wrapper_fini (&slave);
481 status = _cairo_surface_set_error (&surface->base, status);
484 slim_hidden_def (cairo_tee_surface_add);
487 cairo_tee_surface_remove (cairo_surface_t *abstract_surface,
488 cairo_surface_t *target)
490 cairo_tee_surface_t *surface;
491 cairo_surface_wrapper_t *slaves;
494 if (unlikely (abstract_surface->status))
496 if (unlikely (abstract_surface->finished)) {
497 _cairo_surface_set_error (abstract_surface,
498 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
502 if (abstract_surface->backend != &cairo_tee_surface_backend) {
503 _cairo_surface_set_error (abstract_surface,
504 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
508 surface = (cairo_tee_surface_t *) abstract_surface;
509 if (target == surface->master.target) {
510 _cairo_surface_set_error (abstract_surface,
511 _cairo_error (CAIRO_STATUS_INVALID_INDEX));
515 num_slaves = _cairo_array_num_elements (&surface->slaves);
516 slaves = _cairo_array_index (&surface->slaves, 0);
517 for (n = 0; n < num_slaves; n++) {
518 if (slaves[n].target == target)
522 if (n == num_slaves) {
523 _cairo_surface_set_error (abstract_surface,
524 _cairo_error (CAIRO_STATUS_INVALID_INDEX));
528 _cairo_surface_wrapper_fini (&slaves[n]);
529 for (n++; n < num_slaves; n++)
530 slaves[n-1] = slaves[n];
531 surface->slaves.num_elements--; /* XXX: cairo_array_remove()? */
535 cairo_tee_surface_index (cairo_surface_t *abstract_surface,
538 cairo_tee_surface_t *surface;
540 if (unlikely (abstract_surface->status))
541 return _cairo_surface_create_in_error (abstract_surface->status);
542 if (unlikely (abstract_surface->finished))
543 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
545 if (abstract_surface->backend != &cairo_tee_surface_backend)
546 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
548 surface = (cairo_tee_surface_t *) abstract_surface;
550 return surface->master.target;
552 cairo_surface_wrapper_t *slave;
556 if (index >= _cairo_array_num_elements (&surface->slaves))
557 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX));
559 slave = _cairo_array_index (&surface->slaves, index);
560 return slave->target;
565 _cairo_tee_surface_find_match (void *abstract_surface,
566 const cairo_surface_backend_t *backend,
567 cairo_content_t content)
569 cairo_tee_surface_t *surface = abstract_surface;
570 cairo_surface_wrapper_t *slaves;
573 /* exact match first */
574 if (surface->master.target->backend == backend &&
575 surface->master.target->content == content)
577 return surface->master.target;
580 num_slaves = _cairo_array_num_elements (&surface->slaves);
581 slaves = _cairo_array_index (&surface->slaves, 0);
582 for (n = 0; n < num_slaves; n++) {
583 if (slaves[n].target->backend == backend &&
584 slaves[n].target->content == content)
586 return slaves[n].target;
590 /* matching backend? */
591 if (surface->master.target->backend == backend)
592 return surface->master.target;
594 num_slaves = _cairo_array_num_elements (&surface->slaves);
595 slaves = _cairo_array_index (&surface->slaves, 0);
596 for (n = 0; n < num_slaves; n++) {
597 if (slaves[n].target->backend == backend)
598 return slaves[n].target;