gfx/skia/trunk/src/core/SkPathRef.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkPathRef.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,492 @@
     1.4 +/*
     1.5 + * Copyright 2013 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkBuffer.h"
    1.12 +#include "SkOnce.h"
    1.13 +#include "SkPath.h"
    1.14 +#include "SkPathRef.h"
    1.15 +
    1.16 +//////////////////////////////////////////////////////////////////////////////
    1.17 +SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef,
    1.18 +                          int incReserveVerbs,
    1.19 +                          int incReservePoints)
    1.20 +{
    1.21 +    if ((*pathRef)->unique()) {
    1.22 +        (*pathRef)->incReserve(incReserveVerbs, incReservePoints);
    1.23 +    } else {
    1.24 +        SkPathRef* copy = SkNEW(SkPathRef);
    1.25 +        copy->copy(**pathRef, incReserveVerbs, incReservePoints);
    1.26 +        pathRef->reset(copy);
    1.27 +    }
    1.28 +    fPathRef = *pathRef;
    1.29 +    fPathRef->fGenerationID = 0;
    1.30 +    SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
    1.31 +}
    1.32 +
    1.33 +//////////////////////////////////////////////////////////////////////////////
    1.34 +static SkPathRef* gEmptyPathRef = NULL;
    1.35 +static void cleanup_gEmptyPathRef() { gEmptyPathRef->unref(); }
    1.36 +
    1.37 +void SkPathRef::CreateEmptyImpl(int) {
    1.38 +    gEmptyPathRef = SkNEW(SkPathRef);
    1.39 +    gEmptyPathRef->computeBounds();  // Preemptively avoid a race to clear fBoundsIsDirty.
    1.40 +}
    1.41 +
    1.42 +SkPathRef* SkPathRef::CreateEmpty() {
    1.43 +    SK_DECLARE_STATIC_ONCE(once);
    1.44 +    SkOnce(&once, SkPathRef::CreateEmptyImpl, 0, cleanup_gEmptyPathRef);
    1.45 +    return SkRef(gEmptyPathRef);
    1.46 +}
    1.47 +
    1.48 +void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
    1.49 +                                      const SkPathRef& src,
    1.50 +                                      const SkMatrix& matrix) {
    1.51 +    SkDEBUGCODE(src.validate();)
    1.52 +    if (matrix.isIdentity()) {
    1.53 +        if (*dst != &src) {
    1.54 +            src.ref();
    1.55 +            dst->reset(const_cast<SkPathRef*>(&src));
    1.56 +            SkDEBUGCODE((*dst)->validate();)
    1.57 +        }
    1.58 +        return;
    1.59 +    }
    1.60 +
    1.61 +    if (!(*dst)->unique()) {
    1.62 +        dst->reset(SkNEW(SkPathRef));
    1.63 +    }
    1.64 +
    1.65 +    if (*dst != &src) {
    1.66 +        (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
    1.67 +        memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t));
    1.68 +        (*dst)->fConicWeights = src.fConicWeights;
    1.69 +    }
    1.70 +
    1.71 +    SkASSERT((*dst)->countPoints() == src.countPoints());
    1.72 +    SkASSERT((*dst)->countVerbs() == src.countVerbs());
    1.73 +    SkASSERT((*dst)->fConicWeights.count() == src.fConicWeights.count());
    1.74 +
    1.75 +    // Need to check this here in case (&src == dst)
    1.76 +    bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1;
    1.77 +
    1.78 +    matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
    1.79 +
    1.80 +    /*
    1.81 +        *  Here we optimize the bounds computation, by noting if the bounds are
    1.82 +        *  already known, and if so, we just transform those as well and mark
    1.83 +        *  them as "known", rather than force the transformed path to have to
    1.84 +        *  recompute them.
    1.85 +        *
    1.86 +        *  Special gotchas if the path is effectively empty (<= 1 point) or
    1.87 +        *  if it is non-finite. In those cases bounds need to stay empty,
    1.88 +        *  regardless of the matrix.
    1.89 +        */
    1.90 +    if (canXformBounds) {
    1.91 +        (*dst)->fBoundsIsDirty = false;
    1.92 +        if (src.fIsFinite) {
    1.93 +            matrix.mapRect(&(*dst)->fBounds, src.fBounds);
    1.94 +            if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) {
    1.95 +                (*dst)->fBounds.setEmpty();
    1.96 +            }
    1.97 +        } else {
    1.98 +            (*dst)->fIsFinite = false;
    1.99 +            (*dst)->fBounds.setEmpty();
   1.100 +        }
   1.101 +    } else {
   1.102 +        (*dst)->fBoundsIsDirty = true;
   1.103 +    }
   1.104 +
   1.105 +    (*dst)->fSegmentMask = src.fSegmentMask;
   1.106 +
   1.107 +    // It's an oval only if it stays a rect.
   1.108 +    (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect();
   1.109 +
   1.110 +    SkDEBUGCODE((*dst)->validate();)
   1.111 +}
   1.112 +
   1.113 +SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
   1.114 +    SkPathRef* ref = SkNEW(SkPathRef);
   1.115 +    bool isOval;
   1.116 +    uint8_t segmentMask;
   1.117 +
   1.118 +    int32_t packed;
   1.119 +    if (!buffer->readS32(&packed)) {
   1.120 +        SkDELETE(ref);
   1.121 +        return NULL;
   1.122 +    }
   1.123 +
   1.124 +    ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
   1.125 +    segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
   1.126 +    isOval  = (packed >> kIsOval_SerializationShift) & 1;
   1.127 +
   1.128 +    int32_t verbCount, pointCount, conicCount;
   1.129 +    if (!buffer->readU32(&(ref->fGenerationID)) ||
   1.130 +        !buffer->readS32(&verbCount) ||
   1.131 +        !buffer->readS32(&pointCount) ||
   1.132 +        !buffer->readS32(&conicCount)) {
   1.133 +        SkDELETE(ref);
   1.134 +        return NULL;
   1.135 +    }
   1.136 +
   1.137 +    ref->resetToSize(verbCount, pointCount, conicCount);
   1.138 +    SkASSERT(verbCount == ref->countVerbs());
   1.139 +    SkASSERT(pointCount == ref->countPoints());
   1.140 +    SkASSERT(conicCount == ref->fConicWeights.count());
   1.141 +
   1.142 +    if (!buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)) ||
   1.143 +        !buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)) ||
   1.144 +        !buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)) ||
   1.145 +        !buffer->read(&ref->fBounds, sizeof(SkRect))) {
   1.146 +        SkDELETE(ref);
   1.147 +        return NULL;
   1.148 +    }
   1.149 +    ref->fBoundsIsDirty = false;
   1.150 +
   1.151 +    // resetToSize clears fSegmentMask and fIsOval
   1.152 +    ref->fSegmentMask = segmentMask;
   1.153 +    ref->fIsOval = isOval;
   1.154 +    return ref;
   1.155 +}
   1.156 +
   1.157 +void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
   1.158 +    if ((*pathRef)->unique()) {
   1.159 +        SkDEBUGCODE((*pathRef)->validate();)
   1.160 +        (*pathRef)->fBoundsIsDirty = true;  // this also invalidates fIsFinite
   1.161 +        (*pathRef)->fVerbCnt = 0;
   1.162 +        (*pathRef)->fPointCnt = 0;
   1.163 +        (*pathRef)->fFreeSpace = (*pathRef)->currSize();
   1.164 +        (*pathRef)->fGenerationID = 0;
   1.165 +        (*pathRef)->fConicWeights.rewind();
   1.166 +        (*pathRef)->fSegmentMask = 0;
   1.167 +        (*pathRef)->fIsOval = false;
   1.168 +        SkDEBUGCODE((*pathRef)->validate();)
   1.169 +    } else {
   1.170 +        int oldVCnt = (*pathRef)->countVerbs();
   1.171 +        int oldPCnt = (*pathRef)->countPoints();
   1.172 +        pathRef->reset(SkNEW(SkPathRef));
   1.173 +        (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
   1.174 +    }
   1.175 +}
   1.176 +
   1.177 +bool SkPathRef::operator== (const SkPathRef& ref) const {
   1.178 +    SkDEBUGCODE(this->validate();)
   1.179 +    SkDEBUGCODE(ref.validate();)
   1.180 +
   1.181 +    // We explicitly check fSegmentMask as a quick-reject. We could skip it,
   1.182 +    // since it is only a cache of info in the fVerbs, but its a fast way to
   1.183 +    // notice a difference
   1.184 +    if (fSegmentMask != ref.fSegmentMask) {
   1.185 +        return false;
   1.186 +    }
   1.187 +
   1.188 +    bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
   1.189 +#ifdef SK_RELEASE
   1.190 +    if (genIDMatch) {
   1.191 +        return true;
   1.192 +    }
   1.193 +#endif
   1.194 +    if (fPointCnt != ref.fPointCnt ||
   1.195 +        fVerbCnt != ref.fVerbCnt) {
   1.196 +        SkASSERT(!genIDMatch);
   1.197 +        return false;
   1.198 +    }
   1.199 +    if (0 != memcmp(this->verbsMemBegin(),
   1.200 +                    ref.verbsMemBegin(),
   1.201 +                    ref.fVerbCnt * sizeof(uint8_t))) {
   1.202 +        SkASSERT(!genIDMatch);
   1.203 +        return false;
   1.204 +    }
   1.205 +    if (0 != memcmp(this->points(),
   1.206 +                    ref.points(),
   1.207 +                    ref.fPointCnt * sizeof(SkPoint))) {
   1.208 +        SkASSERT(!genIDMatch);
   1.209 +        return false;
   1.210 +    }
   1.211 +    if (fConicWeights != ref.fConicWeights) {
   1.212 +        SkASSERT(!genIDMatch);
   1.213 +        return false;
   1.214 +    }
   1.215 +    // We've done the work to determine that these are equal. If either has a zero genID, copy
   1.216 +    // the other's. If both are 0 then genID() will compute the next ID.
   1.217 +    if (0 == fGenerationID) {
   1.218 +        fGenerationID = ref.genID();
   1.219 +    } else if (0 == ref.fGenerationID) {
   1.220 +        ref.fGenerationID = this->genID();
   1.221 +    }
   1.222 +    return true;
   1.223 +}
   1.224 +
   1.225 +void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
   1.226 +    SkDEBUGCODE(this->validate();)
   1.227 +    SkDEBUGCODE(size_t beforePos = buffer->pos();)
   1.228 +
   1.229 +    // Call getBounds() to ensure (as a side-effect) that fBounds
   1.230 +    // and fIsFinite are computed.
   1.231 +    const SkRect& bounds = this->getBounds();
   1.232 +
   1.233 +    int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
   1.234 +                     ((fIsOval & 1) << kIsOval_SerializationShift) |
   1.235 +                     (fSegmentMask << kSegmentMask_SerializationShift);
   1.236 +    buffer->write32(packed);
   1.237 +
   1.238 +    // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
   1.239 +    // SkWBuffer. Until this is fixed we write 0.
   1.240 +    buffer->write32(0);
   1.241 +    buffer->write32(fVerbCnt);
   1.242 +    buffer->write32(fPointCnt);
   1.243 +    buffer->write32(fConicWeights.count());
   1.244 +    buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
   1.245 +    buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
   1.246 +    buffer->write(fConicWeights.begin(), fConicWeights.bytes());
   1.247 +    buffer->write(&bounds, sizeof(bounds));
   1.248 +
   1.249 +    SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
   1.250 +}
   1.251 +
   1.252 +uint32_t SkPathRef::writeSize() const {
   1.253 +    return uint32_t(5 * sizeof(uint32_t) +
   1.254 +                    fVerbCnt * sizeof(uint8_t) +
   1.255 +                    fPointCnt * sizeof(SkPoint) +
   1.256 +                    fConicWeights.bytes() +
   1.257 +                    sizeof(SkRect));
   1.258 +}
   1.259 +
   1.260 +void SkPathRef::copy(const SkPathRef& ref,
   1.261 +                     int additionalReserveVerbs,
   1.262 +                     int additionalReservePoints) {
   1.263 +    SkDEBUGCODE(this->validate();)
   1.264 +    this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
   1.265 +                        additionalReserveVerbs, additionalReservePoints);
   1.266 +    memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof(uint8_t));
   1.267 +    memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
   1.268 +    fConicWeights = ref.fConicWeights;
   1.269 +    // We could call genID() here to force a real ID (instead of 0). However, if we're making
   1.270 +    // a copy then presumably we intend to make a modification immediately afterwards.
   1.271 +    fGenerationID = ref.fGenerationID;
   1.272 +    fBoundsIsDirty = ref.fBoundsIsDirty;
   1.273 +    if (!fBoundsIsDirty) {
   1.274 +        fBounds = ref.fBounds;
   1.275 +        fIsFinite = ref.fIsFinite;
   1.276 +    }
   1.277 +    fSegmentMask = ref.fSegmentMask;
   1.278 +    fIsOval = ref.fIsOval;
   1.279 +    SkDEBUGCODE(this->validate();)
   1.280 +}
   1.281 +
   1.282 +SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
   1.283 +                                        int numVbs,
   1.284 +                                        SkScalar** weights) {
   1.285 +    // This value is just made-up for now. When count is 4, calling memset was much
   1.286 +    // slower than just writing the loop. This seems odd, and hopefully in the
   1.287 +    // future this will appear to have been a fluke...
   1.288 +    static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16;
   1.289 +
   1.290 +    SkDEBUGCODE(this->validate();)
   1.291 +    int pCnt;
   1.292 +    bool dirtyAfterEdit = true;
   1.293 +    switch (verb) {
   1.294 +        case SkPath::kMove_Verb:
   1.295 +            pCnt = numVbs;
   1.296 +            dirtyAfterEdit = false;
   1.297 +            break;
   1.298 +        case SkPath::kLine_Verb:
   1.299 +            fSegmentMask |= SkPath::kLine_SegmentMask;
   1.300 +            pCnt = numVbs;
   1.301 +            break;
   1.302 +        case SkPath::kQuad_Verb:
   1.303 +            fSegmentMask |= SkPath::kQuad_SegmentMask;
   1.304 +            pCnt = 2 * numVbs;
   1.305 +            break;
   1.306 +        case SkPath::kConic_Verb:
   1.307 +            fSegmentMask |= SkPath::kConic_SegmentMask;
   1.308 +            pCnt = 2 * numVbs;
   1.309 +            break;
   1.310 +        case SkPath::kCubic_Verb:
   1.311 +            fSegmentMask |= SkPath::kCubic_SegmentMask;
   1.312 +            pCnt = 3 * numVbs;
   1.313 +            break;
   1.314 +        case SkPath::kClose_Verb:
   1.315 +            SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb");
   1.316 +            pCnt = 0;
   1.317 +            dirtyAfterEdit = false;
   1.318 +            break;
   1.319 +        case SkPath::kDone_Verb:
   1.320 +            SkDEBUGFAIL("growForRepeatedVerb called for kDone");
   1.321 +            // fall through
   1.322 +        default:
   1.323 +            SkDEBUGFAIL("default should not be reached");
   1.324 +            pCnt = 0;
   1.325 +            dirtyAfterEdit = false;
   1.326 +    }
   1.327 +
   1.328 +    size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint);
   1.329 +    this->makeSpace(space);
   1.330 +
   1.331 +    SkPoint* ret = fPoints + fPointCnt;
   1.332 +    uint8_t* vb = fVerbs - fVerbCnt;
   1.333 +
   1.334 +    // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
   1.335 +    // be 0, the compiler will remove the test/branch entirely.
   1.336 +    if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
   1.337 +        memset(vb - numVbs, verb, numVbs);
   1.338 +    } else {
   1.339 +        for (int i = 0; i < numVbs; ++i) {
   1.340 +            vb[~i] = verb;
   1.341 +        }
   1.342 +    }
   1.343 +
   1.344 +    fVerbCnt += numVbs;
   1.345 +    fPointCnt += pCnt;
   1.346 +    fFreeSpace -= space;
   1.347 +    fBoundsIsDirty = true;  // this also invalidates fIsFinite
   1.348 +    if (dirtyAfterEdit) {
   1.349 +        fIsOval = false;
   1.350 +    }
   1.351 +
   1.352 +    if (SkPath::kConic_Verb == verb) {
   1.353 +        SkASSERT(NULL != weights);
   1.354 +        *weights = fConicWeights.append(numVbs);
   1.355 +    }
   1.356 +
   1.357 +    SkDEBUGCODE(this->validate();)
   1.358 +    return ret;
   1.359 +}
   1.360 +
   1.361 +SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) {
   1.362 +    SkDEBUGCODE(this->validate();)
   1.363 +    int pCnt;
   1.364 +    bool dirtyAfterEdit = true;
   1.365 +    switch (verb) {
   1.366 +        case SkPath::kMove_Verb:
   1.367 +            pCnt = 1;
   1.368 +            dirtyAfterEdit = false;
   1.369 +            break;
   1.370 +        case SkPath::kLine_Verb:
   1.371 +            fSegmentMask |= SkPath::kLine_SegmentMask;
   1.372 +            pCnt = 1;
   1.373 +            break;
   1.374 +        case SkPath::kQuad_Verb:
   1.375 +            fSegmentMask |= SkPath::kQuad_SegmentMask;
   1.376 +            pCnt = 2;
   1.377 +            break;
   1.378 +        case SkPath::kConic_Verb:
   1.379 +            fSegmentMask |= SkPath::kConic_SegmentMask;
   1.380 +            pCnt = 2;
   1.381 +            break;
   1.382 +        case SkPath::kCubic_Verb:
   1.383 +            fSegmentMask |= SkPath::kCubic_SegmentMask;
   1.384 +            pCnt = 3;
   1.385 +            break;
   1.386 +        case SkPath::kClose_Verb:
   1.387 +            pCnt = 0;
   1.388 +            dirtyAfterEdit = false;
   1.389 +            break;
   1.390 +        case SkPath::kDone_Verb:
   1.391 +            SkDEBUGFAIL("growForVerb called for kDone");
   1.392 +            // fall through
   1.393 +        default:
   1.394 +            SkDEBUGFAIL("default is not reached");
   1.395 +            dirtyAfterEdit = false;
   1.396 +            pCnt = 0;
   1.397 +    }
   1.398 +    size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
   1.399 +    this->makeSpace(space);
   1.400 +    this->fVerbs[~fVerbCnt] = verb;
   1.401 +    SkPoint* ret = fPoints + fPointCnt;
   1.402 +    fVerbCnt += 1;
   1.403 +    fPointCnt += pCnt;
   1.404 +    fFreeSpace -= space;
   1.405 +    fBoundsIsDirty = true;  // this also invalidates fIsFinite
   1.406 +    if (dirtyAfterEdit) {
   1.407 +        fIsOval = false;
   1.408 +    }
   1.409 +
   1.410 +    if (SkPath::kConic_Verb == verb) {
   1.411 +        *fConicWeights.append() = weight;
   1.412 +    }
   1.413 +
   1.414 +    SkDEBUGCODE(this->validate();)
   1.415 +    return ret;
   1.416 +}
   1.417 +
   1.418 +uint32_t SkPathRef::genID() const {
   1.419 +    SkASSERT(!fEditorsAttached);
   1.420 +    static const uint32_t kMask = (static_cast<int64_t>(1) << SkPath::kPathRefGenIDBitCnt) - 1;
   1.421 +    if (!fGenerationID) {
   1.422 +        if (0 == fPointCnt && 0 == fVerbCnt) {
   1.423 +            fGenerationID = kEmptyGenID;
   1.424 +        } else {
   1.425 +            static int32_t  gPathRefGenerationID;
   1.426 +            // do a loop in case our global wraps around, as we never want to return a 0 or the
   1.427 +            // empty ID
   1.428 +            do {
   1.429 +                fGenerationID = (sk_atomic_inc(&gPathRefGenerationID) + 1) & kMask;
   1.430 +            } while (fGenerationID <= kEmptyGenID);
   1.431 +        }
   1.432 +    }
   1.433 +    return fGenerationID;
   1.434 +}
   1.435 +
   1.436 +#ifdef SK_DEBUG
   1.437 +void SkPathRef::validate() const {
   1.438 +    this->INHERITED::validate();
   1.439 +    SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
   1.440 +    SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) >= 0);
   1.441 +    SkASSERT((NULL == fPoints) == (NULL == fVerbs));
   1.442 +    SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
   1.443 +    SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
   1.444 +    SkASSERT(!(NULL == fPoints && fPointCnt));
   1.445 +    SkASSERT(!(NULL == fVerbs && fVerbCnt));
   1.446 +    SkASSERT(this->currSize() ==
   1.447 +                fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt);
   1.448 +
   1.449 +    if (!fBoundsIsDirty && !fBounds.isEmpty()) {
   1.450 +        bool isFinite = true;
   1.451 +        for (int i = 0; i < fPointCnt; ++i) {
   1.452 +            SkASSERT(!fPoints[i].isFinite() || (
   1.453 +                     fBounds.fLeft - fPoints[i].fX   < SK_ScalarNearlyZero &&
   1.454 +                     fPoints[i].fX - fBounds.fRight  < SK_ScalarNearlyZero &&
   1.455 +                     fBounds.fTop  - fPoints[i].fY   < SK_ScalarNearlyZero &&
   1.456 +                     fPoints[i].fY - fBounds.fBottom < SK_ScalarNearlyZero));
   1.457 +            if (!fPoints[i].isFinite()) {
   1.458 +                isFinite = false;
   1.459 +            }
   1.460 +        }
   1.461 +        SkASSERT(SkToBool(fIsFinite) == isFinite);
   1.462 +    }
   1.463 +
   1.464 +#ifdef SK_DEBUG_PATH
   1.465 +    uint32_t mask = 0;
   1.466 +    for (int i = 0; i < fVerbCnt; ++i) {
   1.467 +        switch (fVerbs[~i]) {
   1.468 +            case SkPath::kMove_Verb:
   1.469 +                break;
   1.470 +            case SkPath::kLine_Verb:
   1.471 +                mask |= SkPath::kLine_SegmentMask;
   1.472 +                break;
   1.473 +            case SkPath::kQuad_Verb:
   1.474 +                mask |= SkPath::kQuad_SegmentMask;
   1.475 +                break;
   1.476 +            case SkPath::kConic_Verb:
   1.477 +                mask |= SkPath::kConic_SegmentMask;
   1.478 +                break;
   1.479 +            case SkPath::kCubic_Verb:
   1.480 +                mask |= SkPath::kCubic_SegmentMask;
   1.481 +                break;
   1.482 +            case SkPath::kClose_Verb:
   1.483 +                break;
   1.484 +            case SkPath::kDone_Verb:
   1.485 +                SkDEBUGFAIL("Done verb shouldn't be recorded.");
   1.486 +                break;
   1.487 +            default:
   1.488 +                SkDEBUGFAIL("Unknown Verb");
   1.489 +                break;
   1.490 +        }
   1.491 +    }
   1.492 +    SkASSERT(mask == fSegmentMask);
   1.493 +#endif // SK_DEBUG_PATH
   1.494 +}
   1.495 +#endif

mercurial