summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@gnome.org>2011-11-26 23:33:34 +0100
committerChristian Persch <chpe@gnome.org>2011-11-26 23:33:34 +0100
commit1b3d2ea55a1be67e0548bf76903ff905888e2e18 (patch)
tree480fa2d884d667b24374ee30cde7af78c3ddfea8
parent6ceaecc069bdc606f9cbf9ed3bcd57fb6861f4f0 (diff)
downloadlibrsvg-1b3d2ea55a1be67e0548bf76903ff905888e2e18.tar.gz
Make filters render to a surface
... instead of into a GdkPixbuf.
-rw-r--r--rsvg-cairo-draw.c70
-rw-r--r--rsvg-cairo-render.c2
-rw-r--r--rsvg-cairo-render.h2
-rw-r--r--rsvg-filter.c60
-rw-r--r--rsvg-filter.h7
5 files changed, 80 insertions, 61 deletions
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index fe93c360..3054a9e6 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -790,39 +790,26 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx * ctx)
&& !state->filter && !state->mask && !lateclip && (state->comp_op == CAIRO_OPERATOR_OVER)
&& (state->enable_background == RSVG_ENABLE_BACKGROUND_ACCUMULATE))
return;
- if (!state->filter)
+
+ if (!state->filter) {
surface = cairo_surface_create_similar (cairo_get_target (render->cr),
CAIRO_CONTENT_COLOR_ALPHA,
render->width, render->height);
- else {
- guchar *pixels;
- int rowstride = render->width * 4;
- GdkPixbuf *pixbuf;
-
- pixels = g_try_malloc0 (render->width * render->height * 4);
- if (pixels == NULL)
- return; /* not really correct, but the best we can do here */
-
- /* The pixbuf takes ownership of @pixels */
- pixbuf = gdk_pixbuf_new_from_data (pixels,
- GDK_COLORSPACE_RGB,
- TRUE,
- 8,
- render->width,
- render->height,
- rowstride,
- (GdkPixbufDestroyNotify) rsvg_pixmap_destroy,
- NULL);
- render->pixbuf_stack = g_list_prepend (render->pixbuf_stack, pixbuf);
-
- surface = cairo_image_surface_create_for_data (pixels,
- CAIRO_FORMAT_ARGB32,
- render->width, render->height, rowstride);
- /* Also keep a reference to the pixbuf which owns the pixels */
- cairo_surface_set_user_data (surface, &surface_pixel_data_key,
- g_object_ref (pixbuf),
- (cairo_destroy_func_t) g_object_unref);
+ } else {
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ render->width, render->height);
+
+ /* The surface reference is owned by the child_cr created below and put on the cr_stack! */
+ render->surfaces_stack = g_list_prepend (render->surfaces_stack, surface);
+ }
+
+#if 0
+ if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy (surface);
+ return;
}
+#endif
+
child_cr = cairo_create (surface);
cairo_surface_destroy (surface);
@@ -862,26 +849,17 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
return;
if (state->filter) {
- GdkPixbuf *pixbuf = render->pixbuf_stack->data;
- GdkPixbuf *output;
-
- render->pixbuf_stack = g_list_remove (render->pixbuf_stack, pixbuf);
-
+ cairo_surface_t *output;
- output = rsvg_filter_render (state->filter, pixbuf, ctx, &render->bbox, "2103");
- g_object_unref (pixbuf);
+ output = render->surfaces_stack->data;
+ render->surfaces_stack = g_list_delete_link (render->surfaces_stack, render->surfaces_stack);
- surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (output),
- CAIRO_FORMAT_ARGB32,
- gdk_pixbuf_get_width (output),
- gdk_pixbuf_get_height (output),
- gdk_pixbuf_get_rowstride (output));
- cairo_surface_set_user_data (surface, &surface_pixel_data_key,
- output,
- (cairo_destroy_func_t) g_object_unref);
+ surface = rsvg_filter_render (state->filter, output, ctx, &render->bbox, "2103");
- } else
+ /* Don't destroy the output surface, it's owned by child_cr */
+ } else {
surface = cairo_get_target (child_cr);
+ }
render->cr = (cairo_t *) render->cr_stack->data;
render->cr_stack = g_list_delete_link (render->cr_stack, render->cr_stack);
@@ -903,8 +881,8 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
cairo_paint_with_alpha (render->cr, (double) state->opacity / 255.0);
else
cairo_paint (render->cr);
- cairo_destroy (child_cr);
+ cairo_destroy (child_cr);
rsvg_bbox_insert ((RsvgBbox *) render->bb_stack->data, &render->bbox);
diff --git a/rsvg-cairo-render.c b/rsvg-cairo-render.c
index afbfb5f3..db80c483 100644
--- a/rsvg-cairo-render.c
+++ b/rsvg-cairo-render.c
@@ -73,7 +73,7 @@ rsvg_cairo_render_new (cairo_t * cr, double width, double height)
cairo_render->cr = cr;
cairo_render->cr_stack = NULL;
cairo_render->bb_stack = NULL;
- cairo_render->pixbuf_stack = NULL;
+ cairo_render->surfaces_stack = NULL;
return cairo_render;
}
diff --git a/rsvg-cairo-render.h b/rsvg-cairo-render.h
index e26b7d36..66cce634 100644
--- a/rsvg-cairo-render.h
+++ b/rsvg-cairo-render.h
@@ -47,7 +47,7 @@ struct _RsvgCairoRender {
RsvgBbox bbox;
GList *bb_stack;
- GList *pixbuf_stack;
+ GList *surfaces_stack;
};
#define RSVG_CAIRO_RENDER(render) (_RSVG_RENDER_CIC ((render), RSVG_RENDER_TYPE_CAIRO, RsvgCairoRender))
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 27f962ed..dba9796d 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -31,6 +31,7 @@
#include "rsvg-image.h"
#include "rsvg-css.h"
#include "rsvg-cairo-render.h"
+
#include <string.h>
#include <math.h>
@@ -454,37 +455,63 @@ rsvg_filter_context_free (RsvgFilterContext * ctx)
g_free (ctx);
}
+static void
+unref_surface (guchar *pixels,
+ gpointer user_data)
+{
+ cairo_surface_t *surface = user_data;
+
+ cairo_surface_destroy (surface);
+}
+
/**
* rsvg_filter_render: Create a new pixbuf applied the filter.
* @self: a pointer to the filter to use
- * @source: a pointer to the source pixbuf
+ * @source: the a #cairo_surface_t of type %CAIRO_SURFACE_TYPE_IMAGE
* @context: the context
*
* This function will create a context for itself, set up the coordinate systems
* execute all its little primatives and then clean up its own mess
+ *
+ * Returns: (transfer full): a new #cairo_surface_t
**/
-GdkPixbuf *
-rsvg_filter_render (RsvgFilter * self, GdkPixbuf * source,
- RsvgDrawingCtx * context, RsvgBbox * bounds, char *channelmap)
+cairo_surface_t *
+rsvg_filter_render (RsvgFilter *self,
+ cairo_surface_t *source,
+ RsvgDrawingCtx *context,
+ RsvgBbox *bounds,
+ char *channelmap)
{
+ static const cairo_user_data_key_t surface_pixel_data_key;
RsvgFilterContext *ctx;
RsvgFilterPrimitive *current;
guint i;
- GdkPixbuf *out;
-
+ GdkPixbuf *in, *out;
+ cairo_surface_t *output;
+
+ g_return_val_if_fail (source != NULL, NULL);
+ g_return_val_if_fail (cairo_surface_get_type (source) == CAIRO_SURFACE_TYPE_IMAGE, NULL);
+
+ in = gdk_pixbuf_new_from_data (cairo_image_surface_get_data (source),
+ GDK_COLORSPACE_RGB,
+ cairo_image_surface_get_format (source) == CAIRO_FORMAT_ARGB32,
+ 8,
+ cairo_image_surface_get_width (source),
+ cairo_image_surface_get_height (source),
+ cairo_image_surface_get_stride (source),
+ (GdkPixbufDestroyNotify) unref_surface,
+ cairo_surface_reference (source));
ctx = g_new (RsvgFilterContext, 1);
ctx->filter = self;
- ctx->source = source;
+ ctx->source = in;
ctx->bg = NULL;
ctx->results = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, rsvg_filter_free_pair);
ctx->ctx = context;
- g_object_ref (source);
-
rsvg_filter_fix_coordinate_system (ctx, rsvg_current_state (context), bounds);
- ctx->lastresult.result = source;
+ ctx->lastresult.result = in;
ctx->lastresult.Rused = 1;
ctx->lastresult.Gused = 1;
ctx->lastresult.Bused = 1;
@@ -506,7 +533,18 @@ rsvg_filter_render (RsvgFilter * self, GdkPixbuf * source,
rsvg_filter_context_free (ctx);
- return out;
+ output = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (out),
+ gdk_pixbuf_get_has_alpha (out) ? CAIRO_FORMAT_ARGB32
+ : CAIRO_FORMAT_RGB24,
+ gdk_pixbuf_get_width (out),
+ gdk_pixbuf_get_height (out),
+ gdk_pixbuf_get_rowstride (out));
+ /* Also keep a reference to the pixbuf which owns the pixels */
+ cairo_surface_set_user_data (output, &surface_pixel_data_key,
+ out /* adopt */,
+ (cairo_destroy_func_t) g_object_unref);
+
+ return output;
}
/**
diff --git a/rsvg-filter.h b/rsvg-filter.h
index 6d2d848e..75e9bb05 100644
--- a/rsvg-filter.h
+++ b/rsvg-filter.h
@@ -41,8 +41,11 @@ struct _RsvgFilter {
RsvgFilterUnits primitiveunits;
};
-GdkPixbuf *rsvg_filter_render (RsvgFilter * self, GdkPixbuf * source,
- RsvgDrawingCtx * context, RsvgBbox * dimentions, char *channelmap);
+cairo_surface_t *rsvg_filter_render (RsvgFilter *self,
+ cairo_surface_t *source,
+ RsvgDrawingCtx *context,
+ RsvgBbox *dimentions,
+ char *channelmap);
RsvgNode *rsvg_new_filter (void);
RsvgFilter *rsvg_filter_parse (const RsvgDefs * defs, const char *str);