Add unit test to feed valid SVG sequences to make sure that
path strings can be parsed without returning an error.
Draw the output through Skia and SVG to make sure they are
parsed correctly.
R=fmalita@chromium.org
BUG=skia:4549
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1675053002
Review URL: https://codereview.chromium.org/1675053002
diff --git a/src/utils/SkParsePath.cpp b/src/utils/SkParsePath.cpp
index c0f39aa..8baa661 100644
--- a/src/utils/SkParsePath.cpp
+++ b/src/utils/SkParsePath.cpp
@@ -40,7 +40,9 @@
}
static const char* skip_sep(const char str[]) {
- SkASSERT(str);
+ if (!str) {
+ return nullptr;
+ }
while (is_sep(*str))
str++;
return str;
@@ -61,6 +63,9 @@
static const char* find_scalar(const char str[], SkScalar* value,
bool isRelative, SkScalar relative) {
str = SkParse::FindScalar(str, value);
+ if (!str) {
+ return nullptr;
+ }
if (isRelative) {
*value += relative;
}
@@ -70,7 +75,7 @@
bool SkParsePath::FromSVGString(const char data[], SkPath* result) {
SkPath path;
- SkPoint f = {0, 0};
+ SkPoint first = {0, 0};
SkPoint c = {0, 0};
SkPoint lastc = {0, 0};
SkPoint points[3];
@@ -107,6 +112,7 @@
case 'M':
data = find_points(data, points, 1, relative, &c);
path.moveTo(points[0]);
+ previousOp = '\0';
op = 'L';
c = points[0];
break;
@@ -147,10 +153,10 @@
goto quadraticCommon;
case 'T':
data = find_points(data, &points[1], 1, relative, &c);
- points[0] = points[1];
+ points[0] = c;
if (previousOp == 'Q' || previousOp == 'T') {
- points[0].fX = c.fX * 2 - lastc.fX;
- points[0].fY = c.fY * 2 - lastc.fY;
+ points[0].fX -= lastc.fX - c.fX;
+ points[0].fY -= lastc.fY - c.fY;
}
quadraticCommon:
path.quadTo(points[0], points[1]);
@@ -159,27 +165,24 @@
break;
case 'A': {
SkPoint radii;
- data = find_points(data, &radii, 1, false, nullptr);
SkScalar angle, largeArc, sweep;
- data = find_scalar(data, &angle, false, 0);
- data = find_scalar(data, &largeArc, false, 0);
- data = find_scalar(data, &sweep, false, 0);
- data = find_points(data, &points[0], 1, relative, &c);
- path.arcTo(radii, angle, (SkPath::ArcSize) SkToBool(largeArc),
- (SkPath::Direction) !SkToBool(sweep), points[0]);
+ if ((data = find_points(data, &radii, 1, false, nullptr))
+ && (data = skip_sep(data))
+ && (data = find_scalar(data, &angle, false, 0))
+ && (data = skip_sep(data))
+ && (data = find_scalar(data, &largeArc, false, 0))
+ && (data = skip_sep(data))
+ && (data = find_scalar(data, &sweep, false, 0))
+ && (data = skip_sep(data))
+ && (data = find_points(data, &points[0], 1, relative, &c))) {
+ path.arcTo(radii, angle, (SkPath::ArcSize) SkToBool(largeArc),
+ (SkPath::Direction) !SkToBool(sweep), points[0]);
+ path.getLastPt(&c);
+ }
} break;
case 'Z':
path.close();
-#if 0 // !!! still a bug?
- if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) {
- c.fX -= SkScalar.Epsilon; // !!! enough?
- fPath.moveTo(c);
- fPath.lineTo(f);
- fPath.close();
- }
-#endif
- c = f;
- op = '\0';
+ c = first;
break;
case '~': {
SkPoint args[2];
@@ -191,7 +194,7 @@
return false;
}
if (previousOp == 0) {
- f = c;
+ first = c;
}
previousOp = op;
}