[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