[lasem] [SVG] Start of clipping support.
- From: Emmanuel Pacaud <emmanuel src gnome org>
- To: svn-commits-list gnome org
- Subject: [lasem] [SVG] Start of clipping support.
- Date: Fri, 22 May 2009 17:02:35 -0400 (EDT)
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]