Commit 26b00e86 authored by Emmanuel Pacaud's avatar Emmanuel Pacaud Committed by Emmanuel Pacaud

Add support for porterduff comp-op operators and for enable-background.

2007-01-12  Emmanuel Pacaud <emmanuel.pacaud@lapp.in2p3.fr>

	Add support for porterduff comp-op operators and for enable-background.

	* rsvg-cairo-draw.c (_rsvg_cairo_set_operator): new.
	(rsvg_cairo_render_path): request a temporary buffer when operator is
	not src-over.
	(rsvg_cairo_render_image): set composite operator before painting.
	(rsvg_cairo_push_render_stack): don't exit for operator != src-over
	or enable-background != accumulate.
	(rsvg_cairo_pop_render_stack): ditto. Set composite operator.
	* rsvg-styles.c (rsvg_state_init): added comp_op and
	enable_background.
	(rsvg_state_inherit_run): force inherit for comp_op and
	enable_background.
	(rsvg_parse_style_arg): parse for comp_op and enable_background.
	
	* rsvg-structure.c (rsvg_node_symbol_set_atts): move
	rsvg_parse_style_attrs inside the conditionnal block.


svn path=/trunk/; revision=1087
parent 26978ba4
2007-01-12 Emmanuel Pacaud <emmanuel.pacaud@lapp.in2p3.fr>
Add support for porterduff comp-op operators and for enable-background.
* rsvg-cairo-draw.c (_rsvg_cairo_set_operator): new.
(rsvg_cairo_render_path): request a temporary buffer when operator is
not src-over.
(rsvg_cairo_render_image): set composite operator before painting.
(rsvg_cairo_push_render_stack): don't exit for operator != src-over
or enable-background != accumulate.
(rsvg_cairo_pop_render_stack): ditto. Set composite operator.
* rsvg-styles.c (rsvg_state_init): added comp_op and
enable_background.
(rsvg_state_inherit_run): force inherit for comp_op and
enable_background.
(rsvg_parse_style_arg): parse for comp_op and enable_background.
* rsvg-structure.c (rsvg_node_symbol_set_atts): move
rsvg_parse_style_attrs inside the conditionnal block.
2007-01-05 Christian Persch <chpe@svn.gnome.org>
* gtk-engine/svg-draw.c: (rsvg_style_register_type):
......
......@@ -41,6 +41,40 @@
#include <pango/pangocairo.h>
static void
_rsvg_cairo_set_operator (cairo_t *cr, RsvgCompOpType comp_op)
{
cairo_operator_t op;
switch (comp_op) {
case RSVG_COMP_OP_CLEAR:
op = CAIRO_OPERATOR_CLEAR; break;
case RSVG_COMP_OP_SRC:
op = CAIRO_OPERATOR_SOURCE; break;
case RSVG_COMP_OP_DST:
op = CAIRO_OPERATOR_DEST; break;
case RSVG_COMP_OP_DST_OVER:
op = CAIRO_OPERATOR_DEST_OVER; break;
case RSVG_COMP_OP_SRC_IN:
op = CAIRO_OPERATOR_IN; break;
case RSVG_COMP_OP_DST_IN:
op = CAIRO_OPERATOR_DEST_IN; break;
case RSVG_COMP_OP_SRC_OUT:
op = CAIRO_OPERATOR_OUT; break;
case RSVG_COMP_OP_DST_OUT:
op = CAIRO_OPERATOR_DEST_OUT; break;
case RSVG_COMP_OP_SRC_ATOP:
op = CAIRO_OPERATOR_ATOP; break;
case RSVG_COMP_OP_DST_ATOP:
op = CAIRO_OPERATOR_DEST_ATOP; break;
case RSVG_COMP_OP_XOR:
op = CAIRO_OPERATOR_XOR; break;
default:
op = CAIRO_OPERATOR_OVER; break;
}
cairo_set_operator (cr, op);
}
static void
rsvg_pixmap_destroy (gchar *pixels, gpointer data)
{
......@@ -485,7 +519,8 @@ rsvg_cairo_render_path (RsvgDrawingCtx *ctx, const RsvgBpathDef *bpath_def)
need_tmpbuf = ((state->fill != NULL) && (state->stroke != NULL) &&
state->opacity != 0xff)
|| state->clip_path_ref || state->mask || state->filter;
|| state->clip_path_ref || state->mask || state->filter
|| (state->comp_op != RSVG_COMP_OP_SRC_OVER);
if (need_tmpbuf)
rsvg_cairo_push_discrete_layer (ctx);
......@@ -702,6 +737,7 @@ void rsvg_cairo_render_image (RsvgDrawingCtx *ctx, const GdkPixbuf * pixbuf,
cairo_pixels += 4 * width;
}
_rsvg_cairo_set_operator (render->cr, state->comp_op);
cairo_set_source_surface (render->cr, surface, pixbuf_x, pixbuf_y);
cairo_paint (render->cr);
cairo_surface_destroy (surface);
......@@ -833,9 +869,13 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx *ctx)
objectBoundingBox)
lateclip = TRUE;
if (state->opacity == 0xFF && !state->filter && !state->mask && !lateclip){
return;
}
if (state->opacity == 0xFF
&& !state->filter
&& !state->mask
&& !lateclip
&& (state->comp_op == RSVG_COMP_OP_SRC_OVER)
&& (state->enable_background == RSVG_ENABLE_BACKGROUND_ACCUMULATE))
return;
if (!state->filter)
surface = cairo_surface_create_similar (cairo_get_target (render->cr),
CAIRO_CONTENT_COLOR_ALPHA,
......@@ -878,8 +918,8 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx *ctx)
void
rsvg_cairo_push_discrete_layer (RsvgDrawingCtx *ctx)
{
rsvg_cairo_push_early_clips(ctx);
rsvg_cairo_push_render_stack(ctx);
rsvg_cairo_push_early_clips(ctx);
rsvg_cairo_push_render_stack(ctx);
}
static GdkPixbuf *
......@@ -924,85 +964,93 @@ rsvg_compile_bg(RsvgDrawingCtx *ctx)
static void
rsvg_cairo_pop_render_stack (RsvgDrawingCtx *ctx)
{
RsvgCairoRender *render = (RsvgCairoRender *)ctx->render;
cairo_t *child_cr = render->cr;
gboolean lateclip = FALSE;
GdkPixbuf * output = NULL;
cairo_surface_t *surface = NULL;
RsvgState *state = rsvg_state_current(ctx);
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->filter && !state->mask && !lateclip)
return;
if (state->filter)
{
GdkPixbuf * pixbuf = render->pixbuf_stack->data;
GdkPixbuf * bg = rsvg_compile_bg(ctx);
render->pixbuf_stack = g_list_remove_link (render->pixbuf_stack,
render->pixbuf_stack);
output = rsvg_filter_render (state->filter, pixbuf, bg,
ctx, &render->bbox, "2103");
g_object_unref (G_OBJECT (pixbuf));
g_object_unref (G_OBJECT (bg));
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));
}
else
surface = cairo_get_target (child_cr);
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,
surface,
0, 0);
if (lateclip)
rsvg_cairo_clip(ctx, rsvg_state_current(ctx)->clip_path_ref,
&render->bbox);
if (state->mask)
{
rsvg_cairo_generate_mask(render->cr, state->mask, ctx, &render->bbox);
}
else if (state->opacity != 0xFF)
cairo_paint_with_alpha (render->cr, (double)state->opacity / 255.0);
else
cairo_paint (render->cr);
cairo_destroy (child_cr);
rsvg_bbox_insert((RsvgBbox *)render->bb_stack->data,
&render->bbox);
render->bbox = *((RsvgBbox *)render->bb_stack->data);
g_free(render->bb_stack->data);
render->bb_stack = g_list_remove_link (render->bb_stack, render->bb_stack);
if (state->filter)
{
g_object_unref (G_OBJECT (output));
cairo_surface_destroy(surface);
}
RsvgCairoRender *render = (RsvgCairoRender *)ctx->render;
cairo_t *child_cr = render->cr;
gboolean lateclip = FALSE;
GdkPixbuf * output = NULL;
cairo_surface_t *surface = NULL;
RsvgState *state = rsvg_state_current(ctx);
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->filter
&& !state->mask
&& !lateclip
&& (state->comp_op == RSVG_COMP_OP_SRC_OVER)
&& (state->enable_background == RSVG_ENABLE_BACKGROUND_ACCUMULATE))
return;
if (state->filter)
{
GdkPixbuf * pixbuf = render->pixbuf_stack->data;
GdkPixbuf * bg = rsvg_compile_bg(ctx);
render->pixbuf_stack = g_list_remove_link (render->pixbuf_stack,
render->pixbuf_stack);
output = rsvg_filter_render (state->filter, pixbuf, bg,
ctx, &render->bbox, "2103");
g_object_unref (G_OBJECT (pixbuf));
g_object_unref (G_OBJECT (bg));
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));
}
else
surface = cairo_get_target (child_cr);
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,
surface,
0, 0);
if (lateclip)
rsvg_cairo_clip(ctx, rsvg_state_current(ctx)->clip_path_ref,
&render->bbox);
_rsvg_cairo_set_operator (render->cr, state->comp_op);
if (state->mask)
{
rsvg_cairo_generate_mask(render->cr, state->mask, ctx, &render->bbox);
}
else if (state->opacity != 0xFF)
cairo_paint_with_alpha (render->cr, (double)state->opacity / 255.0);
else
cairo_paint (render->cr);
cairo_destroy (child_cr);
rsvg_bbox_insert((RsvgBbox *)render->bb_stack->data,
&render->bbox);
render->bbox = *((RsvgBbox *)render->bb_stack->data);
g_free(render->bb_stack->data);
render->bb_stack = g_list_remove_link (render->bb_stack, render->bb_stack);
if (state->filter)
{
g_object_unref (G_OBJECT (output));
cairo_surface_destroy(surface);
}
}
void
rsvg_cairo_pop_discrete_layer (RsvgDrawingCtx *ctx)
{
rsvg_cairo_pop_render_stack(ctx);
cairo_restore(((RsvgCairoRender *)ctx->render)->cr);
rsvg_cairo_pop_render_stack(ctx);
cairo_restore(((RsvgCairoRender *)ctx->render)->cr);
}
void
......
......@@ -127,20 +127,20 @@ _rsvg_node_free (RsvgNode *self)
static void
rsvg_node_group_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
{
const char * klazz = NULL, * id = NULL, *value;
if (rsvg_property_bag_size (atts))
{
if ((value = rsvg_property_bag_lookup (atts, "class")))
klazz = value;
if ((value = rsvg_property_bag_lookup (atts, "id")))
{
id = value;
rsvg_defs_register_name (ctx->priv->defs, value, self);
}
const char * klazz = NULL, * id = NULL, *value;
if (rsvg_property_bag_size (atts))
{
if ((value = rsvg_property_bag_lookup (atts, "class")))
klazz = value;
if ((value = rsvg_property_bag_lookup (atts, "id")))
{
id = value;
rsvg_defs_register_name (ctx->priv->defs, value, self);
}
rsvg_parse_style_attrs (ctx, self->state, "g", klazz, id, atts);
}
rsvg_parse_style_attrs (ctx, self->state, "g", klazz, id, atts);
}
}
RsvgNode *
......@@ -460,9 +460,10 @@ rsvg_node_symbol_set_atts(RsvgNode *self, RsvgHandle *ctx, RsvgPropertyBag *atts
if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio")))
symbol->preserve_aspect_ratio =
rsvg_css_parse_aspect_ratio (value);
rsvg_parse_style_attrs (ctx, self->state, "symbol", klazz, id, atts);
}
rsvg_parse_style_attrs (ctx, self->state, "symbol", klazz, id, atts);
}
......
......@@ -55,23 +55,24 @@ rsvg_state_init (RsvgState *state)
_rsvg_affine_identity (state->affine);
_rsvg_affine_identity (state->personal_affine);
state->mask = NULL;
state->opacity = 0xff;
state->adobe_blend = 0;
state->fill = rsvg_paint_server_parse (NULL, NULL, "#000", 0);
state->fill_opacity = 0xff;
state->stroke_opacity = 0xff;
state->stroke_width = _rsvg_css_parse_length("1");
state->miter_limit = 4;
state->cap = RSVG_PATH_STROKE_CAP_BUTT;
state->join = RSVG_PATH_STROKE_JOIN_MITER;
state->stop_opacity = 0xff;
state->fill_rule = FILL_RULE_NONZERO;
state->clip_rule = FILL_RULE_NONZERO;
state->backgroundnew = FALSE;
state->overflow = FALSE;
state->flood_color = 0;
state->flood_opacity = 255;
state->mask = NULL;
state->opacity = 0xff;
state->adobe_blend = 0;
state->fill = rsvg_paint_server_parse (NULL, NULL, "#000", 0);
state->fill_opacity = 0xff;
state->stroke_opacity = 0xff;
state->stroke_width = _rsvg_css_parse_length("1");
state->miter_limit = 4;
state->cap = RSVG_PATH_STROKE_CAP_BUTT;
state->join = RSVG_PATH_STROKE_JOIN_MITER;
state->stop_opacity = 0xff;
state->fill_rule = FILL_RULE_NONZERO;
state->clip_rule = FILL_RULE_NONZERO;
state->enable_background = RSVG_ENABLE_BACKGROUND_ACCUMULATE;
state->comp_op = RSVG_COMP_OP_SRC_OVER;
state->overflow = FALSE;
state->flood_color = 0;
state->flood_opacity = 255;
state->font_family = g_strdup (RSVG_DEFAULT_FONT);
state->font_size = _rsvg_css_parse_length("12.0");
......@@ -257,10 +258,11 @@ rsvg_state_inherit_run (RsvgState *dst, const RsvgState *src,
{
dst->clip_path_ref = src->clip_path_ref;
dst->mask = src->mask;
dst->backgroundnew = src->backgroundnew;
dst->enable_background = src->enable_background;
dst->adobe_blend = src->adobe_blend;
dst->opacity = src->opacity;
dst->filter = src->filter;
dst->comp_op = src->comp_op;
}
}
......@@ -418,64 +420,93 @@ rsvg_parse_style_arg (RsvgHandle *ctx, RsvgState *state, const char *str)
else if (rsvg_css_param_match (str, "enable-background"))
{
if (!strcmp (str + arg_off, "new"))
state->backgroundnew = TRUE;
state->enable_background = RSVG_ENABLE_BACKGROUND_NEW;
else
state->backgroundnew = FALSE;
state->enable_background = RSVG_ENABLE_BACKGROUND_ACCUMULATE;
}
else if (rsvg_css_param_match (str, "display"))
else if (rsvg_css_param_match (str, "comp-op"))
{
state->has_visible = TRUE;
if (!strcmp (str + arg_off, "none"))
state->visible = FALSE;
else if (strcmp (str + arg_off, "inherit") != 0)
state->visible = TRUE;
else
state->has_visible = FALSE;
}
if (!strcmp (str + arg_off, "clear"))
state->comp_op = RSVG_COMP_OP_CLEAR;
else if (!strcmp (str + arg_off, "src"))
state->comp_op = RSVG_COMP_OP_SRC;
else if (!strcmp (str + arg_off, "dst"))
state->comp_op = RSVG_COMP_OP_DST;
else if (!strcmp (str + arg_off, "src-over"))
state->comp_op = RSVG_COMP_OP_SRC_OVER;
else if (!strcmp (str + arg_off, "dst-over"))
state->comp_op = RSVG_COMP_OP_DST_OVER;
else if (!strcmp (str + arg_off, "src-in"))
state->comp_op = RSVG_COMP_OP_SRC_IN;
else if (!strcmp (str + arg_off, "dst-in"))
state->comp_op = RSVG_COMP_OP_DST_IN;
else if (!strcmp (str + arg_off, "src-out"))
state->comp_op = RSVG_COMP_OP_SRC_OUT;
else if (!strcmp (str + arg_off, "dst-out"))
state->comp_op = RSVG_COMP_OP_DST_OUT;
else if (!strcmp (str + arg_off, "src-atop"))
state->comp_op = RSVG_COMP_OP_SRC_ATOP;
else if (!strcmp (str + arg_off, "dst-atop"))
state->comp_op = RSVG_COMP_OP_DST_ATOP;
else if (!strcmp (str + arg_off, "xor"))
state->comp_op = RSVG_COMP_OP_XOR;
else
state->comp_op = RSVG_COMP_OP_SRC_OVER;
}
else if (rsvg_css_param_match (str, "display"))
{
state->has_visible = TRUE;
if (!strcmp (str + arg_off, "none"))
state->visible = FALSE;
else if (strcmp (str + arg_off, "inherit") != 0)
state->visible = TRUE;
else
state->has_visible = FALSE;
}
else if (rsvg_css_param_match (str, "visibility"))
{
state->has_visible = TRUE;
if (!strcmp (str + arg_off, "visible"))
state->visible = TRUE;
else if (strcmp (str + arg_off, "inherit") != 0)
state->visible = FALSE; /* collapse or hidden */
else
state->has_visible = FALSE;
}
{
state->has_visible = TRUE;
if (!strcmp (str + arg_off, "visible"))
state->visible = TRUE;
else if (strcmp (str + arg_off, "inherit") != 0)
state->visible = FALSE; /* collapse or hidden */
else
state->has_visible = FALSE;
}
else if (rsvg_css_param_match (str, "fill"))
{
RsvgPaintServer * fill = state->fill;
state->fill = rsvg_paint_server_parse (&state->has_fill_server, ctx->priv->defs, str + arg_off, 0);
rsvg_paint_server_unref (fill);
}
{
RsvgPaintServer * fill = state->fill;
state->fill = rsvg_paint_server_parse (&state->has_fill_server, ctx->priv->defs, str + arg_off, 0);
rsvg_paint_server_unref (fill);
}
else if (rsvg_css_param_match (str, "fill-opacity"))
{
state->fill_opacity = rsvg_css_parse_opacity (str + arg_off);
state->has_fill_opacity = TRUE;
}
{
state->fill_opacity = rsvg_css_parse_opacity (str + arg_off);
state->has_fill_opacity = TRUE;
}
else if (rsvg_css_param_match (str, "fill-rule"))
{
state->has_fill_rule = TRUE;
if (!strcmp (str + arg_off, "nonzero"))
state->fill_rule = FILL_RULE_NONZERO;
else if (!strcmp (str + arg_off, "evenodd"))
state->fill_rule = FILL_RULE_EVENODD;
else
state->has_fill_rule = FALSE;
}
{
state->has_fill_rule = TRUE;
if (!strcmp (str + arg_off, "nonzero"))
state->fill_rule = FILL_RULE_NONZERO;
else if (!strcmp (str + arg_off, "evenodd"))
state->fill_rule = FILL_RULE_EVENODD;
else
state->has_fill_rule = FALSE;
}
else if (rsvg_css_param_match (str, "clip-rule"))
{
state->has_clip_rule = TRUE;
if (!strcmp (str + arg_off, "nonzero"))
state->clip_rule = FILL_RULE_NONZERO;
else if (!strcmp (str + arg_off, "evenodd"))
state->clip_rule = FILL_RULE_EVENODD;
else
state->has_clip_rule = FALSE;
}
{
state->has_clip_rule = TRUE;
if (!strcmp (str + arg_off, "nonzero"))
state->clip_rule = FILL_RULE_NONZERO;
else if (!strcmp (str + arg_off, "evenodd"))
state->clip_rule = FILL_RULE_EVENODD;
else
state->has_clip_rule = FALSE;
}
else if (rsvg_css_param_match (str, "stroke"))
{
RsvgPaintServer * stroke = state->stroke;
{
RsvgPaintServer * stroke = state->stroke;
state->stroke = rsvg_paint_server_parse (&state->has_stroke_server, ctx->priv->defs, str + arg_off, 0);
......@@ -759,6 +790,7 @@ rsvg_parse_style_pairs (RsvgHandle *ctx, RsvgState *state,
rsvg_lookup_parse_style_pair (ctx, state, "direction", atts);
rsvg_lookup_parse_style_pair (ctx, state, "display", atts);
rsvg_lookup_parse_style_pair (ctx, state, "enable-background", atts);
rsvg_lookup_parse_style_pair (ctx, state, "comp-op", atts);
rsvg_lookup_parse_style_pair (ctx, state, "fill", atts);
rsvg_lookup_parse_style_pair (ctx, state, "fill-opacity", atts);
rsvg_lookup_parse_style_pair (ctx, state, "fill-rule", atts);
......
......@@ -60,6 +60,26 @@ typedef enum {
UNICODE_BIDI_OVERRIDE = 2
} UnicodeBidi;
typedef enum {
RSVG_COMP_OP_CLEAR,
RSVG_COMP_OP_SRC,
RSVG_COMP_OP_DST,
RSVG_COMP_OP_SRC_OVER,
RSVG_COMP_OP_DST_OVER,
RSVG_COMP_OP_SRC_IN,
RSVG_COMP_OP_DST_IN,
RSVG_COMP_OP_SRC_OUT,
RSVG_COMP_OP_DST_OUT,
RSVG_COMP_OP_SRC_ATOP,
RSVG_COMP_OP_DST_ATOP,
RSVG_COMP_OP_XOR
} RsvgCompOpType;
typedef enum {
RSVG_ENABLE_BACKGROUND_ACCUMULATE,
RSVG_ENABLE_BACKGROUND_NEW
} RsvgEnableBackgroundType;
/* enums and data structures are ABI compatible with libart */
typedef enum {
......@@ -91,7 +111,6 @@ struct _RsvgState {
RsvgFilter *filter;
void *mask;
void *clip_path_ref;
gboolean backgroundnew;
guint8 adobe_blend; /* 0..11 */
guint8 opacity; /* 0..255 */
......@@ -175,6 +194,9 @@ struct _RsvgState {
gboolean has_startMarker;
gboolean has_middleMarker;
gboolean has_endMarker;
RsvgCompOpType comp_op;
RsvgEnableBackgroundType enable_background;
};
RsvgState * rsvg_state_new ();
......
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