Commit 37a84c4f authored by Caleb Michael Moore's avatar Caleb Michael Moore

took the really pixel dependant stuff out of rsvg-styles.c and put it in a file of it's own

parent 7072c08c
......@@ -62,6 +62,8 @@ librsvg_2_la_SOURCES = \
rsvg-cond.c \
rsvg-art-draw.c \
rsvg-art-draw.h \
rsvg-art-composite.c \
rsvg-art-composite.h \
librsvg-enum-types.c
librsvg_2_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined -export-dynamic
......
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
rsvg-art-composite.c: Composite different layers using gdk pixbuff for our
libart backend
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Dom Lachowicz <cinamod@hotmail.com>
Copyright (C) 2003, 2004, 2005 Caleb Moore <c.moore@student.unsw.edu.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: Raph Levien <raph@artofcode.com>,
Dom Lachowicz <cinamod@hotmail.com>,
Caleb Moore <c.moore@student.unsw.edu.au>
*/
#include <string.h>
#include "rsvg-art-composite.h"
#include "rsvg-styles.h"
#include "rsvg-structure.h"
#include "rsvg-filter.h"
#include "rsvg-mask.h"
#include <libart_lgpl/art_rgba.h>
static void
rsvg_pixmap_destroy (gchar *pixels, gpointer data)
{
g_free (pixels);
}
void
rsvg_push_discrete_layer (RsvgDrawingCtx *ctx)
{
RsvgState *state;
GdkPixbuf *pixbuf;
art_u8 *pixels;
int width, height, rowstride;
state = rsvg_state_current(ctx);
pixbuf = ctx->pixbuf;
rsvg_state_clip_path_assure(ctx);
if (state->filter == NULL && state->opacity == 0xFF &&
!state->backgroundnew && state->mask == NULL && !state->adobe_blend)
return;
state->save_pixbuf = pixbuf;
state->underbbox = ctx->bbox;
ctx->bbox.x0 = 0;
ctx->bbox.x1 = 0;
ctx->bbox.y0 = 0;
ctx->bbox.y1 = 0;
if (pixbuf == NULL)
{
/* FIXME: What warning/GError here? */
return;
}
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
g_warning (_("push/pop transparency group on non-alpha buffer nyi\n"));
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
pixels = g_new (art_u8, rowstride * height);
memset (pixels, 0, rowstride * height);
pixbuf = gdk_pixbuf_new_from_data (pixels,
GDK_COLORSPACE_RGB,
TRUE,
gdk_pixbuf_get_bits_per_sample (pixbuf),
width,
height,
rowstride,
(GdkPixbufDestroyNotify)rsvg_pixmap_destroy,
NULL);
ctx->pixbuf = pixbuf;
}
static void
rsvg_use_opacity (RsvgDrawingCtx *ctx, int opacity,
GdkPixbuf *tos, GdkPixbuf *nos)
{
art_u8 *tos_pixels, *nos_pixels;
int width;
int height;
int rowstride;
int x, y;
int tmp;
if (tos == NULL || nos == NULL)
{
/* FIXME: What warning/GError here? */
return;
}
if (!gdk_pixbuf_get_has_alpha (nos))
{
g_warning (_("push/pop transparency group on non-alpha buffer nyi\n"));
return;
}
width = gdk_pixbuf_get_width (tos);
height = gdk_pixbuf_get_height (tos);
rowstride = gdk_pixbuf_get_rowstride (tos);
tos_pixels = gdk_pixbuf_get_pixels (tos);
nos_pixels = gdk_pixbuf_get_pixels (nos);
tos_pixels += rowstride * MAX(ctx->bbox.y0, 0);
nos_pixels += rowstride * MAX(ctx->bbox.y0, 0);
for (y = MAX(ctx->bbox.y0, 0); y < MIN(ctx->bbox.y1 + 1, height); y++)
{
for (x = MAX(ctx->bbox.x0, 0); x < MIN(ctx->bbox.x1 + 1, width); x++)
{
art_u8 r, g, b, a;
a = tos_pixels[4 * x + 3];
if (a)
{
r = tos_pixels[4 * x];
g = tos_pixels[4 * x + 1];
b = tos_pixels[4 * x + 2];
tmp = a * opacity + 0x80;
a = (tmp + (tmp >> 8)) >> 8;
art_rgba_run_alpha (nos_pixels + 4 * x, r, g, b, a, 1);
}
}
tos_pixels += rowstride;
nos_pixels += rowstride;
}
}
static GdkPixbuf *
get_next_out(gint * operationsleft, GdkPixbuf * in, GdkPixbuf * tos,
GdkPixbuf * nos, GdkPixbuf *intermediate)
{
GdkPixbuf * out;
if (*operationsleft == 1)
out = nos;
else
{
if (in == tos)
out = intermediate;
else
out = tos;
gdk_pixbuf_fill(out, 0x00000000);
}
(*operationsleft)--;
return out;
}
static GdkPixbuf *
rsvg_compile_bg(RsvgDrawingCtx *ctx, RsvgState *topstate)
{
int i, foundstate;
GdkPixbuf *intermediate, *lastintermediate;
RsvgState *state, *lastvalid;
ArtIRect save;
lastvalid = NULL;
foundstate = 0;
lastintermediate = gdk_pixbuf_copy(topstate->save_pixbuf);
save = ctx->bbox;
ctx->bbox.x0 = 0;
ctx->bbox.y0 = 0;
ctx->bbox.x1 = gdk_pixbuf_get_width(ctx->pixbuf);
ctx->bbox.y1 = gdk_pixbuf_get_height(ctx->pixbuf);
for (i = 0; (state = g_slist_nth_data(ctx->state, i)) != NULL; i++)
{
if (state == topstate)
{
foundstate = 1;
}
else if (!foundstate)
continue;
if (state->backgroundnew)
break;
if (state->save_pixbuf)
{
if (lastvalid)
{
intermediate = gdk_pixbuf_copy(state->save_pixbuf);
rsvg_use_opacity(ctx, 0xFF, lastintermediate, intermediate);
g_object_unref(lastintermediate);
lastintermediate = intermediate;
}
lastvalid = state;
}
}
ctx->bbox = save;
return lastintermediate;
}
static void
rsvg_composite_layer(RsvgDrawingCtx *ctx, RsvgState *state, GdkPixbuf *tos, GdkPixbuf *nos)
{
RsvgFilter *filter = state->filter;
int opacity = state->opacity;
RsvgDefsDrawable * mask = state->mask;
GdkPixbuf *intermediate;
GdkPixbuf *in, *out, *insidebg;
int operationsleft;
gint adobe_blend = state->adobe_blend;
intermediate = NULL;
operationsleft = 0;
if (opacity != 0xFF)
operationsleft++;
if (filter != NULL)
operationsleft++;
if (mask != NULL)
operationsleft++;
if (adobe_blend)
operationsleft++;
if (operationsleft > 1)
intermediate = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 1, 8,
gdk_pixbuf_get_width (tos),
gdk_pixbuf_get_height (tos));
in = tos;
if (operationsleft == 0)
{
rsvg_use_opacity (ctx, 0xFF, tos, nos);
}
if (filter != NULL || adobe_blend)
{
insidebg = rsvg_compile_bg(ctx, state);
}
else
insidebg = NULL;
if (filter != NULL)
{
out = get_next_out(&operationsleft, in, tos, nos, intermediate);
rsvg_filter_render (filter, in, out, insidebg, ctx);
in = out;
}
if (opacity != 0xFF)
{
out = get_next_out(&operationsleft, in, tos, nos, intermediate);
rsvg_use_opacity (ctx, opacity, in, out);
in = out;
}
if (mask != NULL)
{
out = get_next_out(&operationsleft, in, tos, nos, intermediate);
rsvg_mask_render ((RsvgMask *)mask, in, out, ctx);
in = out;
}
if (adobe_blend)
{
out = get_next_out(&operationsleft, in, tos, nos, intermediate);
rsvg_filter_adobe_blend (adobe_blend, in, insidebg, out, ctx);
in = out;
}
if (filter != NULL || adobe_blend)
{
g_object_unref (insidebg);
}
if (intermediate != NULL)
g_object_unref (intermediate);
}
/**
* rsvg_pop_discrete_layer: End a transparency group.
* @ctx: Context in which to push.
*
* Pops a new transparency group from the stack, recompositing with the
* next on stack using a filter, transperency value, or a mask to do so
**/
void
rsvg_pop_discrete_layer(RsvgDrawingCtx *ctx)
{
GdkPixbuf *tos, *nos;
RsvgState *state;
state = rsvg_state_current(ctx);
if (state->filter == NULL && state->opacity == 0xFF &&
!state->backgroundnew && state->mask == NULL && !state->adobe_blend)
return;
tos = ctx->pixbuf;
nos = state->save_pixbuf;
if (nos != NULL)
rsvg_composite_layer(ctx, state, tos, nos);
g_object_unref (tos);
ctx->pixbuf = nos;
art_irect_union(&ctx->bbox, &ctx->bbox, &state->underbbox);
}
gboolean
rsvg_needs_discrete_layer(RsvgState *state)
{
return state->filter || state->mask || state->adobe_blend || state->backgroundnew;
}
void
rsvg_alpha_blt (GdkPixbuf * src, gint srcx, gint srcy, gint srcwidth,
gint srcheight, GdkPixbuf * dst, gint dstx, gint dsty)
{
gint rightx;
gint bottomy;
gint dstwidth;
gint dstheight;
gint srcoffsetx;
gint srcoffsety;
gint dstoffsetx;
gint dstoffsety;
gint x, y, srcrowstride, dstrowstride, sx, sy, dx, dy;
guchar *src_pixels, *dst_pixels;
dstheight = srcheight;
dstwidth = srcwidth;
rightx = srcx + srcwidth;
bottomy = srcy + srcheight;
if (rightx > gdk_pixbuf_get_width (src))
rightx = gdk_pixbuf_get_width (src);
if (bottomy > gdk_pixbuf_get_height (src))
bottomy = gdk_pixbuf_get_height (src);
srcwidth = rightx - srcx;
srcheight = bottomy - srcy;
rightx = dstx + dstwidth;
bottomy = dsty + dstheight;
if (rightx > gdk_pixbuf_get_width (dst))
rightx = gdk_pixbuf_get_width (dst);
if (bottomy > gdk_pixbuf_get_height (dst))
bottomy = gdk_pixbuf_get_height (dst);
dstwidth = rightx - dstx;
dstheight = bottomy - dsty;
if (dstwidth < srcwidth)
srcwidth = dstwidth;
if (dstheight < srcheight)
srcheight = dstheight;
if (srcx < 0)
srcoffsetx = 0 - srcx;
else
srcoffsetx = 0;
if (srcy < 0)
srcoffsety = 0 - srcy;
else
srcoffsety = 0;
if (dstx < 0)
dstoffsetx = 0 - dstx;
else
dstoffsetx = 0;
if (dsty < 0)
dstoffsety = 0 - dsty;
else
dstoffsety = 0;
if (dstoffsetx > srcoffsetx)
srcoffsetx = dstoffsetx;
if (dstoffsety > srcoffsety)
srcoffsety = dstoffsety;
srcrowstride = gdk_pixbuf_get_rowstride (src);
dstrowstride = gdk_pixbuf_get_rowstride (dst);
src_pixels = gdk_pixbuf_get_pixels (src);
dst_pixels = gdk_pixbuf_get_pixels (dst);
for (y = srcoffsety; y < srcheight; y++)
for (x = srcoffsetx; x < srcwidth; x++)
{
guchar r, g, b, a;
sx = x + srcx;
sy = y + srcy;
dx = x + dstx;
dy = y + dsty;
a = src_pixels[4 * sx + sy * srcrowstride + 3];
if (a)
{
r = src_pixels[4 * sx + sy * srcrowstride];
g = src_pixels[4 * sx + 1 + sy * srcrowstride];
b = src_pixels[4 * sx + 2 + sy * srcrowstride];
art_rgba_run_alpha (dst_pixels + 4 * dx +
dy * dstrowstride, r, g, b, a, 1);
}
}
}
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
rsvg-art-composite.h: Composite different layers using gdk pixbuff for our
libart backend
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Dom Lachowicz <cinamod@hotmail.com>
Copyright (C) 2003, 2004, 2005 Caleb Moore <c.moore@student.unsw.edu.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors: Raph Levien <raph@artofcode.com>,
Dom Lachowicz <cinamod@hotmail.com>,
Caleb Moore <c.moore@student.unsw.edu.au>
*/
#ifndef RSVG_ART_COMPOSITE_H
#define RSVG_ART_COMPOSITE_H
#include "rsvg-private.h"
G_BEGIN_DECLS
void rsvg_pop_discrete_layer(RsvgDrawingCtx *ctx);
void rsvg_push_discrete_layer (RsvgDrawingCtx *ctx);
gboolean rsvg_needs_discrete_layer(RsvgState *state);
void
rsvg_alpha_blt (GdkPixbuf * src, gint srcx, gint srcy, gint srcwidth,
gint srcheight, GdkPixbuf * dst, gint dstx, gint dsty);
G_END_DECLS
#endif
......@@ -28,7 +28,6 @@
#include <libart_lgpl/art_vpath_bpath.h>
#include <libart_lgpl/art_render_svp.h>
#include <libart_lgpl/art_svp_vpath.h>
#include <libart_lgpl/art_svp_vpath.h>
#include <libart_lgpl/art_rgb_affine.h>
#include <libart_lgpl/art_rgb_rgba_affine.h>
#include <libart_lgpl/art_rgb_svp.h>
......@@ -37,6 +36,7 @@
#include <libart_lgpl/art_svp_ops.h>
#include "rsvg-art-draw.h"
#include "rsvg-art-composite.h"
#include "rsvg-paint-server.h"
#include "rsvg-styles.h"
#include "rsvg-bpath-util.h"
......
......@@ -230,102 +230,6 @@ gdk_pixbuf_get_interp_pixel(guchar * src, gdouble ox, gdouble oy, guchar ch, FPB
return (guchar)c;
}
void
rsvg_alpha_blt (GdkPixbuf * src, gint srcx, gint srcy, gint srcwidth,
gint srcheight, GdkPixbuf * dst, gint dstx, gint dsty)
{
gint rightx;
gint bottomy;
gint dstwidth;
gint dstheight;
gint srcoffsetx;
gint srcoffsety;
gint dstoffsetx;
gint dstoffsety;
gint x, y, srcrowstride, dstrowstride, sx, sy, dx, dy;
guchar *src_pixels, *dst_pixels;
dstheight = srcheight;
dstwidth = srcwidth;
rightx = srcx + srcwidth;
bottomy = srcy + srcheight;
if (rightx > gdk_pixbuf_get_width (src))
rightx = gdk_pixbuf_get_width (src);
if (bottomy > gdk_pixbuf_get_height (src))
bottomy = gdk_pixbuf_get_height (src);
srcwidth = rightx - srcx;
srcheight = bottomy - srcy;
rightx = dstx + dstwidth;
bottomy = dsty + dstheight;
if (rightx > gdk_pixbuf_get_width (dst))
rightx = gdk_pixbuf_get_width (dst);
if (bottomy > gdk_pixbuf_get_height (dst))
bottomy = gdk_pixbuf_get_height (dst);
dstwidth = rightx - dstx;
dstheight = bottomy - dsty;
if (dstwidth < srcwidth)
srcwidth = dstwidth;
if (dstheight < srcheight)
srcheight = dstheight;
if (srcx < 0)
srcoffsetx = 0 - srcx;
else
srcoffsetx = 0;
if (srcy < 0)
srcoffsety = 0 - srcy;
else
srcoffsety = 0;
if (dstx < 0)
dstoffsetx = 0 - dstx;
else
dstoffsetx = 0;
if (dsty < 0)
dstoffsety = 0 - dsty;
else
dstoffsety = 0;
if (dstoffsetx > srcoffsetx)
srcoffsetx = dstoffsetx;
if (dstoffsety > srcoffsety)
srcoffsety = dstoffsety;
srcrowstride = gdk_pixbuf_get_rowstride (src);
dstrowstride = gdk_pixbuf_get_rowstride (dst);
src_pixels = gdk_pixbuf_get_pixels (src);
dst_pixels = gdk_pixbuf_get_pixels (dst);
for (y = srcoffsety; y < srcheight; y++)
for (x = srcoffsetx; x < srcwidth; x++)
{
guchar r, g, b, a;
sx = x + srcx;
sy = y + srcy;
dx = x + dstx;
dy = y + dsty;
a = src_pixels[4 * sx + sy * srcrowstride + 3];
if (a)
{
r = src_pixels[4 * sx + sy * srcrowstride];
g = src_pixels[4 * sx + 1 + sy * srcrowstride];
b = src_pixels[4 * sx + 2 + sy * srcrowstride];
art_rgba_run_alpha (dst_pixels + 4 * dx +
dy * dstrowstride, r, g, b, a, 1);
}
}
}
static void
rsvg_filter_fix_coordinate_system (RsvgFilterContext * ctx, RsvgState * state)
{
......
......@@ -35,6 +35,7 @@
#include <libart_lgpl/art_rgb_svp.h>
#include "rsvg-css.h"
#include "rsvg-mask.h"
#include "rsvg-art-composite.h"
static const char s_UTF8_B64Alphabet[64] = {
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
......
......@@ -26,6 +26,7 @@
#include "rsvg-mask.h"
#include "rsvg-styles.h"
#include "rsvg-art-draw.h"
#include "rsvg-art-composite.h"
#include "rsvg-css.h"
#include <libart_lgpl/art_rgba.h>
#include <libart_lgpl/art_svp_ops.h>
......
......@@ -30,6 +30,7 @@
#include "rsvg-image.h"
#include "rsvg-mask.h"
#include "rsvg-css.h"
#include "rsvg-art-composite.h"
#include <libart_lgpl/art_svp_ops.h>
#include <libart_lgpl/art_affine.h>
......
......@@ -34,7 +34,6 @@
#include "rsvg-mask.h"
#include "rsvg-marker.h"
#include <libart_lgpl/art_rgba.h>
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_svp_ops.h>
......@@ -1352,313 +1351,6 @@ rsvg_parse_style_attrs (RsvgHandle * ctx,
}
}
static void
rsvg_pixmap_destroy (gchar *pixels, gpointer data)
{
g_free (pixels);
}
/**
* rsvg_push_opacity_group: Begin a new transparency group.
* @ctx: Context in which to push.
*
* Pushes a new transparency group onto the stack. The top of the stack
* is stored in the context, while the "saved" value is in the state
* stack.
**/
void
rsvg_push_discrete_layer (RsvgDrawingCtx *ctx)
{
RsvgState *state;
GdkPixbuf *pixbuf;
art_u8 *pixels;
int width, height, rowstride;
state = rsvg_state_current(ctx);
pixbuf = ctx->pixbuf;
rsvg_state_clip_path_assure(ctx);
if (state->filter == NULL && state->opacity == 0xFF &&
!state->backgroundnew && state->mask == NULL && !state->adobe_blend)
return;
state->save_pixbuf = pixbuf;
state->underbbox = ctx->bbox;
ctx->bbox.x0 = 0;
ctx->bbox.x1 = 0;
ctx->bbox.y0 = 0;
ctx->bbox.y1 = 0;
if (pixbuf == NULL)
{
/* FIXME: What warning/GError here? */
return;
}
if (!gdk_pixbuf_get_has_alpha (pixbuf))
{
g_warning (_("push/pop transparency group on non-alpha buffer nyi\n"));
return;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
pixels = g_new (art_u8, rowstride * height);
memset (pixels, 0, rowstride * height);
pixbuf = gdk_pixbuf_new_from_data (pixels,
GDK_COLORSPACE_RGB,
TRUE,
gdk_pixbuf_get_bits_per_sample (pixbuf),
width,
height,
rowstride,
(GdkPixbufDestroyNotify)rsvg_pixmap_destroy,
NULL);
ctx->pixbuf = pixbuf;
}
static void
rsvg_use_opacity (RsvgDrawingCtx *ctx, int opacity,
GdkPixbuf *tos, GdkPixbuf *nos)
{
art_u8 *tos_pixels, *nos_pixels;
int width;
int height;
int rowstride;
int x, y;
int tmp;
if (tos == NULL || nos == NULL)
{
/* FIXME: What warning/GError here? */
return;
}
if (!gdk_pixbuf_get_has_alpha (nos))
{
g_warning (_("push/pop transparency group on non-alpha buffer nyi\n"));
return;
}
width = gdk_pixbuf_get_width (tos);
height = gdk_pixbuf_get_height (tos);
rowstride = gdk_pixbuf_get_rowstride (tos);
tos_pixels = gdk_pixbuf_get_pixels (tos);
nos_pixels = gdk_pixbuf_get_pixels (nos);
tos_pixels += rowstride * MAX(ctx->bbox.y0, 0);