Ver Fonte

SVG importer fixes: S, T curve commands, surplus commas

Viktor Chlumský há 8 anos atrás
pai
commit
28ee740a33
1 ficheiros alterados com 27 adições e 30 exclusões
  1. 27 30
      ext/import-svg.cpp

+ 27 - 30
ext/import-svg.cpp

@@ -21,11 +21,16 @@ namespace msdfgen {
 #define REQUIRE(cond) { if (!(cond)) return false; }
 #endif
 
+static void skipExtraChars(const char *&pathDef) {
+    while (*pathDef == ',' || *pathDef == ' ' || *pathDef == '\t' || *pathDef == '\r' || *pathDef == '\n')
+        ++pathDef;
+}
+
 static bool readNodeType(char &output, const char *&pathDef) {
-    int shift;
-    char nodeType;
-    if (sscanf(pathDef, " %c%n", &nodeType, &shift) == 1 && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) {
-        pathDef += shift;
+    skipExtraChars(pathDef);
+    char nodeType = *pathDef;
+    if (nodeType && nodeType != '+' && nodeType != '-' && nodeType != '.' && nodeType != ',' && (nodeType < '0' || nodeType > '9')) {
+        ++pathDef;
         output = nodeType;
         return true;
     }
@@ -33,9 +38,10 @@ static bool readNodeType(char &output, const char *&pathDef) {
 }
 
 static bool readCoord(Point2 &output, const char *&pathDef) {
+    skipExtraChars(pathDef);
     int shift;
     double x, y;
-    if (sscanf(pathDef, " %lf%lf%n", &x, &y, &shift) == 2 || sscanf(pathDef, " %lf , %lf%n", &x, &y, &shift) == 2) {
+    if (sscanf(pathDef, "%lf%lf%n", &x, &y, &shift) == 2 || sscanf(pathDef, "%lf , %lf%n", &x, &y, &shift) == 2) {
         output.x = x;
         output.y = y;
         pathDef += shift;
@@ -45,9 +51,10 @@ static bool readCoord(Point2 &output, const char *&pathDef) {
 }
 
 static bool readDouble(double &output, const char *&pathDef) {
+    skipExtraChars(pathDef);
     int shift;
     double v;
-    if (sscanf(pathDef, " %lf%n", &v, &shift) == 1) {
+    if (sscanf(pathDef, "%lf%n", &v, &shift) == 1) {
         pathDef += shift;
         output = v;
         return true;
@@ -56,9 +63,10 @@ static bool readDouble(double &output, const char *&pathDef) {
 }
 
 static bool readBool(bool &output, const char *&pathDef) {
+    skipExtraChars(pathDef);
     int shift;
     int v;
-    if (sscanf(pathDef, " %d%n", &v, &shift) == 1) {
+    if (sscanf(pathDef, "%d%n", &v, &shift) == 1) {
         pathDef += shift;
         output = v != 0;
         return true;
@@ -66,17 +74,6 @@ static bool readBool(bool &output, const char *&pathDef) {
     return false;
 }
 
-static void consumeWhitespace(const char *&pathDef) {
-    while (*pathDef == ' ' || *pathDef == '\t' || *pathDef == '\r' || *pathDef == '\n')
-        ++pathDef;
-}
-
-static void consumeOptionalComma(const char *&pathDef) {
-    consumeWhitespace(pathDef);
-    if (*pathDef == ',')
-        ++pathDef;
-}
-
 static double arcAngle(Vector2 u, Vector2 v) {
     return nonZeroSign(crossProduct(u, v))*acos(clamp(dotProduct(u, v)/(u.length()*v.length()), -1., +1.));
 }
@@ -136,7 +133,8 @@ static void addArcApproximate(Contour &contour, Point2 startPoint, Point2 endPoi
 }
 
 static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
-    char nodeType;
+    char nodeType = '\0';
+    char prevNodeType = '\0';
     Point2 prevNode(0, 0);
     bool nodeTypePreread = false;
     while (nodeTypePreread || readNodeType(nodeType, pathDef)) {
@@ -184,7 +182,6 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
                     break;
                 case 'Q': case 'q':
                     REQUIRE(readCoord(controlPoint[0], pathDef));
-                    consumeOptionalComma(pathDef);
                     REQUIRE(readCoord(node, pathDef));
                     if (nodeType == 'q') {
                         controlPoint[0] += prevNode;
@@ -193,7 +190,10 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
                     contour.addEdge(new QuadraticSegment(prevNode, controlPoint[0], node));
                     break;
                 case 'T': case 't':
-                    controlPoint[0] = node+node-controlPoint[0];
+                    if (prevNodeType == 'Q' || prevNodeType == 'q' || prevNodeType == 'T' || prevNodeType == 't')
+                        controlPoint[0] = node+node-controlPoint[0];
+                    else
+                        controlPoint[0] = node;
                     REQUIRE(readCoord(node, pathDef));
                     if (nodeType == 't')
                         node += prevNode;
@@ -201,9 +201,7 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
                     break;
                 case 'C': case 'c':
                     REQUIRE(readCoord(controlPoint[0], pathDef));
-                    consumeOptionalComma(pathDef);
                     REQUIRE(readCoord(controlPoint[1], pathDef));
-                    consumeOptionalComma(pathDef);
                     REQUIRE(readCoord(node, pathDef));
                     if (nodeType == 'c') {
                         controlPoint[0] += prevNode;
@@ -213,9 +211,11 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
                     contour.addEdge(new CubicSegment(prevNode, controlPoint[0], controlPoint[1], node));
                     break;
                 case 'S': case 's':
-                    controlPoint[0] = node+node-controlPoint[1];
+                    if (prevNodeType == 'C' || prevNodeType == 'c' || prevNodeType == 'S' || prevNodeType == 's')
+                        controlPoint[0] = node+node-controlPoint[1];
+                    else
+                        controlPoint[0] = node;
                     REQUIRE(readCoord(controlPoint[1], pathDef));
-                    consumeOptionalComma(pathDef);
                     REQUIRE(readCoord(node, pathDef));
                     if (nodeType == 's') {
                         controlPoint[1] += prevNode;
@@ -230,13 +230,9 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
                         bool largeArg;
                         bool sweep;
                         REQUIRE(readCoord(radius, pathDef));
-                        consumeOptionalComma(pathDef);
                         REQUIRE(readDouble(angle, pathDef));
-                        consumeOptionalComma(pathDef);
                         REQUIRE(readBool(largeArg, pathDef));
-                        consumeOptionalComma(pathDef);
                         REQUIRE(readBool(sweep, pathDef));
-                        consumeOptionalComma(pathDef);
                         REQUIRE(readCoord(node, pathDef));
                         if (nodeType == 'a')
                             node += prevNode;
@@ -249,8 +245,8 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
             }
             contourStart &= nodeType == 'M' || nodeType == 'm';
             prevNode = node;
+            prevNodeType = nodeType;
             readNodeType(nodeType, pathDef);
-            consumeWhitespace(pathDef);
         }
     NEXT_CONTOUR:
         // Fix contour if it isn't properly closed
@@ -261,6 +257,7 @@ static bool buildFromPath(Shape &shape, const char *pathDef, double size) {
                 contour.addEdge(new LinearSegment(prevNode, startPoint));
         }
         prevNode = startPoint;
+        prevNodeType = '\0';
     }
     return true;
 }