[dia] svg: improve matrix parsing and handling
- From: Hans Breuer <hans src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dia] svg: improve matrix parsing and handling
- Date: Fri, 16 Aug 2013 17:08:55 +0000 (UTC)
commit 6c7fd57ea22b41fd7e17321a85e7b4772f1fed56
Author: Hans Breuer <hans breuer org>
Date: Sat Aug 10 23:14:32 2013 +0200
svg: improve matrix parsing and handling
- basic support for makes the W3C test suite work better
- don't let a non-invertible matrix screw cairo context,
but just don't render with it as SVG expects it to be
animate-elem-34-t
invalid matrix - by sequence of transforms: fixed.
coords-trans-08-t
skewX skewY wrong transformation: fixed
coords-trans-09-t
invalid matrix - by intent: matrix(0 0 0 0 0 0)
stop cairo renderer complaints by not drawing
lib/dia_svg.c | 70 +++++++++++++++++++++++++++--------
lib/geometry.c | 13 +++++++
lib/geometry.h | 1 +
lib/libdia.def | 1 +
plug-ins/cairo/diacairo-renderer.c | 3 ++
5 files changed, 72 insertions(+), 16 deletions(-)
---
diff --git a/lib/dia_svg.c b/lib/dia_svg.c
index a60ffc3..6c84ae4 100644
--- a/lib/dia_svg.c
+++ b/lib/dia_svg.c
@@ -1365,18 +1365,20 @@ MORETOPARSE:
return (points->len > 1);
}
-DiaMatrix *
-dia_svg_parse_transform(const gchar *trans, real scale)
+static gboolean
+_parse_transform (const gchar *trans, DiaMatrix *m, real scale)
{
- DiaMatrix *m;
- gchar *p = strchr (trans, '(');
gchar **list;
+ gchar *p = strchr (trans, '(');
int i = 0;
- if (!p)
- return NULL; /* silently ignore broken format */
+ while ( (*trans != '\0')
+ && (*trans == ' ' || *trans == ',' || *trans == '\t' || *trans == '\n' || *trans == '\r'))
+ ++trans; /* skip whitespace */
+
+ if (!p || !*trans)
+ return FALSE; /* silently fail */
- m = g_new0 (DiaMatrix, 1);
list = g_regex_split_simple ("[\\s,]+", p+1, 0, 0);
if (strncmp (trans, "matrix", 6) == 0) {
if (list[i])
@@ -1405,6 +1407,7 @@ dia_svg_parse_transform(const gchar *trans, real scale)
else
m->yy = m->xx;
} else if (strncmp (trans, "rotate", 6) == 0) {
+ DiaMatrix translate = {1, 0, 0, 1, 0, 0 };
real angle;
if (list[i])
@@ -1419,28 +1422,63 @@ dia_svg_parse_transform(const gchar *trans, real scale)
m->yx = sin(G_PI*angle/180);
m->yy = cos(G_PI*angle/180);
/* FIXME: check with real world data, I'm uncertain */
- if (list[i])
- m->x0 = g_ascii_strtod (list[i], NULL), ++i;
- if (list[i])
- m->y0 = g_ascii_strtod (list[i], NULL), ++i;
+ if (list[i]) {
+ real cx, cy;
+ cx = g_ascii_strtod (list[i], NULL), ++i;
+ if (list[i])
+ cy = g_ascii_strtod (list[i], NULL), ++i;
+ /* rotate around the given offset */
+ translate.x0 = cx;
+ translate.y0 = cy;
+ dia_matrix_multiply (m, m, &translate);
+ translate.x0 = -cx;
+ translate.y0 = -cy;
+ dia_matrix_multiply (m, &translate, m);
+ }
} else if (strncmp (trans, "skewX", 5) == 0) {
m->xx = m->yy = 1.0;
if (list[i])
- m->yx = tan (G_PI*g_ascii_strtod (list[i], NULL)/180);
+ m->xy = tan (G_PI*g_ascii_strtod (list[i], NULL)/180);
} else if (strncmp (trans, "skewY", 5) == 0) {
m->xx = m->yy = 1.0;
if (list[i])
- m->xy = tan (G_PI*g_ascii_strtod (list[i], NULL)/180);
+ m->yx = tan (G_PI*g_ascii_strtod (list[i], NULL)/180);
} else {
g_warning ("SVG: %s?", trans);
- g_free (m);
- m = NULL;
+ return FALSE;
}
+ g_strfreev(list);
+
if (scale > 0 && m) {
m->x0 /= scale;
m->y0 /= scale;
}
- g_strfreev(list);
+ return TRUE;
+}
+
+DiaMatrix *
+dia_svg_parse_transform(const gchar *trans, real scale)
+{
+ DiaMatrix *m = NULL;
+ gchar **transforms = g_regex_split_simple ("\\)", trans, 0, 0);
+ int i = 0;
+
+ /* go through the list of ztansformations - not that one would be enough ;) */
+ while (transforms[i]) {
+ DiaMatrix mat = { 0, };
+
+ if (_parse_transform (transforms[i], &mat, scale)) {
+ if (!m) {
+ m = g_new (DiaMatrix, 1);
+ *m = mat;
+ } else {
+ dia_matrix_multiply (m, &mat, m);
+ }
+ }
+ ++i;
+ }
+ g_strfreev(transforms);
+
return m;
}
diff --git a/lib/geometry.c b/lib/geometry.c
index 662d562..dede3e9 100644
--- a/lib/geometry.c
+++ b/lib/geometry.c
@@ -792,3 +792,16 @@ dia_matrix_set_angle_and_scales (DiaMatrix *m,
cairo_matrix_init_rotate ((cairo_matrix_t *)m, a);
cairo_matrix_scale ((cairo_matrix_t *)m, sx, sy);
}
+
+gboolean
+dia_matrix_is_invertible (const DiaMatrix *matrix)
+{
+ double a, b, c, d;
+ double det;
+
+ a = matrix->xx; b = matrix->yx;
+ c = matrix->xy; d = matrix->yy;
+ det = a*d - b*c;
+
+ return finite(det) && det != 0.0;
+}
\ No newline at end of file
diff --git a/lib/geometry.h b/lib/geometry.h
index 494b671..69a120b 100644
--- a/lib/geometry.h
+++ b/lib/geometry.h
@@ -136,6 +136,7 @@ void dia_matrix_set_angle_and_scales (DiaMatrix *m,
real sx,
real sy);
void dia_matrix_multiply (DiaMatrix *result, const DiaMatrix *a, const DiaMatrix *b);
+gboolean dia_matrix_is_invertible (const DiaMatrix *matrix);
#define ROUND(x) ((int) floor((x)+0.5))
diff --git a/lib/libdia.def b/lib/libdia.def
index 1d2f9fc..4242a39 100644
--- a/lib/libdia.def
+++ b/lib/libdia.def
@@ -371,6 +371,7 @@ EXPORTS
dia_svg_parse_path
dia_svg_parse_transform
dia_svg_from_matrix
+ dia_matrix_is_invertible
dia_svg_renderer_get_type
diff --git a/plug-ins/cairo/diacairo-renderer.c b/plug-ins/cairo/diacairo-renderer.c
index 08863f8..dd295f6 100644
--- a/plug-ins/cairo/diacairo-renderer.c
+++ b/plug-ins/cairo/diacairo-renderer.c
@@ -223,6 +223,9 @@ draw_object (DiaRenderer *self, DiaObject *object, DiaMatrix *matrix)
cairo_matrix_t before;
if (matrix) {
+ /* at least in SVG the intent of an invalid matrix is not rendering */
+ if (!dia_matrix_is_invertible(matrix))
+ return;
cairo_get_matrix (renderer->cr, &before);
g_assert (sizeof(cairo_matrix_t) == sizeof(DiaMatrix));
cairo_transform (renderer->cr, (cairo_matrix_t *)matrix);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]