1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkBuffer.h"
9#include "SkNx.h"
10#include "SkOnce.h"
11#include "SkPath.h"
12#include "SkPathRef.h"
13#include "SkPathPriv.h"
14#include "SkSafeMath.h"
15
16// Conic weights must be 0 < weight <= finite
17static bool validate_conic_weights(const SkScalar weights[], int count) {
18    for (int i = 0; i < count; ++i) {
19        if (weights[i] <= 0 || !SkScalarIsFinite(weights[i])) {
20            return false;
21        }
22    }
23    return true;
24}
25
26//////////////////////////////////////////////////////////////////////////////
27SkPathRef::Editor::Editor(sk_sp<SkPathRef>* pathRef,
28                          int incReserveVerbs,
29                          int incReservePoints)
30{
31    if ((*pathRef)->unique()) {
32        (*pathRef)->incReserve(incReserveVerbs, incReservePoints);
33    } else {
34        SkPathRef* copy = new SkPathRef;
35        copy->copy(**pathRef, incReserveVerbs, incReservePoints);
36        pathRef->reset(copy);
37    }
38    fPathRef = pathRef->get();
39    fPathRef->callGenIDChangeListeners();
40    fPathRef->fGenerationID = 0;
41    SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
42}
43
44//////////////////////////////////////////////////////////////////////////////
45
46SkPathRef::~SkPathRef() {
47    // Deliberately don't validate() this path ref, otherwise there's no way
48    // to read one that's not valid and then free its memory without asserting.
49    this->callGenIDChangeListeners();
50    sk_free(fPoints);
51
52    SkDEBUGCODE(fPoints = nullptr;)
53    SkDEBUGCODE(fVerbs = nullptr;)
54    SkDEBUGCODE(fVerbCnt = 0x9999999;)
55    SkDEBUGCODE(fPointCnt = 0xAAAAAAA;)
56    SkDEBUGCODE(fPointCnt = 0xBBBBBBB;)
57    SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;)
58    SkDEBUGCODE(fEditorsAttached = 0x7777777;)
59}
60
61static SkPathRef* gEmpty = nullptr;
62
63SkPathRef* SkPathRef::CreateEmpty() {
64    static SkOnce once;
65    once([]{
66        gEmpty = new SkPathRef;
67        gEmpty->computeBounds();   // Avoids races later to be the first to do this.
68    });
69    return SkRef(gEmpty);
70}
71
72static void transform_dir_and_start(const SkMatrix& matrix, bool isRRect, bool* isCCW,
73                                    unsigned* start) {
74    int inStart = *start;
75    int rm = 0;
76    if (isRRect) {
77        // Degenerate rrect indices to oval indices and remember the remainder.
78        // Ovals have one index per side whereas rrects have two.
79        rm = inStart & 0b1;
80        inStart /= 2;
81    }
82    // Is the antidiagonal non-zero (otherwise the diagonal is zero)
83    int antiDiag;
84    // Is the non-zero value in the top row (either kMScaleX or kMSkewX) negative
85    int topNeg;
86    // Are the two non-zero diagonal or antidiagonal values the same sign.
87    int sameSign;
88    if (matrix.get(SkMatrix::kMScaleX) != 0) {
89        antiDiag = 0b00;
90        if (matrix.get(SkMatrix::kMScaleX) > 0) {
91            topNeg = 0b00;
92            sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b01 : 0b00;
93        } else {
94            topNeg = 0b10;
95            sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b00 : 0b01;
96        }
97    } else {
98        antiDiag = 0b01;
99        if (matrix.get(SkMatrix::kMSkewX) > 0) {
100            topNeg = 0b00;
101            sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b01 : 0b00;
102        } else {
103            topNeg = 0b10;
104            sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b00 : 0b01;
105        }
106    }
107    if (sameSign != antiDiag) {
108        // This is a rotation (and maybe scale). The direction is unchanged.
109        // Trust me on the start computation (or draw yourself some pictures)
110        *start = (inStart + 4 - (topNeg | antiDiag)) % 4;
111        SkASSERT(*start < 4);
112        if (isRRect) {
113            *start = 2 * *start + rm;
114        }
115    } else {
116        // This is a mirror (and maybe scale). The direction is reversed.
117        *isCCW = !*isCCW;
118        // Trust me on the start computation (or draw yourself some pictures)
119        *start = (6 + (topNeg | antiDiag) - inStart) % 4;
120        SkASSERT(*start < 4);
121        if (isRRect) {
122            *start = 2 * *start + (rm ? 0 : 1);
123        }
124    }
125}
126
127void SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst,
128                                      const SkPathRef& src,
129                                      const SkMatrix& matrix) {
130    SkDEBUGCODE(src.validate();)
131    if (matrix.isIdentity()) {
132        if (dst->get() != &src) {
133            src.ref();
134            dst->reset(const_cast<SkPathRef*>(&src));
135            SkDEBUGCODE((*dst)->validate();)
136        }
137        return;
138    }
139
140    if (!(*dst)->unique()) {
141        dst->reset(new SkPathRef);
142    }
143
144    if (dst->get() != &src) {
145        (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
146        sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(),
147                           src.fVerbCnt * sizeof(uint8_t));
148        (*dst)->fConicWeights = src.fConicWeights;
149    }
150
151    SkASSERT((*dst)->countPoints() == src.countPoints());
152    SkASSERT((*dst)->countVerbs() == src.countVerbs());
153    SkASSERT((*dst)->fConicWeights.count() == src.fConicWeights.count());
154
155    // Need to check this here in case (&src == dst)
156    bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1;
157
158    matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
159
160    /*
161     *  Here we optimize the bounds computation, by noting if the bounds are
162     *  already known, and if so, we just transform those as well and mark
163     *  them as "known", rather than force the transformed path to have to
164     *  recompute them.
165     *
166     *  Special gotchas if the path is effectively empty (<= 1 point) or
167     *  if it is non-finite. In those cases bounds need to stay empty,
168     *  regardless of the matrix.
169     */
170    if (canXformBounds) {
171        (*dst)->fBoundsIsDirty = false;
172        if (src.fIsFinite) {
173            matrix.mapRect(&(*dst)->fBounds, src.fBounds);
174            if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) {
175                (*dst)->fBounds.setEmpty();
176            }
177        } else {
178            (*dst)->fIsFinite = false;
179            (*dst)->fBounds.setEmpty();
180        }
181    } else {
182        (*dst)->fBoundsIsDirty = true;
183    }
184
185    (*dst)->fSegmentMask = src.fSegmentMask;
186
187    // It's an oval only if it stays a rect.
188    bool rectStaysRect = matrix.rectStaysRect();
189    (*dst)->fIsOval = src.fIsOval && rectStaysRect;
190    (*dst)->fIsRRect = src.fIsRRect && rectStaysRect;
191    if ((*dst)->fIsOval || (*dst)->fIsRRect) {
192        unsigned start = src.fRRectOrOvalStartIdx;
193        bool isCCW = SkToBool(src.fRRectOrOvalIsCCW);
194        transform_dir_and_start(matrix, (*dst)->fIsRRect, &isCCW, &start);
195        (*dst)->fRRectOrOvalIsCCW = isCCW;
196        (*dst)->fRRectOrOvalStartIdx = start;
197    }
198
199    SkDEBUGCODE((*dst)->validate();)
200}
201
202static bool validate_verb_sequence(const uint8_t verbs[], int vCount) {
203    // verbs are stored backwards, but we need to visit them in logical order to determine if
204    // they form a valid sequence.
205
206    bool needsMoveTo = true;
207    bool invalidSequence = false;
208
209    for (int i = vCount - 1; i >= 0; --i) {
210        switch (verbs[i]) {
211            case SkPath::kMove_Verb:
212                needsMoveTo = false;
213                break;
214            case SkPath::kLine_Verb:
215            case SkPath::kQuad_Verb:
216            case SkPath::kConic_Verb:
217            case SkPath::kCubic_Verb:
218                invalidSequence |= needsMoveTo;
219                break;
220            case SkPath::kClose_Verb:
221                needsMoveTo = true;
222                break;
223            default:
224                return false;   // unknown verb
225        }
226    }
227    return !invalidSequence;
228}
229
230// Given the verb array, deduce the required number of pts and conics,
231// or if an invalid verb is encountered, return false.
232static bool deduce_pts_conics(const uint8_t verbs[], int vCount, int* ptCountPtr,
233                              int* conicCountPtr) {
234    // When there is at least one verb, the first is required to be kMove_Verb.
235    if (0 < vCount && verbs[vCount-1] != SkPath::kMove_Verb) {
236        return false;
237    }
238
239    SkSafeMath safe;
240    int ptCount = 0;
241    int conicCount = 0;
242    for (int i = 0; i < vCount; ++i) {
243        switch (verbs[i]) {
244            case SkPath::kMove_Verb:
245            case SkPath::kLine_Verb:
246                ptCount = safe.addInt(ptCount, 1);
247                break;
248            case SkPath::kConic_Verb:
249                conicCount += 1;
250                // fall-through
251            case SkPath::kQuad_Verb:
252                ptCount = safe.addInt(ptCount, 2);
253                break;
254            case SkPath::kCubic_Verb:
255                ptCount = safe.addInt(ptCount, 3);
256                break;
257            case SkPath::kClose_Verb:
258                break;
259            default:
260                return false;
261        }
262    }
263    if (!safe) {
264        return false;
265    }
266    *ptCountPtr = ptCount;
267    *conicCountPtr = conicCount;
268    return true;
269}
270
271SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
272    std::unique_ptr<SkPathRef> ref(new SkPathRef);
273
274    int32_t packed;
275    if (!buffer->readS32(&packed)) {
276        return nullptr;
277    }
278
279    ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
280    uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
281
282    int32_t verbCount, pointCount, conicCount;
283    if (!buffer->readU32(&(ref->fGenerationID)) ||
284        !buffer->readS32(&verbCount)            || (verbCount  < 0) ||
285        !buffer->readS32(&pointCount)           || (pointCount < 0) ||
286        !buffer->readS32(&conicCount)           || (conicCount < 0))
287    {
288        return nullptr;
289    }
290
291    uint64_t pointSize64 = sk_64_mul(pointCount, sizeof(SkPoint));
292    uint64_t conicSize64 = sk_64_mul(conicCount, sizeof(SkScalar));
293    if (!SkTFitsIn<size_t>(pointSize64) || !SkTFitsIn<size_t>(conicSize64)) {
294        return nullptr;
295    }
296
297    size_t verbSize = verbCount * sizeof(uint8_t);
298    size_t pointSize = SkToSizeT(pointSize64);
299    size_t conicSize = SkToSizeT(conicSize64);
300
301    {
302        uint64_t requiredBufferSize = sizeof(SkRect);
303        requiredBufferSize += verbSize;
304        requiredBufferSize += pointSize;
305        requiredBufferSize += conicSize;
306        if (buffer->available() < requiredBufferSize) {
307            return nullptr;
308        }
309    }
310
311    ref->resetToSize(verbCount, pointCount, conicCount);
312    SkASSERT(verbCount  == ref->countVerbs());
313    SkASSERT(pointCount == ref->countPoints());
314    SkASSERT(conicCount == ref->fConicWeights.count());
315
316    if (!buffer->read(ref->verbsMemWritable(), verbSize) ||
317        !buffer->read(ref->fPoints, pointSize) ||
318        !buffer->read(ref->fConicWeights.begin(), conicSize) ||
319        !buffer->read(&ref->fBounds, sizeof(SkRect))) {
320        return nullptr;
321    }
322
323    // Check that the verbs are valid, and imply the correct number of pts and conics
324    {
325        int pCount, cCount;
326        if (!validate_verb_sequence(ref->verbsMemBegin(), ref->countVerbs())) {
327            return nullptr;
328        }
329        if (!deduce_pts_conics(ref->verbsMemBegin(), ref->countVerbs(), &pCount, &cCount) ||
330            pCount != ref->countPoints() || cCount != ref->fConicWeights.count()) {
331            return nullptr;
332        }
333        if (!validate_conic_weights(ref->fConicWeights.begin(), ref->fConicWeights.count())) {
334            return nullptr;
335        }
336        // Check that the bounds match the serialized bounds.
337        SkRect bounds;
338        if (ComputePtBounds(&bounds, *ref) != SkToBool(ref->fIsFinite) || bounds != ref->fBounds) {
339            return nullptr;
340        }
341    }
342
343    ref->fBoundsIsDirty = false;
344
345    // resetToSize clears fSegmentMask and fIsOval
346    ref->fSegmentMask = segmentMask;
347    return ref.release();
348}
349
350void SkPathRef::Rewind(sk_sp<SkPathRef>* pathRef) {
351    if ((*pathRef)->unique()) {
352        SkDEBUGCODE((*pathRef)->validate();)
353        (*pathRef)->callGenIDChangeListeners();
354        (*pathRef)->fBoundsIsDirty = true;  // this also invalidates fIsFinite
355        (*pathRef)->fVerbCnt = 0;
356        (*pathRef)->fPointCnt = 0;
357        (*pathRef)->fFreeSpace = (*pathRef)->currSize();
358        (*pathRef)->fGenerationID = 0;
359        (*pathRef)->fConicWeights.rewind();
360        (*pathRef)->fSegmentMask = 0;
361        (*pathRef)->fIsOval = false;
362        (*pathRef)->fIsRRect = false;
363        SkDEBUGCODE((*pathRef)->validate();)
364    } else {
365        int oldVCnt = (*pathRef)->countVerbs();
366        int oldPCnt = (*pathRef)->countPoints();
367        pathRef->reset(new SkPathRef);
368        (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
369    }
370}
371
372bool SkPathRef::operator== (const SkPathRef& ref) const {
373    SkDEBUGCODE(this->validate();)
374    SkDEBUGCODE(ref.validate();)
375
376    // We explicitly check fSegmentMask as a quick-reject. We could skip it,
377    // since it is only a cache of info in the fVerbs, but its a fast way to
378    // notice a difference
379    if (fSegmentMask != ref.fSegmentMask) {
380        return false;
381    }
382
383    bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
384#ifdef SK_RELEASE
385    if (genIDMatch) {
386        return true;
387    }
388#endif
389    if (fPointCnt != ref.fPointCnt ||
390        fVerbCnt != ref.fVerbCnt) {
391        SkASSERT(!genIDMatch);
392        return false;
393    }
394    if (0 == ref.fVerbCnt) {
395        SkASSERT(0 == ref.fPointCnt);
396        return true;
397    }
398    SkASSERT(this->verbsMemBegin() && ref.verbsMemBegin());
399    if (0 != memcmp(this->verbsMemBegin(),
400                    ref.verbsMemBegin(),
401                    ref.fVerbCnt * sizeof(uint8_t))) {
402        SkASSERT(!genIDMatch);
403        return false;
404    }
405    SkASSERT(this->points() && ref.points());
406    if (0 != memcmp(this->points(),
407                    ref.points(),
408                    ref.fPointCnt * sizeof(SkPoint))) {
409        SkASSERT(!genIDMatch);
410        return false;
411    }
412    if (fConicWeights != ref.fConicWeights) {
413        SkASSERT(!genIDMatch);
414        return false;
415    }
416    return true;
417}
418
419void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
420    SkDEBUGCODE(this->validate();)
421    SkDEBUGCODE(size_t beforePos = buffer->pos();)
422
423    // Call getBounds() to ensure (as a side-effect) that fBounds
424    // and fIsFinite are computed.
425    const SkRect& bounds = this->getBounds();
426
427    int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
428                     (fSegmentMask << kSegmentMask_SerializationShift);
429    buffer->write32(packed);
430
431    // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
432    // SkWBuffer. Until this is fixed we write 0.
433    buffer->write32(0);
434    buffer->write32(fVerbCnt);
435    buffer->write32(fPointCnt);
436    buffer->write32(fConicWeights.count());
437    buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
438    buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
439    buffer->write(fConicWeights.begin(), fConicWeights.bytes());
440    buffer->write(&bounds, sizeof(bounds));
441
442    SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
443}
444
445uint32_t SkPathRef::writeSize() const {
446    return uint32_t(5 * sizeof(uint32_t) +
447                    fVerbCnt * sizeof(uint8_t) +
448                    fPointCnt * sizeof(SkPoint) +
449                    fConicWeights.bytes() +
450                    sizeof(SkRect));
451}
452
453void SkPathRef::copy(const SkPathRef& ref,
454                     int additionalReserveVerbs,
455                     int additionalReservePoints) {
456    SkDEBUGCODE(this->validate();)
457    this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
458                        additionalReserveVerbs, additionalReservePoints);
459    sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t));
460    sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
461    fConicWeights = ref.fConicWeights;
462    fBoundsIsDirty = ref.fBoundsIsDirty;
463    if (!fBoundsIsDirty) {
464        fBounds = ref.fBounds;
465        fIsFinite = ref.fIsFinite;
466    }
467    fSegmentMask = ref.fSegmentMask;
468    fIsOval = ref.fIsOval;
469    fIsRRect = ref.fIsRRect;
470    fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW;
471    fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx;
472    SkDEBUGCODE(this->validate();)
473}
474
475
476void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const {
477    const SkScalar* inValues = &ending.getPoints()->fX;
478    SkScalar* outValues = &out->getPoints()->fX;
479    int count = out->countPoints() * 2;
480    for (int index = 0; index < count; ++index) {
481        outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight);
482    }
483    out->fBoundsIsDirty = true;
484    out->fIsOval = false;
485    out->fIsRRect = false;
486}
487
488SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
489                                        int numVbs,
490                                        SkScalar** weights) {
491    // This value is just made-up for now. When count is 4, calling memset was much
492    // slower than just writing the loop. This seems odd, and hopefully in the
493    // future this will appear to have been a fluke...
494    static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16;
495
496    SkDEBUGCODE(this->validate();)
497    int pCnt;
498    bool dirtyAfterEdit = true;
499    switch (verb) {
500        case SkPath::kMove_Verb:
501            pCnt = numVbs;
502            dirtyAfterEdit = false;
503            break;
504        case SkPath::kLine_Verb:
505            fSegmentMask |= SkPath::kLine_SegmentMask;
506            pCnt = numVbs;
507            break;
508        case SkPath::kQuad_Verb:
509            fSegmentMask |= SkPath::kQuad_SegmentMask;
510            pCnt = 2 * numVbs;
511            break;
512        case SkPath::kConic_Verb:
513            fSegmentMask |= SkPath::kConic_SegmentMask;
514            pCnt = 2 * numVbs;
515            break;
516        case SkPath::kCubic_Verb:
517            fSegmentMask |= SkPath::kCubic_SegmentMask;
518            pCnt = 3 * numVbs;
519            break;
520        case SkPath::kClose_Verb:
521            SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb");
522            pCnt = 0;
523            dirtyAfterEdit = false;
524            break;
525        case SkPath::kDone_Verb:
526            SkDEBUGFAIL("growForRepeatedVerb called for kDone");
527            // fall through
528        default:
529            SkDEBUGFAIL("default should not be reached");
530            pCnt = 0;
531            dirtyAfterEdit = false;
532    }
533
534    size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint);
535    this->makeSpace(space);
536
537    SkPoint* ret = fPoints + fPointCnt;
538    uint8_t* vb = fVerbs - fVerbCnt;
539
540    // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
541    // be 0, the compiler will remove the test/branch entirely.
542    if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
543        memset(vb - numVbs, verb, numVbs);
544    } else {
545        for (int i = 0; i < numVbs; ++i) {
546            vb[~i] = verb;
547        }
548    }
549
550    fVerbCnt += numVbs;
551    fPointCnt += pCnt;
552    fFreeSpace -= space;
553    fBoundsIsDirty = true;  // this also invalidates fIsFinite
554    if (dirtyAfterEdit) {
555        fIsOval = false;
556        fIsRRect = false;
557    }
558
559    if (SkPath::kConic_Verb == verb) {
560        SkASSERT(weights);
561        *weights = fConicWeights.append(numVbs);
562    }
563
564    SkDEBUGCODE(this->validate();)
565    return ret;
566}
567
568SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) {
569    SkDEBUGCODE(this->validate();)
570    int pCnt;
571    bool dirtyAfterEdit = true;
572    switch (verb) {
573        case SkPath::kMove_Verb:
574            pCnt = 1;
575            dirtyAfterEdit = false;
576            break;
577        case SkPath::kLine_Verb:
578            fSegmentMask |= SkPath::kLine_SegmentMask;
579            pCnt = 1;
580            break;
581        case SkPath::kQuad_Verb:
582            fSegmentMask |= SkPath::kQuad_SegmentMask;
583            pCnt = 2;
584            break;
585        case SkPath::kConic_Verb:
586            fSegmentMask |= SkPath::kConic_SegmentMask;
587            pCnt = 2;
588            break;
589        case SkPath::kCubic_Verb:
590            fSegmentMask |= SkPath::kCubic_SegmentMask;
591            pCnt = 3;
592            break;
593        case SkPath::kClose_Verb:
594            pCnt = 0;
595            dirtyAfterEdit = false;
596            break;
597        case SkPath::kDone_Verb:
598            SkDEBUGFAIL("growForVerb called for kDone");
599            // fall through
600        default:
601            SkDEBUGFAIL("default is not reached");
602            dirtyAfterEdit = false;
603            pCnt = 0;
604    }
605    SkSafeMath safe;
606    int newPointCnt = safe.addInt(fPointCnt, pCnt);
607    int newVerbCnt  = safe.addInt(fVerbCnt, 1);
608    if (!safe) {
609        SK_ABORT("cannot grow path");
610    }
611    size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
612    this->makeSpace(space);
613    this->fVerbs[~fVerbCnt] = verb;
614    SkPoint* ret = fPoints + fPointCnt;
615    fVerbCnt = newVerbCnt;
616    fPointCnt = newPointCnt;
617    fFreeSpace -= space;
618    fBoundsIsDirty = true;  // this also invalidates fIsFinite
619    if (dirtyAfterEdit) {
620        fIsOval = false;
621        fIsRRect = false;
622    }
623
624    if (SkPath::kConic_Verb == verb) {
625        *fConicWeights.append() = weight;
626    }
627
628    SkDEBUGCODE(this->validate();)
629    return ret;
630}
631
632uint32_t SkPathRef::genID() const {
633    SkASSERT(!fEditorsAttached);
634    static const uint32_t kMask = (static_cast<int64_t>(1) << SkPathPriv::kPathRefGenIDBitCnt) - 1;
635    if (!fGenerationID) {
636        if (0 == fPointCnt && 0 == fVerbCnt) {
637            fGenerationID = kEmptyGenID;
638        } else {
639            static int32_t  gPathRefGenerationID;
640            // do a loop in case our global wraps around, as we never want to return a 0 or the
641            // empty ID
642            do {
643                fGenerationID = (sk_atomic_inc(&gPathRefGenerationID) + 1) & kMask;
644            } while (fGenerationID <= kEmptyGenID);
645        }
646    }
647    return fGenerationID;
648}
649
650void SkPathRef::addGenIDChangeListener(GenIDChangeListener* listener) {
651    if (nullptr == listener || this == gEmpty) {
652        delete listener;
653        return;
654    }
655    *fGenIDChangeListeners.append() = listener;
656}
657
658// we need to be called *before* the genID gets changed or zerod
659void SkPathRef::callGenIDChangeListeners() {
660    for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
661        fGenIDChangeListeners[i]->onChange();
662    }
663
664    // Listeners get at most one shot, so whether these triggered or not, blow them away.
665    fGenIDChangeListeners.deleteAll();
666}
667
668SkRRect SkPathRef::getRRect() const {
669    const SkRect& bounds = this->getBounds();
670    SkVector radii[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
671    Iter iter(*this);
672    SkPoint pts[4];
673    uint8_t verb = iter.next(pts);
674    SkASSERT(SkPath::kMove_Verb == verb);
675    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
676        if (SkPath::kConic_Verb == verb) {
677            SkVector v1_0 = pts[1] - pts[0];
678            SkVector v2_1 = pts[2] - pts[1];
679            SkVector dxdy;
680            if (v1_0.fX) {
681                SkASSERT(!v2_1.fX && !v1_0.fY);
682                dxdy.set(SkScalarAbs(v1_0.fX), SkScalarAbs(v2_1.fY));
683            } else if (!v1_0.fY) {
684                SkASSERT(!v2_1.fX || !v2_1.fY);
685                dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v2_1.fY));
686            } else {
687                SkASSERT(!v2_1.fY);
688                dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v1_0.fY));
689            }
690            SkRRect::Corner corner =
691                    pts[1].fX == bounds.fLeft ?
692                        pts[1].fY == bounds.fTop ?
693                            SkRRect::kUpperLeft_Corner : SkRRect::kLowerLeft_Corner :
694                    pts[1].fY == bounds.fTop ?
695                            SkRRect::kUpperRight_Corner : SkRRect::kLowerRight_Corner;
696            SkASSERT(!radii[corner].fX && !radii[corner].fY);
697            radii[corner] = dxdy;
698        } else {
699            SkASSERT((verb == SkPath::kLine_Verb
700                    && (!(pts[1].fX - pts[0].fX) || !(pts[1].fY - pts[0].fY)))
701                    || verb == SkPath::kClose_Verb);
702        }
703    }
704    SkRRect rrect;
705    rrect.setRectRadii(bounds, radii);
706    return rrect;
707}
708
709///////////////////////////////////////////////////////////////////////////////
710
711SkPathRef::Iter::Iter() {
712#ifdef SK_DEBUG
713    fPts = nullptr;
714    fConicWeights = nullptr;
715#endif
716    // need to init enough to make next() harmlessly return kDone_Verb
717    fVerbs = nullptr;
718    fVerbStop = nullptr;
719}
720
721SkPathRef::Iter::Iter(const SkPathRef& path) {
722    this->setPathRef(path);
723}
724
725void SkPathRef::Iter::setPathRef(const SkPathRef& path) {
726    fPts = path.points();
727    fVerbs = path.verbs();
728    fVerbStop = path.verbsMemBegin();
729    fConicWeights = path.conicWeights();
730    if (fConicWeights) {
731      fConicWeights -= 1;  // begin one behind
732    }
733
734    // Don't allow iteration through non-finite points.
735    if (!path.isFinite()) {
736        fVerbStop = fVerbs;
737    }
738}
739
740uint8_t SkPathRef::Iter::next(SkPoint pts[4]) {
741    SkASSERT(pts);
742    if (fVerbs == fVerbStop) {
743        return (uint8_t) SkPath::kDone_Verb;
744    }
745
746    // fVerbs points one beyond next verb so decrement first.
747    unsigned verb = *(--fVerbs);
748    const SkPoint* srcPts = fPts;
749
750    switch (verb) {
751        case SkPath::kMove_Verb:
752            pts[0] = srcPts[0];
753            srcPts += 1;
754            break;
755        case SkPath::kLine_Verb:
756            pts[0] = srcPts[-1];
757            pts[1] = srcPts[0];
758            srcPts += 1;
759            break;
760        case SkPath::kConic_Verb:
761            fConicWeights += 1;
762            // fall-through
763        case SkPath::kQuad_Verb:
764            pts[0] = srcPts[-1];
765            pts[1] = srcPts[0];
766            pts[2] = srcPts[1];
767            srcPts += 2;
768            break;
769        case SkPath::kCubic_Verb:
770            pts[0] = srcPts[-1];
771            pts[1] = srcPts[0];
772            pts[2] = srcPts[1];
773            pts[3] = srcPts[2];
774            srcPts += 3;
775            break;
776        case SkPath::kClose_Verb:
777            break;
778        case SkPath::kDone_Verb:
779            SkASSERT(fVerbs == fVerbStop);
780            break;
781    }
782    fPts = srcPts;
783    return (uint8_t) verb;
784}
785
786uint8_t SkPathRef::Iter::peek() const {
787    const uint8_t* next = fVerbs - 1;
788    return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : *next;
789}
790
791
792bool SkPathRef::isValid() const {
793    if (static_cast<ptrdiff_t>(fFreeSpace) < 0) {
794        return false;
795    }
796    if (reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) < 0) {
797        return false;
798    }
799    if ((nullptr == fPoints) != (nullptr == fVerbs)) {
800        return false;
801    }
802    if (nullptr == fPoints && 0 != fFreeSpace) {
803        return false;
804    }
805    if (nullptr == fPoints && fPointCnt) {
806        return false;
807    }
808    if (nullptr == fVerbs && fVerbCnt) {
809        return false;
810    }
811    if (this->currSize() !=
812                fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt) {
813        return false;
814    }
815
816    if (fIsOval || fIsRRect) {
817        // Currently we don't allow both of these to be set, even though ovals are ro
818        if (fIsOval == fIsRRect) {
819            return false;
820        }
821        if (fIsOval) {
822            if (fRRectOrOvalStartIdx >= 4) {
823                return false;
824            }
825        } else {
826            if (fRRectOrOvalStartIdx >= 8) {
827                return false;
828            }
829        }
830    }
831
832    if (!fBoundsIsDirty && !fBounds.isEmpty()) {
833        bool isFinite = true;
834        Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop);
835        Sk2s rightBot = Sk2s(fBounds.fRight, fBounds.fBottom);
836        for (int i = 0; i < fPointCnt; ++i) {
837            Sk2s point = Sk2s(fPoints[i].fX, fPoints[i].fY);
838#ifdef SK_DEBUG
839            if (fPoints[i].isFinite() &&
840                ((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) {
841                SkDebugf("bounds: %f %f %f %f\n",
842                         fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
843                for (int j = 0; j < fPointCnt; ++j) {
844                    if (i == j) {
845                        SkDebugf("*");
846                    }
847                    SkDebugf("%f %f\n", fPoints[j].fX, fPoints[j].fY);
848                }
849            }
850#endif
851
852            if (fPoints[i].isFinite() && (point < leftTop).anyTrue() && !(point > rightBot).anyTrue())
853                return false;
854            if (!fPoints[i].isFinite()) {
855                isFinite = false;
856            }
857        }
858        if (SkToBool(fIsFinite) != isFinite) {
859            return false;
860        }
861    }
862
863#ifdef SK_DEBUG_PATH
864    uint32_t mask = 0;
865    for (int i = 0; i < fVerbCnt; ++i) {
866        switch (fVerbs[~i]) {
867            case SkPath::kMove_Verb:
868                break;
869            case SkPath::kLine_Verb:
870                mask |= SkPath::kLine_SegmentMask;
871                break;
872            case SkPath::kQuad_Verb:
873                mask |= SkPath::kQuad_SegmentMask;
874                break;
875            case SkPath::kConic_Verb:
876                mask |= SkPath::kConic_SegmentMask;
877                break;
878            case SkPath::kCubic_Verb:
879                mask |= SkPath::kCubic_SegmentMask;
880                break;
881            case SkPath::kClose_Verb:
882                break;
883            case SkPath::kDone_Verb:
884                SkDEBUGFAIL("Done verb shouldn't be recorded.");
885                break;
886            default:
887                SkDEBUGFAIL("Unknown Verb");
888                break;
889        }
890    }
891    if (mask != fSegmentMask) {
892        return false;
893    }
894#endif // SK_DEBUG_PATH
895    return true;
896}
897