[cairo] New surface: cairo_combined_surface_t
Kouhei Sutou
kou at cozmixng.org
Mon Jun 5 06:15:08 PDT 2006
Hi,
I made an example for cairo_combined_surface_t that is a
GTK+ widget named GtkTransparent. The widget helps us to
make custom shape widget. The widget automatically set mask
whose shape is same as we draw by expose-event.
An example code that makes a circle shape widget:
statci gboolean
expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0);
cairo_new_path (cr);
cairo_move_to (cr, 50, 50);
cairo_arc (cr, 50.0, 50.0, 50, 0.0, 2 * M_PI);
cairo_fill (cr);
cairo_destroy (cr);
return FALSE;
}
int
main (int argc, char **argv)
{
..
transparent = gtk_transparent_new ();
g_signal_connect (trnasparent, "expose-event",
G_CALLBACK (expose_cb), NULL);
..
}
To try example, type the following command:
% cc `pkg-config gtk+-2.0 --cflags --libs` -o example example.c gtktransparent.c
I attached four files:
* gtktransparent.c: an implementation custom shape widget.
* gtktransparent.h: an interface of custom shape widget.
* example.c: an example code to use GtkTransparent widget.
* cairo-combined-surface.diff: second version patch of
cairo_combined_surface_t.
Thanks,
--
kou
In <a799fada0605311820r4173033bm3074cd8599d8369d at mail.gmail.com>
"[cairo] New surface: cairo_combined_surface_t" on Thu, 1 Jun 2006 10:20:52 +0900,
"Kouhei Sutou" <kou at cozmixng.org> wrote:
> --
> Even if we want to write same contents to different serfaces, we must make
> cairo_t for each cairo_surface_t. For example, if we wants to output PS and PDF
> with same contents, we write the following code:
>
> static void
> render(cairo_surface_t *surface)
> {
> cairo_t *cr;
>
> cr = cairo_create(surface);
> ...
> cairo_rectangle(cr, ...);
> cairo_fill(cr);
> ...
> cairo_show_page(cr);
> ...
> cairo_surface_finish(cairo_get_target(cr));
> }
>
> static void
> output(void)
> {
> cairo_surface_t *ps_surface, *pdf_surface;
> ...
> render(ps_surface);
> render(pdf_surface);
> }
>
> There is some problems:
> * If render() loads a image each time, the image is loaded twice.
> * We must define a function to render. (Yes, we can use "copy and paste" but
> this is a bad manner.)
> * ...
>
> To solve those problems, I suggeste that cairo provides a surface can combine
> some surfaces and show those surfaces as a surface to cairo_t. And then, we can
> write the above code as the following:
>
> static void
> output(void)
> {
> cairo_t *cr;
> cairo_surface_t *ps_surface, *pdf_surface, *combined_surface;
>
> ...
> combined_surface = cairo_combined_surface(ps_surface, pdf_surface, NULL);
>
> cr = cairo_create(combined_surface);
> ...
> cairo_rectangle(cr, ...);
> cairo_fill(cr);
> ...
> cairo_show_page(cr);
> ...
> cairo_surface_finish(cairo_get_target(cr));
> }
> --
-------------- next part --------------
/* GtkTransparent
* Copyright (C) 2006 Kouhei Sutou <kou at cozmixng.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <cairo-combined.h>
#include "gtktransparent.h"
#define GTK_TRANSPARENT_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TRANSPARENT, GtkTransparentPrivate))
struct _GtkTransparentPrivate
{
GdkBitmap *mask;
};
static void gtk_transparent_finalize (GObject *object);
static gboolean gtk_transparent_expose_event (GtkWidget *widget,
GdkEventExpose *event);
static gboolean expose_event_cb (GtkWidget *widget,
GdkEventExpose *event,
gpointer data);
G_DEFINE_TYPE (GtkTransparent, gtk_transparent, GTK_TYPE_DRAWING_AREA)
static void
gtk_transparent_class_init (GtkTransparentClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
gobject_class->finalize = gtk_transparent_finalize;
widget_class->expose_event = gtk_transparent_expose_event;
g_type_class_add_private (class, sizeof (GtkTransparentPrivate));
}
static void
gtk_transparent_init (GtkTransparent *transparent)
{
GtkTransparentPrivate *priv;
priv = transparent->priv = GTK_TRANSPARENT_GET_PRIVATE (transparent);
priv->mask = NULL;
g_signal_connect (transparent, "expose_event",
G_CALLBACK (expose_event_cb), NULL);
}
static void
gtk_transparent_free_mask (GtkTransparent *transparent)
{
if (transparent->priv->mask) {
g_object_unref (transparent->priv->mask);
transparent->priv->mask = NULL;
}
}
static void
gtk_transparent_reset_mask (GtkTransparent *transparent)
{
gtk_transparent_free_mask (transparent);
gtk_widget_shape_combine_mask (GTK_WIDGET (transparent), NULL, 0, 0);
}
static void
gtk_transparent_finalize (GObject *object)
{
GtkTransparent *transparent = GTK_TRANSPARENT (object);
gtk_transparent_free_mask (transparent);
G_OBJECT_CLASS (gtk_transparent_parent_class)->finalize (object);
}
GtkWidget*
gtk_transparent_new (void)
{
return g_object_new (GTK_TYPE_TRANSPARENT, NULL);
}
static gboolean
expose_event_cb (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
GtkTransparent *transparent;
g_return_val_if_fail (GTK_IS_TRANSPARENT (widget), FALSE);
transparent = GTK_TRANSPARENT (widget);
gtk_transparent_free_mask (transparent);
return FALSE;
}
static gboolean
gtk_transparent_expose_event (GtkWidget *widget,
GdkEventExpose *event)
{
GtkTransparent *transparent;
g_return_val_if_fail (GTK_IS_TRANSPARENT (widget), FALSE);
transparent = GTK_TRANSPARENT (widget);
if (transparent->priv->mask)
{
gtk_widget_shape_combine_mask (widget, transparent->priv->mask, 0, 0);
gtk_transparent_free_mask (transparent);
return TRUE;
}
else
{
gtk_transparent_reset_mask (transparent);
return FALSE;
}
}
cairo_t *
gtk_transparent_cairo_create (GtkTransparent *transparent)
{
GtkWidget *widget;
gint width, height;
cairo_t *cr, *drawable_cr, *mask_cr;
cairo_surface_t *drawable_surface, *mask_surface, *combined_surface;
g_return_val_if_fail (GTK_IS_TRANSPARENT (transparent), NULL);
widget = GTK_WIDGET (transparent);
g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL);
width = widget->allocation.width;
height = widget->allocation.height;
if (!transparent->priv->mask)
{
gchar *data;
data = g_malloc0 (width * height);
transparent->priv->mask =
gdk_bitmap_create_from_data (NULL, data, width, height);
g_free (data);
}
drawable_cr = gdk_cairo_create (GDK_DRAWABLE (widget->window));
drawable_surface = cairo_get_target (drawable_cr);
mask_cr = gdk_cairo_create (GDK_DRAWABLE (transparent->priv->mask));
mask_surface = cairo_get_target (mask_cr);
combined_surface = cairo_combined_surface_create (drawable_surface,
mask_surface,
NULL);
cairo_destroy (drawable_cr);
cairo_destroy (mask_cr);
cr = cairo_create (combined_surface);
cairo_surface_destroy (combined_surface);
return cr;
}
-------------- next part --------------
/* GtkTransparent
* Copyright (C) 2006 Kouhei Sutou <kou at cozmixng.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_TRANSPARENT_H__
#define __GTK_TRANSPARENT_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GTK_TYPE_TRANSPARENT (gtk_transparent_get_type ())
#define GTK_TRANSPARENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TRANSPARENT, GtkTransparent))
#define GTK_TRANSPARENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_TRANSPARENT, GtkTransparentClass))
#define GTK_IS_TRANSPARENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TRANSPARENT))
#define GTK_IS_TRANSPARENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TRANSPARENT))
#define GTK_TRANSPARENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TRANSPARENT, GtkTransparentClass))
typedef struct _GtkTransparent GtkTransparent;
typedef struct _GtkTransparentClass GtkTransparentClass;
typedef struct _GtkTransparentPrivate GtkTransparentPrivate;
struct _GtkTransparent
{
GtkDrawingArea parent_instance;
GtkTransparentPrivate *priv;
};
struct _GtkTransparentClass
{
GtkDrawingAreaClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_transparent_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_transparent_new (void);
cairo_t *gtk_transparent_cairo_create (GtkTransparent *transparent);
G_END_DECLS
#endif /* __GTK_TRANSPARENT_H__ */
-------------- next part --------------
#include <math.h>
#include "gtktransparent.h"
static void
draw_rectangle (cairo_t *cr)
{
cairo_new_path (cr);
cairo_move_to (cr, 0.0, 0.0);
cairo_rectangle (cr, 0.0, 0.0, 100.0, 100.0);
cairo_stroke (cr);
}
static void
draw_arc (cairo_t *cr)
{
cairo_new_path (cr);
cairo_move_to (cr, 50, 50);
cairo_arc (cr, 50.0, 50.0, g_random_double_range (0.0, 50.0),
0.0, 2 * M_PI);
cairo_fill (cr);
}
static gboolean
darea_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (GDK_DRAWABLE (widget->window));
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0);
draw_rectangle (cr);
cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, 1.0);
draw_arc (cr);
cairo_destroy (cr);
return FALSE;
}
static gboolean
transparent_expose_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr;
cr = gtk_transparent_cairo_create (GTK_TRANSPARENT (widget));
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0);
draw_rectangle (cr);
cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0);
draw_arc (cr);
cairo_destroy (cr);
return FALSE;
}
static gboolean
refresh (gpointer data)
{
GtkWidget *layout = data;
gtk_widget_queue_draw (layout);
return TRUE;
}
int
main (int argc, char **argv)
{
GtkWidget *window, *layout, *darea1, *darea2, *transparent;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
layout = gtk_layout_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), layout);
gtk_widget_set_size_request (layout, 200, 200);
darea1 = gtk_drawing_area_new ();
gtk_widget_set_size_request (darea1, 100, 100);
g_signal_connect(darea1, "expose-event",
G_CALLBACK (darea_expose_cb), NULL);
darea2 = gtk_drawing_area_new ();
gtk_widget_set_size_request (darea2, 100, 100);
g_signal_connect(darea2, "expose-event",
G_CALLBACK (darea_expose_cb), NULL);
transparent = gtk_transparent_new ();
gtk_widget_set_size_request (transparent, 100, 100);
g_signal_connect(transparent, "expose-event",
G_CALLBACK (transparent_expose_cb), NULL);
gtk_layout_put (GTK_LAYOUT (layout), darea1, 0, 0);
gtk_layout_put (GTK_LAYOUT (layout), transparent, 50, 50);
gtk_layout_put (GTK_LAYOUT (layout), darea2, 100, 100);
gtk_widget_show_all (window);
g_timeout_add (1000, refresh, layout);
gtk_main ();
return 0;
}
-------------- next part --------------
diff --git a/configure.in b/configure.in
index 1335e4c..5a5e922 100644
--- a/configure.in
+++ b/configure.in
@@ -709,6 +709,15 @@ fi
dnl ===========================================================================
+CAIRO_BACKEND_ENABLE(combined, Combined, no, [])
+AM_CONDITIONAL(CAIRO_HAS_COMBINED_SURFACE, test "x$use_combined" = "xyes")
+if test "x$use_combined" = "xyes"; then
+ COMBINED_SURFACE_FEATURE="#define CAIRO_HAS_COMBINED_SURFACE 1"
+fi
+AC_SUBST(COMBINED_SURFACE_FEATURE)
+
+dnl ===========================================================================
+
AC_ARG_ENABLE(test-surfaces,
AS_HELP_STRING([--enable-test-surfaces],
[Add backends for more test suite coverage (no additional public functionality)]),
@@ -749,6 +758,7 @@ echo " SVG: $use_svg"
echo " glitz: $use_glitz"
echo " BeOS: $use_beos"
echo " DirectFB: $use_directfb"
+echo " Combined: $use_combined"
echo ""
echo "the following font backends:"
echo " FreeType: $use_freetype"
diff --git a/src/Makefile.am b/src/Makefile.am
index 42ae71f..996fdb4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -100,6 +100,12 @@ cairo_win32_api_headers += \
$(srcdir)/cairo-ps.h
endif
+if CAIRO_HAS_COMBINED_SURFACE
+libcairo_combined_headers = cairo-combined.h
+libcairo_combined_sources = cairo-combined-surface.c
+endif
+
+
# These names match automake style variable definition conventions so
# without these lines, automake will complain during the handling of
# the libcairo_la_LIBADD below. (The INCLUDES is an autoconf only
@@ -122,7 +128,8 @@ cairoinclude_HEADERS = \
$(libcairo_beos_headers) \
$(libcairo_xcb_headers) \
$(libcairo_xlib_headers) \
- $(libcairo_directfb_headers)
+ $(libcairo_directfb_headers) \
+ $(libcairo_combined_headers)
lib_LTLIBRARIES = libcairo.la
@@ -195,6 +202,7 @@ libcairo_la_SOURCES = \
$(libcairo_glitz_sources) \
$(libcairo_win32_sources) \
$(libcairo_directfb_sources) \
+ $(libcairo_combined_sources) \
cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined $(export_symbols)
diff --git a/src/cairo-combined-surface.c b/src/cairo-combined-surface.c
new file mode 100644
index 0000000..ab21621
--- /dev/null
+++ b/src/cairo-combined-surface.c
@@ -0,0 +1,685 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright ? 2006 Kouhei Sutou <kou at cozmixng.org>
+ *
+ * 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):
+ */
+
+#include "cairoint.h"
+#include "cairo-combined.h"
+
+typedef struct _cairo_combined_surface
+{
+ cairo_surface_t base;
+
+ cairo_array_t surfaces;
+} cairo_combined_surface_t;
+
+static const cairo_surface_backend_t cairo_combined_surface_backend;
+
+
+static cairo_surface_t *
+_cairo_combined_surface_create_array (cairo_array_t *surfaces)
+{
+ int i, n;
+ cairo_combined_surface_t *surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_content_t content = CAIRO_CONTENT_COLOR;
+
+ n = _cairo_array_num_elements (surfaces);
+ child_surfaces = _cairo_array_index (surfaces, 0);
+ for (i = 0; i < n; i++) {
+ child_surface = child_surfaces[i];
+ if (child_surface->status) {
+ _cairo_error (child_surface->status);
+ return (cairo_surface_t*) &_cairo_surface_nil;
+ }
+ content |= cairo_surface_get_content (child_surface);
+ }
+
+ surface = malloc (sizeof (cairo_combined_surface_t));
+ if (surface == NULL) {
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_surface_t*) &_cairo_surface_nil;
+ }
+
+ _cairo_surface_init (&surface->base, &cairo_combined_surface_backend,
+ content);
+
+ _cairo_array_init (&surface->surfaces, sizeof (cairo_surface_t *));
+
+ child_surfaces = _cairo_array_index (surfaces, 0);
+ for (i = 0; i < n; i++) {
+ child_surface = child_surfaces[i];
+ cairo_surface_reference (child_surface);
+ _cairo_array_append (&surface->surfaces, &child_surface);
+ }
+
+ return &surface->base;
+}
+
+/**
+ * cairo_combined_surface_create:
+ * @child_surface1: a surface to combined
+ * @...: other surfaces to combined. NULL terminate.
+ *
+ * Creates a combined surface with the specified surfaces.
+ *
+ * Return value: a pointer to the newly created surface. The caller
+ * owns the surface and should call cairo_surface_destroy when done
+ * with it.
+ *
+ * This function always returns a valid pointer, but it will return a
+ * pointer to a "nil" surface if an error such as out of memory
+ * occurs. You can use cairo_surface_status() to check for this.
+ **/
+cairo_surface_t *
+cairo_combined_surface_create (cairo_surface_t *child_surface1, ...)
+{
+ va_list ap;
+ cairo_array_t surfaces;
+ cairo_surface_t *surface;
+ cairo_surface_t *child_surface_n;
+
+ _cairo_array_init (&surfaces, sizeof (cairo_surface_t *));
+
+ va_start (ap, child_surface1);
+ for (child_surface_n = child_surface1;
+ child_surface_n;
+ child_surface_n = (cairo_surface_t *) va_arg (ap, cairo_surface_t *)) {
+ _cairo_array_append (&surfaces, &child_surface_n);
+ }
+ va_end (ap);
+
+ surface = _cairo_combined_surface_create_array (&surfaces);
+ _cairo_array_fini (&surfaces);
+ return surface;
+}
+
+/**
+ * cairo_combined_surface_create2:
+ * @n_surface: number of surfaces.
+ * @child_surfaces: surfaces to combined.
+ *
+ * Creates a combined surface with the specified surfaces.
+ *
+ * Return value: a pointer to the newly created surface. The caller
+ * owns the surface and should call cairo_surface_destroy when done
+ * with it.
+ *
+ * This function always returns a valid pointer, but it will return a
+ * pointer to a "nil" surface if an error such as out of memory
+ * occurs. You can use cairo_surface_status() to check for this.
+ **/
+cairo_surface_t *
+cairo_combined_surface_create2 (int n_surfaces,
+ cairo_surface_t **child_surfaces)
+{
+ cairo_array_t surfaces;
+ cairo_surface_t *surface;
+
+ if (n_surfaces < 1)
+ return (cairo_surface_t *) &_cairo_surface_nil;
+
+ _cairo_array_init (&surfaces, sizeof (cairo_surface_t *));
+ _cairo_array_append_multiple (&surfaces, child_surfaces, n_surfaces);
+ surface = _cairo_combined_surface_create_array (&surfaces);
+ _cairo_array_fini (&surfaces);
+ return surface;
+}
+
+
+
+static cairo_surface_t *
+_cairo_combined_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_combined_surface_t *other_surface = abstract_surface;
+
+ if (((cairo_surface_t *)other_surface)->status)
+ return (cairo_surface_t *) &_cairo_surface_nil;
+
+ if (! CAIRO_CONTENT_VALID (content)) {
+ _cairo_error (CAIRO_STATUS_INVALID_CONTENT);
+ return (cairo_surface_t *) &_cairo_surface_nil;
+ }
+
+ return _cairo_combined_surface_create_array (&other_surface->surfaces);
+}
+
+static cairo_status_t
+_cairo_combined_surface_finish (void *abstract_surface)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; i < n; i++) {
+ child_surface = child_surfaces[i];
+ cairo_surface_finish (child_surface);
+ cairo_surface_destroy (child_surface);
+ }
+ _cairo_array_fini (&surface->surfaces);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_combined_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ cairo_surface_t **clone_out)
+{
+ cairo_combined_surface_t *surface = abstract_surface;
+
+ if (src->backend == surface->base.backend) {
+ *clone_out = cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_composite (cairo_operator_t op,
+ cairo_pattern_t *src_pattern,
+ cairo_pattern_t *mask_pattern,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int fdst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_dst;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_composite (op, src_pattern, mask_pattern,
+ child_surface, src_x, src_y,
+ mask_x, mask_y, fdst_x, dst_y,
+ width, height);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_fixed_t *rects,
+ int num_rects)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_fill_rectangles (child_surface, op, color,
+ rects, num_rects);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_composite_trapezoids (cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_dst,
+ cairo_antialias_t antialias,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ int i, n;
+ cairo_combined_surface_t *dst = abstract_dst;
+ cairo_surface_t *child_dst;
+ cairo_surface_t **child_dsts;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&dst->surfaces);
+ child_dsts = _cairo_array_index (&dst->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_dst = child_dsts[i];
+ status = _cairo_surface_composite_trapezoids (op, pattern,
+ child_dst, antialias,
+ src_x, src_y,
+ dst_x, dst_y,
+ width, height,
+ traps, num_traps);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_copy_page (void *abstract_surface)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_copy_page (child_surface);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_show_page (void *abstract_surface)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_show_page (child_surface);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+ unsigned int serial;
+
+ serial = _cairo_surface_get_current_clip_serial(&surface->base);
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_set_clip_region (child_surface, region, serial);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_intersect_clip_path (void *abstract_surface,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_intersect_clip_path (child_surface, path,
+ fill_rule, tolerance,
+ antialias);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_fixed_t *rectangle)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ if (n < 1)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ status = _cairo_surface_get_extents (child_surfaces[0], rectangle);
+
+ for (i = 1; !status && i < n; i++) {
+ cairo_rectangle_fixed_t tmp_rectangle;
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_get_extents (child_surface, &tmp_rectangle);
+ if (tmp_rectangle.x != rectangle->x ||
+ tmp_rectangle.y != rectangle->y ||
+ tmp_rectangle.width != rectangle->width ||
+ tmp_rectangle.height != rectangle->height)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_old_show_glyphs (cairo_scaled_font_t *font,
+ cairo_operator_t op,
+ cairo_pattern_t *pattern,
+ void *abstract_surface,
+ int source_x,
+ int source_y,
+ int dest_x,
+ int dest_y,
+ unsigned int width,
+ unsigned int height,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_old_show_glyphs (font, op, pattern,
+ child_surface,
+ source_x, source_y,
+ dest_x, dest_y,
+ width, height,
+ glyphs, num_glyphs);
+ }
+
+ return status;
+}
+
+static void
+_cairo_combined_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_bool_t got = FALSE;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; i < n; i++) {
+ child_surface = child_surfaces[i];
+ if (!child_surface->finished &&
+ child_surface->backend->get_font_options) {
+ child_surface->backend->get_font_options (child_surface, options);
+ got = TRUE;
+ break;
+ }
+ }
+
+ if (!got)
+ _cairo_font_options_init_default (options);
+}
+
+static cairo_status_t
+_cairo_combined_surface_flush (void *abstract_surface)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ cairo_surface_flush (child_surface);
+ status = cairo_surface_status (child_surface);
+ }
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_combined_surface_mark_dirty_rectangle (void *abstract_surface,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ cairo_surface_mark_dirty_rectangle (child_surface, x, y, width, height);
+ status = cairo_surface_status (child_surface);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_paint (child_surface, op, source);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_pattern_t *mask)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_mask (child_surface, op, source, mask);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ 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)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ child_surface->clip = surface->base.clip;
+ status = _cairo_surface_stroke (child_surface, op, source, path, style,
+ ctm, ctm_inverse, tolerance, antialias);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ if (!status) {
+ child_surface = child_surfaces[i];
+ child_surface->clip = surface->base.clip;
+ status = _cairo_surface_fill (child_surface, op, source, path,
+ fill_rule, tolerance, antialias);
+ }
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_combined_surface_show_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font)
+{
+ int i, n;
+ cairo_combined_surface_t *surface = abstract_surface;
+ cairo_surface_t *child_surface;
+ cairo_surface_t **child_surfaces;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+ n = _cairo_array_num_elements (&surface->surfaces);
+ child_surfaces = _cairo_array_index (&surface->surfaces, 0);
+ for (i = 0; !status && i < n; i++) {
+ child_surface = child_surfaces[i];
+ status = _cairo_surface_show_glyphs (child_surface, op, source,
+ glyphs, num_glyphs, scaled_font);
+ }
+
+ return status;
+}
+
+static const cairo_surface_backend_t cairo_combined_surface_backend = {
+ CAIRO_SURFACE_TYPE_COMBINED,
+ _cairo_combined_surface_create_similar,
+ _cairo_combined_surface_finish,
+ NULL, /* acquire_source_image */
+ NULL, /* release_source_image */
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ _cairo_combined_surface_clone_similar,
+ _cairo_combined_surface_composite,
+ _cairo_combined_surface_fill_rectangles,
+ _cairo_combined_surface_composite_trapezoids,
+ _cairo_combined_surface_copy_page,
+ _cairo_combined_surface_show_page,
+ _cairo_combined_surface_set_clip_region,
+ _cairo_combined_surface_intersect_clip_path,
+ _cairo_combined_surface_get_extents,
+ _cairo_combined_surface_old_show_glyphs,
+ _cairo_combined_surface_get_font_options,
+ _cairo_combined_surface_flush,
+ _cairo_combined_surface_mark_dirty_rectangle,
+ NULL, /* scaled_font_fini */
+ NULL, /* scaled_glyph_fini */
+ _cairo_combined_surface_paint,
+ _cairo_combined_surface_mask,
+ _cairo_combined_surface_stroke,
+ _cairo_combined_surface_fill,
+ _cairo_combined_surface_show_glyphs,
+ NULL, /* snapshot */
+};
diff --git a/src/cairo-combined.h b/src/cairo-combined.h
new file mode 100644
index 0000000..6766927
--- /dev/null
+++ b/src/cairo-combined.h
@@ -0,0 +1,57 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright ? 2006 Kouhei Sutou <kou at cozmixng.org>
+ *
+ * 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):
+ */
+
+#ifndef CAIRO_COMBINED_H
+#define CAIRO_COMBINED_H
+
+#include <cairo.h>
+
+#if CAIRO_HAS_COMBINED_SURFACE
+
+CAIRO_BEGIN_DECLS
+
+cairo_public cairo_surface_t *
+cairo_combined_surface_create (cairo_surface_t *surface, ...);
+
+cairo_public cairo_surface_t *
+cairo_combined_surface_create2 (int n_surface, cairo_surface_t **child_surfaces);
+
+CAIRO_END_DECLS
+
+#else /* CAIRO_HAS_COMBINED_SURFACE */
+# error Cairo was not compiled with support for the combined backend
+#endif /* CAIRO_HAS_COMBINED_SURFACE */
+
+#endif /* CAIRO_COMBINED_H */
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index 4b845bf..2608e97 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -75,6 +75,10 @@ #define CAIRO_VERSION_STRING "@CAIRO_VER
@DIRECTFB_SURFACE_FEATURE@
+ at COMBINED_SURFACE_FEATURE@
+
+ at COMBINED_SURFACE_FEATURE@
+
@FT_FONT_FEATURE@
@WIN32_FONT_FEATURE@
diff --git a/src/cairo.h b/src/cairo.h
index 980ecc0..abd1c23 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1260,7 +1260,8 @@ typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_WIN32,
CAIRO_SURFACE_TYPE_BEOS,
CAIRO_SURFACE_TYPE_DIRECTFB,
- CAIRO_SURFACE_TYPE_SVG
+ CAIRO_SURFACE_TYPE_SVG,
+ CAIRO_SURFACE_TYPE_COMBINED
} cairo_surface_type_t;
cairo_public cairo_surface_type_t
More information about the cairo
mailing list