diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | rsvg-cairo-draw.c | 162 | ||||
-rw-r--r-- | rsvg-cairo-draw.h | 3 | ||||
-rw-r--r-- | rsvg-cairo-render.c | 2 | ||||
-rw-r--r-- | rsvg-cairo-render.h | 1 | ||||
-rw-r--r-- | rsvg.c | 26 |
6 files changed, 144 insertions, 55 deletions
@@ -1,3 +1,8 @@ +2005-10-19 Caleb Moore <c.moore@student.unsw.edu.au> + + * rsvg-cairo-draw.c: series of hacks to make filters work + + 2005-10-16 Dom Lachowicz <cinamod@hotmail.com> * rsvg-cairo-draw.c: No need to new0() image data, it just wastes CPU diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c index 24de990c..f9ad404f 100644 --- a/rsvg-cairo-draw.c +++ b/rsvg-cairo-draw.c @@ -39,6 +39,13 @@ #include <math.h> #include <string.h> + +static void +rsvg_pixmap_destroy (gchar *pixels, gpointer data) +{ + g_free (pixels); +} + static void _pattern_add_rsvg_color_stops (cairo_pattern_t *pattern, GPtrArray *stops, @@ -390,8 +397,8 @@ rsvg_cairo_render_path (RsvgDrawingCtx *ctx, const RsvgBpathDef *bpath_def) return; need_tmpbuf = ((state->fill != NULL) && (state->stroke != NULL) && - state->opacity != 0xff) || state->clip_path_ref - || state->mask; + state->opacity != 0xff) + || state->clip_path_ref || state->mask || state->filter; if (need_tmpbuf) rsvg_cairo_push_discrete_layer (ctx); @@ -685,7 +692,6 @@ rsvg_cairo_generate_mask(RsvgMask * self, RsvgDrawingCtx *ctx, state->opacity); } } - cairo_destroy (mask_cr); return surface; @@ -719,12 +725,36 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx *ctx) objectBoundingBox) lateclip = TRUE; - if (state->opacity == 0xFF && !state->mask && !lateclip){ + if (state->opacity == 0xFF && !state->filter && !state->mask && !lateclip){ return; } - surface = cairo_surface_create_similar (cairo_get_target (render->cr), - CAIRO_CONTENT_COLOR_ALPHA, - render->width, render->height); + 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; + pixels = g_new0(guint8, render->width * render->height * 4); + + surface = cairo_image_surface_create_for_data (pixels, + CAIRO_FORMAT_ARGB32, + render->width, + render->height, + rowstride); + render->pixbuf_stack = + g_list_prepend(render->pixbuf_stack, + gdk_pixbuf_new_from_data (pixels, + GDK_COLORSPACE_RGB, + TRUE, + 8, + render->width, + render->height, + rowstride, + (GdkPixbufDestroyNotify)rsvg_pixmap_destroy, + NULL)); + } child_cr = cairo_create (surface); cairo_surface_destroy (surface); @@ -752,22 +782,60 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx *ctx) RsvgState *state; state = rsvg_state_current(ctx); gboolean lateclip = FALSE; + GdkPixbuf * output = NULL; + cairo_surface_t *surface = NULL; if (rsvg_state_current(ctx)->clip_path_ref) if (((RsvgClipPath *)rsvg_state_current(ctx)->clip_path_ref)->units == objectBoundingBox) lateclip = TRUE; - if (state->opacity == 0xFF && !state->mask && !lateclip) + if (state->opacity == 0xFF && !state->filter && !state->mask && !lateclip) return; render->cr = (cairo_t *)render->cr_stack->data; render->cr_stack = g_list_remove_link (render->cr_stack, render->cr_stack); - cairo_set_source_surface (render->cr, - cairo_get_target (child_cr), - 0, 0); - + if (state->filter) + { + GdkPixbuf * pixbuf = render->pixbuf_stack->data; + RsvgIRect bounds; + RsvgCairoBbox bbox; + double affine[6]; + _rsvg_affine_identity(affine); + rsvg_cairo_bbox_init(&bbox, affine); + rsvg_cairo_bbox_insert(&bbox, &render->bbox); + bounds.x0 = bbox.x; + bounds.y0 = bbox.y; + bounds.x1 = bbox.w + bbox.x; + bounds.y1 = bbox.h + bbox.y; + render->pixbuf_stack = g_list_remove_link (render->pixbuf_stack, + render->pixbuf_stack); + + + rsvg_cairo_to_pixbuf(gdk_pixbuf_get_pixels(pixbuf), + gdk_pixbuf_get_rowstride(pixbuf), + gdk_pixbuf_get_height(pixbuf)); + output = rsvg_filter_render (state->filter, pixbuf, pixbuf, + ctx, &bounds); + gdk_pixbuf_unref(pixbuf); + rsvg_pixbuf_to_cairo(gdk_pixbuf_get_pixels(output), + gdk_pixbuf_get_rowstride(output), + gdk_pixbuf_get_height(output)); + + 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_set_source_surface (render->cr, + surface, + 0, 0); + } + else + cairo_set_source_surface (render->cr, + cairo_get_target (child_cr), + 0, 0); if (lateclip) { cairo_save(render->cr); @@ -797,6 +865,12 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx *ctx) render->bb_stack = g_list_remove_link (render->bb_stack, render->bb_stack); if (lateclip) cairo_restore(render->cr); + + if (state->filter) + { + gdk_pixbuf_unref(output); + cairo_surface_destroy(surface); + } } void @@ -824,12 +898,6 @@ rsvg_cairo_add_clipping_rect (RsvgDrawingCtx *ctx, cairo_set_matrix (cr, &save); } -static void -rsvg_pixmap_destroy (gchar *pixels, gpointer data) -{ - g_free (pixels); -} - GdkPixbuf * rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx, RsvgNode *drawable, @@ -842,7 +910,7 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx, cairo_surface_t * surface; cairo_t * cr; guint8 *pixels; - int row, rowstride; + int rowstride; RsvgCairoRender *save_render = (RsvgCairoRender *)ctx->render; RsvgCairoRender *render; @@ -856,6 +924,8 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx, cr = cairo_create (surface); cairo_surface_destroy (surface); + rsvg_cairo_to_pixbuf(pixels, rowstride, height); + render = rsvg_cairo_render_new(cr, width, height); ctx->render = (RsvgRender *)render; @@ -863,6 +933,25 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx, rsvg_node_draw (drawable, ctx, 0); rsvg_state_pop(ctx); + img = gdk_pixbuf_new_from_data (pixels, + GDK_COLORSPACE_RGB, + TRUE, + 8, + width, + height, + rowstride, + (GdkPixbufDestroyNotify)rsvg_pixmap_destroy, + NULL); + + cairo_destroy (cr); + ctx->render = (RsvgRender *)save_render; + + return img; +} + +void rsvg_cairo_to_pixbuf(guint8 *pixels, int rowstride, int height) +{ + int row; /* un-premultiply data */ for(row = 0; row < height; row++) { guint8 *row_data = (pixels + (row * rowstride)); @@ -885,19 +974,30 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx, } } } +} - img = gdk_pixbuf_new_from_data (pixels, - GDK_COLORSPACE_RGB, - TRUE, - 8, - width, - height, - rowstride, - (GdkPixbufDestroyNotify)rsvg_pixmap_destroy, - NULL); +void rsvg_pixbuf_to_cairo(guint8 *pixels, int rowstride, int height) +{ + int row; + /* un-premultiply data */ + for(row = 0; row < height; row++) { + guint8 *row_data = (pixels + (row * rowstride)); + int i; - cairo_destroy (cr); - ctx->render = (RsvgRender *)save_render; + for(i = 0; i < rowstride; i += 4) { + guint32 *b = (guint32 *)&row_data[i]; + guint8 pixel[4]; + int alpha; - return img; + memcpy(&pixel, b, sizeof(guint32)); + alpha = pixel[3]; + if(alpha == 0) + *b = 0; + else + *b = alpha << 24 | + (int)pixel[0] * alpha / 255 << 16 | + (int)pixel[1] * alpha / 255 << 8 | + (int)pixel[2] * alpha / 255; + } + } } diff --git a/rsvg-cairo-draw.h b/rsvg-cairo-draw.h index 6a3e5a76..5065482b 100644 --- a/rsvg-cairo-draw.h +++ b/rsvg-cairo-draw.h @@ -57,6 +57,9 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx, double width, double height); +void rsvg_cairo_to_pixbuf(guint8 *pixels, int rowstride, int height); +void rsvg_pixbuf_to_cairo(guint8 *pixels, int rowstride, int height); + G_END_DECLS #endif /*RSVG_CAIRO_DRAW_H*/ diff --git a/rsvg-cairo-render.c b/rsvg-cairo-render.c index ab5fdab5..d7446428 100644 --- a/rsvg-cairo-render.c +++ b/rsvg-cairo-render.c @@ -62,7 +62,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; return cairo_render; } diff --git a/rsvg-cairo-render.h b/rsvg-cairo-render.h index 729f62fc..52151bba 100644 --- a/rsvg-cairo-render.h +++ b/rsvg-cairo-render.h @@ -50,6 +50,7 @@ struct _RsvgCairoRender { RsvgCairoBbox bbox; GList *bb_stack; + GList *pixbuf_stack; }; RsvgCairoRender * rsvg_cairo_render_new(cairo_t * cr, double width, double height); @@ -115,6 +115,7 @@ static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle) #elif defined(WITH_CAIRO_BACKEND) #include "rsvg-cairo.h" +#include "rsvg-cairo-draw.h" static void rsvg_pixmap_destroy (gchar *pixels, gpointer data) @@ -129,7 +130,7 @@ static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle) guint8 *pixels; cairo_surface_t *surface; cairo_t *cr; - int row, rowstride; + int rowstride; rsvg_handle_get_dimensions (handle, &dimensions); rowstride = dimensions.width * 4; @@ -145,28 +146,7 @@ static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle) rsvg_cairo_render (cr, handle); - /* un-premultiply data */ - for(row = 0; row < dimensions.height; row++) { - guint8 *row_data = (pixels + (row * rowstride)); - int i; - - for(i = 0; i < rowstride; i += 4) { - guint8 *b = &row_data[i]; - guint32 pixel; - guint8 alpha; - - memcpy(&pixel, b, sizeof(guint32)); - alpha = (pixel & 0xff000000) >> 24; - if(alpha == 0) { - b[0] = b[1] = b[2] = b[3] = 0; - } else { - b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; - b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; - b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; - b[3] = alpha; - } - } - } + rsvg_cairo_to_pixbuf(pixels, rowstride, dimensions.height); output = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, |