[dia] introduce graphene



commit 2bbd4fe78a20dab56295abe65cbdfab63b688e97
Author: Zander Brown <zbrown gnome org>
Date:   Sun May 3 12:36:34 2020 +0100

    introduce graphene
    
    Add a dependency on graphene, eventually this will replace our geometry functions
    
    Replace usage of DiaMatrix in DiaSvg with graphene_matrix_t

 lib/dia-graphene.h        |   52 +++
 lib/dia_svg.c             |  399 ++++++++++-------
 lib/dia_svg.h             |   53 ++-
 lib/geometry.h            |    3 +
 lib/meson.build           |    2 +
 meson.build               |    1 +
 plug-ins/svg/render_svg.c |   23 +-
 plug-ins/svg/svg-import.c | 1092 +++++++++++++++++++++++++--------------------
 8 files changed, 958 insertions(+), 667 deletions(-)
---
diff --git a/lib/dia-graphene.h b/lib/dia-graphene.h
new file mode 100644
index 00000000..af2fd0a9
--- /dev/null
+++ b/lib/dia-graphene.h
@@ -0,0 +1,52 @@
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright © 2020 Zander Brown <zbrown gnome org>
+ */
+
+#pragma once
+
+#include <graphene.h>
+
+#include "geometry.h"
+
+static inline void
+dia_matrix_from_graphene (DiaMatrix         *matrix,
+                          graphene_matrix_t *graphene)
+{
+  matrix->xx = graphene_matrix_get_value (graphene, 0, 0);
+  matrix->yx = graphene_matrix_get_value (graphene, 0, 1);
+  matrix->xy = graphene_matrix_get_value (graphene, 1, 0);
+  matrix->yy = graphene_matrix_get_value (graphene, 1, 1);
+  matrix->x0 = graphene_matrix_get_x_translation (graphene);
+  matrix->y0 = graphene_matrix_get_y_translation (graphene);
+}
+
+static inline void
+dia_graphene_from_matrix (graphene_matrix_t *graphene,
+                          const DiaMatrix   *matrix)
+{
+  graphene_matrix_init_from_2d (graphene,
+                                matrix->xx,
+                                matrix->yx,
+                                matrix->xy,
+                                matrix->yy,
+                                matrix->x0,
+                                matrix->y0);
+}
diff --git a/lib/dia_svg.c b/lib/dia_svg.c
index 28fcb5a0..36e10f5a 100644
--- a/lib/dia_svg.c
+++ b/lib/dia_svg.c
@@ -30,10 +30,10 @@
 
 #include "dia_svg.h"
 
-/*!
- * \defgroup DiaSvg Services for SVG
- * \ingroup Plugins
- * \brief A set of function helping to read and write SVG with Dia
+/**
+ * SECTION:dia_svg
+ * @title: Dia SVG
+ * @short_description: A set of function helping to read and write SVG with Dia
  *
  * The Dia application supports various variants of SVG. There are
  * at least two importers of SVG dialects, namely \ref Shapes and
@@ -347,7 +347,7 @@ _parse_color(gint32 *color, const char *str)
       *color = ((0xFF<<24) & 0xFF000000) | ((r<<16) & 0xFF0000) | ((g<<8) & 0xFF00) | (b & 0xFF);
     } else if (strchr (str+4, '%')) {
       /* e.g. cairo uses percent values */
-      gchar **vals = g_strsplit (str+4, "%,", -1);
+      char **vals = g_strsplit (str+4, "%,", -1);
       int     i;
 
       *color = 0xFF000000;
@@ -392,7 +392,7 @@ _parse_color(gint32 *color, const char *str)
  * \ingroup DiaSvg
  */
 gboolean
-dia_svg_parse_color (const gchar *str, Color *color)
+dia_svg_parse_color (const char *str, Color *color)
 {
   gint32 c;
   gboolean ret = _parse_color (&c, str);
@@ -412,13 +412,13 @@ enum
 };
 
 static void
-_parse_dasharray (DiaSvgStyle *s, real user_scale, gchar *str, gchar **end)
+_parse_dasharray (DiaSvgStyle *s, double user_scale, char *str, char **end)
 {
-  gchar *ptr;
+  char *ptr;
   /* by also splitting on ';' we can also parse the continued style string */
-  gchar **dashes = g_regex_split_simple ("[\\s,;]+", (gchar *)str, 0, 0);
+  char **dashes = g_regex_split_simple ("[\\s,;]+", (char *)str, 0, 0);
   int n = 0;
-  real dl;
+  double dl;
 
   s->dashlength = g_ascii_strtod(str, &ptr);
   if (s->dashlength <= 0.0) /* e.g. "none" */
@@ -515,7 +515,7 @@ _style_adjust_font (DiaSvgStyle *s, const char *family, const char *style, const
       * seen, like 'Arial'. If the given family name can not be resolved by
       * Pango it complaints loudly with g_warning().
       */
-    gchar **families = g_strsplit (family, ",", -1);
+    char **families = g_strsplit (family, ",", -1);
     int i = 0;
     gboolean found = FALSE;
     while (!found && families[i]) {
@@ -550,7 +550,7 @@ _style_adjust_font (DiaSvgStyle *s, const char *family, const char *style, const
 
 
 static void
-_parse_text_align(DiaSvgStyle *s, const gchar *ptr)
+_parse_text_align (DiaSvgStyle *s, const char *ptr)
 {
   if (!strncmp(ptr, "start", 5))
     s->alignment = ALIGN_LEFT;
@@ -572,10 +572,10 @@ _parse_text_align(DiaSvgStyle *s, const gchar *ptr)
  * \ingroup DiaSvg
  */
 void
-dia_svg_parse_style_string (DiaSvgStyle *s, real user_scale, const gchar *str)
+dia_svg_parse_style_string (DiaSvgStyle *s, double user_scale, const char *str)
 {
   int i = 0;
-  gchar *ptr = (gchar *)str;
+  char *ptr = (char *) str;
   char *family = NULL, *style = NULL, *weight = NULL;
 
   while (ptr[0] != '\0') {
@@ -658,7 +658,7 @@ dia_svg_parse_style_string (DiaSvgStyle *s, real user_scale, const gchar *str)
       ptr += 13;
       s->stop_opacity = g_ascii_strtod(ptr, &ptr);
     } else if (!strncmp("opacity", ptr, 7)) {
-      real opacity;
+      double opacity;
       ptr += 7;
       opacity = g_ascii_strtod(ptr, &ptr);
       /* multiplicative effect of opacity */
@@ -751,14 +751,14 @@ dia_svg_parse_style_string (DiaSvgStyle *s, real user_scale, const gchar *str)
  * \ingroup DiaSvg
  */
 void
-dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
+dia_svg_parse_style (xmlNodePtr node, DiaSvgStyle *s, double user_scale)
 {
   xmlChar *str;
 
   str = xmlGetProp(node, (const xmlChar *)"style");
 
   if (str) {
-    dia_svg_parse_style_string (s, user_scale, (gchar *)str);
+    dia_svg_parse_style_string (s, user_scale, (char *)str);
     xmlFree(str);
   }
 
@@ -774,7 +774,7 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
   }
   str = xmlGetProp(node, (const xmlChar *)"opacity");
   if (str) {
-    real opacity = g_ascii_strtod((char *) str, NULL);
+    double opacity = g_ascii_strtod ((char *) str, NULL);
     /* multiplicative effect of opacity */
     s->stroke_opacity *= opacity;
     s->fill_opacity *= opacity;
@@ -823,19 +823,19 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
   str = xmlGetProp(node, (const xmlChar *)"stroke-dasharray");
   if (str) {
     if (strcmp ((const char *)str, "inherit") != 0)
-      _parse_dasharray (s, user_scale, (gchar *)str, NULL);
+      _parse_dasharray (s, user_scale, (char *)str, NULL);
     xmlFree(str);
   }
   str = xmlGetProp(node, (const xmlChar *)"stroke-linejoin");
   if (str) {
     if (strcmp ((const char *)str, "inherit") != 0)
-      _parse_linejoin (s, (gchar *)str);
+      _parse_linejoin (s, (char *)str);
     xmlFree(str);
   }
   str = xmlGetProp(node, (const xmlChar *)"stroke-linecap");
   if (str) {
     if (strcmp ((const char *)str, "inherit") != 0)
-      _parse_linecap (s, (gchar *)str);
+      _parse_linecap (s, (char *)str);
     xmlFree(str);
   }
 
@@ -846,7 +846,7 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
      * should be initialized by parent style already
      */
     if (strcmp ((const char *)str, "inherit") != 0) {
-      s->font_height = g_ascii_strtod((gchar *)str, NULL);
+      s->font_height = g_ascii_strtod ((char *)str, NULL);
       if (user_scale > 0)
        s->font_height /= user_scale;
     }
@@ -854,7 +854,7 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
   }
   str = xmlGetProp(node, (const xmlChar *)"text-anchor");
   if (str) {
-    _parse_text_align (s, (const gchar*)str);
+    _parse_text_align (s, (const char*) str);
     xmlFree(str);
   }
   {
@@ -862,7 +862,7 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
     xmlChar *slant  = xmlGetProp(node, (const xmlChar *)"font-style");
     xmlChar *weight = xmlGetProp(node, (const xmlChar *)"font-weight");
     if (family || slant || weight) {
-      _style_adjust_font (s, (gchar *)family, (gchar *)slant, (gchar *)weight);
+      _style_adjust_font (s, (char *)family, (char *)slant, (char *)weight);
 
       if (family)
         xmlFree(family);
@@ -874,37 +874,45 @@ dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale)
   }
 }
 
-/*!
- * \brief Parse a SVG description of an arc segment.
+
+/**
+ * _path_arc_segment:
+ * @points: destination array of #BezPoint
+ * @xc: center x
+ * @yc: center y
+ * @th0: first angle
+ * @th1: second angle
+ * @rx: radius x
+ * @ry: radius y
+ * @x_axis_rotation: rotation of the axis
+ * @last_p2: the resulting current point
+ *
+ * Parse a SVG description of an arc segment.
+ *
  * Code stolen from (and adapted)
  * http://www.inkscape.org/doc/doxygen/html/svg-path_8cpp.php#a7
  * which may have got it from rsvg, hope it is correct ;)
- * @param points destination array of _BezPoint
- * @param xc center x
- * @param yc center y
- * @param th0 first angle
- * @param th1 second angle
- * @param rx radius x
- * @param ry radius y
- * @param x_axis_rotation rotation of the axis
- * @param last_p2 the resulting current point
+ *
  * If you want the description of the algorithm read the SVG specs:
  * http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
  */
 static void
-_path_arc_segment(GArray* points,
-                 real xc, real yc,
-                 real th0, real th1,
-                 real rx, real ry,
-                 real x_axis_rotation,
-                 Point *last_p2)
+_path_arc_segment (GArray *points,
+                   double  xc,
+                   double  yc,
+                   double  th0,
+                   double  th1,
+                   double  rx,
+                   double  ry,
+                   double  x_axis_rotation,
+                   Point  *last_p2)
 {
   BezPoint bez;
-  real sin_th, cos_th;
-  real a00, a01, a10, a11;
-  real x1, y1, x2, y2, x3, y3;
-  real t;
-  real th_half;
+  double sin_th, cos_th;
+  double a00, a01, a10, a11;
+  double x1, y1, x2, y2, x3, y3;
+  double t;
+  double th_half;
 
   sin_th = sin (x_axis_rotation * (M_PI / 180.0));
   cos_th = cos (x_axis_rotation * (M_PI / 180.0));
@@ -1032,20 +1040,21 @@ _path_arc (GArray *points,
 /* routine to chomp off the start of the string */
 #define path_chomp(path) while (path[0]!='\0'&&strchr(" \t\n\r,", path[0])) path++
 
-/*!
- * \brief Takes SVG path content and converts it in an array of BezPoint.
+/**
+ * dia_svg_parse_path:
+ * @path_str: A string describing an SVG path.
+ * @unparsed: The position in @path_str where parsing ended, or %NULL if
+ *            the string was completely parsed. This should be used for
+ *            calling the function until it is fully parsed.
+ * @closed: Whether the path was closed.
+ * @current_point: to retain it over splitting
+ *
+ * Takes SVG path content and converts it in an array of BezPoint.
  *
  * SVG pathes can contain multiple MOVE_TO commands while Dia's bezier
  * object can only contain one so you may need to call this function
  * multiple times.
  *
- * @param path_str A string describing an SVG path.
- * @param unparsed The position in `path_str' where parsing ended, or NULL if
- *                 the string was completely parsed.  This should be used for
- *                 calling the function until it is fully parsed.
- * @param closed Whether the path was closed.
- * @param current_point to retain it over splitting
- * @return TRUE if there is any useful data in parsed to points
  * @bug This function is way too long (324 lines). So dont touch it. please!
  * Shouldn't we try to turn straight lines, simple arc, polylines and
  * zigzaglines into their appropriate objects?  Could either be done by
@@ -1053,10 +1062,15 @@ _path_arc (GArray *points,
  * specific simple paths.
  * NOPE: Dia is capable to handle beziers and the file has given us some so
  * WHY should be break it in to pieces ???
+ *
+ * Returns: %TRUE if there is any useful data in parsed to points
  */
 gboolean
-dia_svg_parse_path(GArray *points, const gchar *path_str, gchar **unparsed,
-                  gboolean *closed, Point *current_point)
+dia_svg_parse_path (GArray      *points,
+                    const char  *path_str,
+                    char       **unparsed,
+                    gboolean    *closed,
+                    Point       *current_point)
 {
   enum {
     PATH_MOVE, PATH_LINE, PATH_HLINE, PATH_VLINE, PATH_CURVE,
@@ -1067,7 +1081,7 @@ dia_svg_parse_path(GArray *points, const gchar *path_str, gchar **unparsed,
   Point last_control = {0.0, 0.0};
   gboolean last_relative = FALSE;
   BezPoint bez = { 0, };
-  gchar *path = (gchar *)path_str;
+  char *path = (char *)path_str;
   gboolean need_next_element = FALSE;
   /* we can grow the same array in multiple steps */
   gsize points_at_start = points->len;
@@ -1378,7 +1392,7 @@ dia_svg_parse_path(GArray *points, const gchar *path_str, gchar **unparsed,
         break;
       case PATH_QUBICCURVE: {
           /* raise quadratic bezier to cubic (copied from librsvg) */
-          real x1, y1;
+          double x1, y1;
           x1 = g_ascii_strtod (path, &path);
           path_chomp (path);
           y1 = g_ascii_strtod (path, &path);
@@ -1435,10 +1449,10 @@ dia_svg_parse_path(GArray *points, const gchar *path_str, gchar **unparsed,
         break;
       case PATH_ARC:
         {
-          real  rx, ry;
-          real  xrot;
-          int   largearc, sweep;
-          Point dest, dest_c;
+          double rx, ry;
+          double xrot;
+          int    largearc, sweep;
+          Point  dest, dest_c;
           dest_c.x=0;
           dest_c.y=0;
 
@@ -1549,143 +1563,226 @@ MORETOPARSE:
 
 
 static gboolean
-_parse_transform (const gchar *trans, DiaMatrix *m, real scale)
+_parse_transform (const char *trans, graphene_matrix_t *m, double scale)
 {
-  gchar **list;
-  gchar *p = strchr (trans, '(');
+  char **list;
+  char *p = strchr (trans, '(');
   int i = 0;
 
   while (   (*trans != '\0')
-         && (*trans == ' ' || *trans == ',' || *trans == '\t' || *trans == '\n' || *trans == '\r'))
+         && (*trans == ' ' || *trans == ',' || *trans == '\t' ||
+             *trans == '\n' || *trans == '\r')) {
     ++trans; /* skip whitespace */
+  }
 
-  if (!p || !*trans)
+  if (!p || !*trans) {
     return FALSE; /* silently fail */
+  }
 
-  list = g_regex_split_simple ("[\\s,]+", p+1, 0, 0);
+  list = g_regex_split_simple ("[\\s,]+", p + 1, 0, 0);
   if (strncmp (trans, "matrix", 6) == 0) {
-    if (list[i])
-      m->xx = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->yx = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->xy = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->yy = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->x0 = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->y0 = g_ascii_strtod (list[i], NULL), ++i;
+    float xx = 0, yx = 0, xy = 0, yy = 0, x0 = 0, y0 = 0;
+
+    if (list[i]) {
+      xx = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      yx = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      xy = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      yy = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      x0 = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      y0 = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    graphene_matrix_init_from_2d (m, xx, yx, xy, yy, x0 / scale, y0 / scale);
   } else if (strncmp (trans, "translate", 9) == 0) {
-    m->xx = m->yy = 1.0;
-    if (list[i])
-      m->x0 = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->y0 = g_ascii_strtod (list[i], NULL), ++i;
+    double x0 = 0, y0 = 0;
+
+    if (list[i]) {
+      x0 = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      y0 = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    graphene_matrix_init_translate (m, &GRAPHENE_POINT3D_INIT (x0 / scale, y0 / scale, 0));
   } else if (strncmp (trans, "scale", 5) == 0) {
-    if (list[i])
-      m->xx = g_ascii_strtod (list[i], NULL), ++i;
-    if (list[i])
-      m->yy = g_ascii_strtod (list[i], NULL), ++i;
-    else
-      m->yy = m->xx;
+    double xx = 0, yy = 0;
+
+    if (list[i]) {
+      xx = g_ascii_strtod (list[i], NULL);
+      ++i;
+    }
+
+    if (list[i]) {
+      yy = g_ascii_strtod (list[i], NULL);
+      ++i;
+    } else {
+      yy = xx;
+    }
+
+    graphene_matrix_init_scale (m, xx, yy, 1.0);
   } else if (strncmp (trans, "rotate", 6) == 0) {
-    DiaMatrix translate = {1, 0, 0, 1, 0, 0 };
-    real angle;
+    double angle = 0;
+    double cx = 0, cy = 0;
 
-    if (list[i])
-      angle = g_ascii_strtod (list[i], NULL), ++i;
-    else {
-      angle = 0;
+    if (list[i]) {
+      angle = g_ascii_strtod (list[i], NULL);
+      ++i;
+    } else {
       g_warning ("transform=rotate no angle?");
     }
-    m->xx =  cos(G_PI*angle/180);
-    m->yx =  sin(G_PI*angle/180);
-    m->xy = -sin(G_PI*angle/180);
-    m->yy =  cos(G_PI*angle/180);
+
     /* FIXME: check with real world data, I'm uncertain */
+    /* rotate around the given offset */
     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;
-      else
+      graphene_point3d_t point;
+
+      cx = g_ascii_strtod (list[i], NULL);
+      ++i;
+
+      if (list[i]) {
+        cy = g_ascii_strtod (list[i], NULL);
+        ++i;
+      } else {
         cy = 0.0; /* if offsets don't come in pairs */
-      /* 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);
+      }
+
+      /* translate by -cx,-cy */
+      graphene_point3d_init (&point, -(cx / scale), -(cy / scale), 0);
+      graphene_matrix_init_translate (m, &point);
+
+      /* rotate by angle */
+      graphene_matrix_rotate_z (m, angle);
+
+      /* translate by cx,cy */
+      graphene_point3d_init (&point, cx / scale, cy / scale, 0);
+      graphene_matrix_translate (m, &point);
+    } else {
+      graphene_matrix_init_rotate (m, angle, graphene_vec3_z_axis ());
     }
   } else if (strncmp (trans, "skewX", 5) == 0) {
-    m->xx = m->yy = 1.0;
-    if (list[i])
-      m->xy = tan (G_PI*g_ascii_strtod (list[i], NULL)/180);
+    float skew = 0;
+
+    if (list[i]) {
+      skew = g_ascii_strtod (list[i], NULL);
+    }
+
+    graphene_matrix_init_skew (m, DIA_RADIANS (skew), 0);
   } else if (strncmp (trans, "skewY", 5) == 0) {
-    m->xx = m->yy = 1.0;
-    if (list[i])
-      m->yx = tan (G_PI*g_ascii_strtod (list[i], NULL)/180);
+    float skew = 0;
+
+    if (list[i]) {
+      skew = g_ascii_strtod (list[i], NULL);
+    }
+
+    graphene_matrix_init_skew (m, 0, DIA_RADIANS (skew));
   } else {
     g_warning ("SVG: %s?", trans);
+
     return FALSE;
   }
-  g_strfreev(list);
 
-  if (scale > 0 && m) {
-    m->x0 /= scale;
-    m->y0 /= scale;
-  }
+  g_clear_pointer (&list, g_strfreev);
+
   return TRUE;
 }
 
-DiaMatrix *
-dia_svg_parse_transform(const gchar *trans, real scale)
+
+graphene_matrix_t *
+dia_svg_parse_transform (const char *trans, double scale)
 {
-  DiaMatrix *m = NULL;
-  gchar **transforms = g_regex_split_simple ("\\)", trans, 0, 0);
+  graphene_matrix_t *m = NULL;
+  char **transforms = g_regex_split_simple ("\\)", trans, 0, 0);
   int i = 0;
 
   /* go through the list of transformations - not that one would be enough ;) */
   while (transforms[i]) {
-    DiaMatrix mat = { 0, };
+    graphene_matrix_t mat;
 
     if (_parse_transform (transforms[i], &mat, scale)) {
       if (!m) {
-        m = g_new0 (DiaMatrix, 1);
-        *m = mat;
+        m = graphene_matrix_alloc ();
+        graphene_matrix_init_from_matrix (m, &mat);
       } else {
-        dia_matrix_multiply (m, &mat, m);
+        graphene_matrix_multiply (m, &mat, m);
       }
     }
     ++i;
   }
-  g_strfreev(transforms);
+
+  g_clear_pointer (&transforms, g_strfreev);
 
   return m;
 }
 
-gchar *
-dia_svg_from_matrix(const DiaMatrix *matrix, real scale)
+
+char *
+dia_svg_from_matrix (const graphene_matrix_t *matrix, double scale)
 {
   /*  transform="matrix(1,0,0,1,0,0)" */
-  gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+  char buf[G_ASCII_DTOSTR_BUF_SIZE];
   GString *sm = g_string_new ("matrix(");
-  gchar *s;
-
-  g_ascii_formatd (buf, sizeof(buf), "%g", matrix->xx);
-  g_string_append (sm, buf); g_string_append (sm, ",");
-  g_ascii_formatd (buf, sizeof(buf), "%g", matrix->yx);
-  g_string_append (sm, buf); g_string_append (sm, ",");
-  g_ascii_formatd (buf, sizeof(buf), "%g", matrix->xy);
-  g_string_append (sm, buf); g_string_append (sm, ",");
-  g_ascii_formatd (buf, sizeof(buf), "%g", matrix->yy);
-  g_string_append (sm, buf); g_string_append (sm, ",");
-  g_ascii_formatd (buf, sizeof(buf), "%g", matrix->x0 * scale);
-  g_string_append (sm, buf); g_string_append (sm, ",");
-  g_ascii_formatd (buf, sizeof(buf), "%g", matrix->y0 * scale);
-  g_string_append (sm, buf); g_string_append (sm, ")");
+  char *s;
+
+  g_ascii_formatd (buf,
+                   sizeof (buf),
+                   "%g",
+                   graphene_matrix_get_value (matrix, 0, 0));
+  g_string_append (sm, buf);
+  g_string_append (sm, ",");
+  g_ascii_formatd (buf,
+                   sizeof (buf),
+                   "%g",
+                   graphene_matrix_get_value (matrix, 0, 1));
+  g_string_append (sm, buf);
+  g_string_append (sm, ",");
+  g_ascii_formatd (buf,
+                   sizeof (buf),
+                   "%g",
+                   graphene_matrix_get_value (matrix, 1, 0));
+  g_string_append (sm, buf);
+  g_string_append (sm, ",");
+  g_ascii_formatd (buf,
+                   sizeof (buf),
+                   "%g",
+                   graphene_matrix_get_value (matrix, 1, 1));
+  g_string_append (sm, buf);
+  g_string_append (sm, ",");
+  g_ascii_formatd (buf,
+                   sizeof (buf),
+                   "%g",
+                   graphene_matrix_get_x_translation (matrix) * scale);
+  g_string_append (sm, buf);
+  g_string_append (sm, ",");
+  g_ascii_formatd (buf,
+                   sizeof (buf),
+                   "%g",
+                   graphene_matrix_get_y_translation (matrix) * scale);
+  g_string_append (sm, buf);
+  g_string_append (sm, ")");
 
   s = sm->str;
   g_string_free (sm, FALSE);
diff --git a/lib/dia_svg.h b/lib/dia_svg.h
index 08beca3e..cdb7155e 100644
--- a/lib/dia_svg.h
+++ b/lib/dia_svg.h
@@ -16,15 +16,15 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifndef DIA_SVG_H
-#define DIA_SVG_H
+#pragma once
+
+#include <graphene.h>
 
 #include "dia_xml.h"
 #include "font.h"
 
 /* special colours */
-enum DiaSvgColours
-{
+enum DiaSvgColours {
   DIA_SVG_COLOUR_NONE = -1,
   DIA_SVG_COLOUR_FOREGROUND = -2,
   DIA_SVG_COLOUR_BACKGROUND = -3,
@@ -35,34 +35,45 @@ enum DiaSvgColours
 
 typedef struct _DiaSvgStyle DiaSvgStyle;
 struct _DiaSvgStyle {
-  real line_width;
+  double line_width;
   gint32 stroke;
-  real   stroke_opacity;
+  double stroke_opacity;
   gint32 fill;
-  real   fill_opacity;
+  double fill_opacity;
 
   LineCaps linecap;
   LineJoin linejoin;
   LineStyle linestyle;
-  real dashlength;
+  double dashlength;
 
   DiaFont *font;
-  real font_height;
+  double font_height;
   Alignment alignment;
 
   gint32 stop_color;
-  real   stop_opacity;
+  double stop_opacity;
 };
 
-void dia_svg_style_init (DiaSvgStyle *gs, DiaSvgStyle *parent_style);
-void dia_svg_style_copy (DiaSvgStyle *dest, DiaSvgStyle *src);
-gboolean dia_svg_parse_color(const gchar *str, Color *color);
-void dia_svg_parse_style(xmlNodePtr node, DiaSvgStyle *s, real user_scale);
-void dia_svg_parse_style_string (DiaSvgStyle *s, real user_scale, const gchar *str);
-/* parse the svg sub format for pathes int an array of BezPoint */
-gboolean dia_svg_parse_path(GArray *points, const gchar *path_str, gchar **unparsed,
-                           gboolean *closed, Point *current_point);
-DiaMatrix *dia_svg_parse_transform(const gchar *trans, real scale);
-gchar *dia_svg_from_matrix(const DiaMatrix *matrix, real scale);
 
-#endif /* DIA_SVG_H */
+void               dia_svg_style_init         (DiaSvgStyle             *gs,
+                                               DiaSvgStyle             *parent_style);
+void               dia_svg_style_copy         (DiaSvgStyle             *dest,
+                                               DiaSvgStyle             *src);
+gboolean           dia_svg_parse_color        (const char              *str,
+                                               Color                   *color);
+void               dia_svg_parse_style        (xmlNodePtr               node,
+                                               DiaSvgStyle             *s,
+                                               double                   user_scale);
+void               dia_svg_parse_style_string (DiaSvgStyle             *s,
+                                               double                   user_scale,
+                                               const char              *str);
+/* parse the svg sub format for pathes int an array of BezPoint */
+gboolean           dia_svg_parse_path         (GArray                  *points,
+                                               const char              *path_str,
+                                               char                   **unparsed,
+                                               gboolean                *closed,
+                                               Point                   *current_point);
+graphene_matrix_t *dia_svg_parse_transform    (const char              *trans,
+                                               double                   scale);
+char              *dia_svg_from_matrix        (const graphene_matrix_t *matrix,
+                                               double                   scale);
diff --git a/lib/geometry.h b/lib/geometry.h
index ef0ce36c..05e964c4 100644
--- a/lib/geometry.h
+++ b/lib/geometry.h
@@ -68,6 +68,9 @@
 
 G_BEGIN_DECLS
 
+#define DIA_RADIANS(degrees) ((degrees) * G_PI / 180.0)
+#define DIA_DEGREES(radians) ((radians) * 180.0 / G_PI)
+
 
 /*
   Coordinate system used:
diff --git a/lib/meson.build b/lib/meson.build
index 634981e4..a9c40d36 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -160,6 +160,7 @@ libdia_sources = stdprop_sources + [
     'dia-simple-list.c',
     'dia-simple-list.h',
     'dia-autoptr.h',
+    'dia-graphene.h',
 ]
 
 gnome = import('gnome')
@@ -187,6 +188,7 @@ libdia_deps = [
     libm_dep,
     libzlib_dep,
     gmodule_dep,
+    graphene_dep,
 ]
 
 libdia_inc = include_directories('.')
diff --git a/meson.build b/meson.build
index ea54a764..9dd51821 100644
--- a/meson.build
+++ b/meson.build
@@ -15,6 +15,7 @@ libxml_dep  = dependency('libxml-2.0', version: '>= 2.9.4')
 gmodule_dep = dependency('gmodule-2.0')
 libzlib_dep = dependency('zlib')
 libcairo_dep = dependency('cairo')
+graphene_dep = dependency('graphene-1.0')
 
 # Not required since not all platforms ship a separate libm.
 libm_dep = cc.find_library('m', required: false)
diff --git a/plug-ins/svg/render_svg.c b/plug-ins/svg/render_svg.c
index 2a3dccca..fe084553 100644
--- a/plug-ins/svg/render_svg.c
+++ b/plug-ins/svg/render_svg.c
@@ -47,6 +47,7 @@
 #include "textline.h"
 #include "dia_svg.h"
 #include "dia-layer.h"
+#include "dia-graphene.h"
 
 G_BEGIN_DECLS
 
@@ -352,23 +353,37 @@ draw_object(DiaRenderer *self,
     GList *objs = group_objects (object);
 
     if (gm) {
-      char *s = dia_svg_from_matrix (gm, renderer->scale);
-      xmlSetProp(renderer->root, (const xmlChar *)"transform", (xmlChar *) s);
+      char *s;
+      graphene_matrix_t graphene_matrix;
+
+      dia_graphene_from_matrix (&graphene_matrix, gm);
+
+      s = dia_svg_from_matrix (&graphene_matrix, renderer->scale);
+
+      xmlSetProp (renderer->root, (const xmlChar *) "transform", (xmlChar *) s);
+
       g_clear_pointer (&s, g_free);
     }
 
     while (objs) {
       DiaObject *obj = (DiaObject *)objs->data;
 
-      obj->ops->draw(obj, DIA_RENDERER (renderer));
+      dia_object_draw (obj, DIA_RENDERER (renderer));
       objs = objs->next;
     }
     renderer->root = g_queue_pop_tail (svg_renderer->parents);
     xmlAddChild (renderer->root, group);
   } else {
     if (matrix) {
-      char *s = dia_svg_from_matrix (matrix, renderer->scale);
+      char *s;
+      graphene_matrix_t graphene_matrix;
+
+      dia_graphene_from_matrix (&graphene_matrix, matrix);
+
+      s = dia_svg_from_matrix (&graphene_matrix, renderer->scale);
+
       xmlSetProp(renderer->root, (const xmlChar *)"transform", (xmlChar *) s);
+
       g_clear_pointer (&s, g_free);
     }
 
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index 93b700d7..11fd7a4b 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -50,11 +50,14 @@
 #include "attributes.h"
 #include "pattern.h"
 #include "dia-layer.h"
+#include "dia-graphene.h"
 
-/*!
- * \defgroup SvgImport Import SVG
- * \ingroup SvgPlugin
- * \brief Based on \ref DiaSvg this plug-in translates SVG to Dia \ref StandardObjects.
+/**
+ * SECTION:svg-import
+ *
+ * Import SVG
+ *
+ * Based on \ref DiaSvg this plug-in translates SVG to Dia \ref StandardObjects.
  *
  * Sometimes SVG import is the only way to create complex objects ...
  */
@@ -156,20 +159,23 @@ static PropDescription _arrow_prop_descs[] = {
     PROP_DESC_END
 };
 
+
 static void
 reset_arrows (DiaObject *obj)
 {
-    GPtrArray *props;
-    int i;
-
-    props = prop_list_from_descs(_arrow_prop_descs,pdtpp_true);
-    g_assert(props->len == 2);
-    for (i = 0; i < 2; ++i)
-        ((ArrowProperty *)g_ptr_array_index(props, 0))->arrow_data.type = ARROW_NONE;
-    obj->ops->set_props(obj, props);
-    prop_list_free(props);
+  GPtrArray *props;
+  int i;
+
+  props = prop_list_from_descs (_arrow_prop_descs, pdtpp_true);
+  g_return_if_fail (props->len == 2);
+  for (i = 0; i < 2; ++i) {
+    ((ArrowProperty *) g_ptr_array_index (props, 0))->arrow_data.type = ARROW_NONE;
+  }
+  dia_object_set_properties (obj, props);
+  prop_list_free (props);
 }
 
+
 static GPtrArray *
 make_element_props(real xpos, real ypos,
                    real width, real height)
@@ -211,15 +217,15 @@ _node_get_real (xmlNodePtr node, const char *name, real defval)
     return val;
 }
 
+
 static void
 _transform_object (DiaObject *obj, DiaMatrix *m, DiaContext *ctx)
 {
-  g_return_if_fail (obj->ops->transform != NULL);
-
-  if (!obj->ops->transform (obj, m))
+  if (!dia_object_transform (obj, m)) {
     dia_context_add_message (ctx,
-                            _("Failed to apply transformation for '%s'"),
-                            obj->type->name);
+                             _("Failed to apply transformation for '%s'"),
+                             obj->type->name);
+  }
 }
 
 
@@ -244,7 +250,10 @@ use_position (DiaObject *obj, xmlNodePtr node, DiaContext *ctx)
 
   str = xmlGetProp(node, (const xmlChar *)"transform");
   if (str) {
-    DiaMatrix *m = dia_svg_parse_transform ((char *) str, user_scale);
+    graphene_matrix_t *graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+    DiaMatrix *m = g_new0 (DiaMatrix, 1);
+
+    dia_matrix_from_graphene (m, graphene_matrix);
 
     if (m) {
       if (obj->ops->transform) {
@@ -276,7 +285,7 @@ use_position (DiaObject *obj, xmlNodePtr node, DiaContext *ctx)
         pr = g_ptr_array_index (props, 3);
         pr->real_data *= m->yy;
 
-        obj->ops->set_props (obj, props);
+        dia_object_set_properties (obj, props);
         prop_list_free (props);
       }
       g_clear_pointer (&m, g_free);
@@ -432,137 +441,151 @@ _set_pattern_from_key (DiaObject    *obj,
 }
 
 
-/*!
- * \brief apply SVG style to object
+/**
+ * apply_style
+ *
+ * Apply SVG style to object
+ *
  * Styling with SVG is a complicated thing. The style can be given with:
  *  - single attributes on the node
  *  - a style attribute on the node
  *  - accumulation from parent objects/groups
  *  - a reference to further information in single or style attribute
  *  - inheritance from object type, class, id or a combination thereof
- * This method uses all of this information to apply the best style approximation
- * possible with DIa's rendering model.
- * \ingroup SvgImport
+ *
+ * This method uses all of this information to apply the best style
+ * approximation possible with Dia's rendering model.
  */
 static void
-apply_style(DiaObject *obj, xmlNodePtr node, DiaSvgStyle *parent_style,
-           GHashTable *style_ht, GHashTable *pattern_ht, gboolean init)
+apply_style (DiaObject   *obj,
+             xmlNodePtr   node,
+             DiaSvgStyle *parent_style,
+             GHashTable  *style_ht,
+             GHashTable  *pattern_ht,
+             gboolean     init)
 {
-      DiaSvgStyle *gs;
-      GPtrArray *props;
-      LinestyleProperty *lsprop;
-      ColorProperty *cprop;
-      RealProperty *rprop;
-      BoolProperty *bprop;
-      EnumProperty *eprop;
-      real scale = 1.0;
+  DiaSvgStyle *gs;
+  GPtrArray *props;
+  LinestyleProperty *lsprop;
+  ColorProperty *cprop;
+  RealProperty *rprop;
+  BoolProperty *bprop;
+  EnumProperty *eprop;
+  real scale = 1.0;
 
 
-      xmlChar *str = xmlGetProp(node, (const xmlChar *)"transform");
-      if (str) {
-         DiaMatrix *m = dia_svg_parse_transform ((char *)str, user_scale);
-         if (m) {
-           transform_length (&scale, m);
-           g_clear_pointer (&m, g_free);
-         }
-         xmlFree(str);
-      }
-      gs = g_new0(DiaSvgStyle, 1);
-      /* SVG defaults */
-      dia_svg_style_init (gs, parent_style);
-      _node_css_parse_style (node, gs, user_scale, style_ht);
-      dia_svg_parse_style(node, gs, user_scale);
-      props = prop_list_from_descs(svg_style_prop_descs, pdtpp_true);
-      g_assert(props->len == 7);
-
-      cprop = g_ptr_array_index(props,0);
-      if (gs->stroke == DIA_SVG_COLOUR_DEFAULT) {
-        if (init) /* no stroke */
-         cprop->color_data = get_colour(0xFFFFFF, 0.0);
-       else /* leave it alone */
-         cprop->common.experience |= PXP_NOTSET; /* no overwrite */
-      } else if (gs->stroke == DIA_SVG_COLOUR_NONE) /* transparent */
-       cprop->color_data = get_colour(0xFFFFFF, 0.0);
-      else if (gs->stroke == DIA_SVG_COLOUR_FOREGROUND)
-       cprop->color_data = attributes_get_foreground();
-      else if (gs->stroke == DIA_SVG_COLOUR_BACKGROUND)
-       cprop->color_data = attributes_get_background();
-      else
-        cprop->color_data = get_colour(gs->stroke, gs->stroke_opacity);
-
-      rprop = g_ptr_array_index(props,1);
-      rprop->real_data = gs->line_width * scale;
-
-      lsprop = g_ptr_array_index(props,2);
-      if (gs->linestyle != LINESTYLE_DEFAULT)
-       lsprop->style = gs->linestyle;
-      else if (init)
-       lsprop->style = LINESTYLE_SOLID;
-      else
-       lsprop->common.experience |= PXP_NOTSET; /* no overwrite */
-      lsprop->dash = gs->dashlength * scale;
-
-      cprop = g_ptr_array_index(props,3);
-      if (gs->fill == DIA_SVG_COLOUR_DEFAULT) {
-       if (init)
-         cprop->color_data = get_colour(0x000000, gs->fill_opacity); /* black */
-       else
-         cprop->common.experience |= PXP_NOTSET; /* no overwrite */
-      } else if (gs->fill == DIA_SVG_COLOUR_NONE) /* transparent */
-       cprop->color_data = get_colour(0x000000, 0.0);
-      else if (gs->fill == DIA_SVG_COLOUR_FOREGROUND)
-       cprop->color_data = attributes_get_foreground();
-      else if (gs->fill == DIA_SVG_COLOUR_BACKGROUND)
-       cprop->color_data = attributes_get_background();
-      else
-       cprop->color_data = get_colour(gs->fill, gs->fill_opacity);
-
-      bprop = g_ptr_array_index(props,4);
-      if(gs->fill == DIA_SVG_COLOUR_NONE || gs->fill_opacity == 0) {
-       bprop->bool_data = FALSE;
-      } else {
-       if (init)
-         bprop->bool_data = TRUE;
-       else
-         bprop->common.experience |= PXP_NOTSET; /* no overwrite */
-      }
-      /* apply pattern, gradient if any */
-      str = xmlGetProp(node, (const xmlChar *)"fill");
-      if (str) {
-        const char *left = strstr ((const char*)str, "url(#");
-        const char *right = strrchr ((const char*)str, ')');
-        if (left && right) {
-          char *key = g_strndup (left + 5, right - left - 5);
-          _set_pattern_from_key (obj, bprop, pattern_ht, key);
-          g_clear_pointer (&key, g_free);
-        }
-        xmlFree(str);
-      } else if (gs->fill == DIA_SVG_COLOUR_NONE) {
-        /* check the style again, it might contain a pattern */
-        str = xmlGetProp(node, (const xmlChar*)"style");
-        if (str) {
-          const char *left = strstr ((const char*)str, "fill:url(#");
-          const char *right = left ? strrchr (left, ')') : NULL;
-          if (left && right) {
-            char *key = g_strndup (left + 10, right - left - 10);
-            _set_pattern_from_key (obj, bprop, pattern_ht, key);
-            g_clear_pointer (&key, g_free);
-          }
-          xmlFree (str);
-        }
+  xmlChar *str = xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    graphene_matrix_t *graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+    DiaMatrix *m = g_new0 (DiaMatrix, 1);
+
+    dia_matrix_from_graphene (m, graphene_matrix);
+
+    if (m) {
+      transform_length (&scale, m);
+      g_clear_pointer (&m, g_free);
+      g_clear_pointer (&graphene_matrix, graphene_matrix_free);
+    }
+
+    xmlFree(str);
+  }
+  gs = g_new0(DiaSvgStyle, 1);
+  /* SVG defaults */
+  dia_svg_style_init (gs, parent_style);
+  _node_css_parse_style (node, gs, user_scale, style_ht);
+  dia_svg_parse_style(node, gs, user_scale);
+  props = prop_list_from_descs(svg_style_prop_descs, pdtpp_true);
+  g_assert(props->len == 7);
+
+  cprop = g_ptr_array_index(props,0);
+  if (gs->stroke == DIA_SVG_COLOUR_DEFAULT) {
+    if (init) /* no stroke */
+      cprop->color_data = get_colour(0xFFFFFF, 0.0);
+    else /* leave it alone */
+      cprop->common.experience |= PXP_NOTSET; /* no overwrite */
+  } else if (gs->stroke == DIA_SVG_COLOUR_NONE) /* transparent */
+    cprop->color_data = get_colour(0xFFFFFF, 0.0);
+  else if (gs->stroke == DIA_SVG_COLOUR_FOREGROUND)
+    cprop->color_data = attributes_get_foreground();
+  else if (gs->stroke == DIA_SVG_COLOUR_BACKGROUND)
+    cprop->color_data = attributes_get_background();
+  else
+    cprop->color_data = get_colour(gs->stroke, gs->stroke_opacity);
+
+  rprop = g_ptr_array_index(props,1);
+  rprop->real_data = gs->line_width * scale;
+
+  lsprop = g_ptr_array_index(props,2);
+  if (gs->linestyle != LINESTYLE_DEFAULT)
+    lsprop->style = gs->linestyle;
+  else if (init)
+    lsprop->style = LINESTYLE_SOLID;
+  else
+    lsprop->common.experience |= PXP_NOTSET; /* no overwrite */
+  lsprop->dash = gs->dashlength * scale;
+
+  cprop = g_ptr_array_index(props,3);
+  if (gs->fill == DIA_SVG_COLOUR_DEFAULT) {
+    if (init)
+      cprop->color_data = get_colour(0x000000, gs->fill_opacity); /* black */
+    else
+      cprop->common.experience |= PXP_NOTSET; /* no overwrite */
+  } else if (gs->fill == DIA_SVG_COLOUR_NONE) /* transparent */
+    cprop->color_data = get_colour(0x000000, 0.0);
+  else if (gs->fill == DIA_SVG_COLOUR_FOREGROUND)
+    cprop->color_data = attributes_get_foreground();
+  else if (gs->fill == DIA_SVG_COLOUR_BACKGROUND)
+    cprop->color_data = attributes_get_background();
+  else
+    cprop->color_data = get_colour(gs->fill, gs->fill_opacity);
+
+  bprop = g_ptr_array_index(props,4);
+  if(gs->fill == DIA_SVG_COLOUR_NONE || gs->fill_opacity == 0) {
+    bprop->bool_data = FALSE;
+  } else {
+    if (init)
+      bprop->bool_data = TRUE;
+    else
+      bprop->common.experience |= PXP_NOTSET; /* no overwrite */
+  }
+
+  /* apply pattern, gradient if any */
+  str = xmlGetProp(node, (const xmlChar *)"fill");
+  if (str) {
+    const char *left = strstr ((const char*)str, "url(#");
+    const char *right = strrchr ((const char*)str, ')');
+    if (left && right) {
+      char *key = g_strndup (left + 5, right - left - 5);
+      _set_pattern_from_key (obj, bprop, pattern_ht, key);
+      g_clear_pointer (&key, g_free);
+    }
+    xmlFree(str);
+  } else if (gs->fill == DIA_SVG_COLOUR_NONE) {
+    /* check the style again, it might contain a pattern */
+    str = xmlGetProp(node, (const xmlChar*)"style");
+    if (str) {
+      const char *left = strstr ((const char*)str, "fill:url(#");
+      const char *right = left ? strrchr (left, ')') : NULL;
+      if (left && right) {
+        char *key = g_strndup (left + 10, right - left - 10);
+        _set_pattern_from_key (obj, bprop, pattern_ht, key);
+        g_clear_pointer (&key, g_free);
       }
+      xmlFree (str);
+    }
+  }
 
-      eprop = g_ptr_array_index(props,5);
-      if (gs->linejoin != LINEJOIN_DEFAULT)
-       eprop->enum_data = gs->linejoin;
-      else
-       eprop->common.experience |= PXP_NOTSET;
+  eprop = g_ptr_array_index(props,5);
+  if (gs->linejoin != LINEJOIN_DEFAULT)
+    eprop->enum_data = gs->linejoin;
+  else
+    eprop->common.experience |= PXP_NOTSET;
 
-      eprop = g_ptr_array_index(props,6);
-      if (gs->linecap != LINECAPS_DEFAULT)
-        eprop->enum_data = gs->linecap;
-      else
-       eprop->common.experience |= PXP_NOTSET;
+  eprop = g_ptr_array_index(props,6);
+  if (gs->linecap != LINECAPS_DEFAULT)
+    eprop->enum_data = gs->linecap;
+  else
+    eprop->common.experience |= PXP_NOTSET;
 
   dia_object_set_properties (obj, props);
 
@@ -570,6 +593,7 @@ apply_style(DiaObject *obj, xmlNodePtr node, DiaSvgStyle *parent_style,
   g_clear_pointer (&gs, g_free);
 }
 
+
 /*!
  * \brief Elements (poly, path) can be closed style, too.
  *
@@ -597,8 +621,10 @@ _node_closed_by_style (xmlNodePtr node, DiaSvgStyle *parent_style)
 }
 
 
-/*!
- * \brief Read a SVG path element
+/**
+ * read_path_svg:
+ *
+ * Read a SVG path element
  *
  * This function parses a SVG path element into a Dia object. All
  * the heavy lifting is done with dia_svg_parse_path() which is called multiple
@@ -611,118 +637,126 @@ _node_closed_by_style (xmlNodePtr node, DiaSvgStyle *parent_style)
  * is not directly supported by Dia and also not especially useful.
  * For path elements it is just an easy transformation of all the
  * single points, so it is done here.
- *
- * \ingroup SvgImport
  */
 static GList *
-read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-             GHashTable *style_ht, GHashTable *pattern_ht,
-             GList *list, DiaContext *ctx)
+read_path_svg (xmlNodePtr   node,
+               DiaSvgStyle *parent_style,
+               GHashTable  *style_ht,
+               GHashTable  *pattern_ht,
+               GList       *list,
+               DiaContext  *ctx)
 {
-    DiaObjectType *otype;
-    DiaObject *new_obj;
-    Handle *h1, *h2;
-    BezierCreateData *bcd;
-    xmlChar *str;
-    char *pathdata, *unparsed = NULL;
-    GArray *bezpoints = NULL;
-    gboolean closed = FALSE;
-    gint i;
-    DiaMatrix *matrix = NULL;
-    Point current_point = {0.0, 0.0};
-    gboolean use_stdpath = FALSE;
-    gboolean closed_by_style;
-
-    str = xmlGetProp(node, (const xmlChar *)"transform");
-    if (str) {
-      matrix = dia_svg_parse_transform ((char *)str, user_scale);
-      xmlFree (str);
+  DiaObjectType *otype;
+  DiaObject *new_obj;
+  Handle *h1, *h2;
+  BezierCreateData *bcd;
+  xmlChar *str;
+  char *pathdata, *unparsed = NULL;
+  GArray *bezpoints = NULL;
+  gboolean closed = FALSE;
+  gint i;
+  DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
+  Point current_point = {0.0, 0.0};
+  gboolean use_stdpath = FALSE;
+  gboolean closed_by_style;
+
+  str = xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+
+    dia_matrix_from_graphene (matrix, graphene_matrix);
+
+    xmlFree (str);
+  }
+
+  closed_by_style = _node_closed_by_style (node, parent_style);
+  str = xmlGetProp(node, (const xmlChar *)"d");
+  pathdata = (char *)str;
+  bezpoints = g_array_new(FALSE, FALSE, sizeof(BezPoint));
+  g_array_set_size(bezpoints, 0);
+  do {
+    int first = bezpoints->len;
+    if (!dia_svg_parse_path (bezpoints, pathdata, &unparsed, &closed, &current_point))
+      break;
+
+    if (!closed) {
+      /* expensive way to possibly close the path */
+      closed = closed_by_style;
+      /* if we close it here add an explicit line-to */
+      if (closed) {
+        BezPoint bp;
+
+        bp.type = BEZ_LINE_TO;
+        bp.p1 = g_array_index(bezpoints, BezPoint, first).p1;
+        g_array_append_val (bezpoints, bp);
+      }
     }
+    if (unparsed) {
+      use_stdpath = TRUE;
+    } else if (bezpoints && bezpoints->len > 0) {
+      /* A stray 'z' can produce extra runs without adding any new BEZ_MOVE_TO.
+      * To have the optimum representation with Dia's objects we check again.
+      */
+      if (use_stdpath) {
+        int move_tos = 0;
+        for (i = 0; i < bezpoints->len; ++i)
+          if (g_array_index(bezpoints, BezPoint, i).type == BEZ_MOVE_TO)
+            ++move_tos;
+        use_stdpath = (move_tos > 1);
+      }
 
-    closed_by_style = _node_closed_by_style (node, parent_style);
-    str = xmlGetProp(node, (const xmlChar *)"d");
-    pathdata = (char *)str;
-    bezpoints = g_array_new(FALSE, FALSE, sizeof(BezPoint));
-    g_array_set_size(bezpoints, 0);
-    do {
-      int first = bezpoints->len;
-      if (!dia_svg_parse_path (bezpoints, pathdata, &unparsed, &closed, &current_point))
+      if (g_array_index(bezpoints, BezPoint, 0).type != BEZ_MOVE_TO) {
+        dia_context_add_message(ctx, _("Invalid path data.\n"
+              "svg:path data must start with moveto."));
         break;
+      } else if (use_stdpath) {
+        otype = object_get_type("Standard - Path");
+      } else if (!closed) {
+        otype = object_get_type("Standard - BezierLine");
+      } else if (bezpoints->len < 3) { /* error path: invalid input or parsing error? */
+        /* Our beziergon can not handle less than three points
+        * So line-to the first point again...
+        */
+        BezPoint bpz = g_array_index(bezpoints, BezPoint, 0);
+        bpz.type = BEZ_LINE_TO;
+        g_array_append_val(bezpoints, bpz);
+        otype = object_get_type("Standard - Beziergon");
+      } else {
+        otype = object_get_type("Standard - Beziergon");
+      }
 
-      if (!closed) {
-       /* expensive way to possibly close the path */
-       closed = closed_by_style;
-       /* if we close it here add an explicit line-to */
-       if (closed) {
-         BezPoint bp;
-
-         bp.type = BEZ_LINE_TO;
-         bp.p1 = g_array_index(bezpoints, BezPoint, first).p1;
-         g_array_append_val (bezpoints, bp);
-       }
+      if (otype == NULL){
+        dia_context_add_message(ctx, _("Can't find standard object"));
+        break;
       }
-      if (unparsed) {
-       use_stdpath = TRUE;
-      } else if (bezpoints && bezpoints->len > 0) {
-       /* A stray 'z' can produce extra runs without adding any new BEZ_MOVE_TO.
-        * To have the optimum representation with Dia's objects we check again.
-        */
-       if (use_stdpath) {
-         int move_tos = 0;
-         for (i = 0; i < bezpoints->len; ++i)
-           if (g_array_index(bezpoints, BezPoint, i).type == BEZ_MOVE_TO)
-             ++move_tos;
-         use_stdpath = (move_tos > 1);
-       }
-        if (g_array_index(bezpoints, BezPoint, 0).type != BEZ_MOVE_TO) {
-         dia_context_add_message(ctx, _("Invalid path data.\n"
-                                        "svg:path data must start with moveto."));
-         break;
-       } else if (use_stdpath) {
-         otype = object_get_type("Standard - Path");
-       } else if (!closed) {
-         otype = object_get_type("Standard - BezierLine");
-       } else if (bezpoints->len < 3) { /* error path: invalid input or parsing error? */
-         /* Our beziergon can not handle less than three points
-          * So line-to the first point again...
-          */
-         BezPoint bpz = g_array_index(bezpoints, BezPoint, 0);
-         bpz.type = BEZ_LINE_TO;
-         g_array_append_val(bezpoints, bpz);
-         otype = object_get_type("Standard - Beziergon");
-       } else {
-         otype = object_get_type("Standard - Beziergon");
-       }
-       if (otype == NULL){
-         dia_context_add_message(ctx, _("Can't find standard object"));
-         break;
-       }
-       bcd = g_new(BezierCreateData, 1);
-       bcd->num_points = bezpoints->len;
-       bcd->points = &(g_array_index(bezpoints, BezPoint, 0));
-       /* dia_svg_parse_path does not scale to the user coordinate system, do it here */
-       for (i = 0; i < bcd->num_points; ++i) {
-         bcd->points[i].p1.x /= user_scale;
-         bcd->points[i].p1.y /= user_scale;
-         bcd->points[i].p2.x /= user_scale;
-         bcd->points[i].p2.y /= user_scale;
-         bcd->points[i].p3.x /= user_scale;
-         bcd->points[i].p3.y /= user_scale;
-         if (matrix)
-           transform_bezpoint (&bcd->points[i], matrix);
-       }
-       new_obj = otype->ops->create(NULL, bcd, &h1, &h2);
-       if (!closed)
-         reset_arrows (new_obj);
-       g_clear_pointer (&bcd, g_free);
-       apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
-       list = g_list_append (list, new_obj);
-
-       g_array_set_size (bezpoints, 0);
+      bcd = g_new(BezierCreateData, 1);
+      bcd->num_points = bezpoints->len;
+      bcd->points = &(g_array_index(bezpoints, BezPoint, 0));
+      /* dia_svg_parse_path does not scale to the user coordinate system, do it here */
+      for (i = 0; i < bcd->num_points; ++i) {
+        bcd->points[i].p1.x /= user_scale;
+        bcd->points[i].p1.y /= user_scale;
+        bcd->points[i].p2.x /= user_scale;
+        bcd->points[i].p2.y /= user_scale;
+        bcd->points[i].p3.x /= user_scale;
+        bcd->points[i].p3.y /= user_scale;
+        if (matrix)
+          transform_bezpoint (&bcd->points[i], matrix);
       }
-      pathdata = unparsed;
-      unparsed = NULL;
-    } while (pathdata);
+      new_obj = otype->ops->create(NULL, bcd, &h1, &h2);
+      if (!closed)
+        reset_arrows (new_obj);
+      g_clear_pointer (&bcd, g_free);
+      apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
+      list = g_list_append (list, new_obj);
+
+      g_array_set_size (bezpoints, 0);
+    }
+    pathdata = unparsed;
+    unparsed = NULL;
+  } while (pathdata);
 
   if (bezpoints) {
     g_array_free (bezpoints, TRUE);
@@ -737,250 +771,281 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   return list;
 }
 
-/*!
- * \brief Read a SVG text element
- * \ingroup SvgImport
+
+/**
+ * read_text_svg:
+ *
+ * Read a SVG text element
  */
 static GList *
-read_text_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-             GHashTable *style_ht, GHashTable *pattern_ht,
-             GList *list, DiaContext *ctx)
+read_text_svg (xmlNodePtr   node,
+               DiaSvgStyle *parent_style,
+               GHashTable  *style_ht,
+               GHashTable  *pattern_ht,
+               GList       *list,
+               DiaContext  *ctx)
 {
-    DiaObjectType *otype = object_get_type("Standard - Text");
-    DiaObject *new_obj;
-    Handle *h1, *h2;
-    Point point;
-    GPtrArray *props;
-    TextProperty *prop;
-    xmlChar *str = NULL;
-    gchar *multiline = NULL;
-    DiaSvgStyle *gs;
-    gboolean any_tspan = FALSE;
-    DiaMatrix *matrix = NULL;
-    real font_height = 0.0;
-    gboolean preserve_space = xmlNodeGetSpacePreserve (node) > 0;
-
-    str = xmlGetProp(node, (const xmlChar *)"transform");
-    if (str) {
-      matrix = dia_svg_parse_transform ((char *)str, user_scale);
-      xmlFree (str);
-    }
+  DiaObjectType *otype = object_get_type ("Standard - Text");
+  DiaObject *new_obj;
+  Handle *h1, *h2;
+  Point point;
+  GPtrArray *props;
+  TextProperty *prop;
+  xmlChar *str = NULL;
+  gchar *multiline = NULL;
+  DiaSvgStyle *gs;
+  gboolean any_tspan = FALSE;
+  DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
+  real font_height = 0.0;
+  gboolean preserve_space = xmlNodeGetSpacePreserve (node) > 0;
 
-    gs = g_new(DiaSvgStyle, 1);
-    dia_svg_style_init (gs, parent_style);
+  str = xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
 
-    point.x = _node_get_real (node, "x", 0.0);
-    point.y = _node_get_real (node, "y", 0.0);
+    dia_matrix_from_graphene (matrix, graphene_matrix);
 
-    /* text property handling is special, don't use apply_style() */
-    _node_css_parse_style (node, gs, user_scale, style_ht);
+    xmlFree (str);
+  }
 
-    /* font-size can be given in the style (with absolute unit) or
-     * with it's own attribute. The latter is preferred - also by
-     * Dia's own export.
-     */
-    str = xmlGetProp(node, (const xmlChar *)"font-size");
-    if (str) {
-      font_height = get_value_as_cm((char *) str, NULL);
-      xmlFree(str);
-    }
+  gs = g_new(DiaSvgStyle, 1);
+  dia_svg_style_init (gs, parent_style);
 
-    /* parse from <text/> before looking at the first <tspan/> */
-    dia_svg_parse_style(node, gs, user_scale);
-
-    {
-      xmlNode *tspan = node->children;
-      GString *paragraph = g_string_sized_new(512);
-      while (tspan) {
-       if (xmlStrcmp (tspan->name, (const xmlChar*)"tspan") == 0) {
-         xmlChar *line = xmlNodeGetContent(tspan);
-         if (any_tspan) { /* every other line needs separation */
-           g_string_append(paragraph, "\n");
-         } else { /* only first time with user scale - but w/o matrix - that shall be
-                   * in effect from the context? */
-           dia_svg_parse_style(tspan, gs, user_scale);
-           point.x = _node_get_real (tspan, "x", point.x);
-           point.y = _node_get_real (tspan, "y", point.y);
-         }
-         g_string_append(paragraph, (gchar*)line);
-         xmlFree(line);
-          any_tspan = TRUE;
-       }
-       tspan = tspan->next;
+  point.x = _node_get_real (node, "x", 0.0);
+  point.y = _node_get_real (node, "y", 0.0);
+
+  /* text property handling is special, don't use apply_style() */
+  _node_css_parse_style (node, gs, user_scale, style_ht);
+
+  /* font-size can be given in the style (with absolute unit) or
+    * with it's own attribute. The latter is preferred - also by
+    * Dia's own export.
+    */
+  str = xmlGetProp(node, (const xmlChar *)"font-size");
+  if (str) {
+    font_height = get_value_as_cm((char *) str, NULL);
+    xmlFree(str);
+  }
+
+  /* parse from <text/> before looking at the first <tspan/> */
+  dia_svg_parse_style(node, gs, user_scale);
+
+  {
+    xmlNode *tspan = node->children;
+    GString *paragraph = g_string_sized_new(512);
+    while (tspan) {
+      if (xmlStrcmp (tspan->name, (const xmlChar*)"tspan") == 0) {
+        xmlChar *line = xmlNodeGetContent(tspan);
+        if (any_tspan) { /* every other line needs separation */
+          g_string_append(paragraph, "\n");
+        } else { /* only first time with user scale - but w/o matrix - that shall be
+            * in effect from the context? */
+          dia_svg_parse_style(tspan, gs, user_scale);
+          point.x = _node_get_real (tspan, "x", point.x);
+          point.y = _node_get_real (tspan, "y", point.y);
+        }
+        g_string_append(paragraph, (gchar*)line);
+        xmlFree(line);
+        any_tspan = TRUE;
       }
-      multiline = paragraph->str;
-      g_string_free (paragraph, FALSE);
-      str = NULL;
-    }
-    if (!any_tspan) {
-      str = xmlNodeGetContent(node);
-      /* so no valid multiline */
-      g_clear_pointer (&multiline, g_free);
-      multiline = NULL;
+      tspan = tspan->next;
     }
-    if(str || multiline) {
-      new_obj = otype->ops->create(&point, otype->default_user_data,
-                                &h1, &h2);
-      list = g_list_append (list, new_obj);
+    multiline = paragraph->str;
+    g_string_free (paragraph, FALSE);
+    str = NULL;
+  }
+  if (!any_tspan) {
+    str = xmlNodeGetContent(node);
+    /* so no valid multiline */
+    g_clear_pointer (&multiline, g_free);
+    multiline = NULL;
+  }
+  if(str || multiline) {
+    new_obj = otype->ops->create(&point, otype->default_user_data, &h1, &h2);
+    list = g_list_append (list, new_obj);
 
-      props = prop_list_from_descs(svg_text_prop_descs, pdtpp_true);
-      g_assert(props->len == 1);
+    props = prop_list_from_descs(svg_text_prop_descs, pdtpp_true);
+    g_assert(props->len == 1);
 
-      if(gs->font == NULL) {
-       gs->font = dia_font_new_from_legacy_name("Courier");
-      }
-      prop = g_ptr_array_index(props, 0);
-      g_clear_pointer (&prop->text_data, g_free);
-      prop->text_data = str ? g_strdup((char *) str) : multiline;
-      if (!preserve_space)
-        prop->text_data = g_strstrip (prop->text_data); /* modifies in-place */
-      xmlFree(str);
-      prop->attr.alignment = gs->alignment;
-      prop->attr.position.x = point.x;
-      prop->attr.position.y = point.y;
-      /* FIXME: looks like a leak but without this an imported svg is
-       * crashing on release */
-      prop->attr.font = g_object_ref (gs->font);
-      if (font_height > 0.0) {
-        /* font-size should be the line-height according to SVG spec,
-        * but see node_set_text_style() - round-trip first */
-        real font_scale = dia_font_get_height (prop->attr.font) / dia_font_get_size (prop->attr.font);
-        prop->attr.height = font_height * font_scale;
-      } else {
-        prop->attr.height = gs->font_height;
-      }
-      /* when operating with default values foreground and background are intentionally swapped
-       * to avoid getting white text by default */
-      switch (gs->fill) {
+    if(gs->font == NULL) {
+      gs->font = dia_font_new_from_legacy_name("Courier");
+    }
+    prop = g_ptr_array_index(props, 0);
+    g_clear_pointer (&prop->text_data, g_free);
+    prop->text_data = str ? g_strdup((char *) str) : multiline;
+    if (!preserve_space) {
+      prop->text_data = g_strstrip (prop->text_data); /* modifies in-place */
+    }
+    xmlFree(str);
+    prop->attr.alignment = gs->alignment;
+    prop->attr.position.x = point.x;
+    prop->attr.position.y = point.y;
+    /* FIXME: looks like a leak but without this an imported svg is
+      * crashing on release */
+    prop->attr.font = g_object_ref (gs->font);
+    if (font_height > 0.0) {
+      /* font-size should be the line-height according to SVG spec,
+      * but see node_set_text_style() - round-trip first */
+      real font_scale = dia_font_get_height (prop->attr.font) / dia_font_get_size (prop->attr.font);
+      prop->attr.height = font_height * font_scale;
+    } else {
+      prop->attr.height = gs->font_height;
+    }
+    /* when operating with default values foreground and background are intentionally swapped
+      * to avoid getting white text by default */
+    switch (gs->fill) {
       case DIA_SVG_COLOUR_NONE :
         /* don't use -1 which would be almost white */
       case DIA_SVG_COLOUR_TEXT :
       case DIA_SVG_COLOUR_BACKGROUND :
-       prop->attr.color = attributes_get_foreground();
-       break;
+        prop->attr.color = attributes_get_foreground();
+        break;
       case DIA_SVG_COLOUR_DEFAULT: /* black */
-       prop->attr.color = get_colour(0x000000, gs->fill_opacity);
-       break;
+        prop->attr.color = get_colour(0x000000, gs->fill_opacity);
+        break;
       case DIA_SVG_COLOUR_FOREGROUND :
-       prop->attr.color = attributes_get_background();
-       break;
-      default :
-       prop->attr.color = get_colour (gs->fill, gs->fill_opacity);
-       break;
-      }
-      new_obj->ops->set_props(new_obj, props);
-      prop_list_free (props);
-      if (matrix)
-        _transform_object (new_obj, matrix, ctx);
+        prop->attr.color = attributes_get_background();
+        break;
+      default:
+        prop->attr.color = get_colour (gs->fill, gs->fill_opacity);
+        break;
     }
-    g_clear_object (&gs->font);
-    g_clear_pointer (&gs, g_free);
-    g_clear_pointer (&matrix, g_free);
+    dia_object_set_properties (new_obj, props);
+    prop_list_free (props);
+    if (matrix) {
+      _transform_object (new_obj, matrix, ctx);
+    }
+  }
+  g_clear_object (&gs->font);
+  g_clear_pointer (&gs, g_free);
+  g_clear_pointer (&matrix, g_free);
 
-    return list;
+  return list;
 }
 
-/*!
- * \brief Read a polygon or a polyline
- * Create a _Polyline or _Polygon from the SVG element at node.
- * \ingroup SvgImport
+
+/**
+ * read_poly_svg:
+ *
+ * Read a polygon or a polyline
+ *
+ * Create a #Polyline or #Polygon from the SVG element at node.
  */
 static GList *
-read_poly_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-             GHashTable *style_ht, GHashTable *pattern_ht,
-             GList *list, char *object_type)
+read_poly_svg (xmlNodePtr   node,
+               DiaSvgStyle *parent_style,
+               GHashTable  *style_ht,
+               GHashTable  *pattern_ht,
+               GList       *list,
+               char        *object_type)
 {
-    DiaObjectType *otype;
-    DiaObject *new_obj;
-    Handle *h1, *h2;
-    MultipointCreateData *pcd;
-    Point *points;
-    GArray *arr = g_array_new(FALSE, FALSE, sizeof(real));
-    real val, *rarr;
-    xmlChar *str;
-    char *tmp;
-    int i;
-    DiaMatrix *matrix = NULL;
-
-    str = xmlGetProp(node, (const xmlChar *)"transform");
-    if (str) {
-      matrix = dia_svg_parse_transform ((char *)str, user_scale);
-      xmlFree (str);
-    }
+  DiaObjectType *otype;
+  DiaObject *new_obj;
+  Handle *h1, *h2;
+  MultipointCreateData *pcd;
+  Point *points;
+  GArray *arr = g_array_new (FALSE, FALSE, sizeof (double));
+  double val, *rarr;
+  xmlChar *str;
+  char *tmp;
+  int i;
+  DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
 
-    /* Uh, oh, no : apparently a fill="" in a group above make this a polygon */
-    if (_node_closed_by_style (node, parent_style))
-      otype = object_get_type("Standard - Polygon");
-    else
-      otype = object_get_type(object_type);
+  str = xmlGetProp(node, (const xmlChar *)"transform");
+  if (str) {
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
 
-    str = xmlGetProp(node, (const xmlChar *)"points");
-    if (!str) {
-      g_warning ("SVG: '%s' without points", node->name);
-      g_clear_pointer (&matrix, g_free);
-      return list;
-    }
-    tmp = (char *) str;
-    while (tmp[0] != '\0') {
-      /* skip junk */
-      while (tmp[0] != '\0' && !g_ascii_isdigit(tmp[0]) && tmp[0]!='.'&&tmp[0]!='-')
-       tmp++;
-      if (tmp[0] == '\0') break;
-      val = get_value_as_cm(tmp, &tmp);
-      g_array_append_val(arr, val);
-    }
-    xmlFree(str);
+    dia_matrix_from_graphene (matrix, graphene_matrix);
+    xmlFree (str);
+  }
 
-    /* If an odd number of coordinates is provided, then the element is in error, cut off below */
-    points = g_malloc0(arr->len/2*sizeof(Point));
-
-    pcd = g_new(MultipointCreateData, 1);
-    pcd->num_points = arr->len/2;
-    rarr = (real *)arr->data;
-    for (i = 0; i < pcd->num_points; i++) {
-      points[i].x = rarr[2*i];
-      points[i].y = rarr[2*i+1];
-      if (matrix) {
-        transform_point (&points[i], matrix);
-      }
-    }
-    g_array_free (arr, TRUE);
+  /* Uh, oh, no : apparently a fill="" in a group above make this a polygon */
+  if (_node_closed_by_style (node, parent_style))
+    otype = object_get_type("Standard - Polygon");
+  else
+    otype = object_get_type(object_type);
+
+  str = xmlGetProp(node, (const xmlChar *)"points");
+  if (!str) {
+    g_warning ("SVG: '%s' without points", node->name);
     g_clear_pointer (&matrix, g_free);
+    return list;
+  }
+  tmp = (char *) str;
+  while (tmp[0] != '\0') {
+    /* skip junk */
+    while (tmp[0] != '\0' && !g_ascii_isdigit(tmp[0]) && tmp[0]!='.'&&tmp[0]!='-')
+tmp++;
+    if (tmp[0] == '\0') break;
+    val = get_value_as_cm(tmp, &tmp);
+    g_array_append_val(arr, val);
+  }
+  xmlFree(str);
 
-    pcd->points = points;
-    new_obj = otype->ops->create(NULL, pcd,
-                                &h1, &h2);
-    reset_arrows (new_obj);
-    apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
-    list = g_list_append (list, new_obj);
-    g_clear_pointer (&points, g_free);
-    g_clear_pointer (&pcd, g_free);
+  /* If an odd number of coordinates is provided, then the element is in error, cut off below */
+  points = g_malloc0(arr->len/2*sizeof(Point));
 
-    return list;
+  pcd = g_new(MultipointCreateData, 1);
+  pcd->num_points = arr->len/2;
+  rarr = (real *)arr->data;
+  for (i = 0; i < pcd->num_points; i++) {
+    points[i].x = rarr[2*i];
+    points[i].y = rarr[2*i+1];
+    if (matrix) {
+      transform_point (&points[i], matrix);
+    }
+  }
+  g_array_free (arr, TRUE);
+  g_clear_pointer (&matrix, g_free);
+
+  pcd->points = points;
+  new_obj = otype->ops->create (NULL, pcd, &h1, &h2);
+  reset_arrows (new_obj);
+  apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
+  list = g_list_append (list, new_obj);
+  g_clear_pointer (&points, g_free);
+  g_clear_pointer (&pcd, g_free);
+
+  return list;
 }
 
-/*!
- * \brief Read an ellipse or circle from SVG
+
+/**
+ * read_ellipse_svg:
+ *
+ * Read an ellipse or circle from SVG
+ *
  * Creates only _Ellipse objects, but could set the 'circle property'.
- * \ingroup SvgImport
  */
 static GList *
-read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-                GHashTable *style_ht, GHashTable *pattern_ht,
-                GList *list, DiaContext *ctx)
+read_ellipse_svg (xmlNodePtr   node,
+                  DiaSvgStyle *parent_style,
+                  GHashTable  *style_ht,
+                  GHashTable  *pattern_ht,
+                  GList       *list,
+                  DiaContext  *ctx)
 {
   xmlChar *str;
   real width, height;
-  DiaObjectType *otype = object_get_type("Standard - Ellipse");
+  DiaObjectType *otype = object_get_type ("Standard - Ellipse");
   DiaObject *new_obj;
   Handle *h1, *h2;
   GPtrArray *props;
   Point start;
   DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
 
   str = xmlGetProp(node, (const xmlChar *)"transform");
   if (str) {
-    matrix = dia_svg_parse_transform ((char *)str, user_scale);
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+
+    dia_matrix_from_graphene (matrix, graphene_matrix);
+
     xmlFree (str);
   }
 
@@ -1004,7 +1069,7 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
 
   props = make_element_props(start.x-(width/2), start.y-(height/2),
                             width, height);
-  new_obj->ops->set_props(new_obj, props);
+  dia_object_set_properties(new_obj, props);
   if (matrix) {
     _transform_object (new_obj, matrix, ctx);
     g_clear_pointer (&matrix, g_free);
@@ -1013,27 +1078,37 @@ read_ellipse_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   return g_list_append (list, new_obj);
 }
 
-/*!
- * \brief Read a line element from SVG
- * \ingroup SvgImport
+
+/**
+ * read_line_svg:
+ *
+ * Read a line element from SVG
  */
 static GList *
-read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-             GHashTable *style_ht, GHashTable *pattern_ht,
-             GList *list, DiaContext *ctx)
+read_line_svg (xmlNodePtr   node,
+               DiaSvgStyle *parent_style,
+               GHashTable  *style_ht,
+               GHashTable  *pattern_ht,
+               GList       *list,
+               DiaContext  *ctx)
 {
   xmlChar *str;
-  DiaObjectType *otype = object_get_type("Standard - Line");
+  DiaObjectType *otype = object_get_type ("Standard - Line");
   DiaObject *new_obj;
   Handle *h1, *h2;
   PointProperty *ptprop;
   GPtrArray *props;
   Point start, end;
   DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
 
   str = xmlGetProp(node, (const xmlChar *)"transform");
   if (str) {
-    matrix = dia_svg_parse_transform ((char *)str, user_scale);
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+
+    dia_matrix_from_graphene (matrix, graphene_matrix);
+
     xmlFree (str);
   }
 
@@ -1054,7 +1129,7 @@ read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   ptprop = g_ptr_array_index(props,1);
   ptprop->point_data = end;
 
-  new_obj->ops->set_props(new_obj, props);
+  dia_object_set_properties (new_obj, props);
   reset_arrows (new_obj);
 
   prop_list_free(props);
@@ -1069,17 +1144,22 @@ read_line_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   return g_list_append (list, new_obj);
 }
 
-/*!
- * \brief Read a rectangle element from SVG
- * \ingroup SvgImport
+
+/**
+ * read_rect_svg:
+ *
+ * Read a rectangle element from SVG
  */
 static GList *
-read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-             GHashTable *style_ht, GHashTable *pattern_ht,
-             GList *list, DiaContext *ctx)
+read_rect_svg (xmlNodePtr   node,
+               DiaSvgStyle *parent_style,
+               GHashTable  *style_ht,
+               GHashTable  *pattern_ht,
+               GList       *list,
+               DiaContext  *ctx)
 {
   xmlChar *str;
-  real width, height;
+  double width, height;
   DiaObjectType *otype = object_get_type("Standard - Box");
   DiaObject *new_obj;
   Handle *h1, *h2;
@@ -1087,12 +1167,17 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   RealProperty *rprop;
   GPtrArray *props;
   Point start,end;
-  real corner_radius = 0.0;
+  double corner_radius = 0.0;
   DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
 
   str = xmlGetProp(node, (const xmlChar *)"transform");
   if (str) {
-    matrix = dia_svg_parse_transform ((char *)str, user_scale);
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+
+    dia_matrix_from_graphene (matrix, graphene_matrix);
+
     xmlFree (str);
   }
 
@@ -1139,10 +1224,10 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   rprop = g_ptr_array_index(props,2);
   rprop->real_data = corner_radius;
 
-  new_obj->ops->set_props(new_obj, props);
-  prop_list_free(props);
-  props = make_element_props(start.x,start.y,width,height);
-  new_obj->ops->set_props(new_obj, props);
+  dia_object_set_properties (new_obj, props);
+  prop_list_free (props);
+  props = make_element_props (start.x,start.y,width,height);
+  dia_object_set_properties (new_obj, props);
 
   apply_style(new_obj, node, parent_style, style_ht, pattern_ht, TRUE);
   prop_list_free(props);
@@ -1154,24 +1239,36 @@ read_rect_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
   return list;
 }
 
-/*!
- * \brief Read SVG image element
- * The result is an _Image object in the list.
- * \ingroup SvgImport
+
+/**
+ * read_image_svg:
+ *
+ * Read SVG image element
+ *
+ * The result is an #Image object in the list.
  */
 static GList *
-read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
-              GHashTable *style_ht, GHashTable *pattern_ht,
-              GList *list, const gchar *filename_svg, DiaContext *ctx)
+read_image_svg (xmlNodePtr   node,
+                DiaSvgStyle *parent_style,
+                GHashTable  *style_ht,
+                GHashTable  *pattern_ht,
+                GList       *list,
+                const char  *filename_svg,
+                DiaContext  *ctx)
 {
   xmlChar *str;
   real x, y, width, height;
   DiaObject *new_obj = NULL;
   DiaMatrix *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
 
   str = xmlGetProp(node, (const xmlChar *)"transform");
   if (str) {
-    matrix = dia_svg_parse_transform ((char *)str, user_scale);
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+
+    dia_matrix_from_graphene (matrix, graphene_matrix);
+
     xmlFree (str);
   }
 
@@ -1215,26 +1312,27 @@ read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
         g_clear_pointer (&dir, g_free);
         filename = absfn;
       }
+
       /* Importing svg as "Misc - Diagram" should produce better results than GdkPixbuf rendering */
       if (filename && g_strrstr (filename, ".svg")) {
-       Handle *h1, *h2;
-       Point point = {x, y};
-       DiaObjectType *otype = object_get_type("Misc - Diagram");
-
-       if (otype) {
-         GPtrArray *props = g_ptr_array_new ();
-         new_obj = otype->ops->create (&point, otype->default_user_data, &h1, &h2);
-         prop_list_add_filename (props, "diagram_file", filename);
-         if (new_obj) {
-           new_obj->ops->set_props (new_obj, props);
-           point.x += width;
-           point.y += height;
-           new_obj->ops->move_handle (new_obj, h2, &point, NULL, HANDLE_MOVE_USER_FINAL, 0);
-         }
-         prop_list_free (props);
-       }
+        Handle *h1, *h2;
+        Point point = {x, y};
+        DiaObjectType *otype = object_get_type ("Misc - Diagram");
+
+        if (otype) {
+          GPtrArray *props = g_ptr_array_new ();
+          new_obj = otype->ops->create (&point, otype->default_user_data, &h1, &h2);
+          prop_list_add_filename (props, "diagram_file", filename);
+          if (new_obj) {
+            dia_object_set_properties (new_obj, props);
+            point.x += width;
+            point.y += height;
+            dia_object_move_handle (new_obj, h2, &point, NULL, HANDLE_MOVE_USER_FINAL, 0);
+          }
+          prop_list_free (props);
+        }
       } else {
-       new_obj = create_standard_image(x, y, width, height, filename ? filename : "<broken>");
+        new_obj = create_standard_image (x, y, width, height, filename ? filename : "<broken>");
       }
       g_clear_pointer (&filename, g_free);
     }
@@ -1270,6 +1368,7 @@ read_gradient (xmlNodePtr node, DiaSvgStyle *parent_gs, GHashTable  *pattern_ht,
   guint       flags = 0;
   real        old_scale = user_scale;
   DiaMatrix  *matrix = NULL;
+  graphene_matrix_t *graphene_matrix = NULL;
   DiaSvgStyle gradient_gs;
 
   str = xmlGetProp (node, (const xmlChar *)"gradientUnits");
@@ -1289,12 +1388,18 @@ read_gradient (xmlNodePtr node, DiaSvgStyle *parent_gs, GHashTable  *pattern_ht,
     xmlFree (str);
   }
   /* this should not be user_scaled */
-  if ((flags & DIA_PATTERN_USER_SPACE) == 0)
+  if ((flags & DIA_PATTERN_USER_SPACE) == 0) {
     user_scale = 1.0;
+  }
+
   str = xmlGetProp (node, (const xmlChar *)"gradientTransform");
   if (str) {
-    matrix = dia_svg_parse_transform ((char *)str, user_scale);
+    matrix = g_new0 (DiaMatrix, 1);
+    graphene_matrix = dia_svg_parse_transform ((char *) str, user_scale);
+
+    dia_matrix_from_graphene (matrix, graphene_matrix);
   }
+
   if (xmlStrcmp(node->name, (const xmlChar *)"linearGradient")==0) {
     Point p1 = {_node_get_real (node, "x1", 0.0), _node_get_real (node, "y1", 0.0)};
     Point p2 = {_node_get_real (node, "x2", 1.0), _node_get_real (node, "y2", 0.0)};
@@ -1581,6 +1686,7 @@ read_items (xmlNodePtr   startnode,
       GList *moreitems;
       DiaSvgStyle *group_gs;
       DiaMatrix *matrix = NULL;
+      graphene_matrix_t *graphene_matrix = NULL;
       xmlChar *trans;
 
       /* We need to have/apply the groups style before the objects style */
@@ -1591,8 +1697,12 @@ read_items (xmlNodePtr   startnode,
 
       trans = xmlGetProp (node, (xmlChar *)"transform");
       if (trans) {
-       matrix = dia_svg_parse_transform ((char *)trans, user_scale);
-       xmlFree (trans);
+        matrix = g_new0 (DiaMatrix, 1);
+        graphene_matrix = dia_svg_parse_transform ((char *) trans, user_scale);
+
+        dia_matrix_from_graphene (matrix, graphene_matrix);
+
+        xmlFree (trans);
       }
 
       moreitems = read_items (node->xmlChildrenNode, group_gs,


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