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

patterns and other things

parent e8b775b3
2004-06-08 Caleb Moore <c.moore@student.unsw.edu.au>
* rsvg.c, rsvg-paint-server.c: added pattern support
* rsvg-shapes.c: return the value of the new group created when pushing defs groups
* rsvg-css.c: fixed problem caused when there are multiple seperating charactors between two elements in a list
* rsvg-filter.c: fixed the constant term in colour matricies.
2004-06-06 Dom Lachowicz <cinamod@hotmail.com>
* rsvg.c: Back out elementNs functions. They're not needed after all.
* test-display.c: Save the input SVG to a file. Better printing code - scales nicely, preserves aspect-ratio
2004-06-05 Caleb Moore <c.moore@student.unsw.edu.au>
2004-06-07 Caleb Moore <c.moore@student.unsw.edu.au>
* rsvg-css.c: fixed css to break strings on the LAST colon rather than the fist one. This allows namespaces to work once more!!!
2004-06-05 Caleb Moore <c.moore@student.unsw.edu.au>
2004-06-06 Caleb Moore <c.moore@student.unsw.edu.au>
* rsvg-filter, rsvg-styles.c: added adobe blending modes, still does not work because of namespace issues
* rsvg.c: got rid of the whole defs handler thing, it was unnecisarry. Now just use ctx->in_defs for everything.
......
......@@ -734,7 +734,9 @@ strtok_r(char *s, const char *delim, char **last)
gchar **
rsvg_css_parse_list(const char * in_str, guint * out_list_len)
{
#if GLIB_CHECK_VERSION(2, 3, 2)
/*the following code is defective because it creates blank entries when two splitting chars are next to each other*/
#if 0//GLIB_CHECK_VERSION(2, 3, 2)
gchar ** string_array;
guint n;
......@@ -752,7 +754,7 @@ rsvg_css_parse_list(const char * in_str, guint * out_list_len)
#else
char *ptr, *tok;
char *str;
char *str, *tmp;
guint n = 0;
GSList * string_list = NULL;
......@@ -761,12 +763,20 @@ rsvg_css_parse_list(const char * in_str, guint * out_list_len)
str = g_strdup (in_str);
tok = strtok_r (str, ", \t", &ptr);
if (tok != NULL) {
string_list = g_slist_prepend(string_list, g_strdup(tok));
n++;
tmp = g_strdup(tok);
if (strcmp(tmp, " "))
{
string_list = g_slist_prepend(string_list, tmp);
n++;
}
while((tok = strtok_r (NULL, ", \t", &ptr)) != NULL) {
string_list = g_slist_prepend(string_list, g_strdup(tok));
n++;
tmp = g_strdup(tok);
if (strcmp(tmp, " "))
{
string_list = g_slist_prepend(string_list, tmp);
n++;
}
}
}
g_free (str);
......@@ -810,7 +820,7 @@ rsvg_css_parse_number_list(const char * in_str, guint * out_list_len){
/* TODO: some error checking */
for (i = 0; i < len; i++)
output[i] = g_ascii_strtod(string_array[i], NULL);
g_strfreev(string_array);
if (out_list_len != NULL)
......
......@@ -2158,7 +2158,7 @@ rsvg_filter_primitive_colour_matrix_render (RsvgFilterPrimitive * self,
sum += cself->KernelMatrix[ch * 5 + i] *
in_pixels[4 * x + y * rowstride + i];
}
sum += cself->KernelMatrix[ch * 5 + 4];
sum += cself->KernelMatrix[ch * 5 + 4] * 255;
tempresult = sum;
if (tempresult > 255)
......
......@@ -26,11 +26,14 @@
#include "rsvg-private.h"
#include "rsvg-defs.h"
#include "rsvg-paint-server.h"
#include "rsvg-styles.h"
#include "rsvg-shapes.h"
#include <glib/gmem.h>
#include <glib/gmessages.h>
#include <glib/gstrfuncs.h>
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_render_mask.h>
#include <string.h>
#include <math.h>
......@@ -39,6 +42,7 @@
typedef struct _RsvgPaintServerSolid RsvgPaintServerSolid;
typedef struct _RsvgPaintServerLinGrad RsvgPaintServerLinGrad;
typedef struct _RsvgPaintServerRadGrad RsvgPaintServerRadGrad;
typedef struct _RsvgPaintServerPattern RsvgPaintServerPattern;
struct _RsvgPaintServer {
int refcnt;
......@@ -63,6 +67,11 @@ struct _RsvgPaintServerRadGrad {
ArtGradientRadial *agr;
};
struct _RsvgPaintServerPattern {
RsvgPaintServer super;
RsvgPattern *pattern;
};
static void
rsvg_paint_server_solid_free (RsvgPaintServer *self)
{
......@@ -337,6 +346,215 @@ rsvg_paint_server_rad_grad (RsvgRadialGradient *gradient)
return &result->super;
}
typedef struct {
ArtImageSource super;
gchar * pixels;
gint x, y, width, height;
gint realwidth, realheight;
gint rowstride;
art_boolean init;
} RsvgImageSourcePattern;
static void
render_image_pattern_done (ArtRenderCallback *self, ArtRender *render)
{
RsvgImageSourcePattern *z;
z = (RsvgImageSourcePattern *) self;
g_free(z->pixels);
g_free(self);
}
#include <libart_lgpl/art_rgb.h>
#include <libart_lgpl/art_render.h>
static int goodmod(int one, int two)
{
while (one < 0)
one += two;
return one % two;
}
static void
render_image_pattern_render(ArtRenderCallback *self, ArtRender *render,
art_u8 *dest, int y)
{
RsvgImageSourcePattern *z = (RsvgImageSourcePattern *)self;
int i;
int x0 = render->x0;
int x1 = render->x1;
int sx, sy;
for (i = 0; i < x1 - x0; i += 1)
{
sx = goodmod((i + x0 + z->x),z->width);
sy = goodmod((y + render->y0 + z->y),z->height);
if (sx < 0 || sx >= z->realwidth || sy < 0 || sy >= z->realheight)
{
render->image_buf[i * 4 + 3] = 0;
continue;
}
//printf("%i, %i -> %i, %i\n", i, y, sx, sy);
render->image_buf[i * 4] = z->pixels[sx * 4 + z->rowstride * sy];
render->image_buf[i * 4 + 1] = z->pixels[sx * 4 + z->rowstride * sy + 1];
render->image_buf[i * 4 + 2] = z->pixels[sx * 4 + z->rowstride * sy + 2];
render->image_buf[i * 4 + 3] = z->pixels[sx * 4 + z->rowstride * sy + 3];
}
}
static void
render_image_pattern_negotiate (ArtImageSource *self, ArtRender *render,
ArtImageSourceFlags *p_flags,
int *p_buf_depth, ArtAlphaType *p_alpha)
{
self->super.render = render_image_pattern_render;
*p_flags = 0;
*p_buf_depth = 8;
*p_alpha = ART_ALPHA_SEPARATE;
}
static void
render_image_pattern (ArtRender *render, gchar * pixels, gint x, gint y,
gint width, gint height, gint realwidth, gint realheight, gint rowstride,
double * affine)
{
RsvgImageSourcePattern *image_source;
int i;
image_source = art_new (RsvgImageSourcePattern, 1);
image_source->super.super.render = NULL;
image_source->super.super.done = render_image_pattern_done;
image_source->super.negotiate = render_image_pattern_negotiate;
image_source->pixels = g_new(gchar, rowstride * realheight);
image_source->rowstride = rowstride;
image_source->width = width;
image_source->height = height;
image_source->realwidth = realwidth;
image_source->realheight = realheight;
image_source->x = x;
image_source->y = y;
for (i = 0; i < rowstride * realheight; i++)
image_source->pixels[i] = pixels[i];
image_source->init = ART_FALSE;
art_render_add_image_source (render, &image_source->super);
}
static void
rsvg_paint_server_pattern_free (RsvgPaintServer *self)
{
RsvgPaintServerPattern *z = (RsvgPaintServerPattern *)self;
g_free (z);
}
static void
rsvg_paint_server_pattern_render (RsvgPaintServer *self, ArtRender *ar,
const RsvgPSCtx *ctx)
{
RsvgPaintServerPattern *z = (RsvgPaintServerPattern *)self;
RsvgPattern *pattern = z->pattern;
RsvgDefsDrawable *drawable = (RsvgDefsDrawable *)pattern->g;
RsvgHandle *hctx = ctx->ctx;
double affine[6];
double caffine[6];
int i;
GdkPixbuf *save, *render;
if (pattern->obj_bbox) {
affine[0] = ctx->x1 - ctx->x0;
affine[1] = 0.;
affine[2] = 0.;
affine[3] = ctx->y1 - ctx->y0;
affine[4] = ctx->x0;
affine[5] = ctx->y0;
} else {
for (i = 0; i < 6; i++)
affine[i] = ctx->affine[i];
}
if (pattern->obj_cbbox) {
caffine[0] = ctx->x1 - ctx->x0;
caffine[1] = 0.;
caffine[2] = 0.;
caffine[3] = ctx->y1 - ctx->y0;
caffine[4] = ctx->x0;
caffine[5] = ctx->y0;
} else {
for (i = 0; i < 6; i++)
caffine[i] = ctx->affine[i];
}
art_affine_multiply(affine, pattern->affine, affine);
render = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 1, 8,
gdk_pixbuf_get_width(hctx->pixbuf),
gdk_pixbuf_get_height(hctx->pixbuf));
gdk_pixbuf_fill(render, 0x00000000);
save = hctx->pixbuf;
hctx->pixbuf = render;
/* push the state stack */
if (hctx->n_state == hctx->n_state_max)
hctx->state = g_renew (RsvgState, hctx->state,
hctx->n_state_max <<= 1);
if (hctx->n_state)
rsvg_state_inherit (&hctx->state[hctx->n_state],
&hctx->state[hctx->n_state - 1]);
else
rsvg_state_init (hctx->state);
hctx->n_state++;
for (i = 0; i < 6; i++)
{
rsvg_state_current(hctx)->personal_affine[i] = caffine[i];
rsvg_state_current(hctx)->affine[i] = caffine[i];
}
rsvg_defs_drawable_draw (drawable, hctx, 2);
/* pop the state stack */
hctx->n_state--;
rsvg_state_finalize (&hctx->state[hctx->n_state]);
hctx->pixbuf = save;
render_image_pattern (ar, gdk_pixbuf_get_pixels (render),
pattern->x * affine[0] + affine[4],
pattern->y * affine[3] + affine[5],
pattern->width * affine[0],
pattern->height * affine[3],
gdk_pixbuf_get_width (render),
gdk_pixbuf_get_height (render),
gdk_pixbuf_get_rowstride (render), affine);
}
static RsvgPaintServer *
rsvg_paint_server_pattern (RsvgPattern *pattern)
{
RsvgPaintServerPattern *result = g_new (RsvgPaintServerPattern, 1);
result->super.refcnt = 1;
result->super.free = rsvg_paint_server_pattern_free;
result->super.render = rsvg_paint_server_pattern_render;
result->pattern = pattern;
return &result->super;
}
/**
* rsvg_paint_server_parse: Parse an SVG paint specification.
* @defs: Defs for looking up gradients.
......@@ -382,6 +600,8 @@ rsvg_paint_server_parse (RsvgPaintServer * current, const RsvgDefs *defs, const
return rsvg_paint_server_lin_grad ((RsvgLinearGradient *)val);
case RSVG_DEF_RADGRAD:
return rsvg_paint_server_rad_grad ((RsvgRadialGradient *)val);
case RSVG_DEF_PATTERN:
return rsvg_paint_server_pattern ((RsvgPattern *)val);
default:
return NULL;
}
......@@ -529,3 +749,23 @@ rsvg_clone_linear_gradient (const RsvgLinearGradient *grad, gboolean * shallow_c
return clone;
}
RsvgPattern *
rsvg_clone_pattern (const RsvgPattern *pattern)
{
printf("cloneing pattern\n");
RsvgPattern * clone = NULL;
int i;
clone = g_new0 (RsvgPattern, 1);
clone->super.type = RSVG_DEF_PATTERN;
clone->super.free = rsvg_pattern_free;
clone->obj_bbox = pattern->obj_bbox;
clone->obj_cbbox = pattern->obj_cbbox;
for (i = 0; i < 6; i++)
clone->affine[i] = pattern->affine[i];
printf("cloned\n");
return clone;
}
......@@ -36,6 +36,7 @@ typedef struct _RsvgGradientStop RsvgGradientStop;
typedef struct _RsvgGradientStops RsvgGradientStops;
typedef struct _RsvgLinearGradient RsvgLinearGradient;
typedef struct _RsvgRadialGradient RsvgRadialGradient;
typedef struct _RsvgPattern RsvgPattern;
typedef struct _RsvgPaintServer RsvgPaintServer;
......@@ -49,6 +50,7 @@ struct _RsvgPSCtx {
guint32 color;
double affine[6];
RsvgHandle *ctx;
};
struct _RsvgGradientStop {
......@@ -87,6 +89,15 @@ struct _RsvgRadialGradient {
gboolean has_current_color;
};
struct _RsvgPattern {
RsvgDefVal super;
gboolean obj_cbbox;
gboolean obj_bbox;
double affine[6]; /* user space to actual at time of gradient def */
double x, y, width, height;
RsvgDefVal * g;
};
/* Create a new paint server based on a specification string. */
RsvgPaintServer *
rsvg_paint_server_parse (RsvgPaintServer * current, const RsvgDefs *defs, const char *str,
......@@ -108,6 +119,9 @@ rsvg_clone_radial_gradient (const RsvgRadialGradient *grad, gboolean * shallow_c
RsvgLinearGradient *
rsvg_clone_linear_gradient (const RsvgLinearGradient *grad, gboolean * shallow_cloned);
RsvgPattern *
rsvg_clone_pattern (const RsvgPattern *pattern);
G_END_DECLS
#endif
......@@ -106,6 +106,7 @@ struct RsvgHandle {
void rsvg_linear_gradient_free (RsvgDefVal *self);
void rsvg_radial_gradient_free (RsvgDefVal *self);
void rsvg_pattern_free (RsvgDefVal *self);
/* "super"/parent calls */
void rsvg_handle_init (RsvgHandle * handle);
......
......@@ -195,6 +195,7 @@ rsvg_render_svp (RsvgHandle *ctx, const ArtSVP *svp,
gradctx.y0 = temprect.y0;
gradctx.x1 = temprect.x1;
gradctx.y1 = temprect.y1;
gradctx.ctx = ctx;
state = rsvg_state_current(ctx);
for (i = 0; i < 6; i++)
......@@ -376,12 +377,28 @@ rsvg_defs_drawable_group_draw (RsvgDefsDrawable * self, RsvgHandle *ctx,
RsvgState *state = rsvg_state_current (ctx);
RsvgDefsDrawableGroup *group = (RsvgDefsDrawableGroup*)self;
guint i;
double tempaffine[6];
for (i = 0; i < 6; i++)
{
tempaffine[i] = ctx->state[ctx->n_state - 1].affine[i];
}
/* combine state definitions */
rsvg_state_clone (state, &self->state);
if (ctx->n_state > 1)
{
if (dominate)
/*This is a special domination mode for patterns, the style
is simply reinherited, wheras the transform is totally overridden*/
if (dominate == 2)
{
rsvg_state_reinherit(state, &ctx->state[ctx->n_state - 2]);
for (i = 0; i < 6; i++)
{
state->affine[i] = tempaffine[i];
}
}
else if (dominate)
rsvg_state_dominate(state, &ctx->state[ctx->n_state - 2]);
else
rsvg_state_reinherit(state, &ctx->state[ctx->n_state - 2]);
......@@ -401,7 +418,7 @@ rsvg_defs_drawable_group_draw (RsvgDefsDrawable * self, RsvgHandle *ctx,
else
rsvg_state_init (ctx->state);
ctx->n_state++;
rsvg_defs_drawable_draw (g_ptr_array_index(group->children, i),
ctx, 0);
......@@ -471,12 +488,13 @@ rsvg_defs_drawable_group_pack (RsvgDefsDrawableGroup *self, RsvgDefsDrawable *ch
g_ptr_array_add(z->children, child);
}
void
RsvgDefsDrawable *
rsvg_push_def_group (RsvgHandle *ctx, const char * id)
{
RsvgDefsDrawableGroup *group;
if (!ctx->in_defs)
return;
return NULL;
group = g_new (RsvgDefsDrawableGroup, 1);
group->children = g_ptr_array_new();
......@@ -493,6 +511,7 @@ rsvg_push_def_group (RsvgHandle *ctx, const char * id)
rsvg_defs_drawable_group_pack((RsvgDefsDrawableGroup *)group->super.parent,
&group->super);
ctx->current_defs_group = group;
return &group->super;
}
void
......
......@@ -31,6 +31,8 @@
G_BEGIN_DECLS
typedef struct _RsvgDefsDrawable RsvgDefsDrawable;
void rsvg_handle_path (RsvgHandle *ctx, const char * d, const char * id);
void rsvg_render_path (RsvgHandle *ctx, const char *d);
void rsvg_start_path (RsvgHandle *ctx, RsvgPropertyBag *atts);
......@@ -43,10 +45,9 @@ void rsvg_start_ellipse (RsvgHandle *ctx, RsvgPropertyBag *atts);
void rsvg_start_image (RsvgHandle *ctx, RsvgPropertyBag *atts);
void rsvg_start_use (RsvgHandle *ctx, RsvgPropertyBag *atts);
void rsvg_push_def_group (RsvgHandle *ctx, const char * id);
RsvgDefsDrawable * 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;
......
......@@ -472,6 +472,14 @@ rsvg_start_linear_gradient (RsvgHandle *ctx, RsvgPropertyBag *atts)
x2 = rsvg_css_parse_normalized_length ("100%", ctx->dpi, (gdouble)ctx->width, state->font_size);
}
/* set up 100% as the default if not gotten */
if (!got_y2) {
if (obj_bbox)
y2 = 1.0;
else
y2 = rsvg_css_parse_normalized_length ("100%", ctx->dpi, (gdouble)ctx->width, state->font_size);
}
if (xlink_href != NULL)
{
RsvgLinearGradient * parent = (RsvgLinearGradient*)rsvg_defs_lookup (ctx->defs, xlink_href+1);
......@@ -689,6 +697,118 @@ rsvg_start_radial_gradient (RsvgHandle *ctx, RsvgPropertyBag *atts, const char *
grad->spread = (cloned && !got_spread) ? grad->spread : spread;
}
void
rsvg_pattern_free (RsvgDefVal *self)
{
RsvgPattern *z = (RsvgPattern *)self;
g_free (z);
}
static void
rsvg_start_pattern (RsvgHandle *ctx, RsvgPropertyBag *atts)
{
RsvgState *state = rsvg_state_current (ctx);
RsvgPattern *pattern = NULL;
const char *id = NULL, *value;
double x = 0., y = 0., width = 0., height = 0.;
const char * xlink_href = NULL;
gboolean obj_bbox = TRUE;
gboolean obj_cbbox = FALSE;
gboolean got_x, got_y, got_width, got_height, got_transform, got_bbox, got_cbbox, cloned;
double affine[6];
int i;
got_x = got_y = got_width = got_height = got_transform = got_bbox = got_cbbox = cloned = FALSE;
if (rsvg_property_bag_size (atts))
{
if ((value = rsvg_property_bag_lookup (atts, "id")))
id = value;
if ((value = rsvg_property_bag_lookup (atts, "x"))) {
x = rsvg_css_parse_normalized_length (value, ctx->dpi, 1, state->font_size);
got_x = TRUE;
}
if ((value = rsvg_property_bag_lookup (atts, "y"))) {
y = rsvg_css_parse_normalized_length (value, ctx->dpi, 1, state->font_size);
got_y = TRUE;
}
if ((value = rsvg_property_bag_lookup (atts, "width"))) {
width = rsvg_css_parse_normalized_length (value, ctx->dpi, 1, state->font_size);
got_width = TRUE;
}
if ((value = rsvg_property_bag_lookup (atts, "height"))) {
height = rsvg_css_parse_normalized_length (value, ctx->dpi, 1, state->font_size);
got_height = TRUE;
}
if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
xlink_href = value;
if ((value = rsvg_property_bag_lookup (atts, "patternTransform")))
got_transform = rsvg_parse_transform (affine, value);
if ((value = rsvg_property_bag_lookup (atts, "patternUnits"))) {
if (!strcmp (value, "userSpaceOnUse"))
obj_bbox = FALSE;
else
obj_bbox = TRUE;
got_bbox = TRUE;
}
if ((value = rsvg_property_bag_lookup (atts, "patternContentUnits"))) {
if (!strcmp (value, "userSpaceOnUse"))
obj_cbbox = FALSE;
else
obj_cbbox = TRUE;
got_cbbox = TRUE;
}
}
/* set up 100% as the default if not gotten */
if (!got_width) {
if (obj_bbox)
width = 1.0;
else
width = rsvg_css_parse_normalized_length ("100%", ctx->dpi, (gdouble)ctx->width, state->font_size);
}
if (xlink_href != NULL)
{
RsvgPattern * parent = (RsvgPattern*)rsvg_defs_lookup (ctx->defs, xlink_href+1);
if (parent != NULL)
{
cloned = TRUE;
pattern = rsvg_clone_pattern (parent);
}
}
if (!cloned)
{
pattern = g_new (RsvgPattern, 1);
pattern->super.type = RSVG_DEF_PATTERN;
pattern->super.free = rsvg_pattern_free;
}
rsvg_defs_set (ctx->defs, id, &pattern->super);
if (got_transform)
for (i = 0; i < 6; i++)
pattern->affine[i] = affine[i];
else
art_affine_identity(pattern->affine);
/* gradient inherits parent/cloned information unless it's explicity gotten */
pattern->obj_bbox = (cloned && !got_bbox) ? pattern->obj_bbox : obj_bbox;
pattern->obj_cbbox = (cloned && !got_cbbox) ? pattern->obj_cbbox : obj_cbbox;
pattern->x = (cloned && !got_x) ? pattern->x : x;
pattern->y = (cloned && !got_y) ? pattern->y : y;
pattern->width = (cloned && !got_width) ? pattern->width : width;
pattern->height = (cloned && !got_height) ? pattern->height : height;
ctx->in_defs++;
pattern->g = &(rsvg_push_def_group (ctx, "")->super);
}
/* end gradients */
static void
......@@ -1040,6 +1160,8 @@ rsvg_start_element (void *data, const xmlChar *name,
rsvg_start_radial_gradient (ctx, bag, "radialGradient");
else if (!strcmp ((char *)name, "conicalGradient"))
rsvg_start_radial_gradient (ctx, bag, "conicalGradient");
else if (!strcmp ((char *)name, "pattern"))
rsvg_start_pattern (ctx, bag);
rsvg_filter_handler_start (ctx, name, bag);
}
......@@ -1082,6 +1204,10 @@ rsvg_end_element (void *data, const xmlChar *name)
rsvg_end_mask(ctx);
ctx->in_defs--;
}
else if (!strcmp ((char *)name, "pattern")) {
ctx->in_defs--;
rsvg_pop_def_group(ctx);
}
/* 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