Commit b9699cc7 authored by Caleb Michael Moore's avatar Caleb Michael Moore

masking is good now

parent 8f93028c
......@@ -44,6 +44,8 @@ librsvg_2_la_SOURCES = \
rsvg-file-util.c \
rsvg-filter.c \
rsvg-filter.h \
rsvg-mask.c \
rsvg-mask.h \
rsvg-shapes.c \
rsvg-shapes.h \
rsvg-styles.c \
......
......@@ -41,7 +41,8 @@ typedef enum {
RSVG_DEF_RADGRAD,
RSVG_DEF_PATTERN,
RSVG_DEF_PATH,
RSVG_DEF_FILTER
RSVG_DEF_FILTER,
RSVG_DEF_MASK
} RsvgDefType;
struct _RsvgDefVal {
......
......@@ -31,9 +31,7 @@
G_BEGIN_DECLS
typedef enum {
objectBoundingBox, userSpaceOnUse
} RsvgFilterUnits;
typedef RsvgCoordUnits RsvgFilterUnits;
struct _RsvgFilter {
RsvgDefVal super;
......
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
rsvg-filter.c: Provides filters
Copyright (C) 2004 Caleb Moore
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.
Author: Caleb Moore <calebmm@tpg.com.au>
*/
#include "rsvg-private.h"
#include "rsvg-mask.h"
#include "rsvg-styles.h"
#include "rsvg-shapes.h"
#include "rsvg-css.h"
#include <libart_lgpl/art_rgba.h>
static void
rsvg_mask_free (RsvgDefVal * self)
{
RsvgMask *z = (RsvgMask *)self;
g_ptr_array_free(z->super.children, FALSE);
g_free (z);
}
void
rsvg_mask_render (RsvgMask *self, GdkPixbuf *tos, GdkPixbuf *nos, RsvgHandle *ctx)
{
art_u8 *tos_pixels, *nos_pixels, *mask_pixels;
int width;
int height;
int rowstride;
int x, y;
GdkPixbuf *save, *mask;
RsvgDefsDrawable *drawable;
drawable = (RsvgDefsDrawable*)self;
mask = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 1, 8,
gdk_pixbuf_get_width(tos),
gdk_pixbuf_get_height(tos));
gdk_pixbuf_fill(mask, 0x00000000);
save = ctx->pixbuf;
ctx->pixbuf = mask;
rsvg_defs_drawable_draw (drawable, ctx, 0);
ctx->pixbuf = save;
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");
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);
mask_pixels = gdk_pixbuf_get_pixels (mask);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
guchar r, g, b, a, rm, gm, bm, am;
gdouble luminance;
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];
rm = mask_pixels[4 * x];
gm = mask_pixels[4 * x + 1];
bm = mask_pixels[4 * x + 2];
am = mask_pixels[4 * x + 3];
luminance = ((gdouble)rm * 0.2125 +
(gdouble)gm * 0.7154 +
(gdouble)bm * 0.0721) / 255.;
a = (guchar)((gdouble)a * luminance
* (gdouble)am / 255.);
art_rgba_run_alpha (nos_pixels + 4 * x, r, g, b, a, 1);
if (*(nos_pixels + 4 * x + 3))
printf("%i\n", *(nos_pixels + 4 * x + 3));
}
}
tos_pixels += rowstride;
nos_pixels += rowstride;
mask_pixels += rowstride;
}
g_object_unref (G_OBJECT (mask));
}
static void
rsvg_defs_drawable_mask_draw (RsvgDefsDrawable * self, RsvgHandle *ctx,
int dominate)
{
RsvgState *state = rsvg_state_current (ctx);
RsvgDefsDrawableGroup *group = (RsvgDefsDrawableGroup*)self;
guint i;
/* combine state definitions */
if (ctx->n_state > 1)
rsvg_state_dominate(state, &ctx->state[ctx->n_state - 2]);
if (state->opacity != 0xff || state->filter)
rsvg_push_discrete_layer (ctx);
for (i = 0; i < group->children->len; i++)
{
/* push the state stack */
if (ctx->n_state == ctx->n_state_max)
ctx->state = g_renew (RsvgState, ctx->state,
ctx->n_state_max <<= 1);
if (ctx->n_state)
rsvg_state_inherit (&ctx->state[ctx->n_state],
&ctx->state[ctx->n_state - 1]);
else
rsvg_state_init (ctx->state);
ctx->n_state++;
rsvg_defs_drawable_draw (g_ptr_array_index(group->children, i),
ctx, 0);
/* pop the state stack */
ctx->n_state--;
rsvg_state_finalize (&ctx->state[ctx->n_state]);
}
if (state->opacity != 0xff || state->filter)
rsvg_pop_discrete_layer (ctx);
}
static RsvgMask *
rsvg_new_mask (void)
{
RsvgMask *mask;
mask = g_new (RsvgMask, 1);
mask->maskunits = objectBoundingBox;
mask->contentunits = userSpaceOnUse;
mask->x = 0;
mask->y = 0;
mask->width = 1;
mask->height = 1;
mask->super.children = g_ptr_array_new ();
return mask;
}
void
rsvg_start_mask (RsvgHandle *ctx, RsvgPropertyBag *atts)
{
const char *id = NULL, *value;
RsvgMask *mask;
double font_size;
font_size = rsvg_state_current_font_size (ctx);
mask = rsvg_new_mask ();
if (rsvg_property_bag_size (atts))
{
if ((value = rsvg_property_bag_lookup (atts, "maskUnits")))
{
if (!strcmp (value, "userSpaceOnUse"))
mask->maskunits = userSpaceOnUse;
else
mask->maskunits = objectBoundingBox;
}
if ((value = rsvg_property_bag_lookup (atts, "maskContentUnits")))
{
if (!strcmp (value, "objectBoundingBox"))
mask->contentunits = objectBoundingBox;
else
mask->contentunits = userSpaceOnUse;
}
if ((value = rsvg_property_bag_lookup (atts, "x")))
mask->x =
rsvg_css_parse_normalized_length (value,
ctx->dpi,
1,
font_size);
if ((value = rsvg_property_bag_lookup (atts, "y")))
mask->y =
rsvg_css_parse_normalized_length (value,
ctx->dpi,
1,
font_size);
if ((value = rsvg_property_bag_lookup (atts, "width")))
mask->width =
rsvg_css_parse_normalized_length (value,
ctx->dpi,
1,
font_size);
if ((value = rsvg_property_bag_lookup (atts, "height")))
mask->height =
rsvg_css_parse_normalized_length (value,
ctx->dpi,
1,
font_size);
if ((value = rsvg_property_bag_lookup (atts, "id")))
id = value;
}
ctx->current_defs_group = &mask->super;
/* set up the defval stuff */
mask->super.super.super.type = RSVG_DEF_MASK;
mask->super.super.super.free = &rsvg_mask_free;
mask->super.super.draw = &rsvg_defs_drawable_mask_draw;
rsvg_defs_set (ctx->defs, id, &mask->super.super.super);
}
void
rsvg_end_mask (RsvgHandle *ctx)
{
ctx->current_defs_group = NULL;
}
RsvgDefsDrawable *
rsvg_mask_parse (const RsvgDefs * defs, const char *str)
{
if (!strncmp (str, "url(", 4))
{
const char *p = str + 4;
int ix;
char *name;
RsvgDefVal *val;
while (g_ascii_isspace (*p))
p++;
if (*p == '#')
{
p++;
for (ix = 0; p[ix]; ix++)
if (p[ix] == ')')
break;
if (p[ix] == ')')
{
name = g_strndup (p, ix);
val = rsvg_defs_lookup (defs, name);
g_free (name);
if (val && val->type == RSVG_DEF_MASK)
return (RsvgDefsDrawable *) val;
}
}
}
return NULL;
}
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
rsvg-mask.h : Provides Masks
Copyright (C) 2004 Caleb Moore
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.
Author: Caleb Moore <calebmm@tpg.com.au>
*/
#ifndef RSVG_MASK_H
#define RSVG_MASK_H
#include "rsvg.h"
#include "rsvg-defs.h"
#include "rsvg-styles.h"
#include "rsvg-shapes.h"
#include <libxml/SAX.h>
G_BEGIN_DECLS
typedef RsvgCoordUnits RsvgMaskUnits;
typedef struct _RsvgMask RsvgMask;
struct _RsvgMask {
RsvgDefsDrawableGroup super;
double x, y, width, height;
RsvgMaskUnits maskunits;
RsvgMaskUnits contentunits;
};
void
rsvg_mask_render (RsvgMask *self, GdkPixbuf *source, GdkPixbuf *output, RsvgHandle *ctx);
void
rsvg_start_mask (RsvgHandle *ctx, RsvgPropertyBag *atts);
void
rsvg_end_mask (RsvgHandle *ctx);
RsvgDefsDrawable *
rsvg_mask_parse (const RsvgDefs * defs, const char *str);
G_END_DECLS
#endif
......@@ -119,6 +119,10 @@ typedef enum {
RSVG_SIZE_ZOOM_MAX
} RsvgSizeType;
typedef enum {
objectBoundingBox, userSpaceOnUse
} RsvgCoordUnits;
struct RsvgSizeCallbackData
{
RsvgSizeType type;
......
......@@ -47,26 +47,6 @@
#define RSVG_ARC_MAGIC ((double) 0.5522847498)
typedef struct _RsvgDefsDrawablePath RsvgDefsDrawablePath;
typedef struct _RsvgDefsDrawableGroup RsvgDefsDrawableGroup;
typedef struct _RsvgDefsDrawableUse RsvgDefsDrawableUse;
struct _RsvgDefsDrawablePath {
RsvgDefsDrawable super;
char *d;
};
struct _RsvgDefsDrawableGroup {
RsvgDefsDrawable super;
GPtrArray *children;
};
struct _RsvgDefsDrawableUse {
RsvgDefsDrawable super;
RsvgDefsDrawable *child;
};
/**
* rsvg_close_vpath: Close a vector path.
* @src: Source vector path.
......@@ -258,7 +238,7 @@ rsvg_render_bpath (RsvgHandle *ctx, const ArtBpath *bpath)
art_free (affine_bpath);
need_tmpbuf = ((state->fill != NULL) && (state->stroke != NULL) &&
state->opacity != 0xff) || state->filter;
state->opacity != 0xff) || state->filter || state->mask;
if (need_tmpbuf)
rsvg_push_discrete_layer (ctx);
......
......@@ -47,6 +47,9 @@ void rsvg_push_def_group (RsvgHandle *ctx, const char * id);
void rsvg_pop_def_group (RsvgHandle *ctx);
typedef struct _RsvgDefsDrawable RsvgDefsDrawable;
typedef struct _RsvgDefsDrawablePath RsvgDefsDrawablePath;
typedef struct _RsvgDefsDrawableGroup RsvgDefsDrawableGroup;
typedef struct _RsvgDefsDrawableUse RsvgDefsDrawableUse;
struct _RsvgDefsDrawable {
RsvgDefVal super;
......@@ -55,8 +58,21 @@ struct _RsvgDefsDrawable {
void (*draw) (RsvgDefsDrawable * self, RsvgHandle *ctx, int dominate);
};
struct _RsvgDefsDrawablePath {
RsvgDefsDrawable super;
char *d;
};
struct _RsvgDefsDrawableGroup {
RsvgDefsDrawable super;
GPtrArray *children;
};
struct _RsvgDefsDrawableUse {
RsvgDefsDrawable super;
RsvgDefsDrawable *child;
};
RsvgDefsDrawable * rsvg_mask_parse (const RsvgDefs * defs, const char *str);
void rsvg_defs_drawable_draw (RsvgDefsDrawable * self, RsvgHandle *ctx,
int dominate);
......
......@@ -30,6 +30,7 @@
#include "rsvg-css.h"
#include "rsvg-styles.h"
#include "rsvg-shapes.h"
#include "rsvg-mask.h"
#include <libart_lgpl/art_rgba.h>
#include <libart_lgpl/art_affine.h>
......@@ -1252,137 +1253,6 @@ rsvg_use_opacity (RsvgHandle *ctx, int opacity,
}
}
static void
rsvg_use_mask (RsvgHandle *ctx, RsvgDefsDrawable * maskref,
GdkPixbuf *tos, GdkPixbuf *nos)
{
art_u8 *tos_pixels, *nos_pixels, *mask_pixels;
int width;
int height;
int rowstride;
int x, y;
GdkPixbuf *save, *mask;
RsvgDefsDrawable *drawable;
drawable = (RsvgDefsDrawable*)maskref;
mask = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 1, 8,
gdk_pixbuf_get_width(tos),
gdk_pixbuf_get_height(tos));
gdk_pixbuf_fill(mask, 0x00000000);
save = ctx->pixbuf;
if (ctx->n_state == ctx->n_state_max)
ctx->state = g_renew (RsvgState, ctx->state,
ctx->n_state_max <<= 1);
if (ctx->n_state)
rsvg_state_inherit (&ctx->state[ctx->n_state],
&ctx->state[ctx->n_state - 1]);
else
rsvg_state_init (ctx->state);
ctx->n_state++;
ctx->pixbuf = mask;
rsvg_defs_drawable_draw (drawable, ctx, 0);
/* pop the state stack */
ctx->n_state--;
rsvg_state_finalize (&ctx->state[ctx->n_state]);
ctx->pixbuf = save;
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");
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);
mask_pixels = gdk_pixbuf_get_pixels (mask);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
guchar r, g, b, a, rm, gm, bm, am;
gdouble luminance;
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];
rm = mask_pixels[4 * x];
gm = mask_pixels[4 * x + 1];
bm = mask_pixels[4 * x + 2];
am = mask_pixels[4 * x + 3];
luminance = ((gdouble)rm * 0.2125 +
(gdouble)gm * 0.7154 +
(gdouble)bm * 0.0721) / 255.;
a = (guchar)((gdouble)a * luminance
* (gdouble)am / 255.);
art_rgba_run_alpha (nos_pixels + 4 * x, r, g, b, a, 1);
}
}
tos_pixels += rowstride;
nos_pixels += rowstride;
mask_pixels += rowstride;
}
}
RsvgDefsDrawable *
rsvg_mask_parse (const RsvgDefs * defs, const char *str)
{
if (!strncmp (str, "url(", 4))
{
const char *p = str + 4;
int ix;
char *name;
RsvgDefVal *val;
while (g_ascii_isspace (*p))
p++;
if (*p == '#')
{
p++;
for (ix = 0; p[ix]; ix++)
if (p[ix] == ')')
break;
if (p[ix] == ')')
{
name = g_strndup (p, ix);
val = rsvg_defs_lookup (defs, name);
g_free (name);
if (val && val->type == RSVG_DEF_PATH)
{
return (RsvgDefsDrawable *) val;
}
}
}
}
return NULL;
}
static GdkPixbuf *
get_next_out(gint * operationsleft, GdkPixbuf * in, GdkPixbuf * tos,
GdkPixbuf * nos, GdkPixbuf *intermediate)
......@@ -1495,7 +1365,7 @@ rsvg_composite_layer(RsvgHandle *ctx, RsvgState *state, GdkPixbuf *tos, GdkPixbu
if (mask != NULL)
{
out = get_next_out(&operationsleft, in, tos, nos, intermediate);
rsvg_use_mask (ctx, mask, in, out);
rsvg_mask_render ((RsvgMask *)mask, in, out, ctx);
in = out;
}
......
......@@ -32,6 +32,7 @@
#include "rsvg-shapes.h"
#include "rsvg-text.h"
#include "rsvg-filter.h"
#include "rsvg-mask.h"
#include <math.h>
#include <string.h>
......@@ -818,7 +819,8 @@ rsvg_defs_handler_start (RsvgSaxHandler *self, const xmlChar *name,
rsvg_start_polygon (ctx, atts);
else if (!strcmp ((char *)name, "polyline"))
rsvg_start_polyline (ctx, atts);
else if (!strcmp ((char *)name, "mask"))
rsvg_start_mask(ctx, atts);
rsvg_filter_handler_start (ctx, name, atts);
}
......@@ -842,6 +844,8 @@ rsvg_defs_handler_end (RsvgSaxHandler *self, const xmlChar *name)
rsvg_end_g (ctx);
if (!strcmp ((char *)name, "filter"))
rsvg_end_filter (ctx);
else if (!strcmp ((char *)name, "mask"))
rsvg_end_mask(ctx);
/* pop the state stack */
ctx->n_state--;
......@@ -1080,6 +1084,11 @@ rsvg_start_element (void *data, const xmlChar *name, const xmlChar **atts)
rsvg_start_title (ctx, bag);
else if (!strcmp ((char *)name, "desc"))
rsvg_start_desc (ctx, bag);
else if (!strcmp ((char *)name, "mask"))
{
ctx->in_defs = TRUE;
rsvg_start_mask(ctx, bag);
}
/* see conicalGradient discussion above */
else if (!strcmp ((char *)name, "linearGradient"))
......@@ -1121,7 +1130,10 @@ rsvg_end_element (void *data, const xmlChar *name)
else if (!strcmp ((char *)name, "defs")) {
ctx->in_defs = FALSE;
}
else if (!strcmp ((char *)name, "mask")){
rsvg_end_mask(ctx);
ctx->in_defs = FALSE;
}
/* pop the state stack */
ctx->n_state--;
rsvg_state_finalize (&ctx->state[ctx->n_state]);
......
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