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
;