| Index: src/core/SkPathRef.cpp
|
| ===================================================================
|
| --- src/core/SkPathRef.cpp (revision 12596)
|
| +++ src/core/SkPathRef.cpp (working copy)
|
| @@ -28,13 +28,6 @@
|
| 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 @@
|
| (*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* ref = SkNEW(SkPathRef);
|
| bool isOval;
|
| + uint8_t segmentMask;
|
|
|
| int32_t packed;
|
| if (!buffer->readS32(&packed)) {
|
| @@ -130,9 +126,11 @@
|
| #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 @@
|
| return NULL;
|
| }
|
| ref->fBoundsIsDirty = false;
|
| +
|
| + // resetToSize clears fSegmentMask and fIsOval
|
| + ref->fSegmentMask = segmentMask;
|
| ref->fIsOval = isOval;
|
| return ref;
|
| }
|
| @@ -172,6 +173,7 @@
|
| (*pathRef)->fFreeSpace = (*pathRef)->currSize();
|
| (*pathRef)->fGenerationID = 0;
|
| (*pathRef)->fConicWeights.rewind();
|
| + (*pathRef)->fSegmentMask = 0;
|
| (*pathRef)->fIsOval = false;
|
| SkDEBUGCODE((*pathRef)->validate();)
|
| } else {
|
| @@ -185,6 +187,14 @@
|
| 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 @@
|
| 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 @@
|
| 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 @@
|
| 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,28 +284,113 @@
|
| 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;
|
| + switch (verb) {
|
| + case SkPath::kMove_Verb:
|
| pCnt = 1;
|
| 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 @@
|
| if (dirtyAfterEdit) {
|
| fIsOval = false;
|
| }
|
| +
|
| + if (SkPath::kConic_Verb == verb) {
|
| + *fConicWeights.append() = weight;
|
| + }
|
| +
|
| SkDEBUGCODE(this->validate();)
|
| return ret;
|
| }
|
| @@ -369,5 +470,36 @@
|
| }
|
| 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
|
|
|