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);
}