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
This commit is contained in:
reed@google.com 2011-05-16 14:16:04 +00:00
parent 27a4dc4c36
commit b54455e440
3 changed files with 50 additions and 41 deletions

View File

@ -88,9 +88,10 @@ public:
/** 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 @@ public:
};
/**
* 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 @@ public:
* 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 @@ private:
mutable SkRect fBounds;
mutable uint8_t fBoundsIsDirty;
uint8_t fFillType;
uint8_t fConvexity;
mutable uint8_t fConvexity;
#ifdef ANDROID
uint32_t fGenerationID;
#endif

View File

@ -254,6 +254,12 @@ void SkPath::setConvexity(Convexity c) {
//////////////////////////////////////////////////////////////////////////////
// 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 @@ void SkPath::moveTo(SkScalar x, SkScalar y) {
pt->set(x, y);
GEN_ID_INC;
fBoundsIsDirty = true;
DIRTY_AFTER_EDIT;
}
void SkPath::rMoveTo(SkScalar x, SkScalar y) {
@ -298,7 +304,7 @@ void SkPath::lineTo(SkScalar x, SkScalar y) {
*fVerbs.append() = kLine_Verb;
GEN_ID_INC;
fBoundsIsDirty = true;
DIRTY_AFTER_EDIT;
}
void SkPath::rLineTo(SkScalar x, SkScalar y) {
@ -321,7 +327,7 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
*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 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
*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 @@ void SkPath::unflatten(SkReader32& buffer) {
buffer.read(fVerbs.begin(), fVerbs.count());
GEN_ID_INC;
fBoundsIsDirty = true;
DIRTY_AFTER_EDIT;
SkDEBUGCODE(this->validate();)
}
@ -1410,7 +1416,7 @@ static int CrossProductSign(const SkVector& a, const SkVector& b) {
// 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 @@ private:
if (0 == fSign) {
fSign = sign;
} else if (sign) {
if (fSign == sign) {
fConvexity = SkPath::kConvex_Convexity;
} else {
if (fSign != sign) {
fConvexity = SkPath::kConcave_Convexity;
}
}

View File

@ -13,15 +13,13 @@ static void test_convexity2(skiatest::Reporter* reporter) {
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 setFromString(SkPath* path, const char str[]) {
}
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 @@ static void test_convexity(skiatest::Reporter* reporter) {
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 @@ void TestPath(skiatest::Reporter* reporter) {
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 @@ void TestPath(skiatest::Reporter* reporter) {
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 @@ void TestPath(skiatest::Reporter* reporter) {
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);
}