Commit e7e5622c authored by Christian Persch's avatar Christian Persch

Use cairo image surfaces

... instead of GdkPixbufs to store the filter results.
parent c1981e0d
......@@ -1962,6 +1962,15 @@ rsvg_render_image (RsvgDrawingCtx * ctx, GdkPixbuf * pb, double x, double y, dou
ctx->render->render_image (ctx, pb, x, y, w, h);
}
void
rsvg_render_surface (RsvgDrawingCtx * ctx, cairo_surface_t *surface, double x, double y, double w, double h)
{
/* surface must be a cairo image surface */
g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
ctx->render->render_surface (ctx, surface, x, y, w, h);
}
void
rsvg_add_clipping_rect (RsvgDrawingCtx * ctx, double x, double y, double w, double h)
{
......
......@@ -84,6 +84,16 @@ rsvg_cairo_clip_render_image (RsvgDrawingCtx * ctx,
{
}
static void
rsvg_cairo_clip_render_surface (RsvgDrawingCtx *ctx,
cairo_surface_t *surface,
double src_x,
double src_y,
double w,
double h)
{
}
static void
rsvg_cairo_clip_render_free (RsvgRender * self)
......@@ -122,6 +132,7 @@ rsvg_cairo_clip_render_new (cairo_t * cr, RsvgCairoRender *parent)
render->create_pango_context = rsvg_cairo_create_pango_context;
render->render_pango_layout = rsvg_cairo_render_pango_layout;
render->render_image = rsvg_cairo_clip_render_image;
render->render_surface = rsvg_cairo_clip_render_surface;
render->render_path = rsvg_cairo_clip_render_path;
render->pop_discrete_layer = rsvg_cairo_clip_pop_discrete_layer;
render->push_discrete_layer = rsvg_cairo_clip_push_discrete_layer;
......
......@@ -546,104 +546,62 @@ rsvg_cairo_render_path (RsvgDrawingCtx * ctx, const cairo_path_t *path)
void
rsvg_cairo_render_image (RsvgDrawingCtx * ctx, const GdkPixbuf * pixbuf,
double pixbuf_x, double pixbuf_y, double w, double h)
{
cairo_surface_t *surface;
if (pixbuf == NULL)
return;
surface = rsvg_cairo_surface_from_pixbuf (pixbuf);
if (surface == NULL)
return;
rsvg_cairo_render_surface (ctx, surface, pixbuf_x, pixbuf_y, w, h);
cairo_surface_destroy (surface);
}
void
rsvg_cairo_render_surface (RsvgDrawingCtx *ctx,
cairo_surface_t *surface,
double src_x,
double src_y,
double w,
double h)
{
RsvgCairoRender *render = RSVG_CAIRO_RENDER (ctx->render);
RsvgState *state = rsvg_current_state (ctx);
gint width = gdk_pixbuf_get_width (pixbuf);
gint height = gdk_pixbuf_get_height (pixbuf);
double dwidth = width, dheight = height;
guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
guchar *cairo_pixels;
cairo_format_t format;
cairo_surface_t *surface;
int width, height;
double dwidth, dheight;
int j;
RsvgBbox bbox;
if (pixbuf == NULL)
if (surface == NULL)
return;
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
surface = cairo_image_surface_create (format, width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (surface);
dwidth = width = cairo_image_surface_get_width (surface);
dheight = height = cairo_image_surface_get_height (surface);
if (width == 0 || height == 0)
return;
}
cairo_pixels = cairo_image_surface_get_data (surface);
rsvg_bbox_init (&bbox, &state->affine);
bbox.rect.x = pixbuf_x;
bbox.rect.y = pixbuf_y;
bbox.rect.x = src_x;
bbox.rect.y = src_y;
bbox.rect.width = w;
bbox.rect.height = h;
bbox.virgin = 0;
_set_rsvg_affine (render, &state->affine);
cairo_scale (render->cr, w / dwidth, h / dheight);
pixbuf_x *= dwidth / w;
pixbuf_y *= dheight / h;
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
if (n_channels == 3) {
guchar *end = p + 3 * width;
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
#else
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];
#endif
p += 3;
q += 4;
}
} else {
guchar *end = p + 4 * width;
guint t1, t2, t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT (q[0], p[2], p[3], t1);
MULT (q[1], p[1], p[3], t2);
MULT (q[2], p[0], p[3], t3);
q[3] = p[3];
#else
q[0] = p[3];
MULT (q[1], p[0], p[3], t1);
MULT (q[2], p[1], p[3], t2);
MULT (q[3], p[2], p[3], t3);
#endif
p += 4;
q += 4;
}
#undef MULT
}
gdk_pixels += gdk_rowstride;
cairo_pixels += 4 * width;
}
src_x *= dwidth / w;
src_y *= dheight / h;
cairo_set_operator (render->cr, state->comp_op);
#if 1
cairo_set_source_surface (render->cr, surface, pixbuf_x, pixbuf_y);
cairo_set_source_surface (render->cr, surface, src_x, src_y);
#else
{
cairo_pattern_t *pattern;
......@@ -652,7 +610,7 @@ rsvg_cairo_render_image (RsvgDrawingCtx * ctx, const GdkPixbuf * pixbuf,
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
cairo_matrix_init_translate (&matrix, -pixbuf_x, -pixbuf_y);
cairo_matrix_init_translate (&matrix, -src_x, -src_y);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_set_source (render->cr, pattern);
......@@ -661,7 +619,6 @@ rsvg_cairo_render_image (RsvgDrawingCtx * ctx, const GdkPixbuf * pixbuf,
#endif
cairo_paint (render->cr);
cairo_surface_destroy (surface);
rsvg_bbox_insert (&render->bbox, &bbox);
}
......@@ -1062,3 +1019,94 @@ rsvg_pixbuf_to_cairo (guint8 * pixels, int rowstride, int height)
}
}
}
cairo_surface_t *
rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf)
{
gint width, height, gdk_rowstride, n_channels, cairo_rowstride;
guchar *gdk_pixels, *cairo_pixels;
cairo_format_t format;
cairo_surface_t *surface;
int j;
if (pixbuf == NULL)
return NULL;
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
surface = cairo_image_surface_create (format, width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (surface);
return;
}
cairo_pixels = cairo_image_surface_get_data (surface);
cairo_rowstride = cairo_image_surface_get_stride (surface);
if (n_channels == 3) {
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
guchar *end = p + 3 * width;
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
#else
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];
#endif
p += 3;
q += 4;
}
gdk_pixels += gdk_rowstride;
cairo_pixels += cairo_rowstride;
}
} else {
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
guchar *end = p + 4 * width;
guint t1, t2, t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT (q[0], p[2], p[3], t1);
MULT (q[1], p[1], p[3], t2);
MULT (q[2], p[0], p[3], t3);
q[3] = p[3];
#else
q[0] = p[3];
MULT (q[1], p[0], p[3], t1);
MULT (q[2], p[1], p[3], t2);
MULT (q[3], p[2], p[3], t3);
#endif
p += 4;
q += 4;
}
#undef MULT
gdk_pixels += gdk_rowstride;
cairo_pixels += cairo_rowstride;
}
}
cairo_surface_mark_dirty (surface);
return surface;
}
......@@ -39,6 +39,8 @@ void rsvg_cairo_render_path (RsvgDrawingCtx *ctx,
const cairo_path_t *path);
void rsvg_cairo_render_image (RsvgDrawingCtx *ctx, const GdkPixbuf * img,
double x, double y, double w, double h);
void rsvg_cairo_render_surface (RsvgDrawingCtx *ctx, cairo_surface_t *surface,
double x, double y, double w, double h);
void rsvg_cairo_push_discrete_layer (RsvgDrawingCtx *ctx);
void rsvg_cairo_pop_discrete_layer (RsvgDrawingCtx *ctx);
void rsvg_cairo_add_clipping_rect (RsvgDrawingCtx *ctx,
......
......@@ -59,6 +59,7 @@ rsvg_cairo_render_new (cairo_t * cr, double width, double height)
cairo_render->super.create_pango_context = rsvg_cairo_create_pango_context;
cairo_render->super.render_pango_layout = rsvg_cairo_render_pango_layout;
cairo_render->super.render_image = rsvg_cairo_render_image;
cairo_render->super.render_surface = rsvg_cairo_render_surface;
cairo_render->super.render_path = rsvg_cairo_render_path;
cairo_render->super.pop_discrete_layer = rsvg_cairo_pop_discrete_layer;
cairo_render->super.push_discrete_layer = rsvg_cairo_push_discrete_layer;
......
This diff is collapsed.
......@@ -229,6 +229,24 @@ rsvg_pixbuf_new_from_href (const char *href, const char *base_uri, GError ** err
return NULL;
}
cairo_surface_t *
rsvg_cairo_surface_new_from_href (const char *href,
const char *base_uri,
GError **error)
{
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
pixbuf = rsvg_pixbuf_new_from_href (href, base_uri, error);
if (pixbuf == NULL)
return NULL;
surface = rsvg_cairo_surface_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
return surface;
}
void
rsvg_preserve_aspect_ratio (unsigned int aspect_ratio, double width,
double height, double *w, double *h, double *x, double *y)
......@@ -275,8 +293,8 @@ rsvg_node_image_free (RsvgNode * self)
rsvg_state_finalize (z->super.state);
g_free (z->super.state);
z->super.state = NULL;
if (z->img)
g_object_unref (z->img);
if (z->surface)
cairo_surface_destroy (z->surface);
_rsvg_node_free(self);
}
......@@ -285,10 +303,10 @@ rsvg_node_image_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
{
RsvgNodeImage *z = (RsvgNodeImage *) self;
unsigned int aspect_ratio = z->preserve_aspect_ratio;
GdkPixbuf *img = z->img;
gdouble x, y, w, h;
cairo_surface_t *surface = z->surface;
if (img == NULL)
if (surface == NULL)
return;
x = _rsvg_css_normalize_length (&z->x, ctx, 'h');
......@@ -304,10 +322,12 @@ rsvg_node_image_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
rsvg_add_clipping_rect (ctx, x, y, w, h);
}
rsvg_preserve_aspect_ratio (aspect_ratio, (double) gdk_pixbuf_get_width (img),
(double) gdk_pixbuf_get_height (img), &w, &h, &x, &y);
rsvg_preserve_aspect_ratio (aspect_ratio,
(double) cairo_image_surface_get_width (surface),
(double) cairo_image_surface_get_height (surface),
&w, &h, &x, &y);
rsvg_render_image (ctx, img, x, y, w, h);
rsvg_render_surface (ctx, surface, x, y, w, h);
rsvg_pop_discrete_layer (ctx);
}
......@@ -330,11 +350,13 @@ rsvg_node_image_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * a
/* path is used by some older adobe illustrator versions */
if ((value = rsvg_property_bag_lookup (atts, "path"))
|| (value = rsvg_property_bag_lookup (atts, "xlink:href"))) {
image->img = rsvg_pixbuf_new_from_href (value, rsvg_handle_get_base_uri (ctx), NULL);
image->surface = rsvg_cairo_surface_new_from_href (value,
rsvg_handle_get_base_uri (ctx),
NULL);
if (!image->img) {
if (!image->surface) {
#ifdef G_ENABLE_DEBUG
g_warning (_("Couldn't load image: %s\n"), value);
g_warning ("Couldn't load image: %s\n", value);
#endif
}
}
......@@ -358,7 +380,7 @@ rsvg_new_image (void)
image = g_new (RsvgNodeImage, 1);
_rsvg_node_init (&image->super, RSVG_NODE_TYPE_IMAGE);
g_assert (image->super.state);
image->img = NULL;
image->surface = NULL;
image->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
image->x = image->y = image->w = image->h = _rsvg_css_parse_length ("0");
image->super.free = rsvg_node_image_free;
......
......@@ -32,6 +32,8 @@
#include "rsvg-structure.h"
#include <cairo.h>
G_BEGIN_DECLS
RsvgNode *rsvg_new_image (void);
......@@ -42,7 +44,7 @@ struct _RsvgNodeImage {
RsvgNode super;
gint preserve_aspect_ratio;
RsvgLength x, y, w, h;
GdkPixbuf *img;
cairo_surface_t *surface; /* a cairo image surface */
};
void rsvg_preserve_aspect_ratio (unsigned int aspect_ratio, double width,
......@@ -53,6 +55,8 @@ gchar *rsvg_get_file_path (const gchar * filename, const gchar * basedir);
GdkPixbuf *rsvg_pixbuf_new_from_href (const char *href, const char *base_uri, GError ** error);
cairo_surface_t *rsvg_cairo_surface_new_from_href (const char *href, const char *base_uri, GError ** error);
G_END_DECLS
#endif /* RSVG_IMAGE_H */
......@@ -218,6 +218,8 @@ struct RsvgRender {
void (*render_path) (RsvgDrawingCtx * ctx, const cairo_path_t *path);
void (*render_image) (RsvgDrawingCtx * ctx, const GdkPixbuf * pixbuf,
double x, double y, double w, double h);
void (*render_surface) (RsvgDrawingCtx * ctx, cairo_surface_t *surface,
double x, double y, double w, double h);
void (*pop_discrete_layer) (RsvgDrawingCtx * ctx);
void (*push_discrete_layer) (RsvgDrawingCtx * ctx);
void (*add_clipping_rect) (RsvgDrawingCtx * ctx, double x, double y,
......@@ -376,8 +378,11 @@ void rsvg_push_discrete_layer (RsvgDrawingCtx * ctx);
void rsvg_render_path (RsvgDrawingCtx * ctx, const cairo_path_t *path);
void rsvg_render_image (RsvgDrawingCtx * ctx, GdkPixbuf * pb,
double x, double y, double w, double h);
void rsvg_render_surface (RsvgDrawingCtx * ctx, cairo_surface_t *surface,
double x, double y, double w, double h);
void rsvg_render_free (RsvgRender * render);
void rsvg_add_clipping_rect (RsvgDrawingCtx * ctx, double x, double y, double w, double h);
cairo_surface_t *rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf);
GdkPixbuf *rsvg_get_image_of_node (RsvgDrawingCtx * ctx, RsvgNode * drawable, double w, double h);
cairo_surface_t *rsvg_get_surface_of_node (RsvgDrawingCtx * ctx, RsvgNode * drawable, double w, double h);
......
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