| 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()) {
|
|
|