diff options
-rw-r--r-- | include/core/SkPath.h | 22 | ||||
-rw-r--r-- | src/core/SkPath.cpp | 12 | ||||
-rw-r--r-- | src/core/SkStroke.cpp | 2 | ||||
-rw-r--r-- | tests/PathTest.cpp | 64 |
4 files changed, 84 insertions, 16 deletions
diff --git a/include/core/SkPath.h b/include/core/SkPath.h index 99f8242ff7..fe89766558 100644 --- a/include/core/SkPath.h +++ b/include/core/SkPath.h @@ -206,8 +206,8 @@ public: @return true if the line is of zero length; otherwise false. */ - static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) { - return p1.equalsWithinTolerance(p2); + static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact) { + return exact ? p1 == p2 : p1.equalsWithinTolerance(p2); } /** Test a quad for zero length @@ -215,8 +215,8 @@ public: @return true if the quad is of zero length; otherwise false. */ static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2, - const SkPoint& p3) { - return p1.equalsWithinTolerance(p2) && + const SkPoint& p3, bool exact) { + return exact ? p1 == p2 && p2 == p3 : p1.equalsWithinTolerance(p2) && p2.equalsWithinTolerance(p3); } @@ -225,8 +225,8 @@ public: @return true if the cubic is of zero length; otherwise false. */ static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2, - const SkPoint& p3, const SkPoint& p4) { - return p1.equalsWithinTolerance(p2) && + const SkPoint& p3, const SkPoint& p4, bool exact) { + return exact ? p1 == p2 && p2 == p3 && p3 == p4 : p1.equalsWithinTolerance(p2) && p2.equalsWithinTolerance(p3) && p3.equalsWithinTolerance(p4); } @@ -800,11 +800,15 @@ public: @param pts The points representing the current verb and/or segment @param doConsumeDegerates If true, first scan for segments that are deemed degenerate (too short) and skip those. + @param exact if doConsumeDegenerates is true and exact is true, skip only + degenerate elements with lengths exactly equal to zero. If exact + is false, skip degenerate elements with lengths close to zero. If + doConsumeDegenerates is false, exact has no effect. @return The verb for the current segment */ - Verb next(SkPoint pts[4], bool doConsumeDegerates = true) { + Verb next(SkPoint pts[4], bool doConsumeDegerates = true, bool exact = false) { if (doConsumeDegerates) { - this->consumeDegenerateSegments(); + this->consumeDegenerateSegments(exact); } return this->doNext(pts); } @@ -844,7 +848,7 @@ public: inline const SkPoint& cons_moveTo(); Verb autoClose(SkPoint pts[2]); - void consumeDegenerateSegments(); + void consumeDegenerateSegments(bool exact); Verb doNext(SkPoint pts[4]); }; diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 9381f48f3b..05fc7305ce 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -1612,7 +1612,7 @@ const SkPoint& SkPath::Iter::cons_moveTo() { } } -void SkPath::Iter::consumeDegenerateSegments() { +void SkPath::Iter::consumeDegenerateSegments(bool exact) { // We need to step over anything that will not move the current draw point // forward before the next move is seen const uint8_t* lastMoveVerb = 0; @@ -1643,7 +1643,7 @@ void SkPath::Iter::consumeDegenerateSegments() { break; case kLine_Verb: - if (!IsLineDegenerate(lastPt, fPts[0])) { + if (!IsLineDegenerate(lastPt, fPts[0], exact)) { if (lastMoveVerb) { fVerbs = lastMoveVerb; fPts = lastMovePt; @@ -1659,7 +1659,7 @@ void SkPath::Iter::consumeDegenerateSegments() { case kConic_Verb: case kQuad_Verb: - if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) { + if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1], exact)) { if (lastMoveVerb) { fVerbs = lastMoveVerb; fPts = lastMovePt; @@ -1675,7 +1675,7 @@ void SkPath::Iter::consumeDegenerateSegments() { break; case kCubic_Verb: - if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) { + if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2], exact)) { if (lastMoveVerb) { fVerbs = lastMoveVerb; fPts = lastMovePt; @@ -2116,7 +2116,7 @@ struct Convexicator { SkScalar lengthSqd = vec.lengthSqd(); if (!SkScalarIsFinite(lengthSqd)) { fIsFinite = false; - } else if (!SkScalarNearlyZero(lengthSqd, SK_ScalarNearlyZero*SK_ScalarNearlyZero)) { + } else if (lengthSqd) { fPriorPt = fLastPt; fLastPt = fCurrPt; fCurrPt = pt; @@ -2253,7 +2253,7 @@ SkPath::Convexity SkPath::internalGetConvexity() const { if (!isFinite()) { return kUnknown_Convexity; } - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) { switch (verb) { case kMove_Verb: if (++contourCount > 1) { diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp index 86c0571c4b..d21dc96713 100644 --- a/src/core/SkStroke.cpp +++ b/src/core/SkStroke.cpp @@ -356,7 +356,7 @@ void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) { } void SkPathStroker::lineTo(const SkPoint& currPt) { - if (SkPath::IsLineDegenerate(fPrevPt, currPt)) { + if (SkPath::IsLineDegenerate(fPrevPt, currPt, false)) { return; } SkVector normal, unitNormal; diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp index d7660a196b..313d84a142 100644 --- a/tests/PathTest.cpp +++ b/tests/PathTest.cpp @@ -419,6 +419,68 @@ static void test_crbug_170666() { surface->getCanvas()->drawPath(path, paint); } + +static void test_tiny_path_convexity(skiatest::Reporter* reporter, const char* pathBug, + SkScalar tx, SkScalar ty, SkScalar scale) { + SkPath smallPath; + SkAssertResult(SkParsePath::FromSVGString(pathBug, &smallPath)); + bool smallConvex = smallPath.isConvex(); + SkPath largePath; + SkAssertResult(SkParsePath::FromSVGString(pathBug, &largePath)); + SkMatrix matrix; + matrix.reset(); + matrix.preTranslate(100, 100); + matrix.preScale(scale, scale); + largePath.transform(matrix); + bool largeConvex = largePath.isConvex(); + REPORTER_ASSERT(reporter, smallConvex == largeConvex); +} + +static void test_crbug_493450(skiatest::Reporter* reporter) { + const char reducedCase[] = + "M0,0" + "L0.0002, 0" + "L0.0002, 0.0002" + "L0.0001, 0.0001" + "L0,0.0002" + "Z"; + test_tiny_path_convexity(reporter, reducedCase, 100, 100, 100000); + const char originalFiddleData[] = + "M-0.3383152268862998,-0.11217565719203619L-0.33846085183212765,-0.11212264406895281" + "L-0.338509393480737,-0.11210607966681395L-0.33857792286700894,-0.1121889121487573" + "L-0.3383866116636664,-0.11228834570924921L-0.33842087635680235,-0.11246078673250548" + "L-0.33809536177201055,-0.11245415228342878L-0.33797257995493996,-0.11216571641452182" + "L-0.33802112160354925,-0.11201996164188659L-0.33819815585141844,-0.11218559834671019Z"; + test_tiny_path_convexity(reporter, originalFiddleData, 280081.4116670522f, 93268.04618493588f, + 826357.3384828606f); +} + +static void test_crbug_495894(skiatest::Reporter* reporter) { + const char originalFiddleData[] = + "M-0.34004273849857214,-0.11332803232216355L-0.34008271397389744,-0.11324483772714951" + "L-0.3401940742265893,-0.11324483772714951L-0.34017694188002134,-0.11329807920275889" + "L-0.3402026403998733,-0.11333468903941245L-0.34029972369709194,-0.11334134592705701" + "L-0.3403054344792813,-0.11344121970007795L-0.3403140006525653,-0.11351115418399343" + "L-0.34024261587519866,-0.11353446986281181L-0.3402197727464413,-0.11360442946144192" + "L-0.34013696640469604,-0.11359110237029302L-0.34009128014718143,-0.1135877707043939" + "L-0.3400598708451401,-0.11360776134112742L-0.34004273849857214,-0.11355112520064405" + "L-0.3400113291965308,-0.11355112520064405L-0.3399970522410575,-0.11359110237029302" + "L-0.33997135372120546,-0.11355112520064405L-0.3399627875479215,-0.11353780084493197" + "L-0.3399485105924481,-0.11350782354357004L-0.3400027630232468,-0.11346452910331437" + "L-0.3399485105924481,-0.11340126558629839L-0.33993994441916414,-0.11340126558629839" + "L-0.33988283659727087,-0.11331804756574679L-0.33989140277055485,-0.11324483772714951" + "L-0.33997991989448945,-0.11324483772714951L-0.3399856306766788,-0.11324483772714951" + "L-0.34002560615200417,-0.11334467443478255ZM-0.3400684370184241,-0.11338461985124307" + "L-0.340154098751264,-0.11341791238732665L-0.340162664924548,-0.1134378899559977" + "L-0.34017979727111597,-0.11340126558629839L-0.3401655203156427,-0.11338129083212668" + "L-0.34012268944922275,-0.11332137577529414L-0.34007414780061346,-0.11334467443478255Z" + "M-0.3400027630232468,-0.11290567901106024L-0.3400113291965308,-0.11298876531245433" + "L-0.33997991989448945,-0.11301535852306784L-0.33990282433493346,-0.11296217481488612" + "L-0.33993994441916414,-0.11288906492739594Z"; + test_tiny_path_convexity(reporter, originalFiddleData, 22682.240000000005f,7819.72220766405f, + 65536); +} + static void test_addrect(skiatest::Reporter* reporter) { SkPath path; path.lineTo(0, 0); @@ -3758,6 +3820,8 @@ DEF_TEST(Paths, reporter) { test_tricky_cubic(); test_clipped_cubic(); test_crbug_170666(); + test_crbug_493450(reporter); + test_crbug_495894(reporter); test_bad_cubic_crbug229478(); test_bad_cubic_crbug234190(); test_gen_id(reporter); |