treat backwards quads as not convex
authorcaryclark <caryclark@google.com>
Mon, 2 Mar 2015 18:07:56 +0000 (10:07 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 2 Mar 2015 18:07:56 +0000 (10:07 -0800)
If a quad, cubic, or conic goes back on itself, assume it's not convex.
In a future CL, we could check to see if the curve is linear so that
linear curves are treated the same as lines.

BUG=skia:3469

Review URL: https://codereview.chromium.org/971773002

src/core/SkPath.cpp
tests/PathTest.cpp

index 2babe70..738edd9 100644 (file)
@@ -2129,7 +2129,8 @@ struct Convexicator {
     : fPtCount(0)
     , fConvexity(SkPath::kConvex_Convexity)
     , fDirection(SkPath::kUnknown_Direction)
-    , fIsFinite(true) {
+    , fIsFinite(true)
+    , fIsCurve(false) {
         fExpectedDir = kInvalid_DirChange;
         // warnings
         fLastPt.set(0, 0);
@@ -2193,6 +2194,10 @@ struct Convexicator {
         return fIsFinite;
     }
 
+    void setCurve(bool isCurve) {
+        fIsCurve = isCurve;
+    }
+
 private:
     void addVec(const SkVector& vec) {
         SkASSERT(vec.fX || vec.fY);
@@ -2213,6 +2218,10 @@ private:
             case kStraight_DirChange:
                 break;
             case kBackwards_DirChange:
+                if (fIsCurve) {
+                    fConvexity = SkPath::kConcave_Convexity;
+                    fDirection = SkPath::kUnknown_Direction;
+                }
                 fLastVec = vec;
                 break;
             case kInvalid_DirChange:
@@ -2232,6 +2241,7 @@ private:
     SkPath::Direction   fDirection;
     int                 fDx, fDy, fSx, fSy;
     bool                fIsFinite;
+    bool                fIsCurve;
 };
 
 SkPath::Convexity SkPath::internalGetConvexity() const {
@@ -2255,13 +2265,23 @@ SkPath::Convexity SkPath::internalGetConvexity() const {
                     return kConcave_Convexity;
                 }
                 pts[1] = pts[0];
+                // fall through
+            case kLine_Verb:
                 count = 1;
+                state.setCurve(false);
+                break;
+            case kQuad_Verb:
+                // fall through
+            case kConic_Verb:
+                // fall through
+            case kCubic_Verb:
+                count = 2 + (kCubic_Verb == verb);
+                // As an additional enhancement, this could set curve true only
+                // if the curve is nonlinear
+                state.setCurve(true);
                 break;
-            case kLine_Verb: count = 1; break;
-            case kQuad_Verb: count = 2; break;
-            case kConic_Verb: count = 2; break;
-            case kCubic_Verb: count = 3; break;
             case kClose_Verb:
+                state.setCurve(false);
                 state.close();
                 count = 0;
                 break;
index a868d93..aeab7e6 100644 (file)
@@ -38,6 +38,14 @@ static void test_add_rrect(skiatest::Reporter* reporter, const SkRect& bounds,
     REPORTER_ASSERT(reporter, bounds == path.getBounds());
 }
 
+static void test_skbug_3469(skiatest::Reporter* reporter) {
+    SkPath path;
+    path.moveTo(20, 20);
+    path.quadTo(20, 50, 80, 50);
+    path.quadTo(20, 50, 20, 80);
+    REPORTER_ASSERT(reporter, !path.isConvex());
+}
+
 static void test_skbug_3239(skiatest::Reporter* reporter) {
     const float min = SkBits2Float(0xcb7f16c8); /* -16717512.000000 */
     const float max = SkBits2Float(0x4b7f1c1d); /*  16718877.000000 */
@@ -3732,5 +3740,6 @@ DEF_TEST(Paths, reporter) {
     PathRefTest_Private::TestPathRef(reporter);
     test_dump(reporter);
     test_path_crbugskia2820(reporter);
+    test_skbug_3469(reporter);
     test_skbug_3239(reporter);
 }