[goffice] GOImage: lifespan issues.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] GOImage: lifespan issues.
- Date: Mon, 18 Oct 2010 15:41:10 +0000 (UTC)
commit 7f2d1533ac87776150790fb3ed008cb12870f50c
Author: Morten Welinder <terra gnome org>
Date: Mon Oct 18 11:40:57 2010 -0400
GOImage: lifespan issues.
ChangeLog | 7 ++
goffice/utils/go-image.c | 130 +++++++++++++++++++++++---------------
goffice/utils/go-style.c | 2 +-
goffice/utils/go-styled-object.c | 2 +-
4 files changed, 87 insertions(+), 54 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 2348469..a6ad505 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2010-10-18 Morten Welinder <terra gnome org>
+
+ * goffice/utils/go-image.c (go_image_create_cairo_pattern):
+ Document lifespan. Make the surface hold a ref to the image so
+ image->data stay valid until cairo is done with it. This is a
+ btter fix for 632439.
+
2010-10-10 Jean Brefort <jean brefort normalesup org>
* */*/*.ui: fixed orientation property for GtkVBox.
diff --git a/goffice/utils/go-image.c b/goffice/utils/go-image.c
index 11f5398..357ace4 100644
--- a/goffice/utils/go-image.c
+++ b/goffice/utils/go-image.c
@@ -130,25 +130,25 @@ go_image_format_to_mime (char const *format)
static GOImageFormatInfo const image_format_infos[GO_IMAGE_FORMAT_UNKNOWN] = {
{GO_IMAGE_FORMAT_SVG, (char *) "svg", (char *) N_("SVG (vector graphics)"),
- (char *) "svg", FALSE, FALSE, TRUE},
+ (char *) "svg", FALSE, FALSE, TRUE},
{GO_IMAGE_FORMAT_PNG, (char *) "png", (char *) N_("PNG (raster graphics)"),
- (char *) "png", TRUE, TRUE, TRUE},
+ (char *) "png", TRUE, TRUE, TRUE},
{GO_IMAGE_FORMAT_JPG, (char *) "jpeg", (char *) N_("JPEG (photograph)"),
- (char *) "jpg", TRUE, TRUE, FALSE},
+ (char *) "jpg", TRUE, TRUE, FALSE},
{GO_IMAGE_FORMAT_PDF, (char *) "pdf", (char *) N_("PDF (portable document format)"),
- (char *) "pdf", FALSE, FALSE, TRUE},
+ (char *) "pdf", FALSE, FALSE, TRUE},
{GO_IMAGE_FORMAT_PS, (char *) "ps", (char *) N_("PS (postscript)"),
- (char *) "ps", FALSE, TRUE, TRUE},
+ (char *) "ps", FALSE, TRUE, TRUE},
{GO_IMAGE_FORMAT_EMF, (char *) "emf", (char *) N_("EMF (extended metafile)"),
- (char *) "emf", FALSE, FALSE, TRUE},
+ (char *) "emf", FALSE, FALSE, TRUE},
{GO_IMAGE_FORMAT_WMF, (char *) "wmf", (char *) N_("WMF (windows metafile)"),
- (char *) "wmf", FALSE, FALSE, TRUE},
+ (char *) "wmf", FALSE, FALSE, TRUE},
#ifdef HAVE_CAIRO_PS_SURFACE_SET_EPS
{GO_IMAGE_FORMAT_EPS, (char *) "eps", (char *) N_("EPS (encapsulated postscript)"),
- (char *) "eps", FALSE, TRUE, TRUE},
+ (char *) "eps", FALSE, TRUE, TRUE},
#else
{GO_IMAGE_FORMAT_EPS, (char *) "", (char *) "",
- (char *) "", FALSE, FALSE, FALSE},
+ (char *) "", FALSE, FALSE, FALSE},
#endif
};
@@ -375,32 +375,32 @@ go_image_set_property (GObject *obj, guint param_id,
break;
#ifdef GOFFICE_WITH_GTK
case IMAGE_PROP_PIXBUF: {
- GdkPixbuf *pixbuf = GDK_PIXBUF (g_value_get_object (value));
- if (!GDK_IS_PIXBUF (pixbuf))
- break;
- if (!gdk_pixbuf_get_has_alpha (pixbuf))
- pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
- else
- g_object_ref (pixbuf);
- if (image->pixbuf)
- g_object_unref (image->pixbuf);
- image->pixbuf = pixbuf;
- g_free (image->data);
- image->data = NULL;
- image->width = gdk_pixbuf_get_width (pixbuf);
- image->height = gdk_pixbuf_get_height (pixbuf);
- image->rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- image->target_cairo = FALSE;
- if (image->thumbnail) {
- g_object_unref (image->thumbnail);
- image->thumbnail = NULL;
- }
+ GdkPixbuf *pixbuf = GDK_PIXBUF (g_value_get_object (value));
+ if (!GDK_IS_PIXBUF (pixbuf))
+ break;
+ if (!gdk_pixbuf_get_has_alpha (pixbuf))
+ pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
+ else
+ g_object_ref (pixbuf);
+ if (image->pixbuf)
+ g_object_unref (image->pixbuf);
+ image->pixbuf = pixbuf;
+ g_free (image->data);
+ image->data = NULL;
+ image->width = gdk_pixbuf_get_width (pixbuf);
+ image->height = gdk_pixbuf_get_height (pixbuf);
+ image->rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ image->target_cairo = FALSE;
+ if (image->thumbnail) {
+ g_object_unref (image->thumbnail);
+ image->thumbnail = NULL;
}
+ }
break;
#endif
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
- return; /* NOTE : RETURN */
+ return; /* NOTE : RETURN */
}
if (size_changed) {
@@ -440,7 +440,7 @@ go_image_get_property (GObject *obj, guint param_id,
#endif
default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
- return; /* NOTE : RETURN */
+ return; /* NOTE : RETURN */
}
}
@@ -469,24 +469,24 @@ go_image_class_init (GOImageClass *klass)
klass->get_property = go_image_get_property;
parent_klass = g_type_class_peek_parent (klass);
g_object_class_install_property (klass, IMAGE_PROP_WIDTH,
- g_param_spec_uint ("width", _("Width"),
- _("Image width in pixels"),
- 0, G_MAXUINT16, 0, G_PARAM_READWRITE));
+ g_param_spec_uint ("width", _("Width"),
+ _("Image width in pixels"),
+ 0, G_MAXUINT16, 0, G_PARAM_READWRITE));
g_object_class_install_property (klass, IMAGE_PROP_HEIGHT,
- g_param_spec_uint ("height", _("Height"),
- _("Image height in pixels"),
- 0, G_MAXUINT16, 0, G_PARAM_READWRITE));
+ g_param_spec_uint ("height", _("Height"),
+ _("Image height in pixels"),
+ 0, G_MAXUINT16, 0, G_PARAM_READWRITE));
#ifdef GOFFICE_WITH_GTK
g_object_class_install_property (klass, IMAGE_PROP_PIXBUF,
- g_param_spec_object ("pixbuf", _("Pixbuf"),
- _("GdkPixbuf object from which the GOImage is built"),
- GDK_TYPE_PIXBUF, G_PARAM_READWRITE));
+ g_param_spec_object ("pixbuf", _("Pixbuf"),
+ _("GdkPixbuf object from which the GOImage is built"),
+ GDK_TYPE_PIXBUF, G_PARAM_READWRITE));
#endif
}
GSF_CLASS (GOImage, go_image,
- go_image_class_init, NULL,
- G_TYPE_OBJECT)
+ go_image_class_init, NULL,
+ G_TYPE_OBJECT)
cairo_t *
go_image_get_cairo (GOImage *image)
@@ -506,20 +506,43 @@ go_image_get_cairo (GOImage *image)
image->target_cairo = TRUE;
}
surface = cairo_image_surface_create_for_data (
- image->data,
- CAIRO_FORMAT_ARGB32,
- image->width, image->height,
- image->rowstride);
+ image->data,
+ CAIRO_FORMAT_ARGB32,
+ image->width, image->height,
+ image->rowstride);
cairo = cairo_create (surface);
cairo_surface_destroy (surface);
image->target_cairo = TRUE;
return cairo;
}
-cairo_pattern_t *go_image_create_cairo_pattern (GOImage *image)
+static void
+cb_surface_destroyed (void *data)
+{
+ GOImage *image = GO_IMAGE (data);
+ /* We no longer need image->data. */
+ g_object_unref (image);
+}
+
+/**
+ * go_image_create_cairo_pattern:
+ * @image: a GOImage.
+ *
+ * returns: a cairo_pattern usable for cairo_set_source.
+ *
+ * Note: this function has lifespan issues. The resulting pattern in only
+ * valid until (a) a pixbuf is set for the, or (b) a pixbuf is _read_ from
+ * the image. In either of these cases, the pattern must have been
+ * destroyed beforehand. In particular, if the pattern has been attached
+ * to a surface, that surface must either be finished itself, or have had
+ * a new pattern attached. See #632439.
+ */
+cairo_pattern_t *
+go_image_create_cairo_pattern (GOImage *image)
{
cairo_surface_t *surface ;
cairo_pattern_t *pat;
+ static const cairo_user_data_key_t key;
g_return_val_if_fail (GO_IS_IMAGE (image), NULL);
if (image->data == NULL && image->pixbuf == NULL)
@@ -532,11 +555,14 @@ cairo_pattern_t *go_image_create_cairo_pattern (GOImage *image)
pixbuf_to_cairo (image);
image->target_cairo = TRUE;
}
- surface = cairo_image_surface_create_for_data (
- image->data,
- CAIRO_FORMAT_ARGB32,
- image->width, image->height,
- image->rowstride);
+ surface = cairo_image_surface_create_for_data
+ (image->data,
+ CAIRO_FORMAT_ARGB32,
+ image->width, image->height,
+ image->rowstride);
+ g_object_ref (image);
+ cairo_surface_set_user_data (surface, &key,
+ image, cb_surface_destroyed);
pat = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
return pat;
diff --git a/goffice/utils/go-style.c b/goffice/utils/go-style.c
index 6262747..fc091b3 100644
--- a/goffice/utils/go-style.c
+++ b/goffice/utils/go-style.c
@@ -2105,7 +2105,7 @@ go_style_set_text_angle (GOStyle *style, double angle)
* A pattern will be created only if the style has the corresponding field
* and if it is not set to a none constant.
*
- * return value: the pattern or NULL if it could not be created.
+ * Returns: the pattern or NULL if it could not be created.
**/
cairo_pattern_t *
go_style_create_cairo_pattern (GOStyle const *style, cairo_t *cr)
diff --git a/goffice/utils/go-styled-object.c b/goffice/utils/go-styled-object.c
index 7204d61..6aee6b3 100644
--- a/goffice/utils/go-styled-object.c
+++ b/goffice/utils/go-styled-object.c
@@ -230,7 +230,7 @@ go_styled_object_set_cairo_line (GOStyledObject const *so, cairo_t *cr)
* Prepares the cairo context @cr to fill a shape according to the
* item style and canvas scale.
*
- * Returns: %TRUE if the filling is not invisible
+ * Returns: %TRUE if the filling is not invisible.
**/
gboolean
go_styled_object_set_cairo_fill (GOStyledObject const *so, cairo_t *cr)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]