[lasem] [SVG] Start of clipping support.



commit 93cefce0ef62c2308d66e93e3156258e945a39c8
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Fri May 22 23:02:11 2009 +0200

    [SVG] Start of clipping support.
---
 src/lsmsvgattributebags.c   |   14 ++++-
 src/lsmsvgattributebags.h   |    2 +
 src/lsmsvgclippathelement.c |    5 +-
 src/lsmsvgdocument.c        |    2 +-
 src/lsmsvgelement.c         |   17 ++++++
 src/lsmsvgelement.h         |    2 +
 src/lsmsvggraphic.c         |   25 +++++++--
 src/lsmsvgpatternelement.c  |    4 +-
 src/lsmsvgstyle.h           |    4 ++
 src/lsmsvguseelement.c      |    4 +-
 src/lsmsvgview.c            |  115 ++++++++++++++++++++++++++++++++++++++-----
 src/lsmsvgview.h            |   10 +++-
 12 files changed, 173 insertions(+), 31 deletions(-)

diff --git a/src/lsmsvgattributebags.c b/src/lsmsvgattributebags.c
index e1f2d15..b34d68e 100644
--- a/src/lsmsvgattributebags.c
+++ b/src/lsmsvgattributebags.c
@@ -61,6 +61,14 @@ lsm_dom_attribute_map_add_fill_attribute_bag (LsmDomAttributeMap *map, ptrdiff_t
 						 offsetof (LsmSvgFillAttributeBag, opacity),
 						 NULL,
 						 bag_offset, &lsm_svg_fill_attribute_bag_class);
+	lsm_dom_attribute_map_add_bag_attribute (map, "clip-path",
+						 offsetof (LsmSvgFillAttributeBag, clip_path),
+						 NULL,
+						 bag_offset, &lsm_svg_fill_attribute_bag_class);
+	lsm_dom_attribute_map_add_bag_attribute (map, "clip-rule",
+						 offsetof (LsmSvgFillAttributeBag, clip_rule),
+						 NULL,
+						 bag_offset, &lsm_svg_fill_attribute_bag_class);
 }
 
 static void *
@@ -150,9 +158,9 @@ void
 lsm_dom_attribute_map_add_transform_attribute_bag (LsmDomAttributeMap *map, ptrdiff_t bag_offset)
 {
 	lsm_dom_attribute_map_add_bag_attribute (map, "transform",
-					      offsetof (LsmSvgTransformAttributeBag, transform),
-					      NULL,
-					      bag_offset, &lsm_svg_transform_attribute_bag_class);
+						 offsetof (LsmSvgTransformAttributeBag, transform),
+						 NULL,
+						 bag_offset, &lsm_svg_transform_attribute_bag_class);
 }
 
 static void *
diff --git a/src/lsmsvgattributebags.h b/src/lsmsvgattributebags.h
index 9fe4ab7..d7dfdd7 100644
--- a/src/lsmsvgattributebags.h
+++ b/src/lsmsvgattributebags.h
@@ -31,6 +31,8 @@ typedef struct {
 	LsmSvgPaintAttribute paint;
 	LsmDomEnumAttribute rule;
 	LsmDomDoubleAttribute opacity;
+	LsmDomAttribute clip_path;
+	LsmDomEnumAttribute clip_rule;
 } LsmSvgFillAttributeBag;
 
 typedef struct {
diff --git a/src/lsmsvgclippathelement.c b/src/lsmsvgclippathelement.c
index 23d0332..eaaff3c 100644
--- a/src/lsmsvgclippathelement.c
+++ b/src/lsmsvgclippathelement.c
@@ -31,7 +31,7 @@ static GObjectClass *parent_class;
 static const char *
 _clip_path_element_get_node_name (LsmDomNode *node)
 {
-	return "clip-path";
+	return "clipPath";
 }
 
 /* LsmSvgElement implementation */
@@ -48,8 +48,6 @@ _clip_path_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
 
-/* LsmSvgClipPathElement implementation */
-
 LsmDomNode *
 lsm_svg_clip_path_element_new (void)
 {
@@ -83,6 +81,7 @@ lsm_svg_clip_path_element_class_init (LsmSvgClipPathElementClass *klass)
 	d_node_class->get_node_name = _clip_path_element_get_node_name;
 
 	s_element_class->update = _clip_path_element_update;
+	s_element_class->render_clip = s_element_class->render;
 	s_element_class->render = NULL;
 
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
diff --git a/src/lsmsvgdocument.c b/src/lsmsvgdocument.c
index cc7f744..941b389 100644
--- a/src/lsmsvgdocument.c
+++ b/src/lsmsvgdocument.c
@@ -94,7 +94,7 @@ lsm_svg_document_create_element (LsmDomDocument *document, const char *tag_name)
 		node = lsm_svg_defs_element_new ();
 	else if (strcmp (tag_name, "symbol") == 0)
 		node = lsm_svg_symbol_element_new ();
-	else if (strcmp (tag_name, "clip-path") == 0)
+	else if (strcmp (tag_name, "clipPath") == 0)
 		node = lsm_svg_clip_path_element_new ();
 
 	if (node != NULL)
diff --git a/src/lsmsvgelement.c b/src/lsmsvgelement.c
index 9bd5e9a..c36e218 100644
--- a/src/lsmsvgelement.c
+++ b/src/lsmsvgelement.c
@@ -165,6 +165,23 @@ lsm_svg_element_render_paint (LsmSvgElement *element, LsmSvgView *view)
 	}
 }
 
+void
+lsm_svg_element_render_clip (LsmSvgElement *element, LsmSvgView *view)
+{
+	LsmSvgElementClass *element_class;
+
+	g_return_if_fail (LSM_IS_SVG_ELEMENT (element));
+
+	element_class = LSM_SVG_ELEMENT_GET_CLASS (element);
+	if (element_class->render_clip != NULL) {
+		lsm_debug ("[LsmSvgElement::render_clip] Render %s (%s)",
+			    lsm_dom_node_get_node_name (LSM_DOM_NODE (element)),
+			    element->id.value != NULL ? element->id.value : "no id");
+
+		element_class->render_clip (element, view);
+	}
+}
+
 static void
 lsm_svg_element_init (LsmSvgElement *element)
 {
diff --git a/src/lsmsvgelement.h b/src/lsmsvgelement.h
index a77627b..442d555 100644
--- a/src/lsmsvgelement.h
+++ b/src/lsmsvgelement.h
@@ -60,6 +60,7 @@ struct _LsmSvgElementClass {
 	void			(*update)		(LsmSvgElement *element, LsmSvgStyle *style);
 	void 			(*render)		(LsmSvgElement *element, LsmSvgView *view);
 	void 			(*render_paint)		(LsmSvgElement *element, LsmSvgView *view);
+	void 			(*render_clip)		(LsmSvgElement *element, LsmSvgView *view);
 };
 
 GType lsm_svg_element_get_type (void);
@@ -67,6 +68,7 @@ GType lsm_svg_element_get_type (void);
 void			lsm_svg_element_update 		(LsmSvgElement *element, const LsmSvgStyle *style);
 void 			lsm_svg_element_render 		(LsmSvgElement *element, LsmSvgView *view);
 void 			lsm_svg_element_render_paint 	(LsmSvgElement *element, LsmSvgView *view);
+void 			lsm_svg_element_render_clip 	(LsmSvgElement *element, LsmSvgView *view);
 
 G_END_DECLS
 
diff --git a/src/lsmsvggraphic.c b/src/lsmsvggraphic.c
index 5c99424..af55c92 100644
--- a/src/lsmsvggraphic.c
+++ b/src/lsmsvggraphic.c
@@ -107,6 +107,7 @@ lsm_svg_graphic_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 					       &graphic->color.value);
 		lsm_svg_fill_rule_attribute_parse (&graphic->fill->rule, &parent_style->fill.rule);
 		lsm_dom_double_attribute_parse (&graphic->fill->opacity, &parent_style->fill.opacity);
+		lsm_svg_fill_rule_attribute_parse (&graphic->fill->clip_rule, &parent_style->clip.rule);
 	}
 
 	if (graphic->stroke != NULL) {
@@ -124,6 +125,8 @@ lsm_svg_graphic_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	}
 
 	if (graphic->transform != NULL) {
+		lsm_debug ("[LsmSvgGraphic::update] transform");
+
 		lsm_svg_transform_attribute_parse (&graphic->transform->transform);
 	}
 
@@ -153,31 +156,41 @@ lsm_svg_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgGraphic *graphic = LSM_SVG_GRAPHIC (self);
 
+	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);
 
-	if (graphic->fill != NULL)
+	if (graphic->fill != NULL) {
 		lsm_svg_view_push_fill_attributes (view, graphic->fill);
+
+		if (graphic->fill->clip_path.value != NULL)
+			lsm_svg_view_push_clip (view, graphic->fill->clip_path.value,
+						graphic->fill->clip_rule.value);
+	}
 	if (graphic->stroke != NULL)
 		lsm_svg_view_push_stroke_attributes (view, graphic->stroke);
 	if (graphic->text != NULL)
 		lsm_svg_view_push_text_attributes (view, graphic->text);
-	if (graphic->transform != NULL)
-		lsm_svg_view_push_transform (view, &graphic->transform->transform.matrix);
 
 	LSM_SVG_GRAPHIC_GET_CLASS (graphic)->graphic_render (self, view);
 
-	if (graphic->transform != NULL)
-		lsm_svg_view_pop_transform (view);
 	if (graphic->text != NULL)
 		lsm_svg_view_pop_text_attributes (view);
 	if (graphic->stroke != NULL)
 		lsm_svg_view_pop_stroke_attributes (view);
-	if (graphic->fill != NULL)
+	if (graphic->fill != NULL) {
+		if (graphic->fill->clip_path.value != NULL)
+			lsm_svg_view_pop_clip (view);
 		lsm_svg_view_pop_fill_attributes (view);
+	}
 
 	if (graphic->opacity.value < 1.0)
 		lsm_svg_view_paint_group (view, graphic->opacity.value);
+
+	if (graphic->transform != NULL)
+		lsm_svg_view_pop_matrix (view);
 }
 
 /* LsmSvgGraphic implementation */
diff --git a/src/lsmsvgpatternelement.c b/src/lsmsvgpatternelement.c
index 5673f10..99590a2 100644
--- a/src/lsmsvgpatternelement.c
+++ b/src/lsmsvgpatternelement.c
@@ -121,7 +121,7 @@ _pattern_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 		extents = lsm_svg_view_get_extents (view);
 		lsm_svg_matrix_init_scale (&matrix, extents.width, extents.height);
 		lsm_svg_view_push_viewbox (view, &extents);
-		lsm_svg_view_push_transform (view, &matrix);
+		lsm_svg_view_push_matrix (view, &matrix);
 	}
 
 	is_viewbox_defined = lsm_dom_attribute_is_defined ((LsmDomAttribute *) &pattern->viewbox);
@@ -138,7 +138,7 @@ _pattern_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 	}
 
 	if (is_object_bounding_box) {
-		lsm_svg_view_pop_transform (view);
+		lsm_svg_view_pop_matrix (view);
 		lsm_svg_view_pop_viewbox (view);
 	}
 }
diff --git a/src/lsmsvgstyle.h b/src/lsmsvgstyle.h
index 20d6ac3..ccd0c37 100644
--- a/src/lsmsvgstyle.h
+++ b/src/lsmsvgstyle.h
@@ -49,6 +49,10 @@ struct _LsmSvgStyle {
 	} stroke;
 
 	struct {
+		LsmSvgFillRule rule;
+	} clip;
+
+	struct {
 		char *font_family;
 		LsmSvgLength font_size;
 	} text;
diff --git a/src/lsmsvguseelement.c b/src/lsmsvguseelement.c
index 51775ac..819ecea 100644
--- a/src/lsmsvguseelement.c
+++ b/src/lsmsvguseelement.c
@@ -117,11 +117,11 @@ lsm_svg_use_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 					   LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 
 	lsm_svg_matrix_init_translate (&matrix, x, y);
-	lsm_svg_view_push_transform (view, &matrix);
+	lsm_svg_view_push_matrix (view, &matrix);
 
 	lsm_svg_element_render (LSM_SVG_ELEMENT (element), view);
 
-	lsm_svg_view_pop_transform (view);
+	lsm_svg_view_pop_matrix (view);
 }
 
 /* LsmSvgUseElement implementation */
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 764a3f5..af40278 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -26,6 +26,7 @@
 #include <lsmsvgsvgelement.h>
 #include <lsmsvggradientelement.h>
 #include <lsmsvgpatternelement.h>
+#include <lsmsvgclippathelement.h>
 #include <lsmsvgutils.h>
 #include <gdk/gdk.h>
 #include <glib/gprintf.h>
@@ -791,25 +792,90 @@ lsm_svg_view_pop_viewport (LsmSvgView *view)
 }
 
 void
-lsm_svg_view_push_transform (LsmSvgView *view, const LsmSvgMatrix *matrix)
+lsm_svg_view_push_matrix (LsmSvgView *view, LsmSvgMatrix *matrix)
 {
 	cairo_matrix_t cr_matrix;
+	cairo_matrix_t *ctm;
 
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
 
+	ctm = g_new (cairo_matrix_t, 1);
+	cairo_get_matrix (view->dom_view.cairo, ctm);
+
+	view->matrix_stack = g_slist_prepend (view->matrix_stack, ctm);
+
 	cairo_matrix_init (&cr_matrix, matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
-	cairo_save (view->dom_view.cairo);
 	cairo_transform (view->dom_view.cairo, &cr_matrix);
 }
 
 void
-lsm_svg_view_pop_transform (LsmSvgView *view)
+lsm_svg_view_pop_matrix (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+	if (view->matrix_stack != NULL) {
+		cairo_matrix_t *ctm;
+
+		ctm = view->matrix_stack->data;
+
+		cairo_set_matrix (view->dom_view.cairo, ctm);
+
+		g_free (ctm);
+		view->matrix_stack = g_slist_delete_link (view->matrix_stack, view->matrix_stack);
+	}
+}
+
+void
+lsm_svg_view_push_clip (LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_rule)
 {
+	LsmDomElement *element;
+	char *uri;
+
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (!view->is_clipping);
+
+	uri = clip_path;
+
+	lsm_debug ("[LsmSvgView::push_clip] Using '%s'", clip_path);
+
+	cairo_save (view->dom_view.cairo);
+
+	if (strncmp (uri, "url(#", 5) ==0) {
+		char *end;
+
+		uri = g_strdup (uri + 5);
+		for (end = uri; *end != '\0' && *end != ')'; end++);
+		*end = '\0';
+
+		element = lsm_dom_document_get_element_by_id (view->dom_view.document, uri);
+
+		g_free (uri);
+
+		if (element != NULL && !LSM_IS_SVG_CLIP_PATH_ELEMENT (element)) {
+			view->is_clipping = TRUE;
+			lsm_svg_element_render_clip (LSM_SVG_ELEMENT (element), view);
+			cairo_clip (view->dom_view.cairo);
+			view->is_clipping = FALSE;
+		}
+	}
+}
+
+void
+lsm_svg_view_pop_clip (LsmSvgView *view)
+{
+	lsm_debug ("[LsmSvgView::pop_clip");
 
 	cairo_restore (view->dom_view.cairo);
 }
 
+gboolean
+lsm_svg_view_is_clipping (LsmSvgView *view)
+{
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), FALSE);
+
+	return view->is_clipping;
+}
+
 void
 lsm_svg_view_push_fill_attributes (LsmSvgView *view, LsmSvgFillAttributeBag *fill)
 {
@@ -965,7 +1031,7 @@ _set_color (LsmSvgView *view, LsmSvgViewPaintOperation operation,
 }
 
 static void
-_paint (LsmSvgView *view)
+paint (LsmSvgView *view)
 {
 	LsmSvgFillAttributeBag *fill;
 	LsmSvgStrokeAttributeBag *stroke;
@@ -1046,6 +1112,20 @@ _paint (LsmSvgView *view)
 	cairo_new_path (cairo);
 }
 
+static void
+process_path (LsmSvgView *view)
+{
+	if (view->is_clipping) {
+		LsmSvgFillAttributeBag *fill;
+
+		fill = view->fill_stack->data;
+		cairo_set_fill_rule (view->dom_view.cairo, fill->clip_rule.value);
+		g_message ("Clip (rule = %s)", lsm_svg_fill_rule_to_string (fill->clip_rule.value));
+/*                cairo_clip (view->dom_view.cairo);*/
+	} else
+		paint (view);
+}
+
 /*
  * Code for show_rectangle and show ellipse is inspired from
  * the librsvg library (rsvg-shapes.c)
@@ -1091,7 +1171,7 @@ lsm_svg_view_show_rectangle (LsmSvgView *view,
 		cairo_close_path (cairo);
 	}
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1101,7 +1181,7 @@ lsm_svg_view_show_circle (LsmSvgView *view, double cx, double cy, double r)
 
 	cairo_arc (view->dom_view.cairo, cx, cy, r, 0, 2 * M_PI);
 
-	_paint (view);
+	process_path (view);
 }
 
 #define LSM_SVG_ARC_MAGIC ((double) 0.5522847498) /* 4/3 * (1-cos 45)/sin 45 = 4/3 * sqrt(2) - 1 */
@@ -1125,7 +1205,7 @@ lsm_svg_view_show_ellipse (LsmSvgView *view, double cx, double cy, double rx, do
 	cairo_curve_to (cairo, cx + LSM_SVG_ARC_MAGIC * rx, cy + ry, cx + rx, cy + LSM_SVG_ARC_MAGIC * ry, cx + rx, cy);
 	cairo_close_path (cairo);
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1136,7 +1216,7 @@ lsm_svg_view_show_path (LsmSvgView *view,
 
 	_emit_svg_path (view->dom_view.cairo, d);
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1147,7 +1227,7 @@ lsm_svg_view_show_line (LsmSvgView *view, double x1, double y1, double x2, doubl
 	cairo_move_to (view->dom_view.cairo, x1, y1);
 	cairo_line_to (view->dom_view.cairo, x2, y2);
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1166,7 +1246,7 @@ lsm_svg_view_show_polyline (LsmSvgView *view, const char *points)
 			cairo_line_to (view->dom_view.cairo, values[0], values[1]);
 	}
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1187,7 +1267,7 @@ lsm_svg_view_show_polygon (LsmSvgView *view, const char *points)
 
 	cairo_close_path (view->dom_view.cairo);
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1231,7 +1311,7 @@ lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y
 
 	pango_cairo_layout_path (view->dom_view.cairo, pango_layout);
 
-	_paint (view);
+	process_path (view);
 }
 
 void
@@ -1293,11 +1373,22 @@ lsm_svg_view_render (LsmDomView *view)
 	svg_view->fill_stack = NULL;
 	svg_view->stroke_stack = NULL;
 	svg_view->text_stack = NULL;
+	svg_view->matrix_stack = NULL;
+
+	svg_view->is_clipping = FALSE;
 
 	svg_view->resolution_ppi = lsm_dom_document_get_resolution (view->document);
 
 	lsm_svg_svg_element_render  (svg_element, svg_view);
 
+	if (svg_view->is_clipping)
+		g_warning ("[LsmSvgView::render] Unfinished clipping");
+
+	if (svg_view->matrix_stack != NULL) {
+		g_warning ("[LsmSvgView::render] Dangling matrix in stack");
+		g_slist_free (svg_view->matrix_stack);
+		svg_view->matrix_stack = NULL;
+	}
 	if (svg_view->viewbox_stack != NULL) {
 		g_warning ("[LsmSvgView::render] Dangling viewport in stack");
 		g_slist_free (svg_view->viewbox_stack);
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 68c7b52..920f884 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -50,10 +50,13 @@ struct _LsmSvgView {
 	GSList *fill_stack;
 	GSList *stroke_stack;
 	GSList *text_stack;
+	GSList *matrix_stack;
 
 	LsmSvgViewPatternData *pattern_data;
 
 	GSList *pattern_stack;
+
+	gboolean is_clipping;
 };
 
 struct _LsmSvgViewClass {
@@ -90,8 +93,11 @@ void 		lsm_svg_view_push_viewport 		(LsmSvgView *view, const LsmBox *viewport,
 							 const LsmBox *viewbox,
 							 const LsmSvgPreserveAspectRatio *aspect_ratio);
 void 		lsm_svg_view_pop_viewport 		(LsmSvgView *view);
-void		lsm_svg_view_push_transform 		(LsmSvgView *view, const LsmSvgMatrix *matrix);
-void		lsm_svg_view_pop_transform		(LsmSvgView *view);
+void 		lsm_svg_view_push_matrix		(LsmSvgView *view, LsmSvgMatrix *matrix);
+void 		lsm_svg_view_pop_matrix			(LsmSvgView *view);
+void 		lsm_svg_view_push_clip 			(LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_rule);
+void 		lsm_svg_view_pop_clip 			(LsmSvgView *view);
+gboolean 	lsm_svg_view_is_clipping 		(LsmSvgView *view);
 void 		lsm_svg_view_push_fill_attributes 	(LsmSvgView *view, LsmSvgFillAttributeBag *fill);
 void 		lsm_svg_view_pop_fill_attributes 	(LsmSvgView *view);
 void 		lsm_svg_view_push_stroke_attributes 	(LsmSvgView *view, LsmSvgStrokeAttributeBag *stroke);



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