Code

Fix a regression in the SVG path data parser (it will now parse things like "M 1...
authorjaspervdg <jaspervdg@users.sourceforge.net>
Tue, 6 May 2008 11:56:53 +0000 (11:56 +0000)
committerjaspervdg <jaspervdg@users.sourceforge.net>
Tue, 6 May 2008 11:56:53 +0000 (11:56 +0000)
src/svg/svg-path-test.h [new file with mode: 0644]
src/svg/svg-path.cpp

diff --git a/src/svg/svg-path-test.h b/src/svg/svg-path-test.h
new file mode 100644 (file)
index 0000000..1b39ca2
--- /dev/null
@@ -0,0 +1,472 @@
+#include <cxxtest/TestSuite.h>\r
+#include "libnr/n-art-bpath.h"\r
+#include "svg/svg.h"\r
+#include "2geom/coord.h"\r
+#include <string>\r
+#include <vector>\r
+#include <glib/gmem.h>\r
+\r
+class SvgPathTest : public CxxTest::TestSuite\r
+{\r
+private:\r
+    std::vector<std::string> rectanglesAbsoluteClosed;\r
+    std::vector<std::string> rectanglesRelativeClosed;\r
+    std::vector<std::string> rectanglesAbsoluteOpen;\r
+    std::vector<std::string> rectanglesRelativeOpen;\r
+    NArtBpath rectangleBpath[5+1];\r
+public:\r
+    SvgPathTest() {\r
+        // Lots of ways to define the same rectangle\r
+        rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2 Z");\r
+        rectanglesAbsoluteClosed.push_back("M 1,2 L 4,2 L 4,8 L 1,8 z");\r
+        rectanglesAbsoluteClosed.push_back("M 1,2 4,2 4,8 1,8 z");\r
+        rectanglesAbsoluteClosed.push_back("M 1,2 H 4 V 8 H 1 z");\r
+        rectanglesRelativeClosed.push_back("m 1,2 l 3,0 l 0,6 l -3,0 z");\r
+        rectanglesRelativeClosed.push_back("m 1,2 3,0 0,6 -3,0 z");\r
+        rectanglesRelativeClosed.push_back("m 1,2 h 3 v 6 h -3 z");\r
+        rectanglesAbsoluteOpen.push_back("M 1,2 L 4,2 L 4,8 L 1,8 L 1,2");\r
+        rectanglesAbsoluteOpen.push_back("M 1,2 4,2 4,8 1,8 1,2");\r
+        rectanglesAbsoluteOpen.push_back("M 1,2 H 4 V 8 H 1 V 2");\r
+        rectanglesRelativeOpen.push_back("m 1,2 l 3,0 l 0,6 l -3,0 l 0,-6");\r
+        rectanglesRelativeOpen.push_back("m 1,2 3,0 0,6 -3,0 0,-6");\r
+        rectanglesRelativeOpen.push_back("m 1,2 h 3 v 6 h -3 v -6");\r
+        rectangleBpath[0].code = NR_MOVETO;\r
+        rectangleBpath[0].x3 = 1;\r
+        rectangleBpath[0].y3 = 2;\r
+        rectangleBpath[1].code = NR_LINETO;\r
+        rectangleBpath[1].x3 = 4;\r
+        rectangleBpath[1].y3 = 2;\r
+        rectangleBpath[2].code = NR_LINETO;\r
+        rectangleBpath[2].x3 = 4;\r
+        rectangleBpath[2].y3 = 8;\r
+        rectangleBpath[3].code = NR_LINETO;\r
+        rectangleBpath[3].x3 = 1;\r
+        rectangleBpath[3].y3 = 8;\r
+        rectangleBpath[4].code = NR_LINETO;\r
+        rectangleBpath[4].x3 = 1;\r
+        rectangleBpath[4].y3 = 2;\r
+        rectangleBpath[5].code = NR_END;\r
+        // TODO: Also test some (smooth) cubic/quadratic beziers and elliptical arcs\r
+    }\r
+\r
+    void testReadRectanglesAbsoluteClosed()\r
+    {\r
+        rectangleBpath[0].code = NR_MOVETO;\r
+        for(size_t i=0; i<rectanglesAbsoluteClosed.size(); i++) {\r
+            NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteClosed[i].c_str());\r
+            TS_ASSERT(bpathEqual(bpath,rectangleBpath));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadRectanglesRelativeClosed()\r
+    {\r
+        rectangleBpath[0].code = NR_MOVETO;\r
+        for(size_t i=0; i<rectanglesRelativeClosed.size(); i++) {\r
+            NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeClosed[i].c_str());\r
+            TS_ASSERT(bpathEqual(bpath,rectangleBpath));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadRectanglesAbsoluteOpen()\r
+    {\r
+        rectangleBpath[0].code = NR_MOVETO_OPEN;\r
+        for(size_t i=0; i<rectanglesAbsoluteOpen.size(); i++) {\r
+            NArtBpath * bpath = sp_svg_read_path(rectanglesAbsoluteOpen[i].c_str());\r
+            TS_ASSERT(bpathEqual(bpath,rectangleBpath));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadRectanglesRelativeOpen()\r
+    {\r
+        rectangleBpath[0].code = NR_MOVETO_OPEN;\r
+        for(size_t i=0; i<rectanglesRelativeOpen.size(); i++) {\r
+            NArtBpath * bpath = sp_svg_read_path(rectanglesRelativeOpen[i].c_str());\r
+            TS_ASSERT(bpathEqual(bpath,rectangleBpath));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadConcatenatedPaths()\r
+    {\r
+        NArtBpath bpath_good[4*5+1];\r
+        for(size_t i=0; i<4; i++) {\r
+            memcpy(bpath_good+i*5,rectangleBpath,sizeof(rectangleBpath[0])*5);\r
+        }\r
+        bpath_good[0*5].code = NR_MOVETO;\r
+        bpath_good[1*5].code = NR_MOVETO_OPEN;\r
+        bpath_good[2*5].code = NR_MOVETO;\r
+        bpath_good[3*5].code = NR_MOVETO_OPEN;\r
+        bpath_good[4*5].code = NR_END;\r
+        for(size_t i=0; i<5; i++) {\r
+            bpath_good[1*5+i].x3 += bpath_good[0*5+4].x3;\r
+            bpath_good[1*5+i].y3 += bpath_good[0*5+4].y3;\r
+        }\r
+        for(size_t i=0; i<5; i++) {\r
+            bpath_good[2*5+i].x3 += bpath_good[1*5+4].x3;\r
+            bpath_good[2*5+i].y3 += bpath_good[1*5+4].y3;\r
+        }\r
+        std::string path_str = rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0];\r
+        NArtBpath * bpath = sp_svg_read_path(path_str.c_str());\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testReadZeroLengthSubpaths() {\r
+        // Per the SVG 1.1 specification (section F5) zero-length subpaths are relevant\r
+        NArtBpath bpath_good[8+1];\r
+        bpath_good[0].code = NR_MOVETO_OPEN;\r
+        bpath_good[0].x3 = bpath_good[0].y3 = 0;\r
+        bpath_good[1].code = NR_MOVETO_OPEN;\r
+        bpath_good[1].x3 = bpath_good[1].y3 = 1;\r
+        bpath_good[2].code = NR_LINETO;\r
+        bpath_good[2].x3 = bpath_good[2].y3 = 2;\r
+        bpath_good[3].code = NR_MOVETO;\r
+        bpath_good[3].x3 = bpath_good[3].y3 = 3;\r
+        bpath_good[4].code = NR_MOVETO;\r
+        bpath_good[4].x3 = bpath_good[4].y3 = 4;\r
+        bpath_good[5].code = NR_LINETO;\r
+        bpath_good[5].x3 = bpath_good[5].y3 = 5;\r
+        bpath_good[6].code = NR_LINETO;\r
+        bpath_good[6].x3 = bpath_good[6].y3 = 4;\r
+        bpath_good[7].code = NR_MOVETO_OPEN;\r
+        bpath_good[7].x3 = bpath_good[7].y3 = 6;\r
+        bpath_good[8].code = NR_END;\r
+        {   // Test absolute version\r
+            char const * path_str = "M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+        {   // Test relative version\r
+            char const * path_str = "m 0,0 m 1,1 l 1,1 m 1,1 z m 1,1 l 1,1 z m 2,2";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadImplicitMoveto() {\r
+        NArtBpath bpath_good[6+1];\r
+        bpath_good[0].code = NR_MOVETO;\r
+        bpath_good[0].x3 = bpath_good[0].y3 = 1;\r
+        bpath_good[1].code = NR_LINETO;\r
+        bpath_good[1].x3 = bpath_good[1].y3 = 2;\r
+        bpath_good[2].code = NR_LINETO;\r
+        bpath_good[2].x3 = bpath_good[2].y3 = 1;\r
+        bpath_good[3].code = NR_MOVETO;\r
+        bpath_good[3].x3 = bpath_good[3].y3 = 1;\r
+        bpath_good[4].code = NR_LINETO;\r
+        bpath_good[4].x3 = bpath_good[4].y3 = 3;\r
+        bpath_good[5].code = NR_LINETO;\r
+        bpath_good[5].x3 = bpath_good[5].y3 = 1;\r
+        bpath_good[6].code = NR_END;\r
+        {   // Test absolute version\r
+            char const * path_str = "M 1,1 L 2,2 z L 3,3 z";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+        {   // Test relative version\r
+            char const * path_str = "M 1,1 L 2,2 z L 3,3 z";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadFloatingPoint() {\r
+        NArtBpath bpath_good[5+1];\r
+        bpath_good[0].code = NR_MOVETO;\r
+        bpath_good[0].x3 = .01;\r
+        bpath_good[0].y3 = .02;\r
+        bpath_good[1].code = NR_LINETO;\r
+        bpath_good[1].x3 = .04;\r
+        bpath_good[1].y3 = .02;\r
+        bpath_good[2].code = NR_LINETO;\r
+        bpath_good[2].x3 = .04;\r
+        bpath_good[2].y3 = .08;\r
+        bpath_good[3].code = NR_LINETO;\r
+        bpath_good[3].x3 = .01;\r
+        bpath_good[3].y3 = .08;\r
+        bpath_good[4].code = NR_LINETO;\r
+        bpath_good[4].x3 = .01;\r
+        bpath_good[4].y3 = .02;\r
+        bpath_good[5].code = NR_END;\r
+        {   // Test decimals\r
+            char const * path_str = "M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+        {   // Test exponent\r
+            char const * path_str = "M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadImplicitSeparation() {\r
+        // Coordinates need not be separated by whitespace if they can still be read unambiguously\r
+        NArtBpath bpath_good[5+1];\r
+        bpath_good[0].code = NR_MOVETO;\r
+        bpath_good[0].x3 = .1;\r
+        bpath_good[0].y3 = .2;\r
+        bpath_good[1].code = NR_LINETO;\r
+        bpath_good[1].x3 = .4;\r
+        bpath_good[1].y3 = .2;\r
+        bpath_good[2].code = NR_LINETO;\r
+        bpath_good[2].x3 = .4;\r
+        bpath_good[2].y3 = .8;\r
+        bpath_good[3].code = NR_LINETO;\r
+        bpath_good[3].x3 = .1;\r
+        bpath_good[3].y3 = .8;\r
+        bpath_good[4].code = NR_LINETO;\r
+        bpath_good[4].x3 = .1;\r
+        bpath_good[4].y3 = .2;\r
+        bpath_good[5].code = NR_END;\r
+        {   // Test absolute\r
+            char const * path_str = "M .1.2+0.4.2e0.4e0+8e-1.1.8 z";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+            g_free(bpath);\r
+        }\r
+        {   // Test relative\r
+            char const * path_str = "m .1.2+0.3.0e0.0e0+6e-1-.3.0 z";\r
+            NArtBpath * bpath = sp_svg_read_path(path_str);\r
+            TS_ASSERT(bpathEqual(bpath,bpath_good,.1e-8));\r
+            g_free(bpath);\r
+        }\r
+    }\r
+\r
+    void testReadErrorMisplacedCharacter() {\r
+        char const * path_str;\r
+        NArtBpath * bpath;\r
+        NArtBpath * bpath_good = rectangleBpath;\r
+        bpath_good[0].code = NR_MOVETO;\r
+        // Comma in the wrong place (commas may only appear between parameters)\r
+        path_str = "M 1,2 4,2 4,8 1,8 z , m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Comma in the wrong place (commas may only appear between parameters)\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m,13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Period in the wrong place (no numbers after a 'z')\r
+        path_str = "M 1,2 4,2 4,8 1,8 z . m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Sign in the wrong place (no numbers after a 'z')\r
+        path_str = "M 1,2 4,2 4,8 1,8 z + - m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Digit in the wrong place (no numbers after a 'z')\r
+        path_str = "M 1,2 4,2 4,8 1,8 z 9809 m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Digit in the wrong place (no numbers after a 'z')\r
+        path_str = "M 1,2 4,2 4,8 1,8 z 9809 876 m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testReadErrorUnrecognizedCharacter() {\r
+        char const * path_str;\r
+        NArtBpath * bpath;\r
+        NArtBpath * bpath_good = rectangleBpath;\r
+        bpath_good[0].code = NR_MOVETO;\r
+        // Unrecognized character\r
+        path_str = "M 1,2 4,2 4,8 1,8 z&m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Unrecognized character\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m &13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testReadErrorTypo() {\r
+        char const * path_str;\r
+        NArtBpath * bpath;\r
+        NArtBpath * bpath_good = rectangleBpath;\r
+        bpath_good[0].code = NR_MOVETO;\r
+        // Typo\r
+        path_str = "M 1,2 4,2 4,8 1,8 z j 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+\r
+        bpath_good[0].code = NR_MOVETO_OPEN;\r
+        // Typo\r
+        path_str = "M 1,2 4,2 4,8 1,8 L 1,2 x m 13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testReadErrorIllformedNumbers() {\r
+        char const * path_str;\r
+        NArtBpath * bpath;\r
+        NArtBpath * bpath_good = rectangleBpath;\r
+        bpath_good[0].code = NR_MOVETO;\r
+        // Double exponent\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m 13e4e5,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Double sign\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m +-13,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Double sign\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m 13e+-12,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // No digit\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m .e12,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // No digit\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m .,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // No digit\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m +,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // No digit\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m +.e+,15";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testReadErrorJunk() {\r
+        char const * path_str;\r
+        NArtBpath * bpath;\r
+        NArtBpath * bpath_good = rectangleBpath;\r
+        bpath_good[0].code = NR_MOVETO;\r
+        // Junk\r
+        path_str = "M 1,2 4,2 4,8 1,8 z j 357 hkjh.,34e34 90ih6kj4 h5k6vlh4N.,6,45wikuyi3yere..3487 m 13,23";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testReadErrorStopReading() {\r
+        char const * path_str;\r
+        NArtBpath * bpath;\r
+        NArtBpath * bpath_good = rectangleBpath;\r
+        bpath_good[0].code = NR_MOVETO;\r
+        // Unrecognized parameter\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Invalid parameter\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m #$%,23,34";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+        // Illformed parameter\r
+        path_str = "M 1,2 4,2 4,8 1,8 z m +-12,23,34";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+\r
+        bpath_good[0].code = NR_MOVETO_OPEN;\r
+        // "Third" parameter\r
+        path_str = "M 1,2 4,2 4,8 1,8 1,2,3 M 12,23";\r
+        bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,bpath_good));\r
+        g_free(bpath);\r
+    }\r
+\r
+    void testRoundTrip() {\r
+        // This is the easiest way to (also) test writing path data, as a path can be written in more than one way.\r
+        NArtBpath * bpath;\r
+        NArtBpath * new_bpath;\r
+        char * path_str;\r
+        // Rectangle (closed)\r
+        bpath = sp_svg_read_path(rectanglesAbsoluteClosed[0].c_str());\r
+        path_str = sp_svg_write_path(bpath);\r
+        new_bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,new_bpath));\r
+        g_free(bpath); g_free(path_str); g_free(new_bpath);\r
+        // Rectangle (open)\r
+        bpath = sp_svg_read_path(rectanglesAbsoluteOpen[0].c_str());\r
+        path_str = sp_svg_write_path(bpath);\r
+        new_bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,new_bpath));\r
+        g_free(bpath); g_free(path_str); g_free(new_bpath);\r
+        // Concatenated rectangles\r
+        bpath = sp_svg_read_path((rectanglesAbsoluteClosed[0] + rectanglesRelativeOpen[0] + rectanglesRelativeClosed[0] + rectanglesAbsoluteOpen[0]).c_str());\r
+        path_str = sp_svg_write_path(bpath);\r
+        new_bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,new_bpath));\r
+        g_free(bpath); g_free(path_str); g_free(new_bpath);\r
+        // Zero-length subpaths\r
+        bpath = sp_svg_read_path("M 0,0 M 1,1 L 2,2 M 3,3 z M 4,4 L 5,5 z M 6,6");\r
+        path_str = sp_svg_write_path(bpath);\r
+        new_bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,new_bpath));\r
+        g_free(bpath); g_free(path_str); g_free(new_bpath);\r
+        // Floating-point\r
+        bpath = sp_svg_read_path("M .01,.02 L 0.04,0.02 L.04,.08L0.01,0.08 z""M 1e-2,.2e-1 L 0.004e1,0.0002e+2 L04E-2,.08e0L1.0e-2,80e-3 z");\r
+        path_str = sp_svg_write_path(bpath);\r
+        new_bpath = sp_svg_read_path(path_str);\r
+        TS_ASSERT(bpathEqual(bpath,new_bpath));\r
+        g_free(bpath); g_free(path_str); g_free(new_bpath);\r
+    }\r
+\r
+private:\r
+    bool bpathEqual(NArtBpath const * a, NArtBpath const * b, double eps = 0) {\r
+        while(a->code != NR_END && b->code == a->code) {\r
+            switch(a->code) {\r
+            case NR_MOVETO:\r
+            case NR_MOVETO_OPEN:\r
+            case NR_LINETO:\r
+                if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;\r
+                break;\r
+            case NR_CURVETO:\r
+                if (!Geom::are_near(a->x1,b->x1, eps) || !Geom::are_near(a->y1,b->y1, eps)) return false;\r
+                if (!Geom::are_near(a->x2,b->x2, eps) || !Geom::are_near(a->y2,b->y2, eps)) return false;\r
+                if (!Geom::are_near(a->x3,b->x3, eps) || !Geom::are_near(a->y3,b->y3, eps)) return false;\r
+                break;\r
+            default:\r
+                TS_FAIL("Unknown path code!");\r
+            }\r
+            a++;\r
+            b++;\r
+        }\r
+        return a->code == b->code;\r
+    }\r
+};\r
+\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r
index 36c0b0ce3c64e4397842550a7bb7f204d50c0538..460bec9220d3bcf24b4b99edd37a86c2a5f7e1d3 100644 (file)
@@ -475,7 +475,7 @@ static void rsvg_parse_path_data(RSVGParsePathCtx *ctx, char const *begin) {
      * At some point we'll need to do all of
      * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.
      */
-    do {
+    while(*begin) {
         double val;
         char const *end = rsvg_parse_float(&val, begin);
         if (end != begin) {
@@ -515,23 +515,25 @@ static void rsvg_parse_path_data(RSVGParsePathCtx *ctx, char const *begin) {
             }
             ctx->params[ctx->param++] = val;
             rsvg_parse_path_do_cmd (ctx, false, 0); // We don't know the next command yet
+        } else {
+            char c = *begin;
+            if (c >= 'A' && c <= 'Z' && c != 'E') {
+                char next_cmd = c + 'a' - 'A';
+                if (ctx->cmd)
+                    rsvg_parse_path_do_cmd (ctx, true, next_cmd);
+                ctx->cmd = next_cmd;
+                ctx->rel = false;
+            } else if (c >= 'a' && c <= 'z' && c != 'e') {
+                char next_cmd = c;
+                if (ctx->cmd)
+                    rsvg_parse_path_do_cmd (ctx, true, next_cmd);
+                ctx->cmd = next_cmd;
+                ctx->rel = true;
+            }
+            /* else c _should_ be whitespace or , */
+            begin++;
         }
-        char c = *begin;
-        if (c >= 'A' && c <= 'Z' && c != 'E') {
-            char next_cmd = c + 'a' - 'A';
-            if (ctx->cmd)
-                rsvg_parse_path_do_cmd (ctx, true, next_cmd);
-            ctx->cmd = next_cmd;
-            ctx->rel = false;
-        } else if (c >= 'a' && c <= 'z' && c != 'e') {
-            char next_cmd = c;
-            if (ctx->cmd)
-                rsvg_parse_path_do_cmd (ctx, true, next_cmd);
-            ctx->cmd = next_cmd;
-            ctx->rel = true;
-        }
-        /* else c _should_ be whitespace or , */
-    } while(*(begin++));
+    }
     if (ctx->cmd)
         rsvg_parse_path_do_cmd (ctx, true, 0);
 }