[cairo] [PATCH] image: Add public API for the creation of a surface for a pixman_image_t

Chris Wilson chris at chris-wilson.co.uk
Tue Mar 20 06:12:40 PDT 2012


Greater interoperablity with pixman is often requested by users dealing
with quirky hardware that prefers niche formats. As the goal is to keep
the number of core, well supported cairo_format_t to a minimum, we need
an alternative mechanism to support the extensive range of formats
supported by pixman. In the future we will also have to look to
supporting pixman colorspaces, but for now we only handled RGBA linear
compositing and so restrict ourselves to that subset of pixman images.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 src/cairo-image-surface.c      |  126 +++++++++++++++++++++++++++++++++++++++-
 src/cairo.h                    |   10 +++
 util/cairo-missing/Makefile.am |    2 +-
 3 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 2a2d59d..5c682f0 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -489,7 +489,7 @@ slim_hidden_def (cairo_format_stride_for_width);
  * See cairo_surface_set_user_data() for a means of attaching a
  * destroy-notification fallback to the surface if necessary.
  **/
-    cairo_surface_t *
+ cairo_surface_t *
 cairo_image_surface_create_for_data (unsigned char     *data,
 				     cairo_format_t	format,
 				     int		width,
@@ -640,7 +640,7 @@ slim_hidden_def (cairo_image_surface_get_height);
  *
  * Since: 1.2
  **/
-    int
+int
 cairo_image_surface_get_stride (cairo_surface_t *surface)
 {
 
@@ -655,7 +655,127 @@ cairo_image_surface_get_stride (cairo_surface_t *surface)
 }
 slim_hidden_def (cairo_image_surface_get_stride);
 
-    cairo_format_t
+static void
+_pixman_image_destroy_notify (pixman_image_t *pixman_image,
+			      void *closure)
+{
+    cairo_surface_finish (closure);
+}
+
+/**
+ * cairo_image_surface_create_for_pixman_image:
+ * @format: the format of pixels in the buffer, specified by the pixman_format_code_t
+ * @image: the pixman_image_t containing the pixels, and dimensions
+ *
+ * Creates an image surface for the provided pixman image. A reference
+ * is taken upon the pixman image, and so the parent copy may be discarded
+ * without the backing data being lost (or freed). The initial contents
+ * of the surface will be the contents of the pixman_image_t, you
+ * must explicitly clear the buffer, using, for example,
+ * cairo_rectangle() and cairo_fill() if you want it cleared.
+ *
+ * Note that cairo takes a copy of the pixman_image_t (rather than directly
+ * use the value passed in) as the object is stateful and cairo makes
+ * assumptions about the values tracked by pixman. Cairo uses the
+ * pixman_image_t destroy notification to ensure that the image is finished
+ * should the underlying resource be freed.
+ *
+ * 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 in the case of an error such as out of
+ * memory or an invalid pixman format code (one that cairo can not use
+ * in its RGBA compositing model as a target surface). In case of invalid
+ * format the error status of the returned surface will be
+ * %CAIRO_STATUS_INVALID_FORMAT.  You can use
+ * cairo_surface_status() to check for this.
+ *
+ * Since: 1.12
+ **/
+cairo_surface_t *
+cairo_image_surface_create_for_pixman_image (pixman_format_code_t format,
+					     pixman_image_t *image)
+{
+    int width, height;
+    pixman_image_t *copy;
+    cairo_surface_t *surface;
+
+    if (! pixman_format_supported_destination (format))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+    width = pixman_image_get_width (image);
+    height = pixman_image_get_width (image);
+    if (! _cairo_image_surface_is_size_valid (width, height))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
+    copy = pixman_image_create_bits (format, width, height,
+				     pixman_image_get_data (image),
+				     pixman_image_get_stride (image));
+    if (unlikely (copy == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    surface = _cairo_image_surface_create_for_pixman_image (copy, format);
+    if (unlikely (surface->status))
+	return surface;
+
+    pixman_image_set_destroy_function (image,
+				       _pixman_image_destroy_notify,
+				       surface);
+    return surface;
+}
+
+/**
+ * cairo_image_surface_get_pixman_image:
+ * @surface: a #cairo_image_surface_t
+ * @image: the returned pixman_image_t
+ *
+ * Retrieve the underlying pixman_image_t for an #cairo_image_surface_t
+ * for inspection or direct modification.
+ *
+ * A call to cairo_surface_flush() is required before accessing the
+ * pixel data to ensure that all pending drawing operations are
+ * finished. A call to cairo_surface_mark_dirty() is required after
+ * the data is modified.
+ *
+ * Note that cairo returns the pixman_image_t used by itself (rather than
+ * create a copy), and that this object is stateful. Cairo assumes that
+ * the pixman_image_t holds the default state, if you modify it (for example
+ * by setting a clip, filter or transformation) you must undo the modification
+ * before returning control to Cairo.
+ *
+ * Return value: the format code of the image, along with the pointer to
+ * the pixman image, or 0 if @surface is not an image surface, or if
+ * cairo_surface_finish() has been called. A reference is not added so
+ * care must be taken to call pixman_image_ref() if you wish to keep the
+ * pixman image around. Also if the #cairo_image_surface_t was created by
+ * a call to cairo_image_surface_create(), the cairo image surface must
+ * be kept around as well or else the pixel buffer may be freed unexpectedly.
+ *
+ * Since: 1.12
+ **/
+pixman_format_code_t
+cairo_image_surface_get_pixman_image (cairo_surface_t *surface,
+				      pixman_image_t *image)
+{
+    cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
+
+    if (! _cairo_surface_is_image (surface)) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return 0;
+    }
+
+    if (surface->finished) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
+	return 0;
+    }
+
+    *image = image_surface->pixman_image;
+    return image_surface->pixman_format;
+}
+
+cairo_format_t
 _cairo_format_from_content (cairo_content_t content)
 {
     switch (content) {
diff --git a/src/cairo.h b/src/cairo.h
index d23cd10..bb93336 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -42,6 +42,8 @@
 #include "cairo-features.h"
 #include "cairo-deprecated.h"
 
+#include <pixman.h>
+
 #ifdef  __cplusplus
 # define CAIRO_BEGIN_DECLS  extern "C" {
 # define CAIRO_END_DECLS    }
@@ -2439,6 +2441,14 @@ cairo_image_surface_create_for_data (unsigned char	       *data,
 				     int			height,
 				     int			stride);
 
+cairo_public cairo_surface_t *
+cairo_image_surface_create_for_pixman_image (pixman_format_code_t format,
+					     pixman_image_t *image);
+
+cairo_public pixman_format_code_t
+cairo_image_surface_get_pixman_image (cairo_surface_t *surface,
+				      pixman_image_t *image);
+
 cairo_public unsigned char *
 cairo_image_surface_get_data (cairo_surface_t *surface);
 
diff --git a/util/cairo-missing/Makefile.am b/util/cairo-missing/Makefile.am
index 9078610..d252b74 100644
--- a/util/cairo-missing/Makefile.am
+++ b/util/cairo-missing/Makefile.am
@@ -1,6 +1,6 @@
 include $(top_srcdir)/util/cairo-missing/Makefile.sources
 
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(CAIRO_CFLAGS)
 
 noinst_LTLIBRARIES = libcairo-missing.la
 
-- 
1.7.9.1



More information about the cairo mailing list