diff options
author | Christian Persch <chpe@gnome.org> | 2011-11-26 23:33:34 +0100 |
---|---|---|
committer | Christian Persch <chpe@gnome.org> | 2011-11-26 23:33:34 +0100 |
commit | 1b3d2ea55a1be67e0548bf76903ff905888e2e18 (patch) | |
tree | 480fa2d884d667b24374ee30cde7af78c3ddfea8 | |
parent | 6ceaecc069bdc606f9cbf9ed3bcd57fb6861f4f0 (diff) | |
download | librsvg-1b3d2ea55a1be67e0548bf76903ff905888e2e18.tar.gz |
Make filters render to a surface
... instead of into a GdkPixbuf.
-rw-r--r-- | rsvg-cairo-draw.c | 70 | ||||
-rw-r--r-- | rsvg-cairo-render.c | 2 | ||||
-rw-r--r-- | rsvg-cairo-render.h | 2 | ||||
-rw-r--r-- | rsvg-filter.c | 60 | ||||
-rw-r--r-- | rsvg-filter.h | 7 |
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); |