Commit 1b3d2ea5 authored by Christian Persch's avatar Christian Persch

Make filters render to a surface

... instead of into a GdkPixbuf.
parent 6ceaecc0
......@@ -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);
......
......@@ -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;
}
......
......@@ -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))
......
......@@ -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;
}
/**
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment