diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-31 15:17:50 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-31 15:17:50 +0000 |
commit | 277c3f87656c44e0a651ed0dd56efa16c0ab07b4 (patch) | |
tree | 863b9897fe1ab6263150dfbd8d391cb0f28ea655 /src | |
parent | 2d76d933ff8ba2090229599f32bdb2b17fb7ad50 (diff) |
bump picture version since SkPath has changed (conics)
enable conics in SkPath
git-svn-id: http://skia.googlecode.com/svn/trunk@9370 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkEdgeBuilder.cpp | 51 | ||||
-rw-r--r-- | src/core/SkEdgeBuilder.h | 1 | ||||
-rw-r--r-- | src/core/SkPath.cpp | 162 | ||||
-rw-r--r-- | src/core/SkPathMeasure.cpp | 3 | ||||
-rw-r--r-- | src/core/SkPathRef.h | 88 | ||||
-rw-r--r-- | src/core/SkRegion_path.cpp | 17 | ||||
-rw-r--r-- | src/effects/SkCornerPathEffect.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrAAHairLinePathRenderer.cpp | 5 | ||||
-rw-r--r-- | src/gpu/GrDefaultPathRenderer.cpp | 3 | ||||
-rw-r--r-- | src/gpu/gl/GrGLPath.cpp | 10 | ||||
-rw-r--r-- | src/pathops/SkOpAngle.cpp | 16 | ||||
-rw-r--r-- | src/pathops/SkOpContour.h | 4 | ||||
-rw-r--r-- | src/pathops/SkOpEdgeBuilder.cpp | 12 | ||||
-rw-r--r-- | src/pathops/SkOpSegment.cpp | 38 | ||||
-rw-r--r-- | src/pathops/SkOpSegment.h | 6 | ||||
-rw-r--r-- | src/pathops/SkPathOpsTypes.h | 44 | ||||
-rw-r--r-- | src/pathops/SkReduceOrder.cpp | 4 | ||||
-rw-r--r-- | src/utils/SkDumpCanvas.cpp | 3 | ||||
-rw-r--r-- | src/utils/SkParsePath.cpp | 5 |
19 files changed, 340 insertions, 135 deletions
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp index 608a83c7c7..9ac4e97443 100644 --- a/src/core/SkEdgeBuilder.cpp +++ b/src/core/SkEdgeBuilder.cpp @@ -153,12 +153,22 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, return edgePtr - fEdgeList; } +static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) { + SkPoint monoX[5]; + int n = SkChopQuadAtYExtrema(pts, monoX); + for (int i = 0; i <= n; i++) { + builder->addQuad(&monoX[i * 2]); + } +} + int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp) { fAlloc.reset(); fList.reset(); fShiftUp = shiftUp; + SkScalar conicTol = SK_ScalarHalf * (1 << shiftUp); + if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) { return this->buildPoly(path, iclip, shiftUp); } @@ -192,6 +202,24 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, this->addClipper(&clipper); } break; + case SkPath::kConic_Verb: { + const int MAX_POW2 = 4; + const int MAX_QUADS = 1 << MAX_POW2; + const int MAX_QUAD_PTS = 1 + 2 * MAX_QUADS; + SkPoint storage[MAX_QUAD_PTS]; + + SkConic conic; + conic.set(pts, iter.conicWeight()); + int pow2 = conic.computeQuadPOW2(conicTol); + pow2 = SkMin32(pow2, MAX_POW2); + int quadCount = conic.chopIntoQuadsPOW2(storage, pow2); + SkASSERT(quadCount <= MAX_QUADS); + for (int i = 0; i < quadCount; ++i) { + if (clipper.clipQuad(&storage[i * 2], clip)) { + this->addClipper(&clipper); + } + } + } break; case SkPath::kCubic_Verb: if (clipper.clipCubic(pts, clip)) { this->addClipper(&clipper); @@ -214,13 +242,26 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, this->addLine(pts); break; case SkPath::kQuad_Verb: { - SkPoint monoX[5]; - int n = SkChopQuadAtYExtrema(pts, monoX); - for (int i = 0; i <= n; i++) { - this->addQuad(&monoX[i * 2]); - } + handle_quad(this, pts); break; } + case SkPath::kConic_Verb: { + const int MAX_POW2 = 4; + const int MAX_QUADS = 1 << MAX_POW2; + const int MAX_QUAD_PTS = 1 + 2 * MAX_QUADS; + SkPoint storage[MAX_QUAD_PTS]; + + SkConic conic; + conic.set(pts, iter.conicWeight()); + int pow2 = conic.computeQuadPOW2(conicTol); + pow2 = SkMin32(pow2, MAX_POW2); + int quadCount = conic.chopIntoQuadsPOW2(storage, pow2); + SkASSERT(quadCount <= MAX_QUADS); + SkDebugf("--- quadCount = %d\n", quadCount); + for (int i = 0; i < quadCount; ++i) { + handle_quad(this, &storage[i * 2]); + } + } break; case SkPath::kCubic_Verb: { SkPoint monoY[10]; int n = SkChopCubicAtYExtrema(pts, monoY); diff --git a/src/core/SkEdgeBuilder.h b/src/core/SkEdgeBuilder.h index b296f773c1..f9e5976e17 100644 --- a/src/core/SkEdgeBuilder.h +++ b/src/core/SkEdgeBuilder.h @@ -40,6 +40,7 @@ private: int fShiftUp; +public: void addLine(const SkPoint pts[]); void addQuad(const SkPoint pts[]); void addCubic(const SkPoint pts[]); diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 95cd9fe938..7485c0b4ff 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()) { diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp index af2579fff1..c519f93dce 100644 --- a/src/core/SkPathMeasure.cpp +++ b/src/core/SkPathMeasure.cpp @@ -152,6 +152,9 @@ void SkPathMeasure::buildSegments() { bool done = false; do { switch (fIter.next(pts)) { + case SkPath::kConic_Verb: + SkASSERT(0); + break; case SkPath::kMove_Verb: ptIndex += 1; fPts.append(1, pts); diff --git a/src/core/SkPathRef.h b/src/core/SkPathRef.h index 5f85b7b896..b670039291 100644 --- a/src/core/SkPathRef.h +++ b/src/core/SkPathRef.h @@ -12,12 +12,6 @@ #include "SkRefCnt.h" #include <stddef.h> // ptrdiff_t -// When we're ready to break the picture format. Changes: -// * Write genID. -// * SkPathRef read/write counts (which will change the field order) -// * SkPathRef reads/writes verbs backwards. -#define NEW_PICTURE_FORMAT 0 - /** * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an @@ -109,6 +103,13 @@ public: return fPathRef->growForVerb(verb); } + SkPoint* growForConic(SkScalar w) { + fPathRef->validate(); + SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb); + *fPathRef->fConicWeights.append() = w; + return pts; + } + /** * Allocates space for additional verbs and points and returns pointers to the new verbs and * points. verbs will point one beyond the first new verb (index it using [~<i>]). pts points @@ -131,8 +132,8 @@ public: * Resets the path ref to a new verb and point count. The new verbs and points are * uninitialized. */ - void resetToSize(int newVerbCnt, int newPointCnt) { - fPathRef->resetToSize(newVerbCnt, newPointCnt); + void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { + fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); } /** * Gets the path ref that is wrapped in the Editor. @@ -202,40 +203,29 @@ public: } else if (rcnt > 1) { dst->reset(SkNEW(SkPathRef)); } - (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt); + (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count()); memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t)); matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); + (*dst)->fConicWeights = src.fConicWeights; (*dst)->validate(); } -#if NEW_PICTURE_FORMAT static SkPathRef* CreateFromBuffer(SkRBuffer* buffer) { SkPathRef* ref = SkNEW(SkPathRef); ref->fGenerationID = buffer->readU32(); int32_t verbCount = buffer->readS32(); int32_t pointCount = buffer->readS32(); - ref->resetToSize(verbCount, pointCount); + int32_t conicCount = buffer->readS32(); + ref->resetToSize(verbCount, pointCount, conicCount); SkASSERT(verbCount == ref->countVerbs()); SkASSERT(pointCount == ref->countPoints()); + SkASSERT(conicCount == ref->fConicWeights.count()); buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)); buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); + buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); return ref; } -#else - static SkPathRef* CreateFromBuffer(int verbCount, int pointCount, SkRBuffer* buffer) { - SkPathRef* ref = SkNEW(SkPathRef); - - ref->resetToSize(verbCount, pointCount); - SkASSERT(verbCount == ref->countVerbs()); - SkASSERT(pointCount == ref->countPoints()); - buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); - for (int i = 0; i < verbCount; ++i) { - ref->fVerbs[~i] = buffer->readU8(); - } - return ref; - } -#endif /** * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be @@ -249,12 +239,13 @@ public: (*pathRef)->fPointCnt = 0; (*pathRef)->fFreeSpace = (*pathRef)->currSize(); (*pathRef)->fGenerationID = 0; + (*pathRef)->fConicWeights.rewind(); (*pathRef)->validate(); } else { int oldVCnt = (*pathRef)->countVerbs(); int oldPCnt = (*pathRef)->countPoints(); pathRef->reset(SkNEW(SkPathRef)); - (*pathRef)->resetToSize(0, 0, oldVCnt, oldPCnt); + (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); } } @@ -299,6 +290,9 @@ public: */ const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } + const SkScalar* conicWeights() const { this->validate(); return fConicWeights.begin(); } + const SkScalar* conicWeightsEnd() const { this->validate(); return fConicWeights.end(); } + /** * Convenience methods for getting to a verb or point by index. */ @@ -337,6 +331,10 @@ public: SkASSERT(!genIDMatch); return false; } + if (fConicWeights != ref.fConicWeights) { + SkASSERT(!genIDMatch); + return false; + } // We've done the work to determine that these are equal. If either has a zero genID, copy // the other's. If both are 0 then genID() will compute the next ID. if (0 == fGenerationID) { @@ -350,7 +348,6 @@ public: /** * Writes the path points and verbs to a buffer. */ -#if NEW_PICTURE_FORMAT void writeToBuffer(SkWBuffer* buffer) { this->validate(); SkDEBUGCODE_X(size_t beforePos = buffer->pos();) @@ -358,10 +355,12 @@ public: // TODO: write gen ID here. Problem: We don't know if we're cross process or not from // SkWBuffer. Until this is fixed we write 0. buffer->write32(0); - buffer->write32(this->fVerbCnt); - buffer->write32(this->fPointCnt); - buffer->write(this->verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); + buffer->write32(fVerbCnt); + buffer->write32(fPointCnt); + buffer->write32(fConicWeights.count()); + buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); + buffer->write(fConicWeights.begin(), fConicWeights.bytes()); SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); } @@ -370,17 +369,11 @@ public: * Gets the number of bytes that would be written in writeBuffer() */ uint32_t writeSize() { - return 3 * sizeof(uint32_t) + fVerbCnt * sizeof(uint8_t) + fPointCnt * sizeof(SkPoint); + return 4 * sizeof(uint32_t) + + fVerbCnt * sizeof(uint8_t) + + fPointCnt * sizeof(SkPoint) + + fConicWeights.bytes(); } -#else - void writeToBuffer(SkWBuffer* buffer) { - this->validate(); - buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); - for (int i = 0; i < fVerbCnt; ++i) { - buffer->write8(fVerbs[~i]); - } - } -#endif private: SkPathRef() { @@ -396,10 +389,11 @@ private: void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints) { this->validate(); - this->resetToSize(ref.fVerbCnt, ref.fPointCnt, + this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(), additionalReserveVerbs, additionalReservePoints); memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof(uint8_t)); memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); + fConicWeights = ref.fConicWeights; // We could call genID() here to force a real ID (instead of 0). However, if we're making // a copy then presumably we intend to make a modification immediately afterwards. fGenerationID = ref.fGenerationID; @@ -416,7 +410,8 @@ private: /** Resets the path ref with verbCount verbs and pointCount points, all unitialized. Also * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ - void resetToSize(int verbCount, int pointCount, int reserveVerbs = 0, int reservePoints = 0) { + void resetToSize(int verbCount, int pointCount, int conicCount, + int reserveVerbs = 0, int reservePoints = 0) { this->validate(); fGenerationID = 0; @@ -442,6 +437,7 @@ private: fVerbCnt = verbCount; fFreeSpace = this->currSize() - minSize; } + fConicWeights.setCount(conicCount); this->validate(); } @@ -474,13 +470,17 @@ private: case SkPath::kLine_Verb: pCnt = 1; break; + case SkPath::kConic_Verb: case SkPath::kQuad_Verb: pCnt = 2; break; case SkPath::kCubic_Verb: pCnt = 3; break; - default: + case SkPath::kDone_Verb: + SkASSERT(!"growForVerb called for kDone"); + // fall through + case SkPath::kClose_Verb: pCnt = 0; } size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); @@ -588,6 +588,8 @@ private: int fVerbCnt; int fPointCnt; size_t fFreeSpace; // redundant but saves computation + SkTDArray<SkScalar> fConicWeights; + enum { kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. }; diff --git a/src/core/SkRegion_path.cpp b/src/core/SkRegion_path.cpp index 80149a3836..0a5a401809 100644 --- a/src/core/SkRegion_path.cpp +++ b/src/core/SkRegion_path.cpp @@ -216,25 +216,36 @@ void SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const { *runs = SkRegion::kRunTypeSentinel; } -static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) { +static unsigned verb_to_initial_last_index(unsigned verb) { static const uint8_t gPathVerbToInitialLastIndex[] = { 0, // kMove_Verb 1, // kLine_Verb 2, // kQuad_Verb + 2, // kConic_Verb 3, // kCubic_Verb 0, // kClose_Verb 0 // kDone_Verb }; + SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex)); + return gPathVerbToInitialLastIndex[verb]; +} +static unsigned verb_to_max_edges(unsigned verb) { static const uint8_t gPathVerbToMaxEdges[] = { 0, // kMove_Verb 1, // kLine_Verb 2, // kQuad_VerbB + 2, // kConic_VerbB 3, // kCubic_Verb 0, // kClose_Verb 0 // kDone_Verb }; + SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges)); + return gPathVerbToMaxEdges[verb]; +} + +static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) { SkPath::Iter iter(path, true); SkPoint pts[4]; SkPath::Verb verb; @@ -244,9 +255,9 @@ static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) { SkScalar bot = SkIntToScalar(SK_MinS16); while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) { - maxEdges += gPathVerbToMaxEdges[verb]; + maxEdges += verb_to_max_edges(verb); - int lastIndex = gPathVerbToInitialLastIndex[verb]; + int lastIndex = verb_to_initial_last_index(verb); if (lastIndex > 0) { for (int i = 1; i <= lastIndex; i++) { if (top > pts[i].fY) { diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp index 1cf797a249..f4c3147301 100644 --- a/src/effects/SkCornerPathEffect.cpp +++ b/src/effects/SkCornerPathEffect.cpp @@ -111,6 +111,9 @@ bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, } dst->close(); break; + case SkPath::kConic_Verb: + SkASSERT(0); + break; case SkPath::kDone_Verb: goto DONE; } diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp index 1a1552130e..bed931c034 100644 --- a/src/gpu/GrAAHairLinePathRenderer.cpp +++ b/src/gpu/GrAAHairLinePathRenderer.cpp @@ -221,7 +221,10 @@ int generate_lines_and_quads(const SkPath& path, GrPoint devPts[4]; SkPath::Verb verb = iter.next(pathPts); switch (verb) { - case SkPath::kMove_Verb: + case SkPath::kConic_Verb: + SkASSERT(0); + break; + case SkPath::kMove_Verb: break; case SkPath::kLine_Verb: m.mapPoints(devPts, pathPts, 2); diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp index 13bfe9233f..19fd2beff8 100644 --- a/src/gpu/GrDefaultPathRenderer.cpp +++ b/src/gpu/GrDefaultPathRenderer.cpp @@ -255,6 +255,9 @@ bool GrDefaultPathRenderer::createGeom(const SkPath& path, for (;;) { SkPath::Verb verb = iter.next(pts); switch (verb) { + case SkPath::kConic_Verb: + SkASSERT(0); + break; case SkPath::kMove_Verb: if (!first) { uint16_t currIdx = (uint16_t) (vert - base); diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp index 8c6e11e667..63c2fa107c 100644 --- a/src/gpu/gl/GrGLPath.cpp +++ b/src/gpu/gl/GrGLPath.cpp @@ -20,14 +20,15 @@ inline GrGLubyte verb_to_gl_path_cmd(const SkPath::Verb verb) { GR_GL_MOVE_TO, GR_GL_LINE_TO, GR_GL_QUADRATIC_CURVE_TO, + 0xFF, // conic GR_GL_CUBIC_CURVE_TO, GR_GL_CLOSE_PATH, }; GR_STATIC_ASSERT(0 == SkPath::kMove_Verb); GR_STATIC_ASSERT(1 == SkPath::kLine_Verb); GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb); - GR_STATIC_ASSERT(3 == SkPath::kCubic_Verb); - GR_STATIC_ASSERT(4 == SkPath::kClose_Verb); + GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb); + GR_STATIC_ASSERT(5 == SkPath::kClose_Verb); GrAssert(verb >= 0 && (size_t)verb < GR_ARRAY_COUNT(gTable)); return gTable[verb]; @@ -39,14 +40,15 @@ inline int num_pts(const SkPath::Verb verb) { 1, // move 1, // line 2, // quad + 2, // conic 3, // cubic 0, // close }; GR_STATIC_ASSERT(0 == SkPath::kMove_Verb); GR_STATIC_ASSERT(1 == SkPath::kLine_Verb); GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb); - GR_STATIC_ASSERT(3 == SkPath::kCubic_Verb); - GR_STATIC_ASSERT(4 == SkPath::kClose_Verb); + GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb); + GR_STATIC_ASSERT(5 == SkPath::kClose_Verb); GrAssert(verb >= 0 && (size_t)verb < GR_ARRAY_COUNT(gTable)); return gTable[verb]; diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp index aa72394043..dee2906b7f 100644 --- a/src/pathops/SkOpAngle.cpp +++ b/src/pathops/SkOpAngle.cpp @@ -113,11 +113,11 @@ bool SkOpAngle::operator<(const SkOpAngle& rh) const { SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb; ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ? part[2] : part[1]; - ray[1].fX = (part[0].fX + part[partVerb].fX) / 2; - ray[1].fY = (part[0].fY + part[partVerb].fY) / 2; + ray[1].fX = (part[0].fX + part[SkPathOpsVerbToPoints(partVerb)].fX) / 2; + ray[1].fY = (part[0].fY + part[SkPathOpsVerbToPoints(partVerb)].fY) / 2; SkASSERT(ray[0] != ray[1]); - roots = (i.*CurveRay[fVerb])(fPts, ray); - rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray); + roots = (i.*CurveRay[SkPathOpsVerbToPoints(fVerb)])(fPts, ray); + rroots = (ri.*CurveRay[SkPathOpsVerbToPoints(rh.fVerb)])(rh.fPts, ray); } while ((roots == 0 || rroots == 0) && (flip ^= true)); if (roots == 0 || rroots == 0) { // FIXME: we don't have a solution in this case. The interim solution @@ -314,8 +314,8 @@ void SkOpAngle::setSpans() { fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd; #if DEBUG_UNSORTABLE if (fUnsortable) { - SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, thisSpan.fT); - SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, nextSpan.fT); + SkPoint iPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, thisSpan.fT); + SkPoint ePt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, nextSpan.fT); SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__, index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); } @@ -330,8 +330,8 @@ void SkOpAngle::setSpans() { } #if 1 #if DEBUG_UNSORTABLE - SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT); - SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT); + SkPoint iPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, startT); + SkPoint ePt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, endT); SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); #endif diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h index c90c218344..c57fbac6ca 100644 --- a/src/pathops/SkOpContour.h +++ b/src/pathops/SkOpContour.h @@ -114,7 +114,7 @@ public: const SkPoint& end() const { const SkOpSegment& segment = fSegments.back(); - return segment.pts()[segment.verb()]; + return segment.pts()[SkPathOpsVerbToPoints(segment.verb())]; } void findTooCloseToCall() { @@ -195,7 +195,7 @@ public: int updateSegment(int index, const SkPoint* pts) { SkOpSegment& segment = fSegments[index]; segment.updatePts(pts); - return segment.verb() + 1; + return SkPathOpsVerbToPoints(segment.verb()) + 1; } #if DEBUG_TEST diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp index 57e3b41912..5803afa11c 100644 --- a/src/pathops/SkOpEdgeBuilder.cpp +++ b/src/pathops/SkOpEdgeBuilder.cpp @@ -76,7 +76,7 @@ int SkOpEdgeBuilder::preFetch() { if (verb == SkPath::kMove_Verb) { *fPathPts.append() = pts[0]; } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) { - fPathPts.append(verb, &pts[1]); + fPathPts.append(SkPathOpsVerbToPoints(verb), &pts[1]); } } while (verb != SkPath::kDone_Verb); return fPathVerbs.count() - 1; @@ -137,7 +137,7 @@ bool SkOpEdgeBuilder::walk() { if (reducedVerb == 0) { break; // skip degenerate points } - if (reducedVerb == 1) { + if (reducedVerb == SkPath::kLine_Verb) { const SkPoint* lineStart = fReducePts.end() - 2; *fExtra.append() = fCurrentContour->addLine(lineStart); break; @@ -150,12 +150,12 @@ bool SkOpEdgeBuilder::walk() { if (reducedVerb == 0) { break; // skip degenerate points } - if (reducedVerb == 1) { + if (reducedVerb == SkPath::kLine_Verb) { const SkPoint* lineStart = fReducePts.end() - 2; *fExtra.append() = fCurrentContour->addLine(lineStart); break; } - if (reducedVerb == 2) { + if (reducedVerb == SkPath::kQuad_Verb) { const SkPoint* quadStart = fReducePts.end() - 3; *fExtra.append() = fCurrentContour->addQuad(quadStart); break; @@ -172,8 +172,8 @@ bool SkOpEdgeBuilder::walk() { SkDEBUGFAIL("bad verb"); return false; } - fFinalCurveStart = &pointsPtr[verb - 1]; - pointsPtr += verb; + fFinalCurveStart = &pointsPtr[SkPathOpsVerbToPoints(verb) - 1]; + pointsPtr += SkPathOpsVerbToPoints(verb); SkASSERT(fCurrentContour); } if (fCurrentContour && !fAllowOpenContours && !close()) { diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp index bcefd71d60..817732e0e5 100644 --- a/src/pathops/SkOpSegment.cpp +++ b/src/pathops/SkOpSegment.cpp @@ -133,7 +133,7 @@ SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const { } } if (fVerb != SkPath::kLine_Verb && !lastDone) { - SkPoint curveTop = (*CurveTop[fVerb])(fPts, lastT, span.fT); + SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT); if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt.fX > curveTop.fX)) { topPt = curveTop; @@ -210,9 +210,9 @@ void SkOpSegment::addAngle(SkTDArray<SkOpAngle>* anglesPtr, int start, int end) #if DEBUG_ANGLE SkTDArray<SkOpAngle>& angles = *anglesPtr; if (angles.count() > 1 && !fTs[start].fTiny) { - SkPoint angle0Pt = (*CurvePointAtT[angles[0].verb()])(angles[0].pts(), + SkPoint angle0Pt = (*CurvePointAtT[SkPathOpsVerbToPoints(angles[0].verb())])(angles[0].pts(), (*angles[0].spans())[angles[0].start()].fT); - SkPoint newPt = (*CurvePointAtT[fVerb])(fPts, fTs[start].fT); + SkPoint newPt = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[start].fT); bool match = AlmostEqualUlps(angle0Pt.fX, newPt.fX); match &= AlmostEqualUlps(angle0Pt.fY, newPt.fY); if (!match) { @@ -354,7 +354,7 @@ void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active if (active) { bool reverse = ePtr == fPts && start != 0; if (reverse) { - path->deferredMoveLine(ePtr[fVerb]); + path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); switch (fVerb) { case SkPath::kLine_Verb: path->deferredLine(ePtr[0]); @@ -386,7 +386,7 @@ void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active } } } - // return ePtr[fVerb]; + // return ePtr[SkPathOpsVerbToPoints(fVerb)]; } void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) { @@ -979,7 +979,7 @@ int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi SkIntersections intersections; // OPTIMIZE: use specialty function that intersects ray with curve, // returning t values only for curve (we don't care about t on ray) - int pts = (intersections.*CurveVertical[fVerb])(fPts, top, bottom, basePt.fX, false); + int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, top, bottom, basePt.fX, false); if (pts == 0 || (current && pts == 1)) { return bestTIndex; } @@ -1003,7 +1003,7 @@ int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi || approximately_greater_than_one(foundT)) { continue; } - SkScalar testY = (*CurvePointAtT[fVerb])(fPts, foundT).fY; + SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY; if (approximately_negative(testY - *bestY) || approximately_negative(basePt.fY - testY)) { continue; @@ -1012,7 +1012,7 @@ int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi return SK_MinS32; // if the intersection is edge on, wait for another one } if (fVerb > SkPath::kLine_Verb) { - SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, foundT).fX; + SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX; if (approximately_zero(dx)) { return SK_MinS32; // hit vertical, wait for another one } @@ -1738,7 +1738,7 @@ the same winding is shared by both. void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) { SkASSERT(hitDx || !winding); - SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, tHit).fX; + SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; SkASSERT(dx); int windVal = windValue(SkMin32(start, end)); #if DEBUG_WINDING_AT_T @@ -2081,7 +2081,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const { SkASSERT(fVerb != SkPath::kLine_Verb); SkPoint edge[4]; subDivide(tStart, tEnd, edge); - double sum = (edge[0].fX - edge[fVerb].fX) * (edge[0].fY + edge[fVerb].fY); + double sum = (edge[0].fX - edge[SkPathOpsVerbToPoints(fVerb)].fX) * (edge[0].fY + edge[SkPathOpsVerbToPoints(fVerb)].fY); if (fVerb == SkPath::kCubic_Verb) { SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); if (edge[1].fY < lesser && edge[2].fY < lesser) { @@ -2095,7 +2095,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const { } } } - for (int idx = 0; idx < fVerb; ++idx){ + for (int idx = 0; idx < SkPathOpsVerbToPoints(fVerb); ++idx){ sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY); } return sum <= 0; @@ -2365,9 +2365,9 @@ bool SkOpSegment::SortAngles(const SkTDArray<SkOpAngle>& angles, void SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { edge[0] = fTs[start].fPt; - edge[fVerb] = fTs[end].fPt; + edge[SkPathOpsVerbToPoints(fVerb)] = fTs[end].fPt; if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) { - SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }}; + SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[SkPathOpsVerbToPoints(fVerb)].fX, edge[SkPathOpsVerbToPoints(fVerb)].fY }}; if (fVerb == SkPath::kQuad_Verb) { edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint(); @@ -2382,7 +2382,7 @@ void SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const { SkPoint edge[4]; subDivide(start, end, edge); - (bounds->*SetCurveBounds[fVerb])(edge); + (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); } bool SkOpSegment::tiny(const SkOpAngle* angle) const { @@ -2473,7 +2473,7 @@ int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal); #endif // see if a + change in T results in a +/- change in X (compute x'(T)) - *dx = (*CurveSlopeAtT[fVerb])(fPts, tHit).fX; + *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { *dx = fPts[2].fX - fPts[1].fX - *dx; } @@ -2611,7 +2611,7 @@ void SkOpSegment::debugShowActiveSpans() const { #endif SkDebugf("%s id=%d", __FUNCTION__, fID); SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); - for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { + for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); } const SkOpSpan* span = &fTs[i]; @@ -2640,7 +2640,7 @@ void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int const SkPoint& pt = xyAtT(&span); SkDebugf("%s id=%d", fun, fID); SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); - for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { + for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); } SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> @@ -2661,7 +2661,7 @@ void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int const SkPoint& pt = xyAtT(&span); SkDebugf("%s id=%d", fun, fID); SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); - for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { + for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); } SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> @@ -2737,7 +2737,7 @@ void SkOpSegment::debugShowSort(const char* fun, const SkTDArray<SkOpAngle*>& an angle.unsortable() ? "*** UNSORTABLE *** " : ""); #if COMPACT_DEBUG_SORT SkDebugf("id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)", - segment.fID, kLVerbStr[segment.fVerb], + segment.fID, kLVerbStr[SkPathOpsVerbToPoints(segment.fVerb)], start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end, segment.xAtT(&eSpan), segment.yAtT(&eSpan)); #else diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h index d2322c8be1..e489acfb02 100644 --- a/src/pathops/SkOpSegment.h +++ b/src/pathops/SkOpSegment.h @@ -54,7 +54,7 @@ public: } SkVector dxdy(int index) const { - return (*CurveSlopeAtT[fVerb])(fPts, fTs[index].fT); + return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT); } SkScalar dy(int index) const { @@ -82,7 +82,7 @@ public: } bool isVertical(int start, int end) const { - return (*CurveIsVertical[fVerb])(fPts, start, end); + return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end); } bool operand() const { @@ -206,7 +206,7 @@ public: // used only by right angle winding finding SkPoint xyAtT(double mid) const { - return (*CurvePointAtT[fVerb])(fPts, mid); + return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); } const SkPoint& xyAtT(int index) const { diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h index 5a5394a0e7..0f689d818e 100644 --- a/src/pathops/SkPathOpsTypes.h +++ b/src/pathops/SkPathOpsTypes.h @@ -7,10 +7,13 @@ #ifndef SkPathOpsTypes_DEFINED #define SkPathOpsTypes_DEFINED +#define SK_CONIC_SUPPORT_ENABLED 1 + #include <float.h> // for FLT_EPSILON #include <math.h> // for fabs, sqrt #include "SkFloatingPoint.h" +#include "SkPath.h" #include "SkPathOps.h" #include "SkPathOpsDebug.h" #include "SkScalar.h" @@ -189,6 +192,47 @@ struct SkDTriangle; struct SkDCubic; struct SkDRect; +#if SK_CONIC_SUPPORT_ENABLED + +inline SkPath::Verb SkPathOpsPointsToVerb(int points) { + int verb = (1 << points) >> 1; +#ifdef SK_DEBUG + switch (points) { + case 0: SkASSERT(SkPath::kMove_Verb == verb); break; + case 1: SkASSERT(SkPath::kLine_Verb == verb); break; + case 2: SkASSERT(SkPath::kQuad_Verb == verb); break; + case 3: SkASSERT(SkPath::kCubic_Verb == verb); break; + default: SkASSERT(!"should not be here"); + } +#endif + return (SkPath::Verb)verb; +} + +inline int SkPathOpsVerbToPoints(SkPath::Verb verb) { + int points = (int) verb - ((int) verb >> 2); +#ifdef SK_DEBUG + switch (verb) { + case SkPath::kLine_Verb: SkASSERT(1 == points); break; + case SkPath::kQuad_Verb: SkASSERT(2 == points); break; + case SkPath::kCubic_Verb: SkASSERT(3 == points); break; + default: SkASSERT(!"should not get here"); + } +#endif + return points; +} + +#else + +inline SkPath::Verb SkOpPointsToVerb(int points) { + return (SkPath::Verb) (points); +} + +inline SkPath::Verb SkOpVerbToPoints(SkPath::Verb verb) { + return (int) verb ; +} + +#endif + inline double SkDInterp(double A, double B, double t) { return A + (B - A) * t; } diff --git a/src/pathops/SkReduceOrder.cpp b/src/pathops/SkReduceOrder.cpp index 5410d35ec9..6d2339c276 100644 --- a/src/pathops/SkReduceOrder.cpp +++ b/src/pathops/SkReduceOrder.cpp @@ -437,7 +437,7 @@ SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkTDArray<SkPoint>* reduceP pt->fY = SkDoubleToScalar(reducer.fLine[index].fY); } } - return (SkPath::Verb) (order - 1); + return SkPathOpsPointsToVerb(order - 1); } SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkTDArray<SkPoint>* reducePts) { @@ -452,5 +452,5 @@ SkPath::Verb SkReduceOrder::Cubic(const SkPoint a[4], SkTDArray<SkPoint>* reduce pt->fY = SkDoubleToScalar(reducer.fQuad[index].fY); } } - return (SkPath::Verb) (order - 1); + return SkPathOpsPointsToVerb(order - 1); } diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp index 87ddd3153d..593ad0cfb7 100644 --- a/src/utils/SkDumpCanvas.cpp +++ b/src/utils/SkDumpCanvas.cpp @@ -84,6 +84,9 @@ static void dumpVerbs(const SkPath& path, SkString* str) { break; case SkPath::kDone_Verb: return; + case SkPath::kConic_Verb: + SkASSERT(0); + break; } } } diff --git a/src/utils/SkParsePath.cpp b/src/utils/SkParsePath.cpp index 8c7a4d0df8..4c9923f49f 100644 --- a/src/utils/SkParsePath.cpp +++ b/src/utils/SkParsePath.cpp @@ -221,7 +221,10 @@ void SkParsePath::ToSVGString(const SkPath& path, SkString* str) { for (;;) { switch (iter.next(pts, false)) { - case SkPath::kMove_Verb: + case SkPath::kConic_Verb: + SkASSERT(0); + break; + case SkPath::kMove_Verb: append_scalars(&stream, 'M', &pts[0].fX, 2); break; case SkPath::kLine_Verb: |