[PATCH] Introduce cairo_image_surface_create_for_target().

Chris Wilson chris at chris-wilson.co.uk
Thu Oct 18 11:48:59 PDT 2007


Add a new function that creates an image surface optimised for use with
the target backend. For example, with the xlib backend, the image may
be placed in an XShm segment and will use the XShm extension when
transferring the data between the XServer.
---
 perf/cairo-perf-cover.c                   |   10 ++-
 perf/subimage_copy.c                      |    4 +-
 src/cairo-image-surface.c                 |   48 +++++++++++++++-
 src/cairo-pattern.c                       |    2 +-
 src/cairo-png.c                           |   89 ++++++++++++++++++++++-------
 src/cairo-surface.c                       |    4 +-
 src/cairo.h                               |   16 +++++
 src/cairoint.h                            |   11 ++++
 test/cairo-test.c                         |    8 +-
 test/cairo-test.h                         |    2 +-
 test/composite-integer-translate-over.c   |    2 +-
 test/composite-integer-translate-source.c |    2 +-
 test/create-from-png-stream.c             |    6 +-
 test/create-from-png.c                    |    2 +-
 test/extend-reflect.c                     |    2 +-
 test/nil-surface.c                        |    4 +-
 16 files changed, 170 insertions(+), 42 deletions(-)

diff --git a/perf/cairo-perf-cover.c b/perf/cairo-perf-cover.c
index 53dc7b7..386ee17 100644
--- a/perf/cairo-perf-cover.c
+++ b/perf/cairo-perf-cover.c
@@ -75,8 +75,9 @@ set_source_image_surface_rgb (cairo_t	*cr,
 {
     cairo_surface_t *source;
 
-    source = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
-					 width, height);
+    source = cairo_image_surface_create_for_target (CAIRO_FORMAT_RGB24,
+					            width, height,
+						    cairo_get_target (cr));
     init_and_set_source_surface (cr, source, width, height);
 
     cairo_surface_destroy (source);
@@ -89,8 +90,9 @@ set_source_image_surface_rgba (cairo_t	*cr,
 {
     cairo_surface_t *source;
 
-    source = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					 width, height);
+    source = cairo_image_surface_create_for_target (CAIRO_FORMAT_ARGB32,
+					            width, height,
+						    cairo_get_target (cr));
     init_and_set_source_surface (cr, source, width, height);
 
     cairo_surface_destroy (source);
diff --git a/perf/subimage_copy.c b/perf/subimage_copy.c
index 54f596f..70246b7 100644
--- a/perf/subimage_copy.c
+++ b/perf/subimage_copy.c
@@ -58,7 +58,9 @@ subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height)
     cairo_set_source_rgb (cr, 0, 0, 1); /* blue */
     cairo_paint (cr);
 
-    image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+    image = cairo_image_surface_create_for_target (CAIRO_FORMAT_ARGB32,
+	                                           width, height,
+						   cairo_get_target (cr));
     cr2 = cairo_create (image);
     cairo_set_source_rgb (cr2, 1, 0, 0); /* red */
     cairo_paint (cr2);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index ec3477b..0f428ba 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -396,7 +396,7 @@ _cairo_image_surface_create_with_masks (unsigned char	       *data,
 							   stride);
 }
 
-static pixman_format_code_t 
+pixman_format_code_t
 _cairo_format_to_pixman_format_code (cairo_format_t format)
 {
     int ret = 0;
@@ -411,7 +411,6 @@ _cairo_format_to_pixman_format_code (cairo_format_t format)
 	ret = PIXMAN_x8r8g8b8;
 	break;
     case CAIRO_FORMAT_ARGB32:
-    default:
 	ret = PIXMAN_a8r8g8b8;
 	break;
     }
@@ -485,6 +484,51 @@ cairo_image_surface_create (cairo_format_t	format,
 }
 slim_hidden_def (cairo_image_surface_create);
 
+/**
+ * cairo_image_surface_create_for_target:
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ * @target: destination surface (or similar)
+ *
+ * Creates an image surface of the specified format and
+ * dimensions optimised for use with the target surface. For example,
+ * when the target is an Xlib surface then the image will be allocated
+ * within an XShm segment. Initially the surface contents are all
+ * 0. (Specifically, within each pixel, each color or alpha channel
+ * belonging to format will be 0. The contents of bits within a pixel,
+ * but not belonging to the given format are undefined).
+ *
+ * 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.
+ *
+ * Since: 1.16
+ **/
+cairo_surface_t *
+cairo_image_surface_create_for_target (cairo_format_t		 format,
+			               int			 width,
+				       int			 height,
+				       cairo_surface_t	*target)
+{
+    if (! CAIRO_FORMAT_VALID (format)) {
+	_cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
+	return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_format;
+    }
+
+    if (target && target->backend->create_image_surface)
+	return target->backend->create_image_surface (format,
+		                                      width, height,
+						      target);
+
+    return cairo_image_surface_create (format, width, height);
+}
+slim_hidden_def (cairo_image_surface_create_for_target);
+
 cairo_surface_t *
 _cairo_image_surface_create_with_content (cairo_content_t	content,
 					  int			width,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 488177b..c60c96e 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1254,7 +1254,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
     }
 
     image = (cairo_image_surface_t *)
-	cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+	cairo_image_surface_create_for_target (CAIRO_FORMAT_ARGB32, width, height, dst);
     if (image->base.status) {
 	pixman_image_unref (pixman_image);
 	return image->base.status;
diff --git a/src/cairo-png.c b/src/cairo-png.c
index c503994..4285075 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -368,7 +368,8 @@ premultiply_data (png_structp   png,
 
 static cairo_surface_t *
 read_png (png_rw_ptr	read_func,
-	  void		*closure)
+	  void		*closure,
+	  cairo_surface_t *target)
 {
     cairo_surface_t *surface = (cairo_surface_t*) &_cairo_surface_nil;
     png_struct *png = NULL;
@@ -378,7 +379,6 @@ read_png (png_rw_ptr	read_func,
     png_uint_32 png_width, png_height, stride;
     int depth, color_type, interlace;
     unsigned int i;
-    unsigned int pixel_size;
     cairo_status_t status;
 
     /* XXX: Perhaps we'll want some other error handlers? */
@@ -407,7 +407,6 @@ read_png (png_rw_ptr	read_func,
     png_get_IHDR (png, info,
                   &png_width, &png_height, &depth,
                   &color_type, &interlace, NULL, NULL);
-    stride = 4 * png_width;
 
     /* convert palette/gray image to rgb */
     if (color_type == PNG_COLOR_TYPE_PALETTE)
@@ -444,35 +443,29 @@ read_png (png_rw_ptr	read_func,
 
     png_read_update_info (png, info);
 
-    pixel_size = 4;
-    data = _cairo_malloc_abc (png_height, png_width, pixel_size);
-    if (data == NULL)
+    surface = cairo_image_surface_create_for_target (CAIRO_FORMAT_ARGB32,
+						     png_width,
+						     png_height,
+						     target);
+    if (surface->status)
 	goto BAIL;
 
     row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
     if (row_pointers == NULL)
 	goto BAIL;
 
+    data   = ((cairo_image_surface_t *) surface)->data;
+    stride = ((cairo_image_surface_t *) surface)->stride;
+
     for (i = 0; i < png_height; i++)
-        row_pointers[i] = &data[i * png_width * pixel_size];
+        row_pointers[i] = &data[i * stride];
 
     png_read_image (png, row_pointers);
     png_read_end (png, info);
 
-    surface = cairo_image_surface_create_for_data (data,
-						   CAIRO_FORMAT_ARGB32,
-						   png_width, png_height, stride);
-    if (surface->status)
-	goto BAIL;
-
-    _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
-    data = NULL;
-
  BAIL:
     if (row_pointers)
 	free (row_pointers);
-    if (data)
-	free (data);
     if (png)
 	png_destroy_read_struct (&png, &info, NULL);
 
@@ -519,6 +512,31 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size)
 cairo_surface_t *
 cairo_image_surface_create_from_png (const char *filename)
 {
+    return cairo_image_surface_create_from_png_for_target (filename, NULL);
+}
+
+/**
+ * cairo_image_surface_create_from_png_for_target:
+ * @filename: name of PNG file to load
+ * @target: target surface to optimise the image data for
+ *
+ * Creates a new image surface, optimised for use with the target surface,
+ * and initializes the contents to the given PNG file.
+ *
+ * Return value: a new #cairo_surface_t initialized with the contents
+ * of the PNG file, or a "nil" surface if any error occurred. A nil
+ * surface can be checked for with cairo_surface_status(surface) which
+ * may return one of the following values:
+ *
+ *	CAIRO_STATUS_NO_MEMORY
+ *	CAIRO_STATUS_FILE_NOT_FOUND
+ *	CAIRO_STATUS_READ_ERROR
+ *
+ * Since: 1.6
+ **/
+cairo_surface_t *
+cairo_image_surface_create_from_png_for_target (const char *filename, cairo_surface_t *target)
+{
     FILE *fp;
     cairo_surface_t *surface;
 
@@ -537,12 +555,13 @@ cairo_image_surface_create_from_png (const char *filename)
 	}
     }
 
-    surface = read_png (stdio_read_func, fp);
+    surface = read_png (stdio_read_func, fp, target);
 
     fclose (fp);
 
     return surface;
 }
+slim_hidden_def (cairo_image_surface_create_from_png_for_target);
 
 struct png_read_closure_t {
     cairo_read_func_t	read_func;
@@ -585,5 +604,35 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t	read_func,
     png_closure.read_func = read_func;
     png_closure.closure = closure;
 
-    return read_png (stream_read_func, &png_closure);
+    return read_png (stream_read_func, &png_closure, NULL);
+}
+
+
+/**
+ * cairo_image_surface_create_from_png_stream_for_target:
+ * @read_func: function called to read the data of the file
+ * @closure: data to pass to @read_func.
+ * @target: target surface to optimise image data for
+ *
+ * Creates a new image surface, optimised for use with the target surface,
+ * from PNG data read incrementally via the @read_func function.
+ *
+ * Return value: a new #cairo_surface_t initialized with the contents
+ * of the PNG file or %NULL if the data read is not a valid PNG image or
+ * memory could not be allocated for the operation.
+ *
+ * Since; 1.6
+ **/
+cairo_surface_t *
+cairo_image_surface_create_from_png_stream_for_target (
+	                                    cairo_read_func_t	 read_func,
+					    void		*closure,
+					    cairo_surface_t	*target)
+{
+    struct png_read_closure_t png_closure;
+
+    png_closure.read_func = read_func;
+    png_closure.closure = closure;
+
+    return read_png (stream_read_func, &png_closure, target);
 }
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index d0a5c46..27d445e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -241,7 +241,9 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
     }
 
     if (surface == NULL)
-	surface = cairo_image_surface_create (format, width, height);
+	surface = cairo_image_surface_create_for_target (format,
+		                                         width, height,
+							 other);
 
     /* If any error occurred, then return the nil surface we received. */
     if (surface->status)
diff --git a/src/cairo.h b/src/cairo.h
index 65d8b36..37fc640 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1589,6 +1589,12 @@ cairo_image_surface_create (cairo_format_t	format,
 			    int			height);
 
 cairo_public cairo_surface_t *
+cairo_image_surface_create_for_target (cairo_format_t		 format,
+			               int			 width,
+				       int			 height,
+				       cairo_surface_t		*target);
+
+cairo_public cairo_surface_t *
 cairo_image_surface_create_for_data (unsigned char	       *data,
 				     cairo_format_t		format,
 				     int			width,
@@ -1616,9 +1622,19 @@ cairo_public cairo_surface_t *
 cairo_image_surface_create_from_png (const char	*filename);
 
 cairo_public cairo_surface_t *
+cairo_image_surface_create_from_png_for_target (const char *filename,
+	                                        cairo_surface_t *target);
+
+cairo_public cairo_surface_t *
 cairo_image_surface_create_from_png_stream (cairo_read_func_t	read_func,
 					    void		*closure);
 
+cairo_public cairo_surface_t *
+cairo_image_surface_create_from_png_stream_for_target (
+	                                    cairo_read_func_t	 read_func,
+					    void		*closure,
+					    cairo_surface_t     *target);
+
 #endif
 
 /* Pattern creation functions */
diff --git a/src/cairoint.h b/src/cairoint.h
index 16e8a08..3d1b5ba 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -828,6 +828,12 @@ struct _cairo_surface_backend {
 				 cairo_matrix_t		*stroke_ctm_inverse,
 				 double			 stroke_tolerance,
 				 cairo_antialias_t	 stroke_antialias);
+
+    cairo_surface_t *
+    (*create_image_surface)    (cairo_format_t           format,
+	                        int                      width,
+				int                      height,
+				void                    *abstract_target);
 };
 
 typedef struct _cairo_format_masks {
@@ -1950,6 +1956,9 @@ _cairo_surface_has_device_transform (cairo_surface_t *surface);
 cairo_private cairo_format_t
 _cairo_format_from_content (cairo_content_t content);
 
+cairo_private pixman_format_code_t
+_cairo_format_to_pixman_format_code (cairo_format_t format);
+
 cairo_private cairo_content_t
 _cairo_content_from_format (cairo_format_t format);
 
@@ -2344,6 +2353,8 @@ slim_hidden_proto (cairo_get_current_point);
 slim_hidden_proto (cairo_get_matrix);
 slim_hidden_proto (cairo_get_tolerance);
 slim_hidden_proto (cairo_image_surface_create);
+slim_hidden_proto (cairo_image_surface_create_from_png_for_target);
+slim_hidden_proto (cairo_image_surface_create_for_target);
 slim_hidden_proto (cairo_image_surface_create_for_data);
 slim_hidden_proto (cairo_image_surface_get_height);
 slim_hidden_proto (cairo_image_surface_get_width);
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 500bb16..fec7edc 100755
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -612,12 +612,12 @@ cairo_test (cairo_test_t *test)
 }
 
 cairo_surface_t *
-cairo_test_create_surface_from_png (const char *filename)
+cairo_test_create_surface_from_png (const char *filename, cairo_surface_t *target)
 {
     cairo_surface_t *image;
     char *srcdir = getenv ("srcdir");
 
-    image = cairo_image_surface_create_from_png (filename);
+    image = cairo_image_surface_create_from_png_for_target (filename, target);
     if (cairo_surface_status(image)) {
         /* expect not found when running with srcdir != builddir
          * such as when 'make distcheck' is run
@@ -625,7 +625,7 @@ cairo_test_create_surface_from_png (const char *filename)
 	if (srcdir) {
 	    char *srcdir_filename;
 	    xasprintf (&srcdir_filename, "%s/%s", srcdir, filename);
-	    image = cairo_image_surface_create_from_png (srcdir_filename);
+	    image = cairo_image_surface_create_from_png_for_target (srcdir_filename, target);
 	    free (srcdir_filename);
 	}
 	if (cairo_surface_status(image))
@@ -641,7 +641,7 @@ cairo_test_create_pattern_from_png (const char *filename)
     cairo_surface_t *image;
     cairo_pattern_t *pattern;
 
-    image = cairo_test_create_surface_from_png (filename);
+    image = cairo_test_create_surface_from_png (filename, NULL);
 
     pattern = cairo_pattern_create_for_surface (image);
 
diff --git a/test/cairo-test.h b/test/cairo-test.h
index d7ed3a7..a0a3488 100755
--- a/test/cairo-test.h
+++ b/test/cairo-test.h
@@ -125,7 +125,7 @@ cairo_test_log (const char *fmt, ...) CAIRO_BOILERPLATE_PRINTF_FORMAT(1, 2);
  * directory that is different from the one where the source image
  * exists). */
 cairo_surface_t *
-cairo_test_create_surface_from_png (const char *filename);
+cairo_test_create_surface_from_png (const char *filename, cairo_surface_t *target);
 
 cairo_pattern_t *
 cairo_test_create_pattern_from_png (const char *filename);
diff --git a/test/composite-integer-translate-over.c b/test/composite-integer-translate-over.c
index 2eac588..6681a26 100644
--- a/test/composite-integer-translate-over.c
+++ b/test/composite-integer-translate-over.c
@@ -44,7 +44,7 @@ draw (cairo_t *cr, int width, int height)
 {
     cairo_surface_t *image;
 
-    image = cairo_test_create_surface_from_png (png_filename);
+    image = cairo_test_create_surface_from_png (png_filename, cairo_get_target (cr));
 
     cairo_set_source_rgba (cr, 0, 0, 0, 1);
     cairo_rectangle (cr, 0, 0, SIZE, SIZE);
diff --git a/test/composite-integer-translate-source.c b/test/composite-integer-translate-source.c
index 67813b7..92652c6 100644
--- a/test/composite-integer-translate-source.c
+++ b/test/composite-integer-translate-source.c
@@ -47,7 +47,7 @@ draw (cairo_t *cr, int width, int height)
 {
     cairo_surface_t *image;
 
-    image = cairo_test_create_surface_from_png (png_filename);
+    image = cairo_test_create_surface_from_png (png_filename, cairo_get_target (cr));
 
     cairo_set_source_rgba (cr, 0, 0, 0, 1);
     cairo_rectangle (cr, 0, 0, SIZE, SIZE);
diff --git a/test/create-from-png-stream.c b/test/create-from-png-stream.c
index 4e8a29d..d659fde 100644
--- a/test/create-from-png-stream.c
+++ b/test/create-from-png-stream.c
@@ -70,8 +70,10 @@ draw (cairo_t *cr, int width, int height)
 	return CAIRO_TEST_FAILURE;
     }
 
-    surface = cairo_image_surface_create_from_png_stream (read_png_from_file,
-							  file);
+    surface = cairo_image_surface_create_from_png_stream_for_target (
+	                                                 read_png_from_file,
+							 file,
+					                 cairo_get_target (cr));
 
     fclose (file);
 
diff --git a/test/create-from-png.c b/test/create-from-png.c
index fe08b30..d00fda3 100644
--- a/test/create-from-png.c
+++ b/test/create-from-png.c
@@ -61,7 +61,7 @@ draw (cairo_t *cr, int width, int height)
     xasprintf (&filename, "%s/%s", srcdir ? srcdir : ".",
 	       "create-from-png-ref.png");
 
-    surface = cairo_image_surface_create_from_png (filename);
+    surface = cairo_image_surface_create_from_png_for_target (filename, cairo_get_target (cr));
     if (cairo_surface_status (surface)) {
 	cairo_test_log ("Error reading PNG image %s: %s\n",
 			filename,
diff --git a/test/extend-reflect.c b/test/extend-reflect.c
index e23c8f6..27c76bd 100644
--- a/test/extend-reflect.c
+++ b/test/extend-reflect.c
@@ -18,7 +18,7 @@ draw (cairo_t *cr, int width, int height)
 {
     cairo_surface_t *surface;
 
-    surface = cairo_test_create_surface_from_png (png_filename);
+    surface = cairo_test_create_surface_from_png (png_filename, cairo_get_target (cr));
     cairo_set_source_surface (cr, surface, 32, 32);
     cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);
 
diff --git a/test/nil-surface.c b/test/nil-surface.c
index 91f1aa6..ff0c673 100644
--- a/test/nil-surface.c
+++ b/test/nil-surface.c
@@ -57,7 +57,7 @@ draw (cairo_t *cr, int width, int height)
     cr2 = cairo_create (cairo_get_target (cr));
 
     /* First, let's make a nil surface. */
-    surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___");
+    surface = cairo_image_surface_create_from_png_for_target ("___THIS_FILE_DOES_NOT_EXIST___", cairo_get_target (cr));
 
     /* Let the error propagate into a nil pattern. */
     pattern = cairo_pattern_create_for_surface (surface);
@@ -112,7 +112,7 @@ draw (cairo_t *cr, int width, int height)
 
     cairo_surface_finish (NULL);
 
-    surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___");
+    surface = cairo_image_surface_create_from_png_for_target ("___THIS_FILE_DOES_NOT_EXIST___", cairo_get_target (cr));
     cairo_surface_finish (surface);
     cairo_surface_destroy (surface);
 
-- 
1.5.2.5


--GvXjxJ+pjyke8COw
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="0002-cairo-xlib-Use-XShm.patch"



More information about the cairo mailing list