aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkPath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkPath.cpp')
-rw-r--r--src/core/SkPath.cpp367
1 files changed, 206 insertions, 161 deletions
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index c6e349bd95..00d3772b57 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -10,6 +10,8 @@
#include "SkPath.h"
#include "SkBuffer.h"
#include "SkMath.h"
+#include "SkPathRef.h"
+#include "SkThread.h"
SK_DEFINE_INST_COUNT(SkPath);
@@ -109,13 +111,13 @@ private:
};
// Return true if the computed bounds are finite.
-static bool compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
- int count = pts.count();
+static bool compute_pt_bounds(SkRect* bounds, const SkPathRef& ref) {
+ int count = ref.countPoints();
if (count <= 1) { // we ignore just 1 point (moveto)
bounds->setEmpty();
- return count ? pts.begin()->isFinite() : true;
+ return count ? ref.points()->isFinite() : true;
} else {
- return bounds->setBoundsCheck(pts.begin(), pts.count());
+ return bounds->setBoundsCheck(ref.points(), count);
}
}
@@ -139,7 +141,8 @@ static bool compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
#define INITIAL_LASTMOVETOINDEX_VALUE ~0
SkPath::SkPath()
- : fFillType(kWinding_FillType)
+ : fPathRef(SkPathRef::CreateEmpty())
+ , fFillType(kWinding_FillType)
, fBoundsIsDirty(true) {
fConvexity = kUnknown_Convexity;
fSegmentMask = 0;
@@ -154,9 +157,17 @@ SkPath::SkPath()
SkPath::SkPath(const SkPath& src) {
SkDEBUGCODE(src.validate();)
- *this = src;
+ src.fPathRef.get()->ref();
+ fPathRef.reset(src.fPathRef.get());
+ fBounds = src.fBounds;
+ fFillType = src.fFillType;
+ fBoundsIsDirty = src.fBoundsIsDirty;
+ fConvexity = src.fConvexity;
+ fIsFinite = src.fIsFinite;
+ fSegmentMask = src.fSegmentMask;
+ fLastMoveToIndex = src.fLastMoveToIndex;
+ fIsOval = src.fIsOval;
#ifdef SK_BUILD_FOR_ANDROID
- // the assignment operator above increments the ID so correct for that here
fGenerationID = src.fGenerationID;
fSourcePath = NULL;
#endif
@@ -170,9 +181,9 @@ SkPath& SkPath::operator=(const SkPath& src) {
SkDEBUGCODE(src.validate();)
if (this != &src) {
+ src.fPathRef.get()->ref();
+ fPathRef.reset(src.fPathRef.get());
fBounds = src.fBounds;
- fPts = src.fPts;
- fVerbs = src.fVerbs;
fFillType = src.fFillType;
fBoundsIsDirty = src.fBoundsIsDirty;
fConvexity = src.fConvexity;
@@ -196,7 +207,7 @@ SK_API bool operator==(const SkPath& a, const SkPath& b) {
return &a == &b ||
(a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
- a.fVerbs == b.fVerbs && a.fPts == b.fPts);
+ *a.fPathRef.get() == *b.fPathRef.get());
}
void SkPath::swap(SkPath& other) {
@@ -204,8 +215,7 @@ void SkPath::swap(SkPath& other) {
if (this != &other) {
SkTSwap<SkRect>(fBounds, other.fBounds);
- fPts.swap(other.fPts);
- fVerbs.swap(other.fVerbs);
+ fPathRef.swap(&other.fPathRef);
SkTSwap<uint8_t>(fFillType, other.fFillType);
SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
SkTSwap<uint8_t>(fConvexity, other.fConvexity);
@@ -234,8 +244,7 @@ void SkPath::setSourcePath(const SkPath* path) {
void SkPath::reset() {
SkDEBUGCODE(this->validate();)
- fPts.reset();
- fVerbs.reset();
+ fPathRef.reset(SkPathRef::CreateEmpty());
GEN_ID_INC;
fBoundsIsDirty = true;
fConvexity = kUnknown_Convexity;
@@ -247,8 +256,7 @@ void SkPath::reset() {
void SkPath::rewind() {
SkDEBUGCODE(this->validate();)
- fPts.rewind();
- fVerbs.rewind();
+ SkPathRef::Rewind(&fPathRef);
GEN_ID_INC;
fConvexity = kUnknown_Convexity;
fBoundsIsDirty = true;
@@ -259,18 +267,18 @@ void SkPath::rewind() {
bool SkPath::isEmpty() const {
SkDEBUGCODE(this->validate();)
- return 0 == fVerbs.count();
+ return 0 == fPathRef->countVerbs();
}
bool SkPath::isLine(SkPoint line[2]) const {
- int verbCount = fVerbs.count();
- int ptCount = fPts.count();
+ int verbCount = fPathRef->countVerbs();
+ int ptCount = fPathRef->countVerbs();
if (2 == verbCount && 2 == ptCount) {
- const uint8_t* verbs = fVerbs.begin();
- if (kMove_Verb == verbs[0] && kLine_Verb == verbs[1]) {
+ if (kMove_Verb == fPathRef->atVerb(0) &&
+ kLine_Verb == fPathRef->atVerb(1)) {
if (line) {
- const SkPoint* pts = fPts.begin();
+ const SkPoint* pts = fPathRef->points();
line[0] = pts[0];
line[1] = pts[1];
}
@@ -327,13 +335,13 @@ bool SkPath::isRect(SkRect* rect) const {
int nextDirection = 0;
bool closedOrMoved = false;
bool autoClose = false;
- const uint8_t* verbs = fVerbs.begin();
- const uint8_t* verbStop = fVerbs.end();
- const SkPoint* pts = fPts.begin();
- while (verbs != verbStop) {
- switch (*verbs++) {
+ const SkPoint* pts = fPathRef->points();
+ int verbCnt = fPathRef->countVerbs();
+ int currVerb = 0;
+ while (currVerb < verbCnt) {
+ switch (fPathRef->atVerb(currVerb++)) {
case kClose_Verb:
- pts = fPts.begin();
+ pts = fPathRef->points();
autoClose = true;
case kLine_Verb: {
SkScalar left = last.fX;
@@ -398,39 +406,56 @@ bool SkPath::isRect(SkRect* rect) const {
return result;
}
+int SkPath::countPoints() const {
+ return fPathRef->countPoints();
+}
+
int SkPath::getPoints(SkPoint dst[], int max) const {
SkDEBUGCODE(this->validate();)
SkASSERT(max >= 0);
SkASSERT(!max || dst);
- int count = fPts.count();
- fPts.copyRange(dst, 0, max);
- return count;
+ int count = SkMin32(max, fPathRef->countPoints());
+ memcpy(dst, fPathRef->points(), count * sizeof(SkPoint));
+ return fPathRef->countPoints();
}
SkPoint SkPath::getPoint(int index) const {
- if ((unsigned)index < (unsigned)fPts.count()) {
- return fPts[index];
+ if ((unsigned)index < (unsigned)fPathRef->countPoints()) {
+ return fPathRef->atPoint(index);
}
return SkPoint::Make(0, 0);
}
+int SkPath::countVerbs() const {
+ return fPathRef->countVerbs();
+}
+
+static inline void copy_verbs_reverse(uint8_t* inorderDst,
+ const uint8_t* reversedSrc,
+ int count) {
+ for (int i = 0; i < count; ++i) {
+ inorderDst[i] = reversedSrc[~i];
+ }
+}
+
int SkPath::getVerbs(uint8_t dst[], int max) const {
SkDEBUGCODE(this->validate();)
SkASSERT(max >= 0);
SkASSERT(!max || dst);
- fVerbs.copyRange(dst, 0, max);
- return fVerbs.count();
+ int count = SkMin32(max, fPathRef->countVerbs());
+ copy_verbs_reverse(dst, fPathRef->verbs(), count);
+ return fPathRef->countVerbs();
}
bool SkPath::getLastPt(SkPoint* lastPt) const {
SkDEBUGCODE(this->validate();)
- int count = fPts.count();
+ int count = fPathRef->countPoints();
if (count > 0) {
if (lastPt) {
- *lastPt = fPts[count - 1];
+ *lastPt = fPathRef->atPoint(count - 1);
}
return true;
}
@@ -443,12 +468,13 @@ bool SkPath::getLastPt(SkPoint* lastPt) const {
void SkPath::setLastPt(SkScalar x, SkScalar y) {
SkDEBUGCODE(this->validate();)
- int count = fPts.count();
+ int count = fPathRef->countPoints();
if (count == 0) {
this->moveTo(x, y);
} else {
fIsOval = false;
- fPts[count - 1].set(x, y);
+ SkPathRef::Editor ed(&fPathRef);
+ ed.atPoint(count-1)->set(x, y);
GEN_ID_INC;
}
}
@@ -457,7 +483,7 @@ void SkPath::computeBounds() const {
SkDEBUGCODE(this->validate();)
SkASSERT(fBoundsIsDirty);
- fIsFinite = compute_pt_bounds(&fBounds, fPts);
+ fIsFinite = compute_pt_bounds(&fBounds, *fPathRef.get());
fBoundsIsDirty = false;
}
@@ -485,24 +511,19 @@ void SkPath::setConvexity(Convexity c) {
void SkPath::incReserve(U16CPU inc) {
SkDEBUGCODE(this->validate();)
-
- fVerbs.setReserve(fVerbs.count() + inc);
- fPts.setReserve(fPts.count() + inc);
-
+ SkPathRef::Editor(&fPathRef, inc, inc);
SkDEBUGCODE(this->validate();)
}
void SkPath::moveTo(SkScalar x, SkScalar y) {
SkDEBUGCODE(this->validate();)
- SkPoint* pt;
+ SkPathRef::Editor ed(&fPathRef);
// remember our index
- fLastMoveToIndex = fPts.count();
+ fLastMoveToIndex = ed.pathRef()->countPoints();
- pt = fPts.append();
- *fVerbs.append() = kMove_Verb;
- pt->set(x, y);
+ ed.growForVerb(kMove_Verb)->set(x, y);
GEN_ID_INC;
DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE;
@@ -517,10 +538,10 @@ void SkPath::rMoveTo(SkScalar x, SkScalar y) {
void SkPath::injectMoveToIfNeeded() {
if (fLastMoveToIndex < 0) {
SkScalar x, y;
- if (fVerbs.count() == 0) {
+ if (fPathRef->countVerbs() == 0) {
x = y = 0;
} else {
- const SkPoint& pt = fPts[~fLastMoveToIndex];
+ const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex);
x = pt.fX;
y = pt.fY;
}
@@ -533,8 +554,8 @@ void SkPath::lineTo(SkScalar x, SkScalar y) {
this->injectMoveToIfNeeded();
- fPts.append()->set(x, y);
- *fVerbs.append() = kLine_Verb;
+ SkPathRef::Editor ed(&fPathRef);
+ ed.growForVerb(kLine_Verb)->set(x, y);
fSegmentMask |= kLine_SegmentMask;
GEN_ID_INC;
@@ -552,10 +573,10 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
this->injectMoveToIfNeeded();
- SkPoint* pts = fPts.append(2);
+ SkPathRef::Editor ed(&fPathRef);
+ SkPoint* pts = ed.growForVerb(kQuad_Verb);
pts[0].set(x1, y1);
pts[1].set(x2, y2);
- *fVerbs.append() = kQuad_Verb;
fSegmentMask |= kQuad_SegmentMask;
GEN_ID_INC;
@@ -574,11 +595,11 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
this->injectMoveToIfNeeded();
- SkPoint* pts = fPts.append(3);
+ SkPathRef::Editor ed(&fPathRef);
+ SkPoint* pts = ed.growForVerb(kCubic_Verb);
pts[0].set(x1, y1);
pts[1].set(x2, y2);
pts[2].set(x3, y3);
- *fVerbs.append() = kCubic_Verb;
fSegmentMask |= kCubic_SegmentMask;
GEN_ID_INC;
@@ -596,16 +617,18 @@ void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
void SkPath::close() {
SkDEBUGCODE(this->validate();)
- int count = fVerbs.count();
+ int count = fPathRef->countVerbs();
if (count > 0) {
- switch (fVerbs[count - 1]) {
+ switch (fPathRef->atVerb(count - 1)) {
case kLine_Verb:
case kQuad_Verb:
case kCubic_Verb:
- case kMove_Verb:
- *fVerbs.append() = kClose_Verb;
+ case kMove_Verb: {
+ SkPathRef::Editor ed(&fPathRef);
+ ed.growForVerb(kClose_Verb);
GEN_ID_INC;
break;
+ }
default:
// don't add a close if it's the first verb or a repeat
break;
@@ -653,31 +676,34 @@ void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
return;
}
- fLastMoveToIndex = fPts.count();
- fPts.append(count, pts);
-
+ SkPathRef::Editor ed(&fPathRef);
+ fLastMoveToIndex = ed.pathRef()->countPoints();
+ uint8_t* vb;
+ SkPoint* p;
// +close makes room for the extra kClose_Verb
- uint8_t* vb = fVerbs.append(count + close);
- vb[0] = kMove_Verb;
+ ed.grow(count + close, count, &vb, &p);
+ memcpy(p, pts, count * sizeof(SkPoint));
+ vb[~0] = kMove_Verb;
if (count > 1) {
// cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
// be 0, the compiler will remove the test/branch entirely.
if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
- memset(&vb[1], kLine_Verb, count - 1);
+ memset(vb - count, kLine_Verb, count - 1);
} else {
for (int i = 1; i < count; ++i) {
- vb[i] = kLine_Verb;
+ vb[~i] = kLine_Verb;
}
}
fSegmentMask |= kLine_SegmentMask;
}
if (close) {
- vb[count] = kClose_Verb;
+ vb[~count] = kClose_Verb;
}
GEN_ID_INC;
DIRTY_AFTER_EDIT;
+ SkDEBUGCODE(this->validate();)
}
#define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
@@ -823,9 +849,9 @@ void SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[],
}
bool SkPath::hasOnlyMoveTos() const {
- const uint8_t* verbs = fVerbs.begin();
- const uint8_t* verbStop = fVerbs.end();
- while (verbs != verbStop) {
+ int count = fPathRef->countVerbs();
+ const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin();
+ for (int i = 0; i < count; ++i) {
if (*verbs == kLine_Verb ||
*verbs == kQuad_Verb ||
*verbs == kCubic_Verb) {
@@ -991,7 +1017,7 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
int count = build_arc_points(oval, startAngle, sweepAngle, pts);
SkASSERT((count & 1) == 1);
- if (fVerbs.count() == 0) {
+ if (fPathRef->countVerbs() == 0) {
forceMoveTo = true;
}
this->incReserve(count);
@@ -1103,7 +1129,7 @@ void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
}
void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
- this->incReserve(path.fPts.count());
+ SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
fIsOval = false;
@@ -1153,21 +1179,23 @@ static const uint8_t gPtsInVerb[] = {
// ignore the initial moveto, and stop when the 1st contour ends
void SkPath::pathTo(const SkPath& path) {
- int i, vcount = path.fVerbs.count();
- if (vcount == 0) {
+ int i, vcount = path.fPathRef->countVerbs();
+ // exit early if the path is empty, or just has a moveTo.
+ if (vcount < 2) {
return;
}
- this->incReserve(vcount);
+ SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
fIsOval = false;
- const uint8_t* verbs = path.fVerbs.begin();
- const SkPoint* pts = path.fPts.begin() + 1; // 1 for the initial moveTo
+ const uint8_t* verbs = path.fPathRef->verbs();
+ // skip the initial moveTo
+ const SkPoint* pts = path.fPathRef->points() + 1;
- SkASSERT(verbs[0] == kMove_Verb);
+ SkASSERT(verbs[~0] == kMove_Verb);
for (i = 1; i < vcount; i++) {
- switch (verbs[i]) {
+ switch (verbs[~i]) {
case kLine_Verb:
this->lineTo(pts[0].fX, pts[0].fY);
break;
@@ -1175,33 +1203,33 @@ void SkPath::pathTo(const SkPath& path) {
this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
break;
case kCubic_Verb:
- this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY,
- pts[2].fX, pts[2].fY);
+ this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
break;
case kClose_Verb:
return;
}
- pts += gPtsInVerb[verbs[i]];
+ pts += gPtsInVerb[verbs[~i]];
}
}
// ignore the last point of the 1st contour
void SkPath::reversePathTo(const SkPath& path) {
- int i, vcount = path.fVerbs.count();
- if (vcount == 0) {
+ int i, vcount = path.fPathRef->countVerbs();
+ // exit early if the path is empty, or just has a moveTo.
+ if (vcount < 2) {
return;
}
- this->incReserve(vcount);
+ SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
fIsOval = false;
- const uint8_t* verbs = path.fVerbs.begin();
- const SkPoint* pts = path.fPts.begin();
+ const uint8_t* verbs = path.fPathRef->verbs();
+ const SkPoint* pts = path.fPathRef->points();
- SkASSERT(verbs[0] == kMove_Verb);
- for (i = 1; i < vcount; i++) {
- int n = gPtsInVerb[verbs[i]];
+ SkASSERT(verbs[~0] == kMove_Verb);
+ for (i = 1; i < vcount; ++i) {
+ int n = gPtsInVerb[verbs[~i]];
if (n == 0) {
break;
}
@@ -1209,7 +1237,7 @@ void SkPath::reversePathTo(const SkPath& path) {
}
while (--i > 0) {
- switch (verbs[i]) {
+ switch (verbs[~i]) {
case kLine_Verb:
this->lineTo(pts[-1].fX, pts[-1].fY);
break;
@@ -1224,23 +1252,24 @@ void SkPath::reversePathTo(const SkPath& path) {
SkDEBUGFAIL("bad verb");
break;
}
- pts -= gPtsInVerb[verbs[i]];
+ pts -= gPtsInVerb[verbs[~i]];
}
}
void SkPath::reverseAddPath(const SkPath& src) {
- this->incReserve(src.fPts.count());
+ SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs());
- const SkPoint* pts = src.fPts.end();
- const uint8_t* startVerbs = src.fVerbs.begin();
- const uint8_t* verbs = src.fVerbs.end();
+ const SkPoint* pts = src.fPathRef->pointsEnd();
+ // we will iterator through src's verbs backwards
+ const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
+ const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb
fIsOval = false;
bool needMove = true;
bool needClose = false;
- while (verbs > startVerbs) {
- uint8_t v = *--verbs;
+ while (verbs < verbsEnd) {
+ uint8_t v = *(verbs++);
int n = gPtsInVerb[v];
if (needMove) {
@@ -1351,7 +1380,8 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
}
dst->swap(tmp);
- matrix.mapPoints(dst->fPts.begin(), dst->fPts.count());
+ SkPathRef::Editor ed(&dst->fPathRef);
+ matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
} else {
/*
* If we're not in perspective, we can transform all of the points at
@@ -1366,7 +1396,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
* if it is non-finite. In those cases bounds need to stay empty,
* regardless of the matrix.
*/
- if (!fBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) {
+ if (!fBoundsIsDirty && matrix.rectStaysRect() && fPathRef->countPoints() > 1) {
dst->fBoundsIsDirty = false;
if (fIsFinite) {
matrix.mapRect(&dst->fBounds, fBounds);
@@ -1382,21 +1412,16 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
dst->fBoundsIsDirty = true;
}
+ SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix);
+
if (this != dst) {
- dst->fVerbs = fVerbs;
- dst->fPts.setCount(fPts.count());
dst->fFillType = fFillType;
dst->fSegmentMask = fSegmentMask;
dst->fConvexity = fConvexity;
- dst->fIsOval = fIsOval;
}
- matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
-
- if (fIsOval) {
- // It's an oval only if it stays a rect.
- dst->fIsOval = matrix.rectStaysRect();
- }
+ // It's an oval only if it stays a rect.
+ dst->fIsOval = fIsOval && matrix.rectStaysRect();
SkDEBUGCODE(dst->validate();)
}
@@ -1432,9 +1457,9 @@ SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
}
void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
- fPts = path.fPts.begin();
- fVerbs = path.fVerbs.begin();
- fVerbStop = path.fVerbs.end();
+ fPts = path.fPathRef->points();
+ fVerbs = path.fPathRef->verbs();
+ fVerbStop = path.fPathRef->verbsMemBegin();
fLastPt.fX = fLastPt.fY = 0;
fMoveTo.fX = fMoveTo.fY = 0;
fForceClose = SkToU8(forceClose);
@@ -1453,12 +1478,13 @@ bool SkPath::Iter::isClosedContour() const {
const uint8_t* verbs = fVerbs;
const uint8_t* stop = fVerbStop;
- if (kMove_Verb == *verbs) {
- verbs += 1; // skip the initial moveto
+ if (kMove_Verb == *(verbs - 1)) {
+ verbs -= 1; // skip the initial moveto
}
- while (verbs < stop) {
- unsigned v = *verbs++;
+ while (verbs > stop) {
+ // verbs points one beyond the current verb, decrement first.
+ unsigned v = *(--verbs);
if (kMove_Verb == v) {
break;
}
@@ -1510,14 +1536,14 @@ void SkPath::Iter::consumeDegenerateSegments() {
const SkPoint* lastMovePt = 0;
SkPoint lastPt = fLastPt;
while (fVerbs != fVerbStop) {
- unsigned verb = *fVerbs;
+ unsigned verb = *(fVerbs - 1); // fVerbs is one beyond the current verb
switch (verb) {
case kMove_Verb:
// Keep a record of this most recent move
lastMoveVerb = fVerbs;
lastMovePt = fPts;
lastPt = fPts[0];
- fVerbs++;
+ fVerbs--;
fPts++;
break;
@@ -1528,7 +1554,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
return;
}
// A close at any other time must be ignored
- fVerbs++;
+ fVerbs--;
break;
case kLine_Verb:
@@ -1541,7 +1567,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
return;
}
// Ignore this line and continue
- fVerbs++;
+ fVerbs--;
fPts++;
break;
@@ -1555,7 +1581,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
return;
}
// Ignore this line and continue
- fVerbs++;
+ fVerbs--;
fPts += 2;
break;
@@ -1569,7 +1595,7 @@ void SkPath::Iter::consumeDegenerateSegments() {
return;
}
// Ignore this line and continue
- fVerbs++;
+ fVerbs--;
fPts += 3;
break;
@@ -1594,14 +1620,15 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
return kDone_Verb;
}
- unsigned verb = *fVerbs++;
+ // fVerbs is one beyond the current verb, decrement first
+ unsigned verb = *(--fVerbs);
const SkPoint* SK_RESTRICT srcPts = fPts;
SkPoint* SK_RESTRICT pts = ptsParam;
switch (verb) {
case kMove_Verb:
if (fNeedClose) {
- fVerbs -= 1;
+ fVerbs++; // move back one verb
verb = this->autoClose(pts);
if (verb == kClose_Verb) {
fNeedClose = false;
@@ -1640,7 +1667,7 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
case kClose_Verb:
verb = this->autoClose(pts);
if (verb == kLine_Verb) {
- fVerbs -= 1;
+ fVerbs++; // move back one verb
} else {
fNeedClose = false;
fSegmentState = kEmptyContour_SegmentState;
@@ -1669,9 +1696,9 @@ SkPath::RawIter::RawIter(const SkPath& path) {
}
void SkPath::RawIter::setPath(const SkPath& path) {
- fPts = path.fPts.begin();
- fVerbs = path.fVerbs.begin();
- fVerbStop = path.fVerbs.end();
+ fPts = path.fPathRef->points();
+ fVerbs = path.fPathRef->verbs();
+ fVerbStop = path.fPathRef->verbsMemBegin();
fMoveTo.fX = fMoveTo.fY = 0;
fLastPt.fX = fLastPt.fY = 0;
}
@@ -1682,8 +1709,9 @@ SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
return kDone_Verb;
}
- unsigned verb = *fVerbs++;
- const SkPoint* srcPts = fPts;
+ // fVerbs points one beyond next verb so decrement first.
+ unsigned verb = *(--fVerbs);
+ const SkPoint* srcPts = fPts;
switch (verb) {
case kMove_Verb:
@@ -1729,16 +1757,23 @@ uint32_t SkPath::writeToMemory(void* storage) const {
SkDEBUGCODE(this->validate();)
if (NULL == storage) {
- const int byteCount = 3 * sizeof(int32_t)
- + sizeof(SkPoint) * fPts.count()
- + sizeof(uint8_t) * fVerbs.count()
+ const int byteCount = sizeof(int32_t)
+#if NEW_PICTURE_FORMAT
+ + fPathRef->writeSize()
+#else
+ + 2 * sizeof(int32_t)
+ + sizeof(SkPoint) * fPathRef->countPoints()
+ + sizeof(uint8_t) * fPathRef->countVerbs()
+#endif
+ sizeof(SkRect);
return SkAlign4(byteCount);
}
SkWBuffer buffer(storage);
- buffer.write32(fPts.count());
- buffer.write32(fVerbs.count());
+#if !NEW_PICTURE_FORMAT
+ buffer.write32(fPathRef->countPoints());
+ buffer.write32(fPathRef->countVerbs());
+#endif
// Call getBounds() to ensure (as a side-effect) that fBounds
// and fIsFinite are computed.
@@ -1753,8 +1788,7 @@ uint32_t SkPath::writeToMemory(void* storage) const {
buffer.write32(packed);
- buffer.write(fPts.begin(), sizeof(SkPoint) * fPts.count());
- buffer.write(fVerbs.begin(), fVerbs.count());
+ fPathRef->writeToBuffer(&buffer);
buffer.write(&bounds, sizeof(bounds));
@@ -1764,8 +1798,10 @@ uint32_t SkPath::writeToMemory(void* storage) const {
uint32_t SkPath::readFromMemory(const void* storage) {
SkRBuffer buffer(storage);
- fPts.setCount(buffer.readS32());
- fVerbs.setCount(buffer.readS32());
+#if !NEW_PICTURE_FORMAT
+ int32_t pcount = buffer.readS32();
+ int32_t vcount = buffer.readS32();
+#endif
uint32_t packed = buffer.readS32();
fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
@@ -1774,8 +1810,11 @@ uint32_t SkPath::readFromMemory(const void* storage) {
fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xFF;
- buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
- buffer.read(fVerbs.begin(), fVerbs.count());
+#if NEW_PICTURE_FORMAT
+ fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer));
+#else
+ fPathRef.reset(SkPathRef::CreateFromBuffer(vcount, pcount, &buffer));
+#endif
buffer.read(&fBounds, sizeof(fBounds));
fBoundsIsDirty = false;
@@ -1839,16 +1878,14 @@ void SkPath::dump() const {
void SkPath::validate() const {
SkASSERT(this != NULL);
SkASSERT((fFillType & ~3) == 0);
- fPts.validate();
- fVerbs.validate();
if (!fBoundsIsDirty) {
SkRect bounds;
- bool isFinite = compute_pt_bounds(&bounds, fPts);
+ bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
SkASSERT(SkToBool(fIsFinite) == isFinite);
- if (fPts.count() <= 1) {
+ if (fPathRef->countPoints() <= 1) {
// if we're empty, fBounds may be empty but translated, so we can't
// necessarily compare to bounds directly
// try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
@@ -1867,8 +1904,9 @@ void SkPath::validate() const {
}
uint32_t mask = 0;
- for (int i = 0; i < fVerbs.count(); i++) {
- switch (fVerbs[i]) {
+ const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbs();
+ for (int i = 0; i < fPathRef->countVerbs(); i++) {
+ switch (verbs[~i]) {
case kLine_Verb:
mask |= kLine_SegmentMask;
break;
@@ -1877,6 +1915,15 @@ void SkPath::validate() const {
break;
case kCubic_Verb:
mask |= kCubic_SegmentMask;
+ case kMove_Verb: // these verbs aren't included in the segment mask.
+ case kClose_Verb:
+ break;
+ case kDone_Verb:
+ SkDEBUGFAIL("Done verb shouldn't be recorded.");
+ break;
+ default:
+ SkDEBUGFAIL("Unknown Verb");
+ break;
}
}
SkASSERT(mask == fSegmentMask);
@@ -2015,7 +2062,7 @@ SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) {
class ContourIter {
public:
- ContourIter(const SkTDArray<uint8_t>& verbs, const SkTDArray<SkPoint>& pts);
+ ContourIter(const SkPathRef& pathRef);
bool done() const { return fDone; }
// if !done() then these may be called
@@ -2032,20 +2079,18 @@ private:
SkDEBUGCODE(int fContourCounter;)
};
-ContourIter::ContourIter(const SkTDArray<uint8_t>& verbs,
- const SkTDArray<SkPoint>& pts) {
- fStopVerbs = verbs.begin() + verbs.count();
-
+ContourIter::ContourIter(const SkPathRef& pathRef) {
+ fStopVerbs = pathRef.verbsMemBegin();
fDone = false;
- fCurrPt = pts.begin();
- fCurrVerb = verbs.begin();
+ fCurrPt = pathRef.points();
+ fCurrVerb = pathRef.verbs();
fCurrPtCount = 0;
SkDEBUGCODE(fContourCounter = 0;)
this->next();
}
void ContourIter::next() {
- if (fCurrVerb >= fStopVerbs) {
+ if (fCurrVerb <= fStopVerbs) {
fDone = true;
}
if (fDone) {
@@ -2055,12 +2100,12 @@ void ContourIter::next() {
// skip pts of prev contour
fCurrPt += fCurrPtCount;
- SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
+ SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
int ptCount = 1; // moveTo
const uint8_t* verbs = fCurrVerb;
- for (++verbs; verbs < fStopVerbs; ++verbs) {
- switch (*verbs) {
+ for (--verbs; verbs > fStopVerbs; --verbs) {
+ switch (verbs[~0]) {
case SkPath::kMove_Verb:
goto CONTOUR_END;
case SkPath::kLine_Verb:
@@ -2237,7 +2282,7 @@ bool SkPath::cheapComputeDirection(Direction* dir) const {
// is unknown, so we don't call isConvex()
const Convexity conv = this->getConvexityOrUnknown();
- ContourIter iter(fVerbs, fPts);
+ ContourIter iter(*fPathRef.get());
// initialize with our logical y-min
SkScalar ymax = this->getBounds().fTop;