diff options
author | robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-12-12 23:03:51 +0000 |
---|---|---|
committer | robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-12-12 23:03:51 +0000 |
commit | d5e04336e89c85513a3a7aac8322e05e1527fc04 (patch) | |
tree | cf0ea5d396346af5422f5f2a655c0833611e2ba5 | |
parent | 113de4128a2a8cfaf886d7a72ee2be0203b79111 (diff) | |
download | src-d5e04336e89c85513a3a7aac8322e05e1527fc04.tar.gz |
Move segment mask from SkPath to SkPathRef
https://codereview.chromium.org/105083003/
git-svn-id: http://skia.googlecode.com/svn/trunk/src@12660 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | core/SkPath.cpp | 97 | ||||
-rw-r--r-- | core/SkPathRef.cpp | 156 |
2 files changed, 168 insertions, 85 deletions
diff --git a/core/SkPath.cpp b/core/SkPath.cpp index eaa6c93d..af8b1aa5 100644 --- a/core/SkPath.cpp +++ b/core/SkPath.cpp @@ -15,11 +15,6 @@ #include "SkRRect.h" #include "SkThread.h" -// This value is just made-up for now. When count is 4, calling memset was much -// slower than just writing the loop. This seems odd, and hopefully in the -// future this we appear to have been a fluke... -#define MIN_COUNT_FOR_MEMSET_TO_BE_FAST 16 - //////////////////////////////////////////////////////////////////////////// /** @@ -143,7 +138,6 @@ void SkPath::resetFields() { //fPathRef is assumed to have been emptied by the caller. fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; fFillType = kWinding_FillType; - fSegmentMask = 0; fConvexity = kUnknown_Convexity; fDirection = kUnknown_Direction; @@ -182,7 +176,6 @@ void SkPath::copyFields(const SkPath& that) { //fPathRef is assumed to have been set by the caller. fLastMoveToIndex = that.fLastMoveToIndex; fFillType = that.fFillType; - fSegmentMask = that.fSegmentMask; fConvexity = that.fConvexity; fDirection = that.fDirection; } @@ -190,14 +183,8 @@ void SkPath::copyFields(const SkPath& that) { bool operator==(const SkPath& a, const SkPath& b) { // note: don't need to look at isConvex or bounds, since just comparing the // raw data is sufficient. - - // We explicitly check fSegmentMask as a quick-reject. We could skip it, - // since it is only a cache of info in the fVerbs, but its a fast way to - // notice a difference - return &a == &b || - (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && - *a.fPathRef.get() == *b.fPathRef.get()); + (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); } void SkPath::swap(SkPath& that) { @@ -207,7 +194,6 @@ void SkPath::swap(SkPath& that) { fPathRef.swap(&that.fPathRef); SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); SkTSwap<uint8_t>(fFillType, that.fFillType); - SkTSwap<uint8_t>(fSegmentMask, that.fSegmentMask); SkTSwap<uint8_t>(fConvexity, that.fConvexity); SkTSwap<uint8_t>(fDirection, that.fDirection); #ifdef SK_BUILD_FOR_ANDROID @@ -674,7 +660,6 @@ void SkPath::lineTo(SkScalar x, SkScalar y) { SkPathRef::Editor ed(&fPathRef); ed.growForVerb(kLine_Verb)->set(x, y); - fSegmentMask |= kLine_SegmentMask; DIRTY_AFTER_EDIT; } @@ -695,7 +680,6 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { SkPoint* pts = ed.growForVerb(kQuad_Verb); pts[0].set(x1, y1); pts[1].set(x2, y2); - fSegmentMask |= kQuad_SegmentMask; DIRTY_AFTER_EDIT; } @@ -723,10 +707,9 @@ void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, this->injectMoveToIfNeeded(); SkPathRef::Editor ed(&fPathRef); - SkPoint* pts = ed.growForConic(w); + SkPoint* pts = ed.growForVerb(kConic_Verb, w); pts[0].set(x1, y1); pts[1].set(x2, y2); - fSegmentMask |= kConic_SegmentMask; DIRTY_AFTER_EDIT; } @@ -751,7 +734,6 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, pts[0].set(x1, y1); pts[1].set(x2, y2); pts[2].set(x3, y3); - fSegmentMask |= kCubic_SegmentMask; DIRTY_AFTER_EDIT; } @@ -838,29 +820,19 @@ void SkPath::addPoly(const SkPoint pts[], int count, bool close) { return; } - SkPathRef::Editor ed(&fPathRef); - fLastMoveToIndex = ed.pathRef()->countPoints(); - uint8_t* vb; - SkPoint* p; + fLastMoveToIndex = fPathRef->countPoints(); + // +close makes room for the extra kClose_Verb - ed.grow(count + close, count, &vb, &p); + SkPathRef::Editor ed(&fPathRef, count+close, count); - memcpy(p, pts, count * sizeof(SkPoint)); - vb[~0] = kMove_Verb; + ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); 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 - count, kLine_Verb, count - 1); - } else { - for (int i = 1; i < count; ++i) { - vb[~i] = kLine_Verb; - } - } - fSegmentMask |= kLine_SegmentMask; + SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1); + memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); } + if (close) { - vb[~count] = kClose_Verb; + ed.growForVerb(kClose_Verb); } DIRTY_AFTER_EDIT; @@ -1343,11 +1315,21 @@ void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle SkPoint pts[kSkBuildQuadArcStorage]; int count = build_arc_points(oval, startAngle, sweepAngle, pts); - this->incReserve(count); - this->moveTo(pts[0]); - for (int i = 1; i < count; i += 2) { - this->quadTo(pts[i], pts[i+1]); + SkDEBUGCODE(this->validate();) + SkASSERT(count & 1); + + fLastMoveToIndex = fPathRef->countPoints(); + + SkPathRef::Editor ed(&fPathRef, 1+(count-1)/2, count); + + ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); + if (count > 1) { + SkPoint* p = ed.growForRepeatedVerb(kQuad_Verb, (count-1)/2); + memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); } + + DIRTY_AFTER_EDIT; + SkDEBUGCODE(this->validate();) } /* @@ -1671,7 +1653,6 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { if (this != dst) { dst->fFillType = fFillType; - dst->fSegmentMask = fSegmentMask; dst->fConvexity = fConvexity; } @@ -2045,7 +2026,6 @@ size_t SkPath::writeToMemory(void* storage) const { int32_t packed = (fConvexity << kConvexity_SerializationShift) | (fFillType << kFillType_SerializationShift) | - (fSegmentMask << kSegmentMask_SerializationShift) | (fDirection << kDirection_SerializationShift) #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO | (0x1 << kNewFormat_SerializationShift) @@ -2070,7 +2050,6 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) { fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; fFillType = (packed >> kFillType_SerializationShift) & 0xFF; - fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; fDirection = (packed >> kDirection_SerializationShift) & 0x3; #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; @@ -2201,34 +2180,6 @@ void SkPath::validate() const { } } } - - uint32_t mask = 0; - 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; - 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. - case kClose_Verb: - break; - case kDone_Verb: - SkDEBUGFAIL("Done verb shouldn't be recorded."); - break; - default: - SkDEBUGFAIL("Unknown Verb"); - break; - } - } - SkASSERT(mask == fSegmentMask); #endif // SK_DEBUG_PATH } #endif // SK_DEBUG diff --git a/core/SkPathRef.cpp b/core/SkPathRef.cpp index a02df302..a57e2f47 100644 --- a/core/SkPathRef.cpp +++ b/core/SkPathRef.cpp @@ -28,13 +28,6 @@ SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef, SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) } -SkPoint* SkPathRef::Editor::growForConic(SkScalar w) { - SkDEBUGCODE(fPathRef->validate();) - SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb); - *fPathRef->fConicWeights.append() = w; - return pts; -} - ////////////////////////////////////////////////////////////////////////////// void SkPathRef::CreateEmptyImpl(SkPathRef** empty) { *empty = SkNEW(SkPathRef); @@ -105,6 +98,8 @@ void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, (*dst)->fBoundsIsDirty = true; } + (*dst)->fSegmentMask = src.fSegmentMask; + // It's an oval only if it stays a rect. (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect(); @@ -118,6 +113,7 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer ) { SkPathRef* ref = SkNEW(SkPathRef); bool isOval; + uint8_t segmentMask; int32_t packed; if (!buffer->readS32(&packed)) { @@ -130,9 +126,11 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO if (newFormat) { #endif + segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; isOval = (packed >> kIsOval_SerializationShift) & 1; #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO } else { + segmentMask = (oldPacked >> SkPath::kOldSegmentMask_SerializationShift) & 0xF; isOval = (oldPacked >> SkPath::kOldIsOval_SerializationShift) & 1; } #endif @@ -159,6 +157,9 @@ SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer return NULL; } ref->fBoundsIsDirty = false; + + // resetToSize clears fSegmentMask and fIsOval + ref->fSegmentMask = segmentMask; ref->fIsOval = isOval; return ref; } @@ -172,6 +173,7 @@ void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) { (*pathRef)->fFreeSpace = (*pathRef)->currSize(); (*pathRef)->fGenerationID = 0; (*pathRef)->fConicWeights.rewind(); + (*pathRef)->fSegmentMask = 0; (*pathRef)->fIsOval = false; SkDEBUGCODE((*pathRef)->validate();) } else { @@ -185,6 +187,14 @@ void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) { bool SkPathRef::operator== (const SkPathRef& ref) const { SkDEBUGCODE(this->validate();) SkDEBUGCODE(ref.validate();) + + // We explicitly check fSegmentMask as a quick-reject. We could skip it, + // since it is only a cache of info in the fVerbs, but its a fast way to + // notice a difference + if (fSegmentMask != ref.fSegmentMask) { + return false; + } + bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID; #ifdef SK_RELEASE if (genIDMatch) { @@ -222,7 +232,7 @@ bool SkPathRef::operator== (const SkPathRef& ref) const { return true; } -void SkPathRef::writeToBuffer(SkWBuffer* buffer) { +void SkPathRef::writeToBuffer(SkWBuffer* buffer) const { SkDEBUGCODE(this->validate();) SkDEBUGCODE(size_t beforePos = buffer->pos();) @@ -231,7 +241,8 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) { const SkRect& bounds = this->getBounds(); int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | - ((fIsOval & 1) << kIsOval_SerializationShift); + ((fIsOval & 1) << kIsOval_SerializationShift) | + (fSegmentMask << kSegmentMask_SerializationShift); buffer->write32(packed); // TODO: write gen ID here. Problem: We don't know if we're cross process or not from @@ -248,7 +259,7 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) { SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); } -uint32_t SkPathRef::writeSize() { +uint32_t SkPathRef::writeSize() const { return uint32_t(5 * sizeof(uint32_t) + fVerbCnt * sizeof(uint8_t) + fPointCnt * sizeof(SkPoint) + @@ -273,11 +284,91 @@ void SkPathRef::copy(const SkPathRef& ref, fBounds = ref.fBounds; fIsFinite = ref.fIsFinite; } + fSegmentMask = ref.fSegmentMask; fIsOval = ref.fIsOval; SkDEBUGCODE(this->validate();) } -SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) { +SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb, + int numVbs, + SkScalar** weights) { + // This value is just made-up for now. When count is 4, calling memset was much + // slower than just writing the loop. This seems odd, and hopefully in the + // future this will appear to have been a fluke... + static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16; + + SkDEBUGCODE(this->validate();) + int pCnt; + bool dirtyAfterEdit = true; + switch (verb) { + case SkPath::kMove_Verb: + pCnt = numVbs; + dirtyAfterEdit = false; + break; + case SkPath::kLine_Verb: + fSegmentMask |= SkPath::kLine_SegmentMask; + pCnt = numVbs; + break; + case SkPath::kQuad_Verb: + fSegmentMask |= SkPath::kQuad_SegmentMask; + pCnt = 2 * numVbs; + break; + case SkPath::kConic_Verb: + fSegmentMask |= SkPath::kConic_SegmentMask; + pCnt = 2 * numVbs; + break; + case SkPath::kCubic_Verb: + fSegmentMask |= SkPath::kCubic_SegmentMask; + pCnt = 3 * numVbs; + break; + case SkPath::kClose_Verb: + SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb"); + pCnt = 0; + dirtyAfterEdit = false; + break; + case SkPath::kDone_Verb: + SkDEBUGFAIL("growForRepeatedVerb called for kDone"); + // fall through + default: + SkDEBUGFAIL("default should not be reached"); + pCnt = 0; + dirtyAfterEdit = false; + } + + size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint); + this->makeSpace(space); + + SkPoint* ret = fPoints + fPointCnt; + uint8_t* vb = fVerbs - fVerbCnt; + + // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to + // be 0, the compiler will remove the test/branch entirely. + if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) { + memset(vb - numVbs, verb, numVbs); + } else { + for (int i = 0; i < numVbs; ++i) { + vb[~i] = verb; + } + } + + fVerbCnt += numVbs; + fPointCnt += pCnt; + fFreeSpace -= space; + fBoundsIsDirty = true; // this also invalidates fIsFinite + if (dirtyAfterEdit) { + fIsOval = false; + } + + if (SkPath::kConic_Verb == verb) { + SkASSERT(NULL != weights); + *weights = fConicWeights.append(numVbs); + } + + SkDEBUGCODE(this->validate();) + return ret; +} + +SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) { SkDEBUGCODE(this->validate();) int pCnt; bool dirtyAfterEdit = true; @@ -287,14 +378,19 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) { dirtyAfterEdit = false; break; case SkPath::kLine_Verb: + fSegmentMask |= SkPath::kLine_SegmentMask; pCnt = 1; break; case SkPath::kQuad_Verb: - // fall through + fSegmentMask |= SkPath::kQuad_SegmentMask; + pCnt = 2; + break; case SkPath::kConic_Verb: + fSegmentMask |= SkPath::kConic_SegmentMask; pCnt = 2; break; case SkPath::kCubic_Verb: + fSegmentMask |= SkPath::kCubic_SegmentMask; pCnt = 3; break; case SkPath::kClose_Verb: @@ -320,6 +416,11 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) { if (dirtyAfterEdit) { fIsOval = false; } + + if (SkPath::kConic_Verb == verb) { + *fConicWeights.append() = weight; + } + SkDEBUGCODE(this->validate();) return ret; } @@ -369,5 +470,36 @@ void SkPathRef::validate() const { } SkASSERT(SkToBool(fIsFinite) == isFinite); } + +#ifdef SK_DEBUG_PATH + uint32_t mask = 0; + for (int i = 0; i < fVerbCnt; ++i) { + switch (fVerbs[~i]) { + case SkPath::kMove_Verb: + break; + case SkPath::kLine_Verb: + mask |= SkPath::kLine_SegmentMask; + break; + case SkPath::kQuad_Verb: + mask |= SkPath::kQuad_SegmentMask; + break; + case SkPath::kConic_Verb: + mask |= SkPath::kConic_SegmentMask; + break; + case SkPath::kCubic_Verb: + mask |= SkPath::kCubic_SegmentMask; + break; + case SkPath::kClose_Verb: + break; + case SkPath::kDone_Verb: + SkDEBUGFAIL("Done verb shouldn't be recorded."); + break; + default: + SkDEBUGFAIL("Unknown Verb"); + break; + } + } + SkASSERT(mask == fSegmentMask); +#endif // SK_DEBUG_PATH } #endif |