automatically inject a moveTo if we see a close followed by a line/quad/cubic
git-svn-id: http://skia.googlecode.com/svn/trunk@3027 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 859486c..ec79a49 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -740,6 +740,7 @@
SkTDArray<SkPoint> fPts;
SkTDArray<uint8_t> fVerbs;
mutable SkRect fBounds;
+ int fLastMoveToIndex;
uint8_t fFillType;
uint8_t fSegmentMask;
mutable uint8_t fBoundsIsDirty;
@@ -767,6 +768,14 @@
*/
void reversePathTo(const SkPath&);
+ // called before we add points for lineTo, quadTo, cubicTo, checking to see
+ // if we need to inject a leading moveTo first
+ //
+ // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0)
+ // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
+ //
+ inline void injectMoveToIfNeeded();
+
friend const SkPoint* sk_get_path_points(const SkPath&, int index);
friend class SkAutoPathBoundsUpdate;
};
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index c99db4c..11e0079 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -101,11 +101,15 @@
////////////////////////////////////////////////////////////////////////////
+// flag to require a moveTo if we begin with something else, like lineTo etc.
+#define INITIAL_LASTMOVETOINDEX_VALUE ~0
+
SkPath::SkPath()
: fFillType(kWinding_FillType)
, fBoundsIsDirty(true) {
fConvexity = kUnknown_Convexity;
fSegmentMask = 0;
+ fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
#ifdef SK_BUILD_FOR_ANDROID
fGenerationID = 0;
#endif
@@ -135,6 +139,7 @@
fBoundsIsDirty = src.fBoundsIsDirty;
fConvexity = src.fConvexity;
fSegmentMask = src.fSegmentMask;
+ fLastMoveToIndex = src.fLastMoveToIndex;
GEN_ID_INC;
}
SkDEBUGCODE(this->validate();)
@@ -165,6 +170,7 @@
SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
SkTSwap<uint8_t>(fConvexity, other.fConvexity);
SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
+ SkTSwap<int>(fLastMoveToIndex, other.fLastMoveToIndex);
GEN_ID_INC;
}
}
@@ -184,6 +190,7 @@
fBoundsIsDirty = true;
fConvexity = kUnknown_Convexity;
fSegmentMask = 0;
+ fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
}
void SkPath::rewind() {
@@ -195,6 +202,7 @@
fConvexity = kUnknown_Convexity;
fBoundsIsDirty = true;
fSegmentMask = 0;
+ fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
}
bool SkPath::isEmpty() const {
@@ -410,6 +418,9 @@
int vc = fVerbs.count();
SkPoint* pt;
+ // remember our index
+ fLastMoveToIndex = fPts.count();
+
#ifdef SK_OLD_EMPTY_PATH_BEHAVIOR
if (vc > 0 && fVerbs[vc - 1] == kMove_Verb) {
pt = &fPts[fPts.count() - 1];
@@ -433,13 +444,25 @@
this->moveTo(pt.fX + x, pt.fY + y);
}
+void SkPath::injectMoveToIfNeeded() {
+ if (fLastMoveToIndex < 0) {
+ SkScalar x, y;
+ if (fVerbs.count() == 0) {
+ x = y = 0;
+ } else {
+ const SkPoint& pt = fPts[~fLastMoveToIndex];
+ x = pt.fX;
+ y = pt.fY;
+ }
+ this->moveTo(x, y);
+ }
+}
+
void SkPath::lineTo(SkScalar x, SkScalar y) {
SkDEBUGCODE(this->validate();)
- if (fVerbs.count() == 0) {
- fPts.append()->set(0, 0);
- *fVerbs.append() = kMove_Verb;
- }
+ this->injectMoveToIfNeeded();
+
fPts.append()->set(x, y);
*fVerbs.append() = kLine_Verb;
fSegmentMask |= kLine_SegmentMask;
@@ -457,10 +480,7 @@
void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
SkDEBUGCODE(this->validate();)
- if (fVerbs.count() == 0) {
- fPts.append()->set(0, 0);
- *fVerbs.append() = kMove_Verb;
- }
+ this->injectMoveToIfNeeded();
SkPoint* pts = fPts.append(2);
pts[0].set(x1, y1);
@@ -482,10 +502,8 @@
SkScalar x3, SkScalar y3) {
SkDEBUGCODE(this->validate();)
- if (fVerbs.count() == 0) {
- fPts.append()->set(0, 0);
- *fVerbs.append() = kMove_Verb;
- }
+ this->injectMoveToIfNeeded();
+
SkPoint* pts = fPts.append(3);
pts[0].set(x1, y1);
pts[1].set(x2, y2);
@@ -525,6 +543,15 @@
break;
}
}
+
+ // signal that we need a moveTo to follow us (unless we're done)
+#if 0
+ if (fLastMoveToIndex >= 0) {
+ fLastMoveToIndex = ~fLastMoveToIndex;
+ }
+#else
+ fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
+#endif
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index fadb0d9..9298d53 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -889,12 +889,14 @@
// Max of 10 segments, max 3 points per segment
SkRandom rand(9876543);
SkPoint expectedPts[31]; // May have leading moveTo
- SkPath::Verb expectedVerbs[11]; // May have leading moveTo
+ SkPath::Verb expectedVerbs[22]; // May have leading moveTo
SkPath::Verb nextVerb;
+
for (int i = 0; i < 500; ++i) {
p.reset();
bool lastWasClose = true;
bool haveMoveTo = false;
+ SkPoint lastMoveToPt = { 0, 0 };
int numPoints = 0;
int numVerbs = (rand.nextU() >> 16) % 10;
int numIterVerbs = 0;
@@ -907,13 +909,14 @@
case SkPath::kMove_Verb:
expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
p.moveTo(expectedPts[numPoints]);
+ lastMoveToPt = expectedPts[numPoints];
numPoints += 1;
lastWasClose = false;
haveMoveTo = true;
break;
case SkPath::kLine_Verb:
if (!haveMoveTo) {
- expectedPts[numPoints++].set(0, 0);
+ expectedPts[numPoints++] = lastMoveToPt;
expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
haveMoveTo = true;
}
@@ -924,7 +927,7 @@
break;
case SkPath::kQuad_Verb:
if (!haveMoveTo) {
- expectedPts[numPoints++].set(0, 0);
+ expectedPts[numPoints++] = lastMoveToPt;
expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
haveMoveTo = true;
}
@@ -936,7 +939,7 @@
break;
case SkPath::kCubic_Verb:
if (!haveMoveTo) {
- expectedPts[numPoints++].set(0, 0);
+ expectedPts[numPoints++] = lastMoveToPt;
expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
haveMoveTo = true;
}
@@ -950,6 +953,7 @@
break;
case SkPath::kClose_Verb:
p.close();
+ haveMoveTo = false;
lastWasClose = true;
break;
default:;