diff options
author | Cary Clark <caryclark@skia.org> | 2017-12-08 11:37:01 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-12-08 18:34:11 +0000 |
commit | 1acd3c7e845572be3fa84022b80643d75dfcfd1a (patch) | |
tree | 98ebfcd6f21a362b840b5336ab04dfff4255b577 | |
parent | 8b225c1396657a8f45281a3226b92d6d3b64e0a0 (diff) |
keep SVG arcs axis aligned with suppression
another attempt at https://skia-review.googlesource.com/c/skia/+/79423
this time, bracket change with SK_SUPPORT_LEGACY_SVG_ARC_TO
to avoid prematurely changing SVG layout test results.
R=djsollen@google.com
Bug: b:69622768
Change-Id: Ia929f89d4f4292dfead191a381cdb431f743726a
Reviewed-on: https://skia-review.googlesource.com/82723
Commit-Queue: Cary Clark <caryclark@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
-rw-r--r-- | src/core/SkPath.cpp | 26 | ||||
-rw-r--r-- | tests/PathTest.cpp | 31 |
2 files changed, 57 insertions, 0 deletions
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index c433424635..422c2b911d 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -1417,7 +1417,12 @@ void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc pointTransform.setRotate(angle); pointTransform.preScale(rx, ry); +#ifdef SK_SUPPORT_LEGACY_SVG_ARC_TO int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (SK_ScalarPI / 2))); +#else + // the arc may be slightly bigger than 1/4 circle, so allow up to 1/3rd + int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (2 * SK_ScalarPI / 3))); +#endif SkScalar thetaWidth = thetaArc / segments; SkScalar t = SkScalarTan(0.5f * thetaWidth); if (!SkScalarIsFinite(t)) { @@ -1425,6 +1430,14 @@ void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc } SkScalar startTheta = theta1; SkScalar w = SkScalarSqrt(SK_ScalarHalf + SkScalarCos(thetaWidth) * SK_ScalarHalf); +#ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO + auto scalar_is_integer = [](SkScalar scalar) -> bool { + return scalar == SkScalarFloorToScalar(scalar); + }; + bool expectIntegers = SkScalarNearlyZero(SK_ScalarPI/2 - SkScalarAbs(thetaWidth)) && + scalar_is_integer(rx) && scalar_is_integer(ry) && + scalar_is_integer(x) && scalar_is_integer(y); +#endif for (int i = 0; i < segments; ++i) { SkScalar endTheta = startTheta + thetaWidth; SkScalar cosEndTheta, sinEndTheta = SkScalarSinCos(endTheta, &cosEndTheta); @@ -1435,6 +1448,19 @@ void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arc unitPts[0].offset(t * sinEndTheta, -t * cosEndTheta); SkPoint mapped[2]; pointTransform.mapPoints(mapped, unitPts, (int) SK_ARRAY_COUNT(unitPts)); + /* + Computing the arc width introduces rounding errors that cause arcs to start + outside their marks. A round rect may lose convexity as a result. If the input + values are on integers, place the conic on integers as well. + */ +#ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO + if (expectIntegers) { + SkScalar* mappedScalars = &mapped[0].fX; + for (unsigned index = 0; index < sizeof(mapped) / sizeof(SkScalar); ++index) { + mappedScalars[index] = SkScalarRoundToScalar(mappedScalars[index]); + } + } +#endif this->conicTo(mapped[0], mapped[1], w); startTheta = endTheta; } diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index b275342e2d..88ca3f8f05 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -4915,3 +4915,34 @@ DEF_TEST(NonFinitePathIteration, reporter) { REPORTER_ASSERT(reporter, verbs == 0); } + + +#ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO +DEF_TEST(AndroidArc, reporter) { + const char* tests[] = { + "M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z", + "M50,0L92,0 A8,8,0,0 1 100,8 L100,92 A8,8,0,0 1 92,100 L8,100" + " A8,8,0,0 1 0,92 L 0,8 A8,8,0,0 1 8,0z", + "M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0" + }; + for (auto test : tests) { + SkPath aPath; + SkAssertResult(SkParsePath::FromSVGString(test, &aPath)); + SkASSERT(aPath.isConvex()); + for (SkScalar scale = 1; scale < 1000; scale *= 1.1f) { + SkPath scalePath = aPath; + SkMatrix matrix; + matrix.setScale(scale, scale); + scalePath.transform(matrix); + SkASSERT(scalePath.isConvex()); + } + for (SkScalar scale = 1; scale < .001; scale /= 1.1f) { + SkPath scalePath = aPath; + SkMatrix matrix; + matrix.setScale(scale, scale); + scalePath.transform(matrix); + SkASSERT(scalePath.isConvex()); + } + } +} +#endif |