Index: src/core/SkPath.cpp |
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp |
index 95cd9fe93895e1cfc84505025a73b20a0792a98f..7485c0b4ff06b3e2d05c2dc568c119f582b30cce 100644 |
--- a/src/core/SkPath.cpp |
+++ b/src/core/SkPath.cpp |
@@ -369,6 +369,7 @@ bool SkPath::conservativelyContainsRect(const SkRect& rect) const { |
SkASSERT(moveCnt); |
break; |
case kQuad_Verb: |
+ case kConic_Verb: |
SkASSERT(moveCnt); |
nextPt = 2; |
break; |
@@ -558,12 +559,16 @@ bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts |
break; |
} |
case kQuad_Verb: |
+ case kConic_Verb: |
case kCubic_Verb: |
return false; // quadratic, cubic not allowed |
case kMove_Verb: |
last = *pts++; |
closedOrMoved = true; |
break; |
+ default: |
+ SkASSERT(!"unexpected verb"); |
+ break; |
} |
*currVerb += 1; |
lastDirection = nextDirection; |
@@ -805,15 +810,15 @@ void SkPath::rLineTo(SkScalar x, SkScalar y) { |
void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
SkDEBUGCODE(this->validate();) |
- |
+ |
this->injectMoveToIfNeeded(); |
- |
+ |
SkPathRef::Editor ed(&fPathRef); |
SkPoint* pts = ed.growForVerb(kQuad_Verb); |
pts[0].set(x1, y1); |
pts[1].set(x2, y2); |
fSegmentMask |= kQuad_SegmentMask; |
- |
+ |
GEN_ID_INC; |
DIRTY_AFTER_EDIT; |
} |
@@ -824,6 +829,39 @@ void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { |
this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); |
} |
+void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
+ SkScalar w) { |
+ // check for <= 0 or NaN with this test |
+ if (!(w > 0)) { |
+ this->lineTo(x2, y2); |
+ } else if (!SkScalarIsFinite(w)) { |
+ this->lineTo(x1, y1); |
+ this->lineTo(x2, y2); |
+ } else if (SK_Scalar1 == w) { |
+ this->quadTo(x1, y1, x2, y2); |
+ } else { |
+ SkDEBUGCODE(this->validate();) |
+ |
+ this->injectMoveToIfNeeded(); |
+ |
+ SkPathRef::Editor ed(&fPathRef); |
+ SkPoint* pts = ed.growForConic(w); |
+ pts[0].set(x1, y1); |
+ pts[1].set(x2, y2); |
+ fSegmentMask |= kConic_SegmentMask; |
+ |
+ GEN_ID_INC; |
+ DIRTY_AFTER_EDIT; |
+ } |
+} |
+ |
+void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, |
+ SkScalar w) { |
+ SkPoint pt; |
+ this->getLastPt(&pt); |
+ this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); |
+} |
+ |
void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, |
SkScalar x3, SkScalar y3) { |
SkDEBUGCODE(this->validate();) |
@@ -857,6 +895,7 @@ void SkPath::close() { |
switch (fPathRef->atVerb(count - 1)) { |
case kLine_Verb: |
case kQuad_Verb: |
+ case kConic_Verb: |
case kCubic_Verb: |
case kMove_Verb: { |
SkPathRef::Editor ed(&fPathRef); |
@@ -864,9 +903,12 @@ void SkPath::close() { |
GEN_ID_INC; |
break; |
} |
- default: |
+ case kClose_Verb: |
// don't add a close if it's the first verb or a repeat |
break; |
+ default: |
+ SkASSERT(!"unexpected verb"); |
+ break; |
} |
} |
@@ -1430,6 +1472,10 @@ void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { |
proc(matrix, &pts[1], &pts[1], 2); |
this->quadTo(pts[1], pts[2]); |
break; |
+ case kConic_Verb: |
+ proc(matrix, &pts[1], &pts[1], 2); |
+ this->conicTo(pts[1], pts[2], iter.conicWeight()); |
+ break; |
case kCubic_Verb: |
proc(matrix, &pts[1], &pts[1], 3); |
this->cubicTo(pts[1], pts[2], pts[3]); |
@@ -1445,14 +1491,20 @@ void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { |
/////////////////////////////////////////////////////////////////////////////// |
-static const uint8_t gPtsInVerb[] = { |
- 1, // kMove |
- 1, // kLine |
- 2, // kQuad |
- 3, // kCubic |
- 0, // kClose |
- 0 // kDone |
-}; |
+static int pts_in_verb(unsigned verb) { |
+ static const uint8_t gPtsInVerb[] = { |
+ 1, // kMove |
+ 1, // kLine |
+ 2, // kQuad |
+ 2, // kConic |
+ 3, // kCubic |
+ 0, // kClose |
+ 0 // kDone |
+ }; |
+ |
+ SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); |
+ return gPtsInVerb[verb]; |
+} |
// ignore the initial moveto, and stop when the 1st contour ends |
void SkPath::pathTo(const SkPath& path) { |
@@ -1469,6 +1521,7 @@ void SkPath::pathTo(const SkPath& path) { |
const uint8_t* verbs = path.fPathRef->verbs(); |
// skip the initial moveTo |
const SkPoint* pts = path.fPathRef->points() + 1; |
+ const SkScalar* conicWeight = path.fPathRef->conicWeights(); |
SkASSERT(verbs[~0] == kMove_Verb); |
for (i = 1; i < vcount; i++) { |
@@ -1479,13 +1532,16 @@ void SkPath::pathTo(const SkPath& path) { |
case kQuad_Verb: |
this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY); |
break; |
+ case kConic_Verb: |
+ this->conicTo(pts[0], pts[1], *conicWeight++); |
+ break; |
case kCubic_Verb: |
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 += pts_in_verb(verbs[~i]); |
} |
} |
@@ -1503,14 +1559,17 @@ void SkPath::reversePathTo(const SkPath& path) { |
const uint8_t* verbs = path.fPathRef->verbs(); |
const SkPoint* pts = path.fPathRef->points(); |
+ const SkScalar* conicWeights = path.fPathRef->conicWeights(); |
SkASSERT(verbs[~0] == kMove_Verb); |
for (i = 1; i < vcount; ++i) { |
- int n = gPtsInVerb[verbs[~i]]; |
+ unsigned v = verbs[~i]; |
+ int n = pts_in_verb(v); |
if (n == 0) { |
break; |
} |
pts += n; |
+ conicWeights += (SkPath::kConic_Verb == v); |
} |
while (--i > 0) { |
@@ -1521,6 +1580,9 @@ void SkPath::reversePathTo(const SkPath& path) { |
case kQuad_Verb: |
this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY); |
break; |
+ case kConic_Verb: |
+ this->conicTo(pts[-1], pts[-2], *--conicWeights); |
+ break; |
case kCubic_Verb: |
this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY, |
pts[-3].fX, pts[-3].fY); |
@@ -1529,7 +1591,7 @@ void SkPath::reversePathTo(const SkPath& path) { |
SkDEBUGFAIL("bad verb"); |
break; |
} |
- pts -= gPtsInVerb[verbs[~i]]; |
+ pts -= pts_in_verb(verbs[~i]); |
} |
} |
@@ -1540,6 +1602,7 @@ void SkPath::reverseAddPath(const SkPath& src) { |
// 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 |
+ const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); |
fIsOval = false; |
@@ -1547,7 +1610,7 @@ void SkPath::reverseAddPath(const SkPath& src) { |
bool needClose = false; |
while (verbs < verbsEnd) { |
uint8_t v = *(verbs++); |
- int n = gPtsInVerb[v]; |
+ int n = pts_in_verb(v); |
if (needMove) { |
--pts; |
@@ -1570,6 +1633,9 @@ void SkPath::reverseAddPath(const SkPath& src) { |
case kQuad_Verb: |
this->quadTo(pts[1], pts[0]); |
break; |
+ case kConic_Verb: |
+ this->conicTo(pts[1], pts[0], *--conicWeights); |
+ break; |
case kCubic_Verb: |
this->cubicTo(pts[2], pts[1], pts[0]); |
break; |
@@ -1644,6 +1710,10 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { |
case kQuad_Verb: |
subdivide_quad_to(&tmp, pts); |
break; |
+ case kConic_Verb: |
+ SkASSERT(!"TODO: compute new weight"); |
+ tmp.conicTo(pts[1], pts[2], iter.conicWeight()); |
+ break; |
case kCubic_Verb: |
subdivide_cubic_to(&tmp, pts); |
break; |
@@ -1741,6 +1811,7 @@ enum SegmentState { |
SkPath::Iter::Iter() { |
#ifdef SK_DEBUG |
fPts = NULL; |
+ fConicWeights = NULL; |
fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0; |
fForceClose = fCloseLine = false; |
fSegmentState = kEmptyContour_SegmentState; |
@@ -1759,6 +1830,7 @@ void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { |
fPts = path.fPathRef->points(); |
fVerbs = path.fPathRef->verbs(); |
fVerbStop = path.fPathRef->verbsMemBegin(); |
+ fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind |
fLastPt.fX = fLastPt.fY = 0; |
fMoveTo.fX = fMoveTo.fY = 0; |
fForceClose = SkToU8(forceClose); |
@@ -1870,6 +1942,7 @@ void SkPath::Iter::consumeDegenerateSegments() { |
fPts++; |
break; |
+ case kConic_Verb: |
case kQuad_Verb: |
if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) { |
if (lastMoveVerb) { |
@@ -1882,6 +1955,7 @@ void SkPath::Iter::consumeDegenerateSegments() { |
// Ignore this line and continue |
fVerbs--; |
fPts += 2; |
+ fConicWeights += (kConic_Verb == verb); |
break; |
case kCubic_Verb: |
@@ -1951,6 +2025,9 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) { |
fCloseLine = false; |
srcPts += 1; |
break; |
+ case kConic_Verb: |
+ fConicWeights += 1; |
+ // fall-through |
case kQuad_Verb: |
pts[0] = this->cons_moveTo(); |
memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); |
@@ -1983,6 +2060,7 @@ SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) { |
SkPath::RawIter::RawIter() { |
#ifdef SK_DEBUG |
fPts = NULL; |
+ fConicWeights = NULL; |
fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0; |
#endif |
// need to init enough to make next() harmlessly return kDone_Verb |
@@ -1998,6 +2076,7 @@ void SkPath::RawIter::setPath(const SkPath& path) { |
fPts = path.fPathRef->points(); |
fVerbs = path.fPathRef->verbs(); |
fVerbStop = path.fPathRef->verbsMemBegin(); |
+ fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind |
fMoveTo.fX = fMoveTo.fY = 0; |
fLastPt.fX = fLastPt.fY = 0; |
} |
@@ -2025,6 +2104,9 @@ SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) { |
fLastPt = srcPts[0]; |
srcPts += 1; |
break; |
+ case kConic_Verb: |
+ fConicWeights += 1; |
+ // fall-through |
case kQuad_Verb: |
pts[0] = fLastPt; |
memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); |
@@ -2057,22 +2139,12 @@ uint32_t SkPath::writeToMemory(void* storage) const { |
if (NULL == storage) { |
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); |
-#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. |
@@ -2098,24 +2170,16 @@ uint32_t SkPath::writeToMemory(void* storage) const { |
uint32_t SkPath::readFromMemory(const void* storage) { |
SkRBuffer buffer(storage); |
-#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; |
fIsOval = (packed >> kIsOval_SerializationShift) & 1; |
fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; |
fFillType = (packed >> kFillType_SerializationShift) & 0xFF; |
- fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0x7; |
+ fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; |
fDirection = (packed >> kDirection_SerializationShift) & 0x3; |
-#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; |
@@ -2142,7 +2206,7 @@ static void append_scalar(SkString* str, SkScalar value) { |
} |
static void append_params(SkString* str, const char label[], const SkPoint pts[], |
- int count) { |
+ int count, SkScalar conicWeight = -1) { |
str->append(label); |
str->append("("); |
@@ -2155,6 +2219,10 @@ static void append_params(SkString* str, const char label[], const SkPoint pts[] |
str->append(", "); |
} |
} |
+ if (conicWeight >= 0) { |
+ str->append(", "); |
+ append_scalar(str, conicWeight); |
+ } |
str->append(");\n"); |
} |
@@ -2180,6 +2248,9 @@ void SkPath::dump(bool forceClose, const char title[]) const { |
case kQuad_Verb: |
append_params(&builder, "path.quadTo", &pts[1], 2); |
break; |
+ case kConic_Verb: |
+ append_params(&builder, "path.conicTo", &pts[1], 2, iter.conicWeight()); |
+ break; |
case kCubic_Verb: |
append_params(&builder, "path.cubicTo", &pts[1], 3); |
break; |
@@ -2239,6 +2310,9 @@ void SkPath::validate() const { |
case kQuad_Verb: |
mask |= kQuad_SegmentMask; |
break; |
+ case kConic_Verb: |
+ mask |= kConic_SegmentMask; |
+ break; |
case kCubic_Verb: |
mask |= kCubic_SegmentMask; |
case kMove_Verb: // these verbs aren't included in the segment mask. |
@@ -2379,6 +2453,7 @@ SkPath::Convexity SkPath::internalGetConvexity() const { |
break; |
case kLine_Verb: count = 1; break; |
case kQuad_Verb: count = 2; break; |
+ case kConic_Verb: count = 2; break; |
case kCubic_Verb: count = 3; break; |
case kClose_Verb: |
state.close(); |
@@ -2423,6 +2498,7 @@ private: |
const SkPoint* fCurrPt; |
const uint8_t* fCurrVerb; |
const uint8_t* fStopVerbs; |
+ const SkScalar* fCurrConicWeight; |
bool fDone; |
SkDEBUGCODE(int fContourCounter;) |
}; |
@@ -2432,6 +2508,7 @@ ContourIter::ContourIter(const SkPathRef& pathRef) { |
fDone = false; |
fCurrPt = pathRef.points(); |
fCurrVerb = pathRef.verbs(); |
+ fCurrConicWeight = pathRef.conicWeights(); |
fCurrPtCount = 0; |
SkDEBUGCODE(fContourCounter = 0;) |
this->next(); |
@@ -2459,13 +2536,19 @@ void ContourIter::next() { |
case SkPath::kLine_Verb: |
ptCount += 1; |
break; |
+ case SkPath::kConic_Verb: |
+ fCurrConicWeight += 1; |
+ // fall-through |
case SkPath::kQuad_Verb: |
ptCount += 2; |
break; |
case SkPath::kCubic_Verb: |
ptCount += 3; |
break; |
- default: // kClose_Verb, just keep going |
+ case SkPath::kClose_Verb: |
+ break; |
+ default: |
+ SkASSERT(!"unexpected verb"); |
break; |
} |
} |
@@ -2957,13 +3040,16 @@ bool SkPath::contains(SkScalar x, SkScalar y) const { |
case SkPath::kQuad_Verb: |
w += winding_quad(pts, x, y); |
break; |
+ case SkPath::kConic_Verb: |
+ SkASSERT(0); |
+ break; |
case SkPath::kCubic_Verb: |
w += winding_cubic(pts, x, y); |
break; |
case SkPath::kDone_Verb: |
done = true; |
break; |
- } |
+ } |
} while (!done); |
switch (this->getFillType()) { |