[cairo] destructor callback for image surfaces

Helge Bahmann hcb at chaoticmind.net
Thu Apr 27 02:43:07 PDT 2006


Hello,

I would like to be able to attach a custom destructor callback function to
cairo_image_surface_create_for_data

Background: I am creating images within a library (from a video decoder,
in case you are interested) and would like to expose the image data via
cairo, both for drawing and as source patterns; the images within the
library are reference counted themselves, and once I give out a cairo
handle to the image data I cannot know how long the cairo surface will
live, but I need to be notified once it is safe to dispose/reuse the image
data.

It is necessary to have a "closure" pointer to carry a reference to the
containing data structure; the pointer to the raw memory area I have
handed out is not sufficient (primarily because sometimes I hand out just
a reference to a sub-image).

How about the attached patch?

Thanks and best regards
-- 
Helge Bahmann <hcb at chaoticmind.net>                     /| \__
The past: Smart users in front of dumb terminals       /_|____\
                                                     _/\ |   __)
$ ./configure                                        \\ \|__/__|
checking whether build environment is sane... yes     \\/___/ |
checking for AIX... no (we already did this)            |
-------------- next part --------------
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index cef455b..b5a8604 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -51,6 +51,11 @@ _cairo_format_bpp (cairo_format_t format
     }
 }
 
+static void _cairo_retain_memory(void *closure)
+{
+    /* dummy destructor; just do nothing with the data */
+}
+
 cairo_surface_t *
 _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
 					      cairo_format_t  format)
@@ -69,7 +74,8 @@ _cairo_image_surface_create_for_pixman_i
 
     surface->format = format;
     surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
-    surface->owns_data = FALSE;
+    surface->destructor_closure = surface->data;
+    surface->destructor = &_cairo_retain_memory;
     surface->has_clip = FALSE;
 
     surface->width = pixman_image_get_width (pixman_image);
@@ -309,6 +315,67 @@ cairo_image_surface_create_for_data (uns
     return surface;
 }
 
+/**
+ * cairo_image_surface_create_for_data_with_destructor:
+ * @data: a pointer to a buffer supplied by the application
+ *    in which to write contents.
+ * @format: the format of pixels in the buffer
+ * @width: the width of the image to be stored in the buffer
+ * @height: the height of the image to be stored in the buffer
+ * @stride: the number of bytes between the start of rows
+ *   in the buffer. Having this be specified separate from @width
+ *   allows for padding at the end of rows, or for writing
+ *   to a subportion of a larger image.
+ * @destructor_callback: function that is called if the cairo context is
+ *   finalized; applications can specify a function that performs
+ *   appropriate cleanup
+ * @destructor_closure: the pointer that will be passed to the
+ *   destructor_callback function as its single argument
+ * 
+ * This function behaves in exactly the same way as
+ * cairo_image_surface_create_for_data() does, but additionally allows
+ * specifying a destructor callback function and context pointer.
+ * This mechanism allows applications to be notified when the last
+ * user of the cairo_surface_t has gone and it is safe to perform
+ * appropriate clean-up actions (e.g. dispose of the memory area or
+ * reuse it).
+ *
+ * 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_public cairo_surface_t *
+cairo_image_surface_create_for_data_with_destructor (
+	unsigned char		*data,
+	cairo_format_t		format,
+	int			width,
+	int			height,
+	int			stride,
+	cairo_destroy_func_t	destructor_callback,
+	void *			destructor_closure)
+{
+    cairo_surface_t *surface;
+    cairo_image_surface_t *image_surface;
+    
+    surface = cairo_image_surface_create_for_data (data, format,
+    						   width, height, stride);
+						   
+    if (surface == &_cairo_surface_nil) return surface;
+    pixman_format_t *pixman_format;
+    pixman_image_t *pixman_image;
+    
+    image_surface = (cairo_image_surface_t *) surface;
+    
+    image_surface->destructor = destructor_callback;
+    image_surface->destructor_closure = destructor_closure;
+    
+    return surface;
+}
+
 cairo_surface_t *
 _cairo_image_surface_create_for_data_with_content (unsigned char	*data,
 						   cairo_content_t	 content,
@@ -420,11 +487,8 @@ _cairo_image_surface_finish (void *abstr
 	pixman_image_destroy (surface->pixman_image);
 	surface->pixman_image = NULL;
     }
-
-    if (surface->owns_data) {
-	free (surface->data);
-	surface->data = NULL;
-    }
+    
+    surface->destructor (surface->destructor_closure);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -432,7 +496,7 @@ _cairo_image_surface_finish (void *abstr
 void
 _cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
 {
-    surface->owns_data = 1;
+    surface->destructor = &free;
 }
 
 static cairo_status_t
diff --git a/src/cairo.h b/src/cairo.h
index db93540..a371dbe 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1345,6 +1345,16 @@ cairo_image_surface_create_for_data (uns
 				     int			height,
 				     int			stride);
 
+cairo_public cairo_surface_t *
+cairo_image_surface_create_for_data_with_destructor (
+	unsigned char		*data,
+	cairo_format_t		format,
+	int			width,
+	int			height,
+	int			stride,
+	cairo_destroy_func_t	destructor_callback,
+	void *			destructor_closure);
+
 cairo_public int
 cairo_image_surface_get_width (cairo_surface_t *surface);
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 65b482f..6cae655 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -892,7 +892,8 @@ struct _cairo_image_surface {
     /* libic-specific fields */
     cairo_format_t format;
     unsigned char *data;
-    cairo_bool_t owns_data;
+    cairo_destroy_func_t destructor;
+    void *destructor_closure;
     cairo_bool_t has_clip;
   
 


More information about the cairo mailing list