From 658cdc7c9aac23f82f3ea5db8df10844aeb3ac75 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 16 Aug 2009 18:04:54 +0100 Subject: Introduce cairo_tee_surface_t Add a new surface type that multiplies it input onto several output surfaces. The only limitation is that it requires a master surface that is used whenever we need to query surface options, such as font options and extents. --- boilerplate/Makefile.win32.features | 8 + build/Makefile.win32.features-h | 1 + build/configure.ac.features | 1 + configure.ac | 1 + src/Makefile.sources | 6 +- src/Makefile.win32.features | 8 + src/cairo-surface-wrapper-private.h | 4 + src/cairo-surface-wrapper.c | 7 + src/cairo-surface.c | 11 + src/cairo-tee-surface-private.h | 47 +++ src/cairo-tee-surface.c | 558 ++++++++++++++++++++++++++++++++++++ src/cairo.h | 13 +- 12 files changed, 662 insertions(+), 3 deletions(-) create mode 100644 src/cairo-tee-surface-private.h create mode 100644 src/cairo-tee-surface.c diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features index e58eed9e..e9c87ea4 100644 --- a/boilerplate/Makefile.win32.features +++ b/boilerplate/Makefile.win32.features @@ -312,6 +312,14 @@ enabled_cairo_boilerplate_headers += $(cairo_boilerplate_meta_headers) enabled_cairo_boilerplate_private += $(cairo_boilerplate_meta_private) enabled_cairo_boilerplate_sources += $(cairo_boilerplate_meta_sources) +supported_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers) +all_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers) +all_cairo_boilerplate_private += $(cairo_boilerplate_tee_private) +all_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources) +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers) +enabled_cairo_boilerplate_private += $(cairo_boilerplate_tee_private) +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources) + supported_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers) all_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers) all_cairo_boilerplate_private += $(cairo_boilerplate_user_private) diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h index 88877edd..f647b166 100644 --- a/build/Makefile.win32.features-h +++ b/build/Makefile.win32.features-h @@ -91,5 +91,6 @@ ifeq ($(CAIRO_HAS_TEST_SURFACES),1) endif @echo "#define CAIRO_HAS_IMAGE_SURFACE 1" >> src/cairo-features.h @echo "#define CAIRO_HAS_META_SURFACE 1" >> src/cairo-features.h + @echo "#define CAIRO_HAS_TEE_SURFACE 1" >> src/cairo-features.h @echo "#define CAIRO_HAS_USER_FONT 1" >> src/cairo-features.h @echo "#endif" >> src/cairo-features.h diff --git a/build/configure.ac.features b/build/configure.ac.features index 154774c1..55f37862 100644 --- a/build/configure.ac.features +++ b/build/configure.ac.features @@ -358,6 +358,7 @@ AC_DEFUN([CAIRO_REPORT], echo "The following surface backends:" echo " Image: yes (always builtin)" echo " Meta: yes (always builtin)" + echo " Tee: yes (always builtin)" echo " Xlib: $use_xlib" echo " Xlib Xrender: $use_xlib_xrender" echo " Qt: $use_qt" diff --git a/configure.ac b/configure.ac index 445cb674..c02b1d2e 100644 --- a/configure.ac +++ b/configure.ac @@ -570,6 +570,7 @@ CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [ dnl =========================================================================== CAIRO_ENABLE_SURFACE_BACKEND(meta, meta, always) +CAIRO_ENABLE_SURFACE_BACKEND(tee, tee, always) dnl =========================================================================== diff --git a/src/Makefile.sources b/src/Makefile.sources index c8da2363..603e8878 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -88,6 +88,7 @@ cairo_private = \ cairo-surface-private.h \ cairo-surface-clipper-private.h \ cairo-surface-wrapper-private.h \ + cairo-tee-surface-private.h \ cairo-types-private.h \ cairo-user-font-private.h \ cairo-wideint-private.h \ @@ -146,10 +147,11 @@ cairo_sources = \ cairo-surface-fallback.c \ cairo-surface-clipper.c \ cairo-surface-wrapper.c \ - cairo-tor-scan-converter.c \ cairo-system.c \ - cairo-traps.c \ + cairo-tee-surface.c \ + cairo-tor-scan-converter.c \ cairo-toy-font-face.c \ + cairo-traps.c \ cairo-unicode.c \ cairo-user-font.c \ cairo-version.c \ diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features index 048ead05..8b17d5c5 100644 --- a/src/Makefile.win32.features +++ b/src/Makefile.win32.features @@ -422,6 +422,14 @@ enabled_cairo_headers += $(cairo_meta_headers) enabled_cairo_private += $(cairo_meta_private) enabled_cairo_sources += $(cairo_meta_sources) +supported_cairo_headers += $(cairo_tee_headers) +all_cairo_headers += $(cairo_tee_headers) +all_cairo_private += $(cairo_tee_private) +all_cairo_sources += $(cairo_tee_sources) +enabled_cairo_headers += $(cairo_tee_headers) +enabled_cairo_private += $(cairo_tee_private) +enabled_cairo_sources += $(cairo_tee_sources) + supported_cairo_headers += $(cairo_user_headers) all_cairo_headers += $(cairo_user_headers) all_cairo_private += $(cairo_user_private) diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h index 3ffd9ab8..7da4cdaa 100644 --- a/src/cairo-surface-wrapper-private.h +++ b/src/cairo-surface-wrapper-private.h @@ -142,6 +142,10 @@ cairo_private cairo_bool_t _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, cairo_rectangle_int_t *extents); +cairo_private void +_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper, + cairo_font_options_t *options); + cairo_private cairo_surface_t * _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper); diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c index 12d67836..0d1dc515 100644 --- a/src/cairo-surface-wrapper.c +++ b/src/cairo-surface-wrapper.c @@ -429,6 +429,13 @@ _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, return _cairo_surface_get_extents (wrapper->target, extents); } +void +_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper, + cairo_font_options_t *options) +{ + return cairo_surface_get_font_options (wrapper->target, options); +} + cairo_surface_t * _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper) { diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 84a30121..624f71ff 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -42,6 +42,7 @@ #include "cairo-clip-private.h" #include "cairo-meta-surface-private.h" #include "cairo-region-private.h" +#include "cairo-tee-surface-private.h" #define DEFINE_NIL_SURFACE(status, name) \ const cairo_surface_t name = { \ @@ -1528,6 +1529,16 @@ _cairo_surface_clone_similar (cairo_surface_t *surface, if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + if (src->type == CAIRO_SURFACE_TYPE_TEE) { + cairo_surface_t *match; + + match = _cairo_tee_surface_find_match (src, + surface->backend, + content); + if (match != NULL) + src = match; + } + if (surface->backend->clone_similar != NULL) { status = surface->backend->clone_similar (surface, src, content, diff --git a/src/cairo-tee-surface-private.h b/src/cairo-tee-surface-private.h new file mode 100644 index 00000000..258816b5 --- /dev/null +++ b/src/cairo-tee-surface-private.h @@ -0,0 +1,47 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_TEE_SURFACE_PRIVATE_H +#define CAIRO_TEE_SURFACE_PRIVATE_H + +#include "cairoint.h" + +cairo_private cairo_surface_t * +_cairo_tee_surface_find_match (void *abstract_surface, + const cairo_surface_backend_t *backend, + cairo_content_t content); + +#endif /* CAIRO_TEE_SURFACE_PRIVATE_H */ diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c new file mode 100644 index 00000000..0a7842f7 --- /dev/null +++ b/src/cairo-tee-surface.c @@ -0,0 +1,558 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + * Chris Wilson + */ + +/* This surface supports redirecting all its input to multiple surfaces. + */ + +#include "cairoint.h" + +#include "cairo-tee-surface-private.h" +#include "cairo-surface-wrapper-private.h" + +typedef struct _cairo_tee_surface { + cairo_surface_t base; + + cairo_surface_wrapper_t master; + cairo_array_t slaves; +} cairo_tee_surface_t; + +slim_hidden_proto (cairo_tee_surface_create); +slim_hidden_proto (cairo_tee_surface_append); + +static cairo_surface_t * +_cairo_tee_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + + cairo_tee_surface_t *other = abstract_surface; + cairo_surface_t *similar; + cairo_surface_t *surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + + similar = _cairo_surface_wrapper_create_similar (&other->master, + content, width, height); + surface = cairo_tee_surface_create (similar); + cairo_surface_destroy (similar); + if (unlikely (surface->status)) + return surface; + + num_slaves = _cairo_array_num_elements (&other->slaves); + slaves = _cairo_array_index (&other->slaves, 0); + for (n = 0; n < num_slaves; n++) { + + similar = _cairo_surface_wrapper_create_similar (&slaves[n], + content, + width, height); + cairo_tee_surface_append (surface, similar); + cairo_surface_destroy (similar); + } + + if (unlikely (surface->status)) { + cairo_status_t status = surface->status; + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + + return surface; +} + +static cairo_status_t +_cairo_tee_surface_finish (void *abstract_surface) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + + _cairo_surface_wrapper_fini (&surface->master); + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) + _cairo_surface_wrapper_fini (&slaves[n]); + + _cairo_array_fini (&surface->slaves); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_tee_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int num_slaves, n; + + /* we prefer to use a real image surface if available */ + if (_cairo_surface_is_image (surface->master.target)) { + return _cairo_surface_wrapper_acquire_source_image (&surface->master, + image_out, image_extra); + } + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + if (_cairo_surface_is_image (slaves[n].target)) { + return _cairo_surface_wrapper_acquire_source_image (&slaves[n], + image_out, + image_extra); + } + } + + return _cairo_surface_wrapper_acquire_source_image (&surface->master, + image_out, image_extra); +} + +static void +_cairo_tee_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_tee_surface_t *surface = abstract_surface; + + _cairo_surface_wrapper_release_source_image (&surface->master, + image, image_extra); +} + +static cairo_surface_t * +_cairo_tee_surface_snapshot (void *abstract_surface) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int num_slaves, n; + + /* we prefer to use a meta surface for our snapshots */ + if (_cairo_surface_is_meta (surface->master.target)) + return _cairo_surface_wrapper_snapshot (&surface->master); + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + if (_cairo_surface_is_meta (slaves[n].target)) + return _cairo_surface_wrapper_snapshot (&slaves[n]); + } + + return _cairo_surface_wrapper_snapshot (&surface->master); +} + +static cairo_bool_t +_cairo_tee_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_tee_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_get_extents (&surface->master, rectangle); +} + +static void +_cairo_tee_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_tee_surface_t *surface = abstract_surface; + + _cairo_surface_wrapper_get_font_options (&surface->master, options); +} + +static cairo_int_status_t +_cairo_tee_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + cairo_status_t status; + + status = _cairo_surface_wrapper_paint (&surface->master, op, source, clip); + if (unlikely (status)) + return status; + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + status = _cairo_surface_wrapper_paint (&slaves[n], op, source, clip); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_tee_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + cairo_status_t status; + + status = _cairo_surface_wrapper_mask (&surface->master, + op, source, mask, clip); + if (unlikely (status)) + return status; + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + status = _cairo_surface_wrapper_mask (&slaves[n], + op, source, mask, clip); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_tee_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + cairo_status_t status; + + status = _cairo_surface_wrapper_stroke (&surface->master, + op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + status = _cairo_surface_wrapper_stroke (&slaves[n], + op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_tee_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + cairo_status_t status; + + status = _cairo_surface_wrapper_fill (&surface->master, + op, source, + path, fill_rule, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + status = _cairo_surface_wrapper_fill (&slaves[n], + op, source, + path, fill_rule, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_tee_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static cairo_int_status_t +_cairo_tee_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int n, num_slaves; + cairo_status_t status; + cairo_glyph_t *glyphs_copy; + + /* XXX: This copying is ugly. */ + glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (glyphs_copy == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op, + source, + utf8, utf8_len, + glyphs_copy, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); + if (unlikely (status)) + goto CLEANUP; + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op, + source, + utf8, utf8_len, + glyphs_copy, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); + if (unlikely (status)) + goto CLEANUP; + } + + CLEANUP: + free (glyphs_copy); + return status; +} + +static const cairo_surface_backend_t cairo_tee_surface_backend = { + CAIRO_SURFACE_TYPE_TEE, + _cairo_tee_surface_create_similar, + _cairo_tee_surface_finish, + _cairo_tee_surface_acquire_source_image, + _cairo_tee_surface_release_source_image, + NULL, NULL, /* dest_image */ + NULL, /* clone_similar */ + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* create_span_renderer */ + NULL, /* check_span_renderer */ + NULL, /* copy_page */ + NULL, /* show_page */ + _cairo_tee_surface_get_extents, + NULL, /* old_show_glyphs */ + _cairo_tee_surface_get_font_options, + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + _cairo_tee_surface_paint, + _cairo_tee_surface_mask, + _cairo_tee_surface_stroke, + _cairo_tee_surface_fill, + NULL, /* replaced by show_text_glyphs */ + + _cairo_tee_surface_snapshot, + NULL, /* is_similar */ + NULL, /* fill_stroke */ + NULL, /* create_solid_pattern_surface */ + NULL, /* can_repaint_solid_pattern_surface */ + + _cairo_tee_surface_has_show_text_glyphs, + _cairo_tee_surface_show_text_glyphs +}; + +cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *master) +{ + cairo_tee_surface_t *surface; + + if (unlikely (master->status)) + return _cairo_surface_create_in_error (master->status); + + surface = malloc (sizeof (cairo_tee_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &cairo_tee_surface_backend, + master->content); + + _cairo_surface_wrapper_init (&surface->master, master); + /* we trust that these are already set and remain constant */ + surface->base.device_transform = master->device_transform; + surface->base.device_transform_inverse = master->device_transform_inverse; + + _cairo_array_init (&surface->slaves, sizeof (cairo_surface_wrapper_t)); + + return &surface->base; +} +slim_hidden_def (cairo_tee_surface_create); + +void +cairo_tee_surface_append (cairo_surface_t *abstract_surface, + cairo_surface_t *target) +{ + cairo_tee_surface_t *surface; + cairo_surface_wrapper_t slave; + cairo_status_t status; + + if (unlikely (abstract_surface->status)) + return; + + if (abstract_surface->backend != &cairo_tee_surface_backend) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (unlikely (target->status)) { + status = _cairo_surface_set_error (abstract_surface, target->status); + return; + } + + surface = (cairo_tee_surface_t *) abstract_surface; + + _cairo_surface_wrapper_init (&slave, target); + status = _cairo_array_append (&surface->slaves, &slave); + if (unlikely (status)) { + _cairo_surface_wrapper_fini (&slave); + status = _cairo_surface_set_error (&surface->base, status); + } +} +slim_hidden_def (cairo_tee_surface_append); + +cairo_surface_t * +cairo_tee_surface_index (cairo_surface_t *abstract_surface, + int index) +{ + cairo_tee_surface_t *surface; + + if (unlikely (abstract_surface->status)) + return _cairo_surface_create_in_error (abstract_surface->status); + + if (abstract_surface->backend != &cairo_tee_surface_backend) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + + surface = (cairo_tee_surface_t *) abstract_surface; + if (index == 0) { + return surface->master.target; + } else { + cairo_surface_wrapper_t *slave; + + index--; + + if (index >= _cairo_array_num_elements (&surface->slaves)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX)); + + slave = _cairo_array_index (&surface->slaves, index); + return slave->target; + } +} + +cairo_surface_t * +_cairo_tee_surface_find_match (void *abstract_surface, + const cairo_surface_backend_t *backend, + cairo_content_t content) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *slaves; + int num_slaves, n; + + /* exact match first */ + if (surface->master.target->backend == backend && + surface->master.target->content == content) + { + return surface->master.target; + } + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + if (slaves[n].target->backend == backend && + slaves[n].target->content == content) + { + return slaves[n].target; + } + } + + /* matching backend? */ + if (surface->master.target->backend == backend) + return surface->master.target; + + num_slaves = _cairo_array_num_elements (&surface->slaves); + slaves = _cairo_array_index (&surface->slaves, 0); + for (n = 0; n < num_slaves; n++) { + if (slaves[n].target->backend == backend) + return slaves[n].target; + } + + return NULL; +} diff --git a/src/cairo.h b/src/cairo.h index e0c53436..9be5c703 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1948,6 +1948,7 @@ cairo_surface_status (cairo_surface_t *surface); * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10 * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10 * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10 + * @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10 * * #cairo_surface_type_t is used to describe the type of a given * surface. The surface types are also known as "backends" or "surface @@ -1992,7 +1993,8 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_META, CAIRO_SURFACE_TYPE_VG, CAIRO_SURFACE_TYPE_GL, - CAIRO_SURFACE_TYPE_DRM + CAIRO_SURFACE_TYPE_DRM, + CAIRO_SURFACE_TYPE_TEE } cairo_surface_type_t; cairo_public cairo_surface_type_t @@ -2187,6 +2189,15 @@ cairo_public cairo_status_t cairo_meta_surface_replay (cairo_surface_t *surface, cairo_surface_t *target); +/* Tee-surface functions */ + +cairo_public cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *master); + +cairo_public void +cairo_tee_surface_append (cairo_surface_t *surface, + cairo_surface_t *target); + /* Pattern creation functions */ cairo_public cairo_pattern_t * -- cgit v1.2.3