[lasem] [LsmSvgView] Avoid if mpossible push_group for opacity handling.



commit b5f08ae879db00815cbf27b750bd6d876e2622dd
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Mon Jun 22 23:15:20 2009 +0200

    [LsmSvgView] Avoid if mpossible push_group for opacity handling.
    
    Push group create a new big surface, which is not efficient when
    global opacity only applies to a graphical element.

 src/lsmsvgcircleelement.c   |    1 +
 src/lsmsvgellipseelement.c  |    1 +
 src/lsmsvggraphic.c         |    8 ++--
 src/lsmsvggraphic.h         |    2 +
 src/lsmsvglineelement.c     |    1 +
 src/lsmsvgpathelement.c     |    1 +
 src/lsmsvgpolygonelement.c  |    1 +
 src/lsmsvgpolylineelement.c |    1 +
 src/lsmsvgrectelement.c     |    1 +
 src/lsmsvgtextelement.c     |    1 +
 src/lsmsvgview.c            |   72 ++++++++++++++++++++++++++++++++++++++----
 src/lsmsvgview.h            |    5 ++-
 12 files changed, 82 insertions(+), 13 deletions(-)
---
diff --git a/src/lsmsvgcircleelement.c b/src/lsmsvgcircleelement.c
index 5371a7d..b0a333b 100644
--- a/src/lsmsvgcircleelement.c
+++ b/src/lsmsvgcircleelement.c
@@ -111,6 +111,7 @@ lsm_svg_circle_element_class_init (LsmSvgCircleElementClass *s_rect_class)
 	s_element_class->update = lsm_svg_circle_element_update;
 
 	s_graphic_class->graphic_render = lsm_svg_circle_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgellipseelement.c b/src/lsmsvgellipseelement.c
index 17f7783..e26fc78 100644
--- a/src/lsmsvgellipseelement.c
+++ b/src/lsmsvgellipseelement.c
@@ -112,6 +112,7 @@ lsm_svg_ellipse_element_class_init (LsmSvgEllipseElementClass *s_rect_class)
 	s_element_class->update = lsm_svg_ellipse_element_update;
 
 	s_graphic_class->graphic_render = lsm_svg_ellipse_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvggraphic.c b/src/lsmsvggraphic.c
index e381e37..d32abb8 100644
--- a/src/lsmsvggraphic.c
+++ b/src/lsmsvggraphic.c
@@ -159,8 +159,8 @@ lsm_svg_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 	if (graphic->transform != NULL)
 		lsm_svg_view_push_matrix (view, &graphic->transform->transform.matrix);
 
-	if (graphic->opacity.value < 1.0)
-		lsm_svg_view_push_group (view);
+	lsm_svg_view_push_opacity (view, graphic->opacity.value,
+				   LSM_SVG_GRAPHIC_GET_CLASS (graphic)->late_opacity_handling);
 
 	if (graphic->fill != NULL) {
 		lsm_svg_view_push_fill_attributes (view, graphic->fill);
@@ -190,8 +190,7 @@ lsm_svg_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 		lsm_svg_view_pop_fill_attributes (view);
 	}
 
-	if (graphic->opacity.value < 1.0)
-		lsm_svg_view_paint_group (view, graphic->opacity.value);
+	lsm_svg_view_pop_opacity (view);
 
 	if (graphic->transform != NULL)
 		lsm_svg_view_pop_matrix (view);
@@ -276,6 +275,7 @@ lsm_svg_graphic_class_init (LsmSvgGraphicClass *s_graphic_class)
 
 	s_graphic_class->graphic_render = _graphic_render;
 	s_graphic_class->graphic_get_extents = _graphic_get_extents;
+	s_graphic_class->late_opacity_handling = FALSE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvggraphic.h b/src/lsmsvggraphic.h
index 4c23a17..4127964 100644
--- a/src/lsmsvggraphic.h
+++ b/src/lsmsvggraphic.h
@@ -57,6 +57,8 @@ struct _LsmSvgGraphicClass {
 
 	void 		(*graphic_render)	(LsmSvgElement *element, LsmSvgView *view);
 	void 		(*graphic_get_extents)	(LsmSvgElement *element, LsmSvgView *view, LsmExtents *extents);
+
+	gboolean	late_opacity_handling;
 };
 
 GType lsm_svg_graphic_get_type (void);
diff --git a/src/lsmsvglineelement.c b/src/lsmsvglineelement.c
index a272bb3..3924c7d 100644
--- a/src/lsmsvglineelement.c
+++ b/src/lsmsvglineelement.c
@@ -107,6 +107,7 @@ lsm_svg_line_element_class_init (LsmSvgLineElementClass *s_rect_class)
 	s_element_class->update = lsm_svg_line_element_update;
 
 	s_graphic_class->graphic_render = lsm_svg_line_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgpathelement.c b/src/lsmsvgpathelement.c
index e7e55d1..408f8cb 100644
--- a/src/lsmsvgpathelement.c
+++ b/src/lsmsvgpathelement.c
@@ -82,6 +82,7 @@ lsm_svg_path_element_class_init (LsmSvgPathElementClass *s_rect_class)
 	d_node_class->get_node_name = lsm_svg_path_element_get_node_name;
 
 	s_graphic_class->graphic_render = lsm_svg_path_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgpolygonelement.c b/src/lsmsvgpolygonelement.c
index a560e6f..b30071c 100644
--- a/src/lsmsvgpolygonelement.c
+++ b/src/lsmsvgpolygonelement.c
@@ -71,6 +71,7 @@ lsm_svg_polygon_element_class_init (LsmSvgPolygonElementClass *s_rect_class)
 	d_node_class->get_node_name = lsm_svg_polygon_element_get_node_name;
 
 	s_graphic_class->graphic_render = lsm_svg_polygon_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgpolylineelement.c b/src/lsmsvgpolylineelement.c
index 0facb9a..37ff4f4 100644
--- a/src/lsmsvgpolylineelement.c
+++ b/src/lsmsvgpolylineelement.c
@@ -71,6 +71,7 @@ lsm_svg_polyline_element_class_init (LsmSvgPolylineElementClass *s_rect_class)
 	d_node_class->get_node_name = lsm_svg_polyline_element_get_node_name;
 
 	s_graphic_class->graphic_render = lsm_svg_polyline_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgrectelement.c b/src/lsmsvgrectelement.c
index b039e9c..4e1388b 100644
--- a/src/lsmsvgrectelement.c
+++ b/src/lsmsvgrectelement.c
@@ -152,6 +152,7 @@ lsm_svg_rect_element_class_init (LsmSvgRectElementClass *s_rect_class)
 
 	s_graphic_class->graphic_render = lsm_svg_rect_element_graphic_render;
 	s_graphic_class->graphic_get_extents = lsm_svg_rect_element_graphic_get_extents;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgtextelement.c b/src/lsmsvgtextelement.c
index f89c44e..845c552 100644
--- a/src/lsmsvgtextelement.c
+++ b/src/lsmsvgtextelement.c
@@ -124,6 +124,7 @@ lsm_svg_text_element_class_init (LsmSvgTextElementClass *s_rect_class)
 	s_element_class->update = lsm_svg_text_element_update;
 
 	s_graphic_class->graphic_render = lsm_svg_text_element_graphic_render;
+	s_graphic_class->late_opacity_handling = TRUE;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 826e0e7..03a6d66 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -36,6 +36,11 @@
 
 static GObjectClass *parent_class;
 
+typedef struct {
+	double opacity;
+	gboolean late_opacity_handling;
+} LsmSvgViewOpacityData;
+
 struct _LsmSvgViewPatternData {
 	cairo_t *old_cairo;
 
@@ -1074,6 +1079,8 @@ paint (LsmSvgView *view)
 	LsmSvgFillAttributeBag *fill;
 	LsmSvgStrokeAttributeBag *stroke;
 	cairo_t *cairo;
+	gboolean use_group;
+	double global_opacity;
 
 	g_return_if_fail (view->fill_stack != NULL);
 	g_return_if_fail (view->stroke_stack != NULL);
@@ -1082,15 +1089,37 @@ paint (LsmSvgView *view)
 	fill = view->fill_stack->data;
 	stroke = view->stroke_stack->data;
 
+	if (view->opacity_stack != NULL) {
+		LsmSvgViewOpacityData *opacity_data;
+
+		opacity_data = view->opacity_stack->data;
+		global_opacity = opacity_data->opacity;
+
+		use_group = fill->paint.paint.type != LSM_SVG_PAINT_TYPE_NONE &&
+			stroke->paint.paint.type != LSM_SVG_PAINT_TYPE_NONE &&
+			global_opacity < 1.0;
+
+		if (!opacity_data->late_opacity_handling)
+			g_warning ("[LsmSvgView::paint] Missing late_opacity_handling declaration in"
+				   " caller element");
+	} else {
+		use_group = FALSE;
+		global_opacity = 1.0;
+	}
+
+	/* FIXME Instead of push_group, restrict to the current path bounding box */
+	if (use_group)
+		cairo_push_group (cairo);
+
 	if (_set_color (view, LSM_SVG_VIEW_PAINT_OPERATION_FILL,
-			&fill->paint.paint, fill->opacity.value)) {
+			&fill->paint.paint, fill->opacity.value * global_opacity)) {
 		cairo_set_fill_rule (cairo, fill->rule.value == LSM_SVG_FILL_RULE_EVEN_ODD ?
 				     CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
 		cairo_fill_preserve (cairo);
 	}
 
 	if (_set_color (view, LSM_SVG_VIEW_PAINT_OPERATION_STROKE,
-			&stroke->paint.paint, stroke->opacity.value)) {
+			&stroke->paint.paint, stroke->opacity.value * global_opacity)) {
 		double line_width;
 
 		switch (stroke->line_join.value) {
@@ -1148,6 +1177,11 @@ paint (LsmSvgView *view)
 	}
 
 	cairo_new_path (cairo);
+
+	if (use_group) {
+		cairo_pop_group_to_source (cairo);
+		cairo_paint_with_alpha (cairo, global_opacity);
+	}
 }
 
 static void
@@ -1362,20 +1396,38 @@ lsm_svg_view_show_pixbuf (LsmSvgView *view, GdkPixbuf *pixbuf)
 }
 
 void
-lsm_svg_view_push_group (LsmSvgView *view)
+lsm_svg_view_push_opacity (LsmSvgView *view, double opacity, gboolean late_opacity_handling)
 {
+	LsmSvgViewOpacityData *opacity_data;
+
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
 
-	cairo_push_group (view->dom_view.cairo);
+	opacity_data = g_new (LsmSvgViewOpacityData, 1);
+	opacity_data->opacity = opacity;
+	opacity_data->late_opacity_handling = late_opacity_handling;
+
+	if (opacity < 1.0 && !late_opacity_handling)
+		cairo_push_group (view->dom_view.cairo);
+
+	view->opacity_stack = g_slist_prepend (view->opacity_stack, opacity_data);
 }
 
 void
-lsm_svg_view_paint_group (LsmSvgView *view, double opacity)
+lsm_svg_view_pop_opacity (LsmSvgView *view)
 {
+	LsmSvgViewOpacityData *opacity_data;
+
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->opacity_stack != NULL);
 
-	cairo_pop_group_to_source (view->dom_view.cairo);
-	cairo_paint_with_alpha (view->dom_view.cairo, opacity);
+	opacity_data = view->opacity_stack->data;
+
+	if (opacity_data->opacity < 1.0 && !opacity_data->late_opacity_handling) {
+		cairo_pop_group_to_source (view->dom_view.cairo);
+		cairo_paint_with_alpha (view->dom_view.cairo, opacity_data->opacity);
+	}
+
+	view->opacity_stack = g_slist_delete_link (view->opacity_stack, view->opacity_stack);
 }
 
 static void
@@ -1409,6 +1461,7 @@ lsm_svg_view_render (LsmDomView *view)
 	svg_view->viewbox_stack = NULL;
 	svg_view->fill_stack = NULL;
 	svg_view->stroke_stack = NULL;
+	svg_view->opacity_stack = NULL;
 	svg_view->text_stack = NULL;
 	svg_view->matrix_stack = NULL;
 
@@ -1431,6 +1484,11 @@ lsm_svg_view_render (LsmDomView *view)
 		g_slist_free (svg_view->viewbox_stack);
 		svg_view->viewbox_stack = NULL;
 	}
+	if (svg_view->opacity_stack != NULL) {
+		g_warning ("[LsmSvgView::render] Dangling opacity data in stack");
+		g_slist_free (svg_view->opacity_stack);
+		svg_view->opacity_stack = NULL;
+	}
 	if (svg_view->fill_stack != NULL) {
 		g_warning ("[LsmSvgView::render] Dangling fill attribute in stack");
 		g_slist_free (svg_view->fill_stack);
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 0bff515..72a0b3a 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -49,6 +49,7 @@ struct _LsmSvgView {
 	GSList *viewbox_stack;
 	GSList *fill_stack;
 	GSList *stroke_stack;
+	GSList *opacity_stack;
 	GSList *text_stack;
 	GSList *matrix_stack;
 
@@ -120,8 +121,8 @@ void 		lsm_svg_view_show_polygon	(LsmSvgView *view, const char *points);
 void 		lsm_svg_view_show_text 		(LsmSvgView *view, char const *text, double x, double y);
 void		lsm_svg_view_show_pixbuf	(LsmSvgView *view, GdkPixbuf *pixbuf);
 
-void 		lsm_svg_view_push_group 	(LsmSvgView *view);
-void 		lsm_svg_view_paint_group 	(LsmSvgView *view, double opacity);
+void 		lsm_svg_view_push_opacity 	(LsmSvgView *view, double opacity, gboolean late_opacity_handling);
+void 		lsm_svg_view_pop_opacity 	(LsmSvgView *view);
 
 G_END_DECLS
 



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