[dia] svg: extend dia_svg_parse_path() to support multiple move-to
- From: Hans Breuer <hans src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dia] svg: extend dia_svg_parse_path() to support multiple move-to
- Date: Wed, 3 Oct 2012 20:04:27 +0000 (UTC)
commit 1541c6a42401098cd39c7fba9fdb7c3b13994bcf
Author: Hans Breuer <hans breuer org>
Date: Tue Oct 2 23:04:17 2012 +0200
svg: extend dia_svg_parse_path() to support multiple move-to
The SVG importer just turns these into 'Standard - Path' when
necessary. This gives almost perfect round-trip with render-test
saved by cairo.
The Shape import works as before, i.e. it is splitting the
multiple move-to into single drawing operations as before.
lib/dia_svg.c | 37 ++++++++++++++++++++-----------------
lib/dia_svg.h | 3 ++-
objects/custom/shape_info.c | 7 +++++--
plug-ins/svg/svg-import.c | 30 ++++++++++++++++++++++++++++--
4 files changed, 55 insertions(+), 22 deletions(-)
---
diff --git a/lib/dia_svg.c b/lib/dia_svg.c
index fa3236b..0980532 100644
--- a/lib/dia_svg.c
+++ b/lib/dia_svg.c
@@ -646,11 +646,12 @@ _path_arc(GArray *points, double cpx, double cpy,
/* routine to chomp off the start of the string */
#define path_chomp(path) while (path[0]!='\0'&&strchr(" \t\n\r,", path[0])) path++
-/** Takes SVG path content and converts it in an array of BezPoint.
+/*!
+ * \brief 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.
+ * 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
@@ -658,8 +659,7 @@ _path_arc(GArray *points, double cpx, double cpy,
* calling the function until it is fully parsed.
* @param closed Whether the path was closed.
* @param current_point to retain it over splitting
- * @returns Array of BezPoint objects, or NULL if an error occurred.
- * The caller is responsible for freeing the array.
+ * @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
@@ -668,8 +668,9 @@ _path_arc(GArray *points, double cpx, double cpy,
* NOPE: Dia is capable to handle beziers and the file has given us some so
* WHY should be break it in to pieces ???
*/
-GArray*
-dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Point *current_point)
+gboolean
+dia_svg_parse_path(GArray *points, const gchar *path_str, gchar **unparsed,
+ gboolean *closed, Point *current_point)
{
enum {
PATH_MOVE, PATH_LINE, PATH_HLINE, PATH_VLINE, PATH_CURVE,
@@ -678,10 +679,11 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Po
Point last_point = {0.0, 0.0};
Point last_control = {0.0, 0.0};
gboolean last_relative = FALSE;
- GArray *points;
BezPoint bez = { 0, };
gchar *path = (gchar *)path_str;
gboolean need_next_element = FALSE;
+ /* we can grow the same array in multiple steps */
+ gsize points_at_start = points->len;
*closed = FALSE;
*unparsed = NULL;
@@ -690,9 +692,6 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Po
if (current_point)
last_point = *current_point;
- points = g_array_new(FALSE, FALSE, sizeof(BezPoint));
- g_array_set_size(points, 0);
-
path_chomp(path);
while (path[0] != '\0') {
#ifdef DEBUG_CUSTOM
@@ -703,7 +702,7 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Po
case 'M':
#undef MULTI_MOVE_BEZIER /* Dia XML serialization can't cope with it */
#ifndef MULTI_MOVE_BEZIER
- if (points->len > 0) {
+ if (points->len - points_at_start > 0) {
need_next_element = TRUE;
goto MORETOPARSE;
}
@@ -838,7 +837,7 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Po
switch (last_type) {
case PATH_MOVE:
#ifndef MULTI_MOVE_BEZIER
- if (points->len > 1)
+ if (points->len - points_at_start > 1)
g_warning ("Only first point should be 'move'");
#endif
bez.type = BEZ_MOVE_TO;
@@ -1008,11 +1007,13 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Po
}
break;
case PATH_CLOSE:
- /* close the path with a line */
- if (last_open.x != last_point.x || last_open.y != last_point.y) {
+ /* close the path with a line - second condition to ignore single close */
+ if ( (last_open.x != last_point.x || last_open.y != last_point.y)
+ && (points->len != points_at_start)) {
bez.type = BEZ_LINE_TO;
bez.p1 = last_open;
g_array_append_val(points, bez);
+ last_point = last_open;
}
*closed = TRUE;
#ifndef MULTI_MOVE_BEZIER
@@ -1026,6 +1027,8 @@ MORETOPARSE:
/* check if there really is more to be parsed */
if (path[0] != 0)
*unparsed = path;
+ else
+ *unparsed = NULL;
break; /* while */
}
}
@@ -1039,7 +1042,7 @@ MORETOPARSE:
}
if (current_point)
*current_point = last_point;
- return points;
+ return (points->len > 1);
}
DiaMatrix *
diff --git a/lib/dia_svg.h b/lib/dia_svg.h
index b421c42..f872b18 100644
--- a/lib/dia_svg.h
+++ b/lib/dia_svg.h
@@ -62,7 +62,8 @@ 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);
/* parse the svg sub format for pathes int an array of BezPoint */
-GArray *dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed, Point *current_point);
+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);
diff --git a/objects/custom/shape_info.c b/objects/custom/shape_info.c
index 53efb25..6a3e757 100644
--- a/objects/custom/shape_info.c
+++ b/objects/custom/shape_info.c
@@ -159,8 +159,11 @@ parse_path(ShapeInfo *info, const char *path_str, DiaSvgStyle *s, const char* fi
gboolean closed = FALSE;
Point current_point = {0.0, 0.0};
+ points = g_array_new(FALSE, FALSE, sizeof(BezPoint));
+ g_array_set_size(points, 0);
do {
- points = dia_svg_parse_path (pathdata, &unparsed, &closed, ¤t_point);
+ if (!dia_svg_parse_path (points, pathdata, &unparsed, &closed, ¤t_point))
+ break;
if (points->len > 0) {
if (g_array_index(points, BezPoint, 0).type != BEZ_MOVE_TO) {
@@ -493,7 +496,7 @@ parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns,
image->image = dia_image_load(imgfn);
}
if (!image->image)
- g_warning("failed to load image file %s", imgfn ? imgfn : "(data:)");
+ g_debug("failed to load image file %s", imgfn ? imgfn : "(data:)");
g_free(imgfn);
xmlFree(str);
}
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index bb43920..8cdfcf5 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -328,6 +328,7 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, DiaContex
gint i;
DiaMatrix *matrix = NULL;
Point current_point = {0.0, 0.0};
+ gboolean use_stdpath = FALSE;
str = xmlGetProp(node, (const xmlChar *)"transform");
if (str) {
@@ -337,25 +338,50 @@ read_path_svg(xmlNodePtr node, DiaSvgStyle *parent_style, GList *list, DiaContex
str = xmlGetProp(node, (const xmlChar *)"d");
pathdata = (char *)str;
+ bezpoints = g_array_new(FALSE, FALSE, sizeof(BezPoint));
+ g_array_set_size(bezpoints, 0);
do {
- bezpoints = dia_svg_parse_path (pathdata, &unparsed, &closed, ¤t_point);
+ int first = bezpoints->len;
+ if (!dia_svg_parse_path (bezpoints, pathdata, &unparsed, &closed, ¤t_point))
+ break;
if (!closed) {
/* expensive way to possibly close the path */
DiaSvgStyle *gs = g_new0(DiaSvgStyle, 1);
+ BezPoint bp;
dia_svg_style_init (gs, NULL);
dia_svg_parse_style(node, gs, user_scale);
if (gs->font)
dia_font_unref (gs->font);
closed = (gs->fill != DIA_SVG_COLOUR_NONE);
+ /* if we close it here add an explicit line-to */
+ if (closed) {
+ bp.type = BEZ_LINE_TO;
+ bp.p1 = g_array_index(bezpoints, BezPoint, first).p1;
+ g_array_append_val (bezpoints, bp);
+ }
g_free(gs);
}
- if (bezpoints && bezpoints->len > 0) {
+ 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 representaion 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
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]