Change getConvexity() to now compute it if the value is set to kUnkown.
Change behavior for degenerate paths: now those return kConvex instead of kUnknown



git-svn-id: http://skia.googlecode.com/svn/trunk@1330 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 18dcd11..7120d3f 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -88,9 +88,10 @@
     /** Returns true if the filltype is one of the Inverse variants */
     bool isInverseFillType() const { return (fFillType & 2) != 0; }
 
-    /** Toggle between inverse and normal filltypes. This reverse the return
-        value of isInverseFillType()
-    */
+    /**
+     *  Toggle between inverse and normal filltypes. This reverse the return
+     *  value of isInverseFillType()
+     */
     void toggleInverseFillType() {
         fFillType ^= 2;
         GEN_ID_INC;
@@ -103,14 +104,33 @@
     };
 
     /**
-     *  Return the path's convexity, as stored in the path.
+     *  Return the path's convexity, as stored in the path. If it is currently
+     *  unknown, and the computeIfUnknown bool is true, then this will first
+     *  call ComputeConvexity() and then return that (cached) value.
      */
-    Convexity getConvexity() const { return (Convexity)fConvexity; }
+    Convexity getConvexity() const {
+        if (kUnknown_Convexity == fConvexity) {
+            fConvexity = (uint8_t)ComputeConvexity(*this);
+        }
+        return (Convexity)fConvexity;
+    }
+
+    /**
+     *  Return the currently cached value for convexity, even if that is set to
+     *  kUnknown_Convexity. Note: getConvexity() will automatically call
+     *  ComputeConvexity and cache its return value if the current setting is
+     *  kUnknown.
+     */
+    Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; }
 
     /**
      *  Store a convexity setting in the path. There is no automatic check to
      *  see if this value actually agress with the return value from
      *  ComputeConvexity().
+     *
+     *  Note: even if this is set to a "known" value, if the path is later
+     *  changed (e.g. lineTo(), addRect(), etc.) then the cached value will be
+     *  reset to kUnknown_Convexity.
      */
     void setConvexity(Convexity);
 
@@ -118,9 +138,11 @@
      *  Compute the convexity of the specified path. This does not look at the
      *  value stored in the path, but computes it directly from the path's data.
      *
+     *  This never returns kUnknown_Convexity.
+     *
      *  If there is more than one contour, this returns kConcave_Convexity.
-     *  If the contour is degenerate (i.e. all segements are colinear,
-     *  then this returns kUnknown_Convexity.
+     *  If the contour is degenerate (e.g. there are fewer than 3 non-degenerate
+     *  segments), then this returns kConvex_Convexity.
      *  The contour is treated as if it were closed, even if there is no kClose
      *  verb.
      */
@@ -635,7 +657,7 @@
     mutable SkRect      fBounds;
     mutable uint8_t     fBoundsIsDirty;
     uint8_t             fFillType;
-    uint8_t             fConvexity;
+    mutable uint8_t     fConvexity;
 #ifdef ANDROID
     uint32_t            fGenerationID;
 #endif
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 68eb35d..ca57237 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -254,6 +254,12 @@
 //////////////////////////////////////////////////////////////////////////////
 //  Construction methods
 
+#define DIRTY_AFTER_EDIT                \
+    do {                                \
+        fBoundsIsDirty = true;          \
+        fConvexity = kUnknown_Convexity;\
+    } while (0)
+
 void SkPath::incReserve(U16CPU inc) {
     SkDEBUGCODE(this->validate();)
 
@@ -278,7 +284,7 @@
     pt->set(x, y);
 
     GEN_ID_INC;
-    fBoundsIsDirty = true;
+    DIRTY_AFTER_EDIT;
 }
 
 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
@@ -298,7 +304,7 @@
     *fVerbs.append() = kLine_Verb;
 
     GEN_ID_INC;
-    fBoundsIsDirty = true;
+    DIRTY_AFTER_EDIT;
 }
 
 void SkPath::rLineTo(SkScalar x, SkScalar y) {
@@ -321,7 +327,7 @@
     *fVerbs.append() = kQuad_Verb;
 
     GEN_ID_INC;
-    fBoundsIsDirty = true;
+    DIRTY_AFTER_EDIT;
 }
 
 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
@@ -345,7 +351,7 @@
     *fVerbs.append() = kCubic_Verb;
 
     GEN_ID_INC;
-    fBoundsIsDirty = true;
+    DIRTY_AFTER_EDIT;
 }
 
 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
@@ -1293,7 +1299,7 @@
     buffer.read(fVerbs.begin(), fVerbs.count());
 
     GEN_ID_INC;
-    fBoundsIsDirty = true;
+    DIRTY_AFTER_EDIT;
 
     SkDEBUGCODE(this->validate();)
 }
@@ -1410,7 +1416,7 @@
 
 // only valid for a single contour
 struct Convexicator {
-    Convexicator() : fPtCount(0), fConvexity(SkPath::kUnknown_Convexity) {
+    Convexicator() : fPtCount(0), fConvexity(SkPath::kConvex_Convexity) {
         fSign = 0;
         // warnings
         fCurrPt.set(0, 0);
@@ -1472,9 +1478,7 @@
         if (0 == fSign) {
             fSign = sign;
         } else if (sign) {
-            if (fSign == sign) {
-                fConvexity = SkPath::kConvex_Convexity;
-            } else {
+            if (fSign != sign) {
                 fConvexity = SkPath::kConcave_Convexity;
             }
         }
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 3884308..a20e431 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -13,15 +13,13 @@
     SkPath pt;
     pt.moveTo(0, 0);
     pt.close();
-//    check_convexity(reporter, pt, SkPath::kConvex_Convexity);
-    check_convexity(reporter, pt, SkPath::kUnknown_Convexity);
+    check_convexity(reporter, pt, SkPath::kConvex_Convexity);
     
     SkPath line;
     line.moveTo(12, 20);
     line.lineTo(-12, -20);
     line.close();
-    //    check_convexity(reporter, pt, SkPath::kConvex_Convexity);
-    check_convexity(reporter, pt, SkPath::kUnknown_Convexity);
+    check_convexity(reporter, pt, SkPath::kConvex_Convexity);
     
     SkPath triLeft;
     triLeft.moveTo(0, 0);
@@ -133,13 +131,12 @@
 }
 
 static void test_convexity(skiatest::Reporter* reporter) {
-    static const SkPath::Convexity U = SkPath::kUnknown_Convexity;
     static const SkPath::Convexity C = SkPath::kConcave_Convexity;
     static const SkPath::Convexity V = SkPath::kConvex_Convexity;
 
     SkPath path;
 
-    REPORTER_ASSERT(reporter, U == SkPath::ComputeConvexity(path));
+    REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
     path.addCircle(0, 0, 10);
     REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
     path.addCircle(0, 0, 10);   // 2nd circle
@@ -155,8 +152,9 @@
         const char*         fPathStr;
         SkPath::Convexity   fExpectedConvexity;
     } gRec[] = {
-        { "0 0", SkPath::kUnknown_Convexity },
-        { "0 0 10 10", SkPath::kUnknown_Convexity },
+        { "", SkPath::kConvex_Convexity },
+        { "0 0", SkPath::kConvex_Convexity },
+        { "0 0 10 10", SkPath::kConvex_Convexity },
         { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity },
         { "0 0 10 10 10 20", SkPath::kConvex_Convexity },
         { "0 0 10 10 10 0", SkPath::kConvex_Convexity },
@@ -188,7 +186,7 @@
     SkRect  bounds, bounds2;
 
     REPORTER_ASSERT(reporter, p.isEmpty());
-    REPORTER_ASSERT(reporter, !p.isConvex());
+    REPORTER_ASSERT(reporter, p.isConvex());
     REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
     REPORTER_ASSERT(reporter, !p.isInverseFillType());
     REPORTER_ASSERT(reporter, p == p2);
@@ -198,17 +196,14 @@
 
     bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
 
-    p.setIsConvex(false);
     p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
     check_convex_bounds(reporter, p, bounds);
 
     p.reset();
-    p.setIsConvex(false);
     p.addOval(bounds);
     check_convex_bounds(reporter, p, bounds);
 
     p.reset();
-    p.setIsConvex(false);
     p.addRect(bounds);
     check_convex_bounds(reporter, p, bounds);
 
@@ -245,18 +240,6 @@
     p.getLastPt(&pt);
     REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
 
-    // check that reset and rewind clear the convex hint back to false
-    p.setIsConvex(false);
-    REPORTER_ASSERT(reporter, !p.isConvex());
-    p.setIsConvex(true);
-    REPORTER_ASSERT(reporter, p.isConvex());
-    p.reset();
-    REPORTER_ASSERT(reporter, !p.isConvex());
-    p.setIsConvex(true);
-    REPORTER_ASSERT(reporter, p.isConvex());
-    p.rewind();
-    REPORTER_ASSERT(reporter, !p.isConvex());
-
     test_convexity(reporter);
     test_convexity2(reporter);
 }