[lasem] svg: add support for comp-op attribute (svg1.2)



commit 18fc0faa6ac4b0ee090c52df6a409c44a48dded7
Author: Emmanuel Pacaud <emmanuel gnome org>
Date:   Sun Oct 28 09:39:50 2012 +0100

    svg: add support for comp-op attribute (svg1.2)

 src/lsmcairo.c     |    1 +
 src/lsmcairo.h     |    1 +
 src/lsmsvgstyle.c  |    6 +++
 src/lsmsvgstyle.h  |    6 +++
 src/lsmsvgtraits.c |   24 +++++++++++++
 src/lsmsvgtraits.h |    1 +
 src/lsmsvgview.c   |   93 ++++++++++++++++++++++++++++++++++++++++-----------
 7 files changed, 112 insertions(+), 20 deletions(-)
---
diff --git a/src/lsmcairo.c b/src/lsmcairo.c
index 980d951..c568fd5 100644
--- a/src/lsmcairo.c
+++ b/src/lsmcairo.c
@@ -595,3 +595,4 @@ lsm_cairo_set_source_pixbuf (cairo_t *cairo,
 	cairo_set_source_surface (cairo, surface, pixbuf_x, pixbuf_y);
 	cairo_surface_destroy (surface);
 }
+
diff --git a/src/lsmcairo.h b/src/lsmcairo.h
index d6f895b..eed4148 100644
--- a/src/lsmcairo.h
+++ b/src/lsmcairo.h
@@ -45,6 +45,7 @@ void 			lsm_cairo_box_user_to_device 		(cairo_t *cairo, LsmBox *to, const LsmBox
 void 			lsm_cairo_box_device_to_user 		(cairo_t *cairo, LsmBox *to, const LsmBox *from);
 void 			lsm_cairo_set_source_pixbuf 		(cairo_t *cairo, const GdkPixbuf *pixbuf,
 								 double pixbuf_x, double pixbuf_y);
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmsvgstyle.c b/src/lsmsvgstyle.c
index 8c0cf77..1f6df04 100644
--- a/src/lsmsvgstyle.c
+++ b/src/lsmsvgstyle.c
@@ -54,6 +54,12 @@ static const LsmPropertyInfos lsm_svg_property_infos[] = {
 		.trait_default = "none"
 	},
 	{
+		.name = "comp-op",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyle, comp_op),
+		.trait_class = &lsm_svg_comp_op_trait_class,
+		.trait_default = "src-over"
+	},
+	{
 		.name = "dominant-baseline",
 		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyle, dominant_baseline),
 		.trait_class = &lsm_null_trait_class,
diff --git a/src/lsmsvgstyle.h b/src/lsmsvgstyle.h
index 8197d49..e76bad5 100644
--- a/src/lsmsvgstyle.h
+++ b/src/lsmsvgstyle.h
@@ -31,6 +31,11 @@ G_BEGIN_DECLS
 
 typedef struct {
 	LsmProperty base;
+	LsmSvgCompOp value;
+} LsmSvgCompOpProperty;
+
+typedef struct {
+	LsmProperty base;
 	double value;
 } LsmSvgDoubleProperty;
 
@@ -126,6 +131,7 @@ struct _LsmSvgStyle {
 	LsmProperty *			baseline_shift;
 	LsmProperty *	 		clip;
 	LsmProperty *	 		clip_path;
+	LsmSvgCompOpProperty *		comp_op;
 	LsmProperty *	 		dominant_baseline;
 	LsmSvgEnableBackgroundProperty *enable_background;
 	LsmProperty *	 		filter;
diff --git a/src/lsmsvgtraits.c b/src/lsmsvgtraits.c
index 9db4bea..053467e 100644
--- a/src/lsmsvgtraits.c
+++ b/src/lsmsvgtraits.c
@@ -56,6 +56,30 @@ const LsmTraitClass lsm_svg_blending_mode_trait_class = {
 };
 
 static gboolean
+lsm_svg_comp_op_trait_from_string (LsmTrait *abstract_trait, char *string)
+{
+	LsmSvgCompOp *trait = (LsmSvgCompOp *) abstract_trait;
+
+	*trait = lsm_svg_comp_op_from_string (string);
+
+	return *trait >= 0;
+}
+
+char *
+lsm_svg_comp_op_trait_to_string (LsmTrait *abstract_trait)
+{
+	LsmSvgCompOp *trait = (LsmSvgCompOp *) abstract_trait;
+
+	return g_strdup (lsm_svg_comp_op_to_string (*trait));
+}
+
+const LsmTraitClass lsm_svg_comp_op_trait_class = {
+	.size = sizeof (LsmSvgCompOp),
+	.from_string = lsm_svg_comp_op_trait_from_string,
+	.to_string = lsm_svg_comp_op_trait_to_string
+};
+
+static gboolean
 lsm_svg_enable_background_trait_from_string (LsmTrait *abstract_trait, char *string)
 {
 	LsmSvgEnableBackground *trait = (LsmSvgEnableBackground *) abstract_trait;
diff --git a/src/lsmsvgtraits.h b/src/lsmsvgtraits.h
index c51f9f2..7fb2644 100644
--- a/src/lsmsvgtraits.h
+++ b/src/lsmsvgtraits.h
@@ -76,6 +76,7 @@ extern const LsmTraitClass lsm_svg_angle_trait_class;
 extern const LsmTraitClass lsm_svg_blending_mode_trait_class;
 extern const LsmTraitClass lsm_svg_enable_background_trait_class;
 extern const LsmTraitClass lsm_svg_color_trait_class;
+extern const LsmTraitClass lsm_svg_comp_op_trait_class;
 extern const LsmTraitClass lsm_svg_dash_array_trait_class;
 extern const LsmTraitClass lsm_svg_display_trait_class;
 extern const LsmTraitClass lsm_svg_fill_rule_trait_class;
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index f72123a..c2fcbc2 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -77,6 +77,40 @@ typedef struct {
 	gboolean enable_background;
 } LsmSvgViewBackground;
 
+cairo_operator_t cairo_operators[] = {
+	CAIRO_OPERATOR_CLEAR,
+	CAIRO_OPERATOR_SOURCE,
+	CAIRO_OPERATOR_DEST,
+	CAIRO_OPERATOR_OVER,
+	CAIRO_OPERATOR_DEST_OVER,
+	CAIRO_OPERATOR_IN,
+	CAIRO_OPERATOR_DEST_IN,
+	CAIRO_OPERATOR_OUT,
+	CAIRO_OPERATOR_DEST_OUT,
+	CAIRO_OPERATOR_ATOP,
+	CAIRO_OPERATOR_DEST_ATOP,
+	CAIRO_OPERATOR_XOR,
+	CAIRO_OPERATOR_ADD,
+	CAIRO_OPERATOR_MULTIPLY,
+	CAIRO_OPERATOR_SCREEN,
+	CAIRO_OPERATOR_OVERLAY,
+	CAIRO_OPERATOR_DARKEN,
+	CAIRO_OPERATOR_LIGHTEN,
+	CAIRO_OPERATOR_COLOR_DODGE,
+	CAIRO_OPERATOR_COLOR_BURN,
+	CAIRO_OPERATOR_HARD_LIGHT,
+	CAIRO_OPERATOR_SOFT_LIGHT,
+	CAIRO_OPERATOR_DIFFERENCE,
+	CAIRO_OPERATOR_EXCLUSION
+};
+
+void
+lsm_cairo_set_comp_op (cairo_t *cairo, LsmSvgCompOp comp_op)
+{
+	if (G_LIKELY (cairo != NULL && comp_op >= LSM_SVG_COMP_OP_CLEAR && comp_op <= LSM_SVG_COMP_OP_EXCLUSION))
+		cairo_set_operator (cairo, cairo_operators[comp_op]);
+}
+
 double
 lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, LsmSvgLengthDirection direction)
 {
@@ -660,7 +694,8 @@ paint (LsmSvgView *view, LsmSvgViewPathInfos *path_infos)
 	cairo = view->dom_view.cairo;
 	style = view->style;
 
-	if (style->opacity != NULL &&
+	if ((style->opacity != NULL ||
+	     style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER ) &&
 	    style->ignore_group_opacity &&
 	    g_strcmp0 (style->filter->value, "none") == 0) {
 		group_opacity = style->opacity->value;
@@ -671,15 +706,17 @@ paint (LsmSvgView *view, LsmSvgViewPathInfos *path_infos)
 			     style->stroke->paint.type == LSM_SVG_PAINT_TYPE_URI_RGB_COLOR ||
 			     style->fill->paint.type == LSM_SVG_PAINT_TYPE_URI_RGB_COLOR ||
 			     style->fill->paint.type == LSM_SVG_PAINT_TYPE_URI) &&
-			group_opacity < 1.0;
+			(group_opacity < 1.0 || style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER );
 	} else {
 		use_group = FALSE;
 		group_opacity = 1.0;
 	}
 
 	/* Instead of push_group, we should restrict to the current path bounding box */
-	if (use_group)
+	if (use_group) {
 		cairo_push_group (cairo);
+	} else if (style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER)
+		lsm_cairo_set_comp_op (cairo, style->comp_op->value);
 
 	if (_set_color (view,
 			path_infos,
@@ -762,8 +799,13 @@ paint (LsmSvgView *view, LsmSvgViewPathInfos *path_infos)
 
 	if (use_group) {
 		cairo_pop_group_to_source (cairo);
+		if (G_UNLIKELY (style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER))
+			lsm_cairo_set_comp_op (cairo, style->comp_op->value);
 		cairo_paint_with_alpha (cairo, group_opacity);
 	}
+
+	if (view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER)
+		lsm_cairo_set_comp_op (cairo, LSM_SVG_COMP_OP_SRC_OVER);
 }
 
 static void
@@ -2076,11 +2118,13 @@ lsm_svg_view_push_composition (LsmSvgView *view, LsmSvgStyle *style)
 	do_mask = (g_strcmp0 (style->mask->value, "none") != 0);
 	do_filter = (g_strcmp0 (style->filter->value, "none") != 0);
 
-	if ((view->style->opacity->value < 1.0 ||
-	     view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW) &&
-	    !do_filter &&
-	    !view->is_clipping &&
-	    !view->style->ignore_group_opacity) {
+	if (G_UNLIKELY((view->style->opacity->value < 1.0 ||
+			view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW ||
+			view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER) &&
+		       !do_filter &&
+		       !view->is_clipping &&
+		       !view->style->ignore_group_opacity &&
+		       view->dom_view.cairo != NULL)) {
 		LsmSvgViewBackground *background;
 
 		lsm_debug_render ("[LsmSvgView::push_composition] Push group");
@@ -2094,12 +2138,12 @@ lsm_svg_view_push_composition (LsmSvgView *view, LsmSvgStyle *style)
 		view->background_stack = g_list_prepend (view->background_stack, background);
 	}
 
-	if (do_clip) {
+	if (G_UNLIKELY (do_clip)) {
 		lsm_debug_render ("[LsmSvgView::push_style] Start clip '%s'", style->clip_path->value);
 		lsm_svg_view_push_clip (view);
 	}
 
-	if (do_mask) {
+	if (G_UNLIKELY (do_mask)) {
 		lsm_debug_render ("[LsmSvgView::push_style] Start mask '%s'", style->mask->value);
 		lsm_svg_view_push_mask (view);
 	}
@@ -2107,7 +2151,7 @@ lsm_svg_view_push_composition (LsmSvgView *view, LsmSvgStyle *style)
 	/* Don't do filtering during a clipping operation, as filter will
 	 * create a new subsurface, where clipping should occur with the path
 	 * of the clip-path element. */ 
-	if (do_filter && !view->is_clipping) {
+	if (G_UNLIKELY (do_filter && !view->is_clipping)) {
 		lsm_debug_render ("[LsmSvgView::push_style] Start filter '%s'", style->filter->value);
 		lsm_svg_view_push_filter (view);
 	}
@@ -2129,6 +2173,7 @@ void lsm_svg_view_pop_composition (LsmSvgView *view)
 	gboolean do_filter;
 	gboolean do_mask;
 	gboolean do_clip;
+	cairo_t *cairo;
 
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
 	g_return_if_fail (view->style != NULL);
@@ -2142,25 +2187,33 @@ void lsm_svg_view_pop_composition (LsmSvgView *view)
 	/* Don't do filtering during a clipping operation, as filter will
 	 * create a new subsurface, where clipping should occur with the path
 	 * of the clip-path element. */ 
-	if (do_filter && !view->is_clipping)
+	if (G_UNLIKELY (do_filter && !view->is_clipping))
 		lsm_svg_view_pop_filter (view);
 
-	if (do_mask)
+	if (G_UNLIKELY (do_mask))
 		lsm_svg_view_pop_mask (view);
 
-	if (do_clip)
+	if (G_UNLIKELY (do_clip))
 		lsm_svg_view_pop_clip (view);
 
-	if ((view->style->opacity->value < 1.0 ||
-	     view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW) &&
-	    !do_filter &&
-	    !view->is_clipping &&
-	    !view->style->ignore_group_opacity) {
+	cairo = view->dom_view.cairo;
+
+	if (G_UNLIKELY ((view->style->opacity->value < 1.0 ||
+			 view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW ||
+			 view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER) &&
+			!do_filter &&
+			!view->is_clipping &&
+			!view->style->ignore_group_opacity &&
+			cairo != NULL)) {
 		g_slice_free (LsmSvgViewBackground, view->background_stack->data);
 		view->background_stack = g_list_delete_link (view->background_stack, view->background_stack);
 
 		cairo_pop_group_to_source (view->dom_view.cairo);
-		cairo_paint_with_alpha (view->dom_view.cairo, view->style->opacity->value);
+		if (G_UNLIKELY (view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER))
+			lsm_cairo_set_comp_op (cairo, view->style->comp_op->value);
+		cairo_paint_with_alpha (cairo, view->style->opacity->value);
+		if (G_UNLIKELY (view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER))
+			lsm_cairo_set_comp_op (cairo, LSM_SVG_COMP_OP_SRC_OVER);
 		lsm_debug_render ("[LsmSvgView::pop_composition] Pop group");
 	}
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]