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

This commit is contained in:
Viktor Chlumský 2017-07-23 20:04:10 +02:00
parent 746767a62b
commit 28ee740a33
1 changed files with 27 additions and 30 deletions

View File

@ -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;
}