1/*
2 * Copyright 2006 The Android Open Source Project
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 "SkCubicClipper.h"
10#include "SkErrorInternals.h"
11#include "SkGeometry.h"
12#include "SkMath.h"
13#include "SkPathPriv.h"
14#include "SkPathRef.h"
15#include "SkRRect.h"
16
17////////////////////////////////////////////////////////////////////////////
18
19/**
20 *  Path.bounds is defined to be the bounds of all the control points.
21 *  If we called bounds.join(r) we would skip r if r was empty, which breaks
22 *  our promise. Hence we have a custom joiner that doesn't look at emptiness
23 */
24static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
25    dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
26    dst->fTop = SkMinScalar(dst->fTop, src.fTop);
27    dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
28    dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
29}
30
31static bool is_degenerate(const SkPath& path) {
32    SkPath::Iter iter(path, false);
33    SkPoint pts[4];
34    return SkPath::kDone_Verb == iter.next(pts);
35}
36
37class SkAutoDisableDirectionCheck {
38public:
39    SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) {
40        fSaved = static_cast<SkPathPriv::FirstDirection>(fPath->fFirstDirection.load());
41    }
42
43    ~SkAutoDisableDirectionCheck() {
44        fPath->fFirstDirection = fSaved;
45    }
46
47private:
48    SkPath*                     fPath;
49    SkPathPriv::FirstDirection  fSaved;
50};
51#define SkAutoDisableDirectionCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableDirectionCheck)
52
53/*  This guy's constructor/destructor bracket a path editing operation. It is
54    used when we know the bounds of the amount we are going to add to the path
55    (usually a new contour, but not required).
56
57    It captures some state about the path up front (i.e. if it already has a
58    cached bounds), and then if it can, it updates the cache bounds explicitly,
59    avoiding the need to revisit all of the points in getBounds().
60
61    It also notes if the path was originally degenerate, and if so, sets
62    isConvex to true. Thus it can only be used if the contour being added is
63    convex.
64 */
65class SkAutoPathBoundsUpdate {
66public:
67    SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
68        this->init(path);
69    }
70
71    SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
72                           SkScalar right, SkScalar bottom) {
73        fRect.set(left, top, right, bottom);
74        this->init(path);
75    }
76
77    ~SkAutoPathBoundsUpdate() {
78        fPath->setConvexity(fDegenerate ? SkPath::kConvex_Convexity
79                                        : SkPath::kUnknown_Convexity);
80        if (fEmpty || fHasValidBounds) {
81            fPath->setBounds(fRect);
82        }
83    }
84
85private:
86    SkPath* fPath;
87    SkRect  fRect;
88    bool    fHasValidBounds;
89    bool    fDegenerate;
90    bool    fEmpty;
91
92    void init(SkPath* path) {
93        // Cannot use fRect for our bounds unless we know it is sorted
94        fRect.sort();
95        fPath = path;
96        // Mark the path's bounds as dirty if (1) they are, or (2) the path
97        // is non-finite, and therefore its bounds are not meaningful
98        fHasValidBounds = path->hasComputedBounds() && path->isFinite();
99        fEmpty = path->isEmpty();
100        if (fHasValidBounds && !fEmpty) {
101            joinNoEmptyChecks(&fRect, fPath->getBounds());
102        }
103        fDegenerate = is_degenerate(*path);
104    }
105};
106#define SkAutoPathBoundsUpdate(...) SK_REQUIRE_LOCAL_VAR(SkAutoPathBoundsUpdate)
107
108////////////////////////////////////////////////////////////////////////////
109
110/*
111    Stores the verbs and points as they are given to us, with exceptions:
112    - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic
113    - we insert a Move(0,0) if Line | Quad | Cubic is our first command
114
115    The iterator does more cleanup, especially if forceClose == true
116    1. If we encounter degenerate segments, remove them
117    2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
118    3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
119    4. if we encounter Line | Quad | Cubic after Close, cons up a Move
120*/
121
122////////////////////////////////////////////////////////////////////////////
123
124// flag to require a moveTo if we begin with something else, like lineTo etc.
125#define INITIAL_LASTMOVETOINDEX_VALUE   ~0
126
127SkPath::SkPath()
128    : fPathRef(SkPathRef::CreateEmpty()) {
129    this->resetFields();
130    fIsVolatile = false;
131}
132
133void SkPath::resetFields() {
134    //fPathRef is assumed to have been emptied by the caller.
135    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
136    fFillType = kWinding_FillType;
137    fConvexity = kUnknown_Convexity;
138    fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
139
140    // We don't touch Android's fSourcePath.  It's used to track texture garbage collection, so we
141    // don't want to muck with it if it's been set to something non-nullptr.
142}
143
144SkPath::SkPath(const SkPath& that)
145    : fPathRef(SkRef(that.fPathRef.get())) {
146    this->copyFields(that);
147    SkDEBUGCODE(that.validate();)
148}
149
150SkPath::~SkPath() {
151    SkDEBUGCODE(this->validate();)
152}
153
154SkPath& SkPath::operator=(const SkPath& that) {
155    SkDEBUGCODE(that.validate();)
156
157    if (this != &that) {
158        fPathRef.reset(SkRef(that.fPathRef.get()));
159        this->copyFields(that);
160    }
161    SkDEBUGCODE(this->validate();)
162    return *this;
163}
164
165void SkPath::copyFields(const SkPath& that) {
166    //fPathRef is assumed to have been set by the caller.
167    fLastMoveToIndex = that.fLastMoveToIndex;
168    fFillType        = that.fFillType;
169    fConvexity       = that.fConvexity;
170    // Simulate fFirstDirection  = that.fFirstDirection;
171    fFirstDirection.store(that.fFirstDirection.load());
172    fIsVolatile      = that.fIsVolatile;
173}
174
175bool operator==(const SkPath& a, const SkPath& b) {
176    // note: don't need to look at isConvex or bounds, since just comparing the
177    // raw data is sufficient.
178    return &a == &b ||
179        (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get());
180}
181
182void SkPath::swap(SkPath& that) {
183    if (this != &that) {
184        fPathRef.swap(that.fPathRef);
185        SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex);
186        SkTSwap<uint8_t>(fFillType, that.fFillType);
187        SkTSwap<uint8_t>(fConvexity, that.fConvexity);
188        // Simulate SkTSwap<uint8_t>(fFirstDirection, that.fFirstDirection);
189        uint8_t temp = fFirstDirection;
190        fFirstDirection.store(that.fFirstDirection.load());
191        that.fFirstDirection.store(temp);
192        SkTSwap<SkBool8>(fIsVolatile, that.fIsVolatile);
193    }
194}
195
196bool SkPath::isInterpolatable(const SkPath& compare) const {
197    int count = fPathRef->countVerbs();
198    if (count != compare.fPathRef->countVerbs()) {
199        return false;
200    }
201    if (!count) {
202        return true;
203    }
204    if (memcmp(fPathRef->verbsMemBegin(), compare.fPathRef->verbsMemBegin(),
205               count)) {
206        return false;
207    }
208    return !fPathRef->countWeights() ||
209            !SkToBool(memcmp(fPathRef->conicWeights(), compare.fPathRef->conicWeights(),
210            fPathRef->countWeights() * sizeof(*fPathRef->conicWeights())));
211}
212
213bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
214    int verbCount = fPathRef->countVerbs();
215    if (verbCount != ending.fPathRef->countVerbs()) {
216        return false;
217    }
218    if (!verbCount) {
219        return true;
220    }
221    out->reset();
222    out->addPath(*this);
223    fPathRef->interpolate(*ending.fPathRef, weight, out->fPathRef);
224    return true;
225}
226
227static inline bool check_edge_against_rect(const SkPoint& p0,
228                                           const SkPoint& p1,
229                                           const SkRect& rect,
230                                           SkPathPriv::FirstDirection dir) {
231    const SkPoint* edgeBegin;
232    SkVector v;
233    if (SkPathPriv::kCW_FirstDirection == dir) {
234        v = p1 - p0;
235        edgeBegin = &p0;
236    } else {
237        v = p0 - p1;
238        edgeBegin = &p1;
239    }
240    if (v.fX || v.fY) {
241        // check the cross product of v with the vec from edgeBegin to each rect corner
242        SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX);
243        SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY);
244        SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX);
245        SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY);
246        if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) {
247            return false;
248        }
249    }
250    return true;
251}
252
253bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
254    // This only handles non-degenerate convex paths currently.
255    if (kConvex_Convexity != this->getConvexity()) {
256        return false;
257    }
258
259    SkPathPriv::FirstDirection direction;
260    if (!SkPathPriv::CheapComputeFirstDirection(*this, &direction)) {
261        return false;
262    }
263
264    SkPoint firstPt;
265    SkPoint prevPt;
266    RawIter iter(*this);
267    SkPath::Verb verb;
268    SkPoint pts[4];
269    SkDEBUGCODE(int moveCnt = 0;)
270    SkDEBUGCODE(int segmentCount = 0;)
271    SkDEBUGCODE(int closeCount = 0;)
272
273    while ((verb = iter.next(pts)) != kDone_Verb) {
274        int nextPt = -1;
275        switch (verb) {
276            case kMove_Verb:
277                SkASSERT(!segmentCount && !closeCount);
278                SkDEBUGCODE(++moveCnt);
279                firstPt = prevPt = pts[0];
280                break;
281            case kLine_Verb:
282                nextPt = 1;
283                SkASSERT(moveCnt && !closeCount);
284                SkDEBUGCODE(++segmentCount);
285                break;
286            case kQuad_Verb:
287            case kConic_Verb:
288                SkASSERT(moveCnt && !closeCount);
289                SkDEBUGCODE(++segmentCount);
290                nextPt = 2;
291                break;
292            case kCubic_Verb:
293                SkASSERT(moveCnt && !closeCount);
294                SkDEBUGCODE(++segmentCount);
295                nextPt = 3;
296                break;
297            case kClose_Verb:
298                SkDEBUGCODE(++closeCount;)
299                break;
300            default:
301                SkDEBUGFAIL("unknown verb");
302        }
303        if (-1 != nextPt) {
304            if (SkPath::kConic_Verb == verb) {
305                SkConic orig;
306                orig.set(pts, iter.conicWeight());
307                SkPoint quadPts[5];
308                int count = orig.chopIntoQuadsPOW2(quadPts, 1);
309                SkASSERT_RELEASE(2 == count);
310
311                if (!check_edge_against_rect(quadPts[0], quadPts[2], rect, direction)) {
312                    return false;
313                }
314                if (!check_edge_against_rect(quadPts[2], quadPts[4], rect, direction)) {
315                    return false;
316                }
317            } else {
318                if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) {
319                    return false;
320                }
321            }
322            prevPt = pts[nextPt];
323        }
324    }
325
326    return check_edge_against_rect(prevPt, firstPt, rect, direction);
327}
328
329uint32_t SkPath::getGenerationID() const {
330    uint32_t genID = fPathRef->genID();
331#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
332    SkASSERT((unsigned)fFillType < (1 << (32 - kPathRefGenIDBitCnt)));
333    genID |= static_cast<uint32_t>(fFillType) << kPathRefGenIDBitCnt;
334#endif
335    return genID;
336}
337
338void SkPath::reset() {
339    SkDEBUGCODE(this->validate();)
340
341    fPathRef.reset(SkPathRef::CreateEmpty());
342    this->resetFields();
343}
344
345void SkPath::rewind() {
346    SkDEBUGCODE(this->validate();)
347
348    SkPathRef::Rewind(&fPathRef);
349    this->resetFields();
350}
351
352bool SkPath::isLastContourClosed() const {
353    int verbCount = fPathRef->countVerbs();
354    if (0 == verbCount) {
355        return false;
356    }
357    return kClose_Verb == fPathRef->atVerb(verbCount - 1);
358}
359
360bool SkPath::isLine(SkPoint line[2]) const {
361    int verbCount = fPathRef->countVerbs();
362
363    if (2 == verbCount) {
364        SkASSERT(kMove_Verb == fPathRef->atVerb(0));
365        if (kLine_Verb == fPathRef->atVerb(1)) {
366            SkASSERT(2 == fPathRef->countPoints());
367            if (line) {
368                const SkPoint* pts = fPathRef->points();
369                line[0] = pts[0];
370                line[1] = pts[1];
371            }
372            return true;
373        }
374    }
375    return false;
376}
377
378/*
379 Determines if path is a rect by keeping track of changes in direction
380 and looking for a loop either clockwise or counterclockwise.
381
382 The direction is computed such that:
383  0: vertical up
384  1: horizontal left
385  2: vertical down
386  3: horizontal right
387
388A rectangle cycles up/right/down/left or up/left/down/right.
389
390The test fails if:
391  The path is closed, and followed by a line.
392  A second move creates a new endpoint.
393  A diagonal line is parsed.
394  There's more than four changes of direction.
395  There's a discontinuity on the line (e.g., a move in the middle)
396  The line reverses direction.
397  The path contains a quadratic or cubic.
398  The path contains fewer than four points.
399 *The rectangle doesn't complete a cycle.
400 *The final point isn't equal to the first point.
401
402  *These last two conditions we relax if we have a 3-edge path that would
403   form a rectangle if it were closed (as we do when we fill a path)
404
405It's OK if the path has:
406  Several colinear line segments composing a rectangle side.
407  Single points on the rectangle side.
408
409The direction takes advantage of the corners found since opposite sides
410must travel in opposite directions.
411
412FIXME: Allow colinear quads and cubics to be treated like lines.
413FIXME: If the API passes fill-only, return true if the filled stroke
414       is a rectangle, though the caller failed to close the path.
415
416 first,last,next direction state-machine:
417    0x1 is set if the segment is horizontal
418    0x2 is set if the segment is moving to the right or down
419 thus:
420    two directions are opposites iff (dirA ^ dirB) == 0x2
421    two directions are perpendicular iff (dirA ^ dirB) == 0x1
422
423 */
424static int rect_make_dir(SkScalar dx, SkScalar dy) {
425    return ((0 != dx) << 0) | ((dx > 0 || dy > 0) << 1);
426}
427bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr,
428        bool* isClosed, Direction* direction) const {
429    int corners = 0;
430    SkPoint first, last;
431    const SkPoint* pts = *ptsPtr;
432    const SkPoint* savePts = nullptr;
433    first.set(0, 0);
434    last.set(0, 0);
435    int firstDirection = 0;
436    int lastDirection = 0;
437    int nextDirection = 0;
438    bool closedOrMoved = false;
439    bool autoClose = false;
440    bool insertClose = false;
441    int verbCnt = fPathRef->countVerbs();
442    while (*currVerb < verbCnt && (!allowPartial || !autoClose)) {
443        uint8_t verb = insertClose ? (uint8_t) kClose_Verb : fPathRef->atVerb(*currVerb);
444        switch (verb) {
445            case kClose_Verb:
446                savePts = pts;
447                pts = *ptsPtr;
448                autoClose = true;
449                insertClose = false;
450            case kLine_Verb: {
451                SkScalar left = last.fX;
452                SkScalar top = last.fY;
453                SkScalar right = pts->fX;
454                SkScalar bottom = pts->fY;
455                ++pts;
456                if (left != right && top != bottom) {
457                    return false; // diagonal
458                }
459                if (left == right && top == bottom) {
460                    break; // single point on side OK
461                }
462                nextDirection = rect_make_dir(right - left, bottom - top);
463                if (0 == corners) {
464                    firstDirection = nextDirection;
465                    first = last;
466                    last = pts[-1];
467                    corners = 1;
468                    closedOrMoved = false;
469                    break;
470                }
471                if (closedOrMoved) {
472                    return false; // closed followed by a line
473                }
474                if (autoClose && nextDirection == firstDirection) {
475                    break; // colinear with first
476                }
477                closedOrMoved = autoClose;
478                if (lastDirection != nextDirection) {
479                    if (++corners > 4) {
480                        return false; // too many direction changes
481                    }
482                }
483                last = pts[-1];
484                if (lastDirection == nextDirection) {
485                    break; // colinear segment
486                }
487                // Possible values for corners are 2, 3, and 4.
488                // When corners == 3, nextDirection opposes firstDirection.
489                // Otherwise, nextDirection at corner 2 opposes corner 4.
490                int turn = firstDirection ^ (corners - 1);
491                int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
492                if ((directionCycle ^ turn) != nextDirection) {
493                    return false; // direction didn't follow cycle
494                }
495                break;
496            }
497            case kQuad_Verb:
498            case kConic_Verb:
499            case kCubic_Verb:
500                return false; // quadratic, cubic not allowed
501            case kMove_Verb:
502                if (allowPartial && !autoClose && firstDirection) {
503                    insertClose = true;
504                    *currVerb -= 1;  // try move again afterwards
505                    goto addMissingClose;
506                }
507                last = *pts++;
508                closedOrMoved = true;
509                break;
510            default:
511                SkDEBUGFAIL("unexpected verb");
512                break;
513        }
514        *currVerb += 1;
515        lastDirection = nextDirection;
516addMissingClose:
517        ;
518    }
519    // Success if 4 corners and first point equals last
520    bool result = 4 == corners && (first == last || autoClose);
521    if (!result) {
522        // check if we are just an incomplete rectangle, in which case we can
523        // return true, but not claim to be closed.
524        // e.g.
525        //    3 sided rectangle
526        //    4 sided but the last edge is not long enough to reach the start
527        //
528        SkScalar closeX = first.x() - last.x();
529        SkScalar closeY = first.y() - last.y();
530        if (closeX && closeY) {
531            return false;   // we're diagonal, abort (can we ever reach this?)
532        }
533        int closeDirection = rect_make_dir(closeX, closeY);
534        // make sure the close-segment doesn't double-back on itself
535        if (3 == corners || (4 == corners && closeDirection == lastDirection)) {
536            result = true;
537            autoClose = false;  // we are not closed
538        }
539    }
540    if (savePts) {
541        *ptsPtr = savePts;
542    }
543    if (result && isClosed) {
544        *isClosed = autoClose;
545    }
546    if (result && direction) {
547        *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Direction : kCW_Direction;
548    }
549    return result;
550}
551
552bool SkPath::isRect(SkRect* rect, bool* isClosed, Direction* direction) const {
553    SkDEBUGCODE(this->validate();)
554    int currVerb = 0;
555    const SkPoint* pts = fPathRef->points();
556    const SkPoint* first = pts;
557    if (!this->isRectContour(false, &currVerb, &pts, isClosed, direction)) {
558        return false;
559    }
560    if (rect) {
561        int32_t num = SkToS32(pts - first);
562        if (num) {
563            rect->set(first, num);
564        } else {
565            // 'pts' isn't updated for open rects
566            *rect = this->getBounds();
567        }
568    }
569    return true;
570}
571
572bool SkPath::isNestedFillRects(SkRect rects[2], Direction dirs[2]) const {
573    SkDEBUGCODE(this->validate();)
574    int currVerb = 0;
575    const SkPoint* pts = fPathRef->points();
576    const SkPoint* first = pts;
577    Direction testDirs[2];
578    if (!isRectContour(true, &currVerb, &pts, nullptr, &testDirs[0])) {
579        return false;
580    }
581    const SkPoint* last = pts;
582    SkRect testRects[2];
583    bool isClosed;
584    if (isRectContour(false, &currVerb, &pts, &isClosed, &testDirs[1])) {
585        testRects[0].set(first, SkToS32(last - first));
586        if (!isClosed) {
587            pts = fPathRef->points() + fPathRef->countPoints();
588        }
589        testRects[1].set(last, SkToS32(pts - last));
590        if (testRects[0].contains(testRects[1])) {
591            if (rects) {
592                rects[0] = testRects[0];
593                rects[1] = testRects[1];
594            }
595            if (dirs) {
596                dirs[0] = testDirs[0];
597                dirs[1] = testDirs[1];
598            }
599            return true;
600        }
601        if (testRects[1].contains(testRects[0])) {
602            if (rects) {
603                rects[0] = testRects[1];
604                rects[1] = testRects[0];
605            }
606            if (dirs) {
607                dirs[0] = testDirs[1];
608                dirs[1] = testDirs[0];
609            }
610            return true;
611        }
612    }
613    return false;
614}
615
616int SkPath::countPoints() const {
617    return fPathRef->countPoints();
618}
619
620int SkPath::getPoints(SkPoint dst[], int max) const {
621    SkDEBUGCODE(this->validate();)
622
623    SkASSERT(max >= 0);
624    SkASSERT(!max || dst);
625    int count = SkMin32(max, fPathRef->countPoints());
626    sk_careful_memcpy(dst, fPathRef->points(), count * sizeof(SkPoint));
627    return fPathRef->countPoints();
628}
629
630SkPoint SkPath::getPoint(int index) const {
631    if ((unsigned)index < (unsigned)fPathRef->countPoints()) {
632        return fPathRef->atPoint(index);
633    }
634    return SkPoint::Make(0, 0);
635}
636
637int SkPath::countVerbs() const {
638    return fPathRef->countVerbs();
639}
640
641static inline void copy_verbs_reverse(uint8_t* inorderDst,
642                                      const uint8_t* reversedSrc,
643                                      int count) {
644    for (int i = 0; i < count; ++i) {
645        inorderDst[i] = reversedSrc[~i];
646    }
647}
648
649int SkPath::getVerbs(uint8_t dst[], int max) const {
650    SkDEBUGCODE(this->validate();)
651
652    SkASSERT(max >= 0);
653    SkASSERT(!max || dst);
654    int count = SkMin32(max, fPathRef->countVerbs());
655    copy_verbs_reverse(dst, fPathRef->verbs(), count);
656    return fPathRef->countVerbs();
657}
658
659bool SkPath::getLastPt(SkPoint* lastPt) const {
660    SkDEBUGCODE(this->validate();)
661
662    int count = fPathRef->countPoints();
663    if (count > 0) {
664        if (lastPt) {
665            *lastPt = fPathRef->atPoint(count - 1);
666        }
667        return true;
668    }
669    if (lastPt) {
670        lastPt->set(0, 0);
671    }
672    return false;
673}
674
675void SkPath::setPt(int index, SkScalar x, SkScalar y) {
676    SkDEBUGCODE(this->validate();)
677
678    int count = fPathRef->countPoints();
679    if (count <= index) {
680        return;
681    } else {
682        SkPathRef::Editor ed(&fPathRef);
683        ed.atPoint(index)->set(x, y);
684    }
685}
686
687void SkPath::setLastPt(SkScalar x, SkScalar y) {
688    SkDEBUGCODE(this->validate();)
689
690    int count = fPathRef->countPoints();
691    if (count == 0) {
692        this->moveTo(x, y);
693    } else {
694        SkPathRef::Editor ed(&fPathRef);
695        ed.atPoint(count-1)->set(x, y);
696    }
697}
698
699void SkPath::setConvexity(Convexity c) {
700    if (fConvexity != c) {
701        fConvexity = c;
702    }
703}
704
705//////////////////////////////////////////////////////////////////////////////
706//  Construction methods
707
708#define DIRTY_AFTER_EDIT                                        \
709    do {                                                        \
710        fConvexity = kUnknown_Convexity;                        \
711        fFirstDirection = SkPathPriv::kUnknown_FirstDirection;  \
712    } while (0)
713
714void SkPath::incReserve(U16CPU inc) {
715    SkDEBUGCODE(this->validate();)
716    SkPathRef::Editor(&fPathRef, inc, inc);
717    SkDEBUGCODE(this->validate();)
718}
719
720void SkPath::moveTo(SkScalar x, SkScalar y) {
721    SkDEBUGCODE(this->validate();)
722
723    SkPathRef::Editor ed(&fPathRef);
724
725    // remember our index
726    fLastMoveToIndex = fPathRef->countPoints();
727
728    ed.growForVerb(kMove_Verb)->set(x, y);
729
730    DIRTY_AFTER_EDIT;
731}
732
733void SkPath::rMoveTo(SkScalar x, SkScalar y) {
734    SkPoint pt;
735    this->getLastPt(&pt);
736    this->moveTo(pt.fX + x, pt.fY + y);
737}
738
739void SkPath::injectMoveToIfNeeded() {
740    if (fLastMoveToIndex < 0) {
741        SkScalar x, y;
742        if (fPathRef->countVerbs() == 0) {
743            x = y = 0;
744        } else {
745            const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex);
746            x = pt.fX;
747            y = pt.fY;
748        }
749        this->moveTo(x, y);
750    }
751}
752
753void SkPath::lineTo(SkScalar x, SkScalar y) {
754    SkDEBUGCODE(this->validate();)
755
756    this->injectMoveToIfNeeded();
757
758    SkPathRef::Editor ed(&fPathRef);
759    ed.growForVerb(kLine_Verb)->set(x, y);
760
761    DIRTY_AFTER_EDIT;
762}
763
764void SkPath::rLineTo(SkScalar x, SkScalar y) {
765    this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
766    SkPoint pt;
767    this->getLastPt(&pt);
768    this->lineTo(pt.fX + x, pt.fY + y);
769}
770
771void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
772    SkDEBUGCODE(this->validate();)
773
774    this->injectMoveToIfNeeded();
775
776    SkPathRef::Editor ed(&fPathRef);
777    SkPoint* pts = ed.growForVerb(kQuad_Verb);
778    pts[0].set(x1, y1);
779    pts[1].set(x2, y2);
780
781    DIRTY_AFTER_EDIT;
782}
783
784void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
785    this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
786    SkPoint pt;
787    this->getLastPt(&pt);
788    this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
789}
790
791void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
792                     SkScalar w) {
793    // check for <= 0 or NaN with this test
794    if (!(w > 0)) {
795        this->lineTo(x2, y2);
796    } else if (!SkScalarIsFinite(w)) {
797        this->lineTo(x1, y1);
798        this->lineTo(x2, y2);
799    } else if (SK_Scalar1 == w) {
800        this->quadTo(x1, y1, x2, y2);
801    } else {
802        SkDEBUGCODE(this->validate();)
803
804        this->injectMoveToIfNeeded();
805
806        SkPathRef::Editor ed(&fPathRef);
807        SkPoint* pts = ed.growForVerb(kConic_Verb, w);
808        pts[0].set(x1, y1);
809        pts[1].set(x2, y2);
810
811        DIRTY_AFTER_EDIT;
812    }
813}
814
815void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
816                      SkScalar w) {
817    this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
818    SkPoint pt;
819    this->getLastPt(&pt);
820    this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w);
821}
822
823void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
824                     SkScalar x3, SkScalar y3) {
825    SkDEBUGCODE(this->validate();)
826
827    this->injectMoveToIfNeeded();
828
829    SkPathRef::Editor ed(&fPathRef);
830    SkPoint* pts = ed.growForVerb(kCubic_Verb);
831    pts[0].set(x1, y1);
832    pts[1].set(x2, y2);
833    pts[2].set(x3, y3);
834
835    DIRTY_AFTER_EDIT;
836}
837
838void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
839                      SkScalar x3, SkScalar y3) {
840    this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
841    SkPoint pt;
842    this->getLastPt(&pt);
843    this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
844                  pt.fX + x3, pt.fY + y3);
845}
846
847void SkPath::close() {
848    SkDEBUGCODE(this->validate();)
849
850    int count = fPathRef->countVerbs();
851    if (count > 0) {
852        switch (fPathRef->atVerb(count - 1)) {
853            case kLine_Verb:
854            case kQuad_Verb:
855            case kConic_Verb:
856            case kCubic_Verb:
857            case kMove_Verb: {
858                SkPathRef::Editor ed(&fPathRef);
859                ed.growForVerb(kClose_Verb);
860                break;
861            }
862            case kClose_Verb:
863                // don't add a close if it's the first verb or a repeat
864                break;
865            default:
866                SkDEBUGFAIL("unexpected verb");
867                break;
868        }
869    }
870
871    // signal that we need a moveTo to follow us (unless we're done)
872#if 0
873    if (fLastMoveToIndex >= 0) {
874        fLastMoveToIndex = ~fLastMoveToIndex;
875    }
876#else
877    fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
878#endif
879}
880
881///////////////////////////////////////////////////////////////////////////////
882
883namespace {
884
885template <unsigned N>
886class PointIterator {
887public:
888    PointIterator(SkPath::Direction dir, unsigned startIndex)
889        : fCurrent(startIndex % N)
890        , fAdvance(dir == SkPath::kCW_Direction ? 1 : N - 1) { }
891
892    const SkPoint& current() const {
893        SkASSERT(fCurrent < N);
894        return fPts[fCurrent];
895    }
896
897    const SkPoint& next() {
898        fCurrent = (fCurrent + fAdvance) % N;
899        return this->current();
900    }
901
902protected:
903    SkPoint fPts[N];
904
905private:
906    unsigned fCurrent;
907    unsigned fAdvance;
908};
909
910class RectPointIterator : public PointIterator<4> {
911public:
912    RectPointIterator(const SkRect& rect, SkPath::Direction dir, unsigned startIndex)
913        : PointIterator(dir, startIndex) {
914
915        fPts[0] = SkPoint::Make(rect.fLeft, rect.fTop);
916        fPts[1] = SkPoint::Make(rect.fRight, rect.fTop);
917        fPts[2] = SkPoint::Make(rect.fRight, rect.fBottom);
918        fPts[3] = SkPoint::Make(rect.fLeft, rect.fBottom);
919    }
920};
921
922class OvalPointIterator : public PointIterator<4> {
923public:
924    OvalPointIterator(const SkRect& oval, SkPath::Direction dir, unsigned startIndex)
925        : PointIterator(dir, startIndex) {
926
927        const SkScalar cx = oval.centerX();
928        const SkScalar cy = oval.centerY();
929
930        fPts[0] = SkPoint::Make(cx, oval.fTop);
931        fPts[1] = SkPoint::Make(oval.fRight, cy);
932        fPts[2] = SkPoint::Make(cx, oval.fBottom);
933        fPts[3] = SkPoint::Make(oval.fLeft, cy);
934    }
935};
936
937class RRectPointIterator : public PointIterator<8> {
938public:
939    RRectPointIterator(const SkRRect& rrect, SkPath::Direction dir, unsigned startIndex)
940        : PointIterator(dir, startIndex) {
941
942        const SkRect& bounds = rrect.getBounds();
943        const SkScalar L = bounds.fLeft;
944        const SkScalar T = bounds.fTop;
945        const SkScalar R = bounds.fRight;
946        const SkScalar B = bounds.fBottom;
947
948        fPts[0] = SkPoint::Make(L + rrect.radii(SkRRect::kUpperLeft_Corner).fX, T);
949        fPts[1] = SkPoint::Make(R - rrect.radii(SkRRect::kUpperRight_Corner).fX, T);
950        fPts[2] = SkPoint::Make(R, T + rrect.radii(SkRRect::kUpperRight_Corner).fY);
951        fPts[3] = SkPoint::Make(R, B - rrect.radii(SkRRect::kLowerRight_Corner).fY);
952        fPts[4] = SkPoint::Make(R - rrect.radii(SkRRect::kLowerRight_Corner).fX, B);
953        fPts[5] = SkPoint::Make(L + rrect.radii(SkRRect::kLowerLeft_Corner).fX, B);
954        fPts[6] = SkPoint::Make(L, B - rrect.radii(SkRRect::kLowerLeft_Corner).fY);
955        fPts[7] = SkPoint::Make(L, T + rrect.radii(SkRRect::kUpperLeft_Corner).fY);
956    }
957};
958
959} // anonymous namespace
960
961static void assert_known_direction(int dir) {
962    SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir);
963}
964
965void SkPath::addRect(const SkRect& rect, Direction dir) {
966    this->addRect(rect, dir, 0);
967}
968
969void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
970                     SkScalar bottom, Direction dir) {
971    this->addRect(SkRect::MakeLTRB(left, top, right, bottom), dir, 0);
972}
973
974void SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) {
975    assert_known_direction(dir);
976    fFirstDirection = this->hasOnlyMoveTos() ?
977        (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
978    SkAutoDisableDirectionCheck addc(this);
979    SkAutoPathBoundsUpdate apbu(this, rect);
980
981    SkDEBUGCODE(int initialVerbCount = this->countVerbs());
982
983    const int kVerbs = 5; // moveTo + 3x lineTo + close
984    this->incReserve(kVerbs);
985
986    RectPointIterator iter(rect, dir, startIndex);
987
988    this->moveTo(iter.current());
989    this->lineTo(iter.next());
990    this->lineTo(iter.next());
991    this->lineTo(iter.next());
992    this->close();
993
994    SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
995}
996
997void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
998    SkDEBUGCODE(this->validate();)
999    if (count <= 0) {
1000        return;
1001    }
1002
1003    fLastMoveToIndex = fPathRef->countPoints();
1004
1005    // +close makes room for the extra kClose_Verb
1006    SkPathRef::Editor ed(&fPathRef, count+close, count);
1007
1008    ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY);
1009    if (count > 1) {
1010        SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1);
1011        memcpy(p, &pts[1], (count-1) * sizeof(SkPoint));
1012    }
1013
1014    if (close) {
1015        ed.growForVerb(kClose_Verb);
1016        fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
1017    }
1018
1019    DIRTY_AFTER_EDIT;
1020    SkDEBUGCODE(this->validate();)
1021}
1022
1023#include "SkGeometry.h"
1024
1025static bool arc_is_lone_point(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
1026                              SkPoint* pt) {
1027    if (0 == sweepAngle && (0 == startAngle || SkIntToScalar(360) == startAngle)) {
1028        // Chrome uses this path to move into and out of ovals. If not
1029        // treated as a special case the moves can distort the oval's
1030        // bounding box (and break the circle special case).
1031        pt->set(oval.fRight, oval.centerY());
1032        return true;
1033    } else if (0 == oval.width() && 0 == oval.height()) {
1034        // Chrome will sometimes create 0 radius round rects. Having degenerate
1035        // quad segments in the path prevents the path from being recognized as
1036        // a rect.
1037        // TODO: optimizing the case where only one of width or height is zero
1038        // should also be considered. This case, however, doesn't seem to be
1039        // as common as the single point case.
1040        pt->set(oval.fRight, oval.fTop);
1041        return true;
1042    }
1043    return false;
1044}
1045
1046// Return the unit vectors pointing at the start/stop points for the given start/sweep angles
1047//
1048static void angles_to_unit_vectors(SkScalar startAngle, SkScalar sweepAngle,
1049                                   SkVector* startV, SkVector* stopV, SkRotationDirection* dir) {
1050    startV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &startV->fX);
1051    stopV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), &stopV->fX);
1052
1053    /*  If the sweep angle is nearly (but less than) 360, then due to precision
1054     loss in radians-conversion and/or sin/cos, we may end up with coincident
1055     vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead
1056     of drawing a nearly complete circle (good).
1057     e.g. canvas.drawArc(0, 359.99, ...)
1058     -vs- canvas.drawArc(0, 359.9, ...)
1059     We try to detect this edge case, and tweak the stop vector
1060     */
1061    if (*startV == *stopV) {
1062        SkScalar sw = SkScalarAbs(sweepAngle);
1063        if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
1064            SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
1065            // make a guess at a tiny angle (in radians) to tweak by
1066            SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
1067            // not sure how much will be enough, so we use a loop
1068            do {
1069                stopRad -= deltaRad;
1070                stopV->fY = SkScalarSinCos(stopRad, &stopV->fX);
1071            } while (*startV == *stopV);
1072        }
1073    }
1074    *dir = sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection;
1075}
1076
1077/**
1078 *  If this returns 0, then the caller should just line-to the singlePt, else it should
1079 *  ignore singlePt and append the specified number of conics.
1080 */
1081static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkVector& stop,
1082                            SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc],
1083                            SkPoint* singlePt) {
1084    SkMatrix    matrix;
1085
1086    matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
1087    matrix.postTranslate(oval.centerX(), oval.centerY());
1088
1089    int count = SkConic::BuildUnitArc(start, stop, dir, &matrix, conics);
1090    if (0 == count) {
1091        matrix.mapXY(start.x(), start.y(), singlePt);
1092    }
1093    return count;
1094}
1095
1096void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
1097                          Direction dir) {
1098    SkRRect rrect;
1099    rrect.setRectRadii(rect, (const SkVector*) radii);
1100    this->addRRect(rrect, dir);
1101}
1102
1103void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
1104    // legacy start indices: 6 (CW) and 7(CCW)
1105    this->addRRect(rrect, dir, dir == kCW_Direction ? 6 : 7);
1106}
1107
1108void SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex) {
1109        assert_known_direction(dir);
1110
1111        if (rrect.isEmpty()) {
1112            return;
1113        }
1114
1115        bool isRRect = hasOnlyMoveTos();
1116        const SkRect& bounds = rrect.getBounds();
1117
1118        if (rrect.isRect()) {
1119            // degenerate(rect) => radii points are collapsing
1120            this->addRect(bounds, dir, (startIndex + 1) / 2);
1121        } else if (rrect.isOval()) {
1122            // degenerate(oval) => line points are collapsing
1123            this->addOval(bounds, dir, startIndex / 2);
1124        } else {
1125            fFirstDirection = this->hasOnlyMoveTos() ?
1126                                (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
1127
1128            SkAutoPathBoundsUpdate apbu(this, bounds);
1129            SkAutoDisableDirectionCheck addc(this);
1130
1131            // we start with a conic on odd indices when moving CW vs. even indices when moving CCW
1132            const bool startsWithConic = ((startIndex & 1) == (dir == kCW_Direction));
1133            const SkScalar weight = SK_ScalarRoot2Over2;
1134
1135            SkDEBUGCODE(int initialVerbCount = this->countVerbs());
1136            const int kVerbs = startsWithConic
1137                ? 9   // moveTo + 4x conicTo + 3x lineTo + close
1138                : 10; // moveTo + 4x lineTo + 4x conicTo + close
1139            this->incReserve(kVerbs);
1140
1141            RRectPointIterator rrectIter(rrect, dir, startIndex);
1142            // Corner iterator indices follow the collapsed radii model,
1143            // adjusted such that the start pt is "behind" the radii start pt.
1144            const unsigned rectStartIndex = startIndex / 2 + (dir == kCW_Direction ? 0 : 1);
1145            RectPointIterator rectIter(bounds, dir, rectStartIndex);
1146
1147            this->moveTo(rrectIter.current());
1148            if (startsWithConic) {
1149                for (unsigned i = 0; i < 3; ++i) {
1150                    this->conicTo(rectIter.next(), rrectIter.next(), weight);
1151                    this->lineTo(rrectIter.next());
1152                }
1153                this->conicTo(rectIter.next(), rrectIter.next(), weight);
1154                // final lineTo handled by close().
1155            } else {
1156                for (unsigned i = 0; i < 4; ++i) {
1157                    this->lineTo(rrectIter.next());
1158                    this->conicTo(rectIter.next(), rrectIter.next(), weight);
1159                }
1160            }
1161            this->close();
1162
1163            SkPathRef::Editor ed(&fPathRef);
1164            ed.setIsRRect(isRRect);
1165
1166            SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
1167        }
1168
1169        SkDEBUGCODE(fPathRef->validate();)
1170}
1171
1172bool SkPath::hasOnlyMoveTos() const {
1173    int count = fPathRef->countVerbs();
1174    const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin();
1175    for (int i = 0; i < count; ++i) {
1176        if (*verbs == kLine_Verb ||
1177            *verbs == kQuad_Verb ||
1178            *verbs == kConic_Verb ||
1179            *verbs == kCubic_Verb) {
1180            return false;
1181        }
1182        ++verbs;
1183    }
1184    return true;
1185}
1186
1187bool SkPath::isZeroLength() const {
1188    int count = fPathRef->countPoints();
1189    if (count < 2) {
1190        return true;
1191    }
1192    const SkPoint* pts = fPathRef.get()->points();
1193    const SkPoint& first = *pts;
1194    for (int index = 1; index < count; ++index) {
1195        if (first != pts[index]) {
1196            return false;
1197        }
1198    }
1199    return true;
1200}
1201
1202void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
1203                          Direction dir) {
1204    assert_known_direction(dir);
1205
1206    if (rx < 0 || ry < 0) {
1207        SkErrorInternals::SetError( kInvalidArgument_SkError,
1208                                    "I got %f and %f as radii to SkPath::AddRoundRect, "
1209                                    "but negative radii are not allowed.",
1210                                    SkScalarToDouble(rx), SkScalarToDouble(ry) );
1211        return;
1212    }
1213
1214    SkRRect rrect;
1215    rrect.setRectXY(rect, rx, ry);
1216    this->addRRect(rrect, dir);
1217}
1218
1219void SkPath::addOval(const SkRect& oval, Direction dir) {
1220    // legacy start index: 1
1221    this->addOval(oval, dir, 1);
1222}
1223
1224void SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex) {
1225    assert_known_direction(dir);
1226
1227    /* If addOval() is called after previous moveTo(),
1228       this path is still marked as an oval. This is used to
1229       fit into WebKit's calling sequences.
1230       We can't simply check isEmpty() in this case, as additional
1231       moveTo() would mark the path non empty.
1232     */
1233    bool isOval = hasOnlyMoveTos();
1234    if (isOval) {
1235        fFirstDirection = (SkPathPriv::FirstDirection)dir;
1236    } else {
1237        fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
1238    }
1239
1240    SkAutoDisableDirectionCheck addc(this);
1241    SkAutoPathBoundsUpdate apbu(this, oval);
1242
1243    SkDEBUGCODE(int initialVerbCount = this->countVerbs());
1244    const int kVerbs = 6; // moveTo + 4x conicTo + close
1245    this->incReserve(kVerbs);
1246
1247    OvalPointIterator ovalIter(oval, dir, startPointIndex);
1248    // The corner iterator pts are tracking "behind" the oval/radii pts.
1249    RectPointIterator rectIter(oval, dir, startPointIndex + (dir == kCW_Direction ? 0 : 1));
1250    const SkScalar weight = SK_ScalarRoot2Over2;
1251
1252    this->moveTo(ovalIter.current());
1253    for (unsigned i = 0; i < 4; ++i) {
1254        this->conicTo(rectIter.next(), ovalIter.next(), weight);
1255    }
1256    this->close();
1257
1258    SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
1259
1260    SkPathRef::Editor ed(&fPathRef);
1261
1262    ed.setIsOval(isOval);
1263}
1264
1265void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
1266    if (r > 0) {
1267        this->addOval(SkRect::MakeLTRB(x - r, y - r, x + r, y + r), dir);
1268    }
1269}
1270
1271void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
1272                   bool forceMoveTo) {
1273    if (oval.width() < 0 || oval.height() < 0) {
1274        return;
1275    }
1276
1277    if (fPathRef->countVerbs() == 0) {
1278        forceMoveTo = true;
1279    }
1280
1281    SkPoint lonePt;
1282    if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) {
1283        forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt);
1284        return;
1285    }
1286
1287    SkVector startV, stopV;
1288    SkRotationDirection dir;
1289    angles_to_unit_vectors(startAngle, sweepAngle, &startV, &stopV, &dir);
1290
1291    SkPoint singlePt;
1292    SkConic conics[SkConic::kMaxConicsForArc];
1293    int count = build_arc_conics(oval, startV, stopV, dir, conics, &singlePt);
1294    if (count) {
1295        this->incReserve(count * 2 + 1);
1296        const SkPoint& pt = conics[0].fPts[0];
1297        forceMoveTo ? this->moveTo(pt) : this->lineTo(pt);
1298        for (int i = 0; i < count; ++i) {
1299            this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
1300        }
1301    } else {
1302        forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
1303    }
1304}
1305
1306// This converts the SVG arc to conics.
1307// Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
1308// Then transcribed from webkit/chrome's SVGPathNormalizer::decomposeArcToCubic()
1309// See also SVG implementation notes:
1310// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
1311// Note that arcSweep bool value is flipped from the original implementation.
1312void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arcLarge,
1313                   SkPath::Direction arcSweep, SkScalar x, SkScalar y) {
1314    this->injectMoveToIfNeeded();
1315    SkPoint srcPts[2];
1316    this->getLastPt(&srcPts[0]);
1317    // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto")
1318    // joining the endpoints.
1319    // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
1320    if (!rx || !ry) {
1321        this->lineTo(x, y);
1322        return;
1323    }
1324    // If the current point and target point for the arc are identical, it should be treated as a
1325    // zero length path. This ensures continuity in animations.
1326    srcPts[1].set(x, y);
1327    if (srcPts[0] == srcPts[1]) {
1328        this->lineTo(x, y);
1329        return;
1330    }
1331    rx = SkScalarAbs(rx);
1332    ry = SkScalarAbs(ry);
1333    SkVector midPointDistance = srcPts[0] - srcPts[1];
1334    midPointDistance *= 0.5f;
1335
1336    SkMatrix pointTransform;
1337    pointTransform.setRotate(-angle);
1338
1339    SkPoint transformedMidPoint;
1340    pointTransform.mapPoints(&transformedMidPoint, &midPointDistance, 1);
1341    SkScalar squareRx = rx * rx;
1342    SkScalar squareRy = ry * ry;
1343    SkScalar squareX = transformedMidPoint.fX * transformedMidPoint.fX;
1344    SkScalar squareY = transformedMidPoint.fY * transformedMidPoint.fY;
1345
1346    // Check if the radii are big enough to draw the arc, scale radii if not.
1347    // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
1348    SkScalar radiiScale = squareX / squareRx + squareY / squareRy;
1349    if (radiiScale > 1) {
1350        radiiScale = SkScalarSqrt(radiiScale);
1351        rx *= radiiScale;
1352        ry *= radiiScale;
1353    }
1354
1355    pointTransform.setScale(1 / rx, 1 / ry);
1356    pointTransform.preRotate(-angle);
1357
1358    SkPoint unitPts[2];
1359    pointTransform.mapPoints(unitPts, srcPts, (int) SK_ARRAY_COUNT(unitPts));
1360    SkVector delta = unitPts[1] - unitPts[0];
1361
1362    SkScalar d = delta.fX * delta.fX + delta.fY * delta.fY;
1363    SkScalar scaleFactorSquared = SkTMax(1 / d - 0.25f, 0.f);
1364
1365    SkScalar scaleFactor = SkScalarSqrt(scaleFactorSquared);
1366    if (SkToBool(arcSweep) != SkToBool(arcLarge)) {  // flipped from the original implementation
1367        scaleFactor = -scaleFactor;
1368    }
1369    delta.scale(scaleFactor);
1370    SkPoint centerPoint = unitPts[0] + unitPts[1];
1371    centerPoint *= 0.5f;
1372    centerPoint.offset(-delta.fY, delta.fX);
1373    unitPts[0] -= centerPoint;
1374    unitPts[1] -= centerPoint;
1375    SkScalar theta1 = SkScalarATan2(unitPts[0].fY, unitPts[0].fX);
1376    SkScalar theta2 = SkScalarATan2(unitPts[1].fY, unitPts[1].fX);
1377    SkScalar thetaArc = theta2 - theta1;
1378    if (thetaArc < 0 && !arcSweep) {  // arcSweep flipped from the original implementation
1379        thetaArc += SK_ScalarPI * 2;
1380    } else if (thetaArc > 0 && arcSweep) {  // arcSweep flipped from the original implementation
1381        thetaArc -= SK_ScalarPI * 2;
1382    }
1383    pointTransform.setRotate(angle);
1384    pointTransform.preScale(rx, ry);
1385
1386    int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (SK_ScalarPI / 2)));
1387    SkScalar thetaWidth = thetaArc / segments;
1388    SkScalar t = SkScalarTan(0.5f * thetaWidth);
1389    if (!SkScalarIsFinite(t)) {
1390        return;
1391    }
1392    SkScalar startTheta = theta1;
1393    SkScalar w = SkScalarSqrt(SK_ScalarHalf + SkScalarCos(thetaWidth) * SK_ScalarHalf);
1394    for (int i = 0; i < segments; ++i) {
1395        SkScalar endTheta = startTheta + thetaWidth;
1396        SkScalar cosEndTheta, sinEndTheta = SkScalarSinCos(endTheta, &cosEndTheta);
1397
1398        unitPts[1].set(cosEndTheta, sinEndTheta);
1399        unitPts[1] += centerPoint;
1400        unitPts[0] = unitPts[1];
1401        unitPts[0].offset(t * sinEndTheta, -t * cosEndTheta);
1402        SkPoint mapped[2];
1403        pointTransform.mapPoints(mapped, unitPts, (int) SK_ARRAY_COUNT(unitPts));
1404        this->conicTo(mapped[0], mapped[1], w);
1405        startTheta = endTheta;
1406    }
1407}
1408
1409void SkPath::rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, SkPath::ArcSize largeArc,
1410                    SkPath::Direction sweep, SkScalar dx, SkScalar dy) {
1411    SkPoint currentPoint;
1412    this->getLastPt(&currentPoint);
1413    this->arcTo(rx, ry, xAxisRotate, largeArc, sweep, currentPoint.fX + dx, currentPoint.fY + dy);
1414}
1415
1416void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) {
1417    if (oval.isEmpty() || 0 == sweepAngle) {
1418        return;
1419    }
1420
1421    const SkScalar kFullCircleAngle = SkIntToScalar(360);
1422
1423    if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
1424        this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction);
1425    } else {
1426        this->arcTo(oval, startAngle, sweepAngle, true);
1427    }
1428}
1429
1430/*
1431    Need to handle the case when the angle is sharp, and our computed end-points
1432    for the arc go behind pt1 and/or p2...
1433*/
1434void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) {
1435    if (radius == 0) {
1436        this->lineTo(x1, y1);
1437        return;
1438    }
1439
1440    SkVector before, after;
1441
1442    // need to know our prev pt so we can construct tangent vectors
1443    {
1444        SkPoint start;
1445        this->getLastPt(&start);
1446        // Handle degenerate cases by adding a line to the first point and
1447        // bailing out.
1448        before.setNormalize(x1 - start.fX, y1 - start.fY);
1449        after.setNormalize(x2 - x1, y2 - y1);
1450    }
1451
1452    SkScalar cosh = SkPoint::DotProduct(before, after);
1453    SkScalar sinh = SkPoint::CrossProduct(before, after);
1454
1455    if (SkScalarNearlyZero(sinh)) {   // angle is too tight
1456        this->lineTo(x1, y1);
1457        return;
1458    }
1459
1460    SkScalar dist = SkScalarAbs(SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh));
1461
1462    SkScalar xx = x1 - SkScalarMul(dist, before.fX);
1463    SkScalar yy = y1 - SkScalarMul(dist, before.fY);
1464    after.setLength(dist);
1465    this->lineTo(xx, yy);
1466    SkScalar weight = SkScalarSqrt(SK_ScalarHalf + cosh * SK_ScalarHalf);
1467    this->conicTo(x1, y1, x1 + after.fX, y1 + after.fY, weight);
1468}
1469
1470///////////////////////////////////////////////////////////////////////////////
1471
1472void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy, AddPathMode mode) {
1473    SkMatrix matrix;
1474
1475    matrix.setTranslate(dx, dy);
1476    this->addPath(path, matrix, mode);
1477}
1478
1479void SkPath::addPath(const SkPath& path, const SkMatrix& matrix, AddPathMode mode) {
1480    SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
1481
1482    RawIter iter(path);
1483    SkPoint pts[4];
1484    Verb    verb;
1485
1486    SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
1487    bool firstVerb = true;
1488    while ((verb = iter.next(pts)) != kDone_Verb) {
1489        switch (verb) {
1490            case kMove_Verb:
1491                proc(matrix, &pts[0], &pts[0], 1);
1492                if (firstVerb && mode == kExtend_AddPathMode && !isEmpty()) {
1493                    injectMoveToIfNeeded(); // In case last contour is closed
1494                    this->lineTo(pts[0]);
1495                } else {
1496                    this->moveTo(pts[0]);
1497                }
1498                break;
1499            case kLine_Verb:
1500                proc(matrix, &pts[1], &pts[1], 1);
1501                this->lineTo(pts[1]);
1502                break;
1503            case kQuad_Verb:
1504                proc(matrix, &pts[1], &pts[1], 2);
1505                this->quadTo(pts[1], pts[2]);
1506                break;
1507            case kConic_Verb:
1508                proc(matrix, &pts[1], &pts[1], 2);
1509                this->conicTo(pts[1], pts[2], iter.conicWeight());
1510                break;
1511            case kCubic_Verb:
1512                proc(matrix, &pts[1], &pts[1], 3);
1513                this->cubicTo(pts[1], pts[2], pts[3]);
1514                break;
1515            case kClose_Verb:
1516                this->close();
1517                break;
1518            default:
1519                SkDEBUGFAIL("unknown verb");
1520        }
1521        firstVerb = false;
1522    }
1523}
1524
1525///////////////////////////////////////////////////////////////////////////////
1526
1527static int pts_in_verb(unsigned verb) {
1528    static const uint8_t gPtsInVerb[] = {
1529        1,  // kMove
1530        1,  // kLine
1531        2,  // kQuad
1532        2,  // kConic
1533        3,  // kCubic
1534        0,  // kClose
1535        0   // kDone
1536    };
1537
1538    SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
1539    return gPtsInVerb[verb];
1540}
1541
1542// ignore the last point of the 1st contour
1543void SkPath::reversePathTo(const SkPath& path) {
1544    int i, vcount = path.fPathRef->countVerbs();
1545    // exit early if the path is empty, or just has a moveTo.
1546    if (vcount < 2) {
1547        return;
1548    }
1549
1550    SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1551
1552    const uint8_t*  verbs = path.fPathRef->verbs();
1553    const SkPoint*  pts = path.fPathRef->points();
1554    const SkScalar* conicWeights = path.fPathRef->conicWeights();
1555
1556    SkASSERT(verbs[~0] == kMove_Verb);
1557    for (i = 1; i < vcount; ++i) {
1558        unsigned v = verbs[~i];
1559        int n = pts_in_verb(v);
1560        if (n == 0) {
1561            break;
1562        }
1563        pts += n;
1564        conicWeights += (SkPath::kConic_Verb == v);
1565    }
1566
1567    while (--i > 0) {
1568        switch (verbs[~i]) {
1569            case kLine_Verb:
1570                this->lineTo(pts[-1].fX, pts[-1].fY);
1571                break;
1572            case kQuad_Verb:
1573                this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
1574                break;
1575            case kConic_Verb:
1576                this->conicTo(pts[-1], pts[-2], *--conicWeights);
1577                break;
1578            case kCubic_Verb:
1579                this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY,
1580                              pts[-3].fX, pts[-3].fY);
1581                break;
1582            default:
1583                SkDEBUGFAIL("bad verb");
1584                break;
1585        }
1586        pts -= pts_in_verb(verbs[~i]);
1587    }
1588}
1589
1590void SkPath::reverseAddPath(const SkPath& src) {
1591    SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs());
1592
1593    const SkPoint* pts = src.fPathRef->pointsEnd();
1594    // we will iterator through src's verbs backwards
1595    const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
1596    const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb
1597    const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
1598
1599    bool needMove = true;
1600    bool needClose = false;
1601    while (verbs < verbsEnd) {
1602        uint8_t v = *(verbs++);
1603        int n = pts_in_verb(v);
1604
1605        if (needMove) {
1606            --pts;
1607            this->moveTo(pts->fX, pts->fY);
1608            needMove = false;
1609        }
1610        pts -= n;
1611        switch (v) {
1612            case kMove_Verb:
1613                if (needClose) {
1614                    this->close();
1615                    needClose = false;
1616                }
1617                needMove = true;
1618                pts += 1;   // so we see the point in "if (needMove)" above
1619                break;
1620            case kLine_Verb:
1621                this->lineTo(pts[0]);
1622                break;
1623            case kQuad_Verb:
1624                this->quadTo(pts[1], pts[0]);
1625                break;
1626            case kConic_Verb:
1627                this->conicTo(pts[1], pts[0], *--conicWeights);
1628                break;
1629            case kCubic_Verb:
1630                this->cubicTo(pts[2], pts[1], pts[0]);
1631                break;
1632            case kClose_Verb:
1633                needClose = true;
1634                break;
1635            default:
1636                SkDEBUGFAIL("unexpected verb");
1637        }
1638    }
1639}
1640
1641///////////////////////////////////////////////////////////////////////////////
1642
1643void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
1644    SkMatrix    matrix;
1645
1646    matrix.setTranslate(dx, dy);
1647    this->transform(matrix, dst);
1648}
1649
1650static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
1651                               int level = 2) {
1652    if (--level >= 0) {
1653        SkPoint tmp[7];
1654
1655        SkChopCubicAtHalf(pts, tmp);
1656        subdivide_cubic_to(path, &tmp[0], level);
1657        subdivide_cubic_to(path, &tmp[3], level);
1658    } else {
1659        path->cubicTo(pts[1], pts[2], pts[3]);
1660    }
1661}
1662
1663void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
1664    SkDEBUGCODE(this->validate();)
1665    if (dst == nullptr) {
1666        dst = (SkPath*)this;
1667    }
1668
1669    if (matrix.hasPerspective()) {
1670        SkPath  tmp;
1671        tmp.fFillType = fFillType;
1672
1673        SkPath::Iter    iter(*this, false);
1674        SkPoint         pts[4];
1675        SkPath::Verb    verb;
1676
1677        while ((verb = iter.next(pts, false)) != kDone_Verb) {
1678            switch (verb) {
1679                case kMove_Verb:
1680                    tmp.moveTo(pts[0]);
1681                    break;
1682                case kLine_Verb:
1683                    tmp.lineTo(pts[1]);
1684                    break;
1685                case kQuad_Verb:
1686                    // promote the quad to a conic
1687                    tmp.conicTo(pts[1], pts[2],
1688                                SkConic::TransformW(pts, SK_Scalar1, matrix));
1689                    break;
1690                case kConic_Verb:
1691                    tmp.conicTo(pts[1], pts[2],
1692                                SkConic::TransformW(pts, iter.conicWeight(), matrix));
1693                    break;
1694                case kCubic_Verb:
1695                    subdivide_cubic_to(&tmp, pts);
1696                    break;
1697                case kClose_Verb:
1698                    tmp.close();
1699                    break;
1700                default:
1701                    SkDEBUGFAIL("unknown verb");
1702                    break;
1703            }
1704        }
1705
1706        dst->swap(tmp);
1707        SkPathRef::Editor ed(&dst->fPathRef);
1708        matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
1709        dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
1710    } else {
1711        SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix);
1712
1713        if (this != dst) {
1714            dst->fFillType = fFillType;
1715            dst->fConvexity = fConvexity;
1716            dst->fIsVolatile = fIsVolatile;
1717        }
1718
1719        if (SkPathPriv::kUnknown_FirstDirection == fFirstDirection) {
1720            dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
1721        } else {
1722            SkScalar det2x2 =
1723                SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix::kMScaleY)) -
1724                SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::kMSkewY));
1725            if (det2x2 < 0) {
1726                dst->fFirstDirection = SkPathPriv::OppositeFirstDirection(
1727                        (SkPathPriv::FirstDirection)fFirstDirection.load());
1728            } else if (det2x2 > 0) {
1729                dst->fFirstDirection = fFirstDirection.load();
1730            } else {
1731                dst->fConvexity = kUnknown_Convexity;
1732                dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
1733            }
1734        }
1735
1736        SkDEBUGCODE(dst->validate();)
1737    }
1738}
1739
1740///////////////////////////////////////////////////////////////////////////////
1741///////////////////////////////////////////////////////////////////////////////
1742
1743enum SegmentState {
1744    kEmptyContour_SegmentState,   // The current contour is empty. We may be
1745                                  // starting processing or we may have just
1746                                  // closed a contour.
1747    kAfterMove_SegmentState,      // We have seen a move, but nothing else.
1748    kAfterPrimitive_SegmentState  // We have seen a primitive but not yet
1749                                  // closed the path. Also the initial state.
1750};
1751
1752SkPath::Iter::Iter() {
1753#ifdef SK_DEBUG
1754    fPts = nullptr;
1755    fConicWeights = nullptr;
1756    fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1757    fForceClose = fCloseLine = false;
1758    fSegmentState = kEmptyContour_SegmentState;
1759#endif
1760    // need to init enough to make next() harmlessly return kDone_Verb
1761    fVerbs = nullptr;
1762    fVerbStop = nullptr;
1763    fNeedClose = false;
1764}
1765
1766SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
1767    this->setPath(path, forceClose);
1768}
1769
1770void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
1771    fPts = path.fPathRef->points();
1772    fVerbs = path.fPathRef->verbs();
1773    fVerbStop = path.fPathRef->verbsMemBegin();
1774    fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind
1775    fLastPt.fX = fLastPt.fY = 0;
1776    fMoveTo.fX = fMoveTo.fY = 0;
1777    fForceClose = SkToU8(forceClose);
1778    fNeedClose = false;
1779    fSegmentState = kEmptyContour_SegmentState;
1780}
1781
1782bool SkPath::Iter::isClosedContour() const {
1783    if (fVerbs == nullptr || fVerbs == fVerbStop) {
1784        return false;
1785    }
1786    if (fForceClose) {
1787        return true;
1788    }
1789
1790    const uint8_t* verbs = fVerbs;
1791    const uint8_t* stop = fVerbStop;
1792
1793    if (kMove_Verb == *(verbs - 1)) {
1794        verbs -= 1; // skip the initial moveto
1795    }
1796
1797    while (verbs > stop) {
1798        // verbs points one beyond the current verb, decrement first.
1799        unsigned v = *(--verbs);
1800        if (kMove_Verb == v) {
1801            break;
1802        }
1803        if (kClose_Verb == v) {
1804            return true;
1805        }
1806    }
1807    return false;
1808}
1809
1810SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
1811    SkASSERT(pts);
1812    if (fLastPt != fMoveTo) {
1813        // A special case: if both points are NaN, SkPoint::operation== returns
1814        // false, but the iterator expects that they are treated as the same.
1815        // (consider SkPoint is a 2-dimension float point).
1816        if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
1817            SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
1818            return kClose_Verb;
1819        }
1820
1821        pts[0] = fLastPt;
1822        pts[1] = fMoveTo;
1823        fLastPt = fMoveTo;
1824        fCloseLine = true;
1825        return kLine_Verb;
1826    } else {
1827        pts[0] = fMoveTo;
1828        return kClose_Verb;
1829    }
1830}
1831
1832const SkPoint& SkPath::Iter::cons_moveTo() {
1833    if (fSegmentState == kAfterMove_SegmentState) {
1834        // Set the first return pt to the move pt
1835        fSegmentState = kAfterPrimitive_SegmentState;
1836        return fMoveTo;
1837    } else {
1838        SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
1839         // Set the first return pt to the last pt of the previous primitive.
1840        return fPts[-1];
1841    }
1842}
1843
1844void SkPath::Iter::consumeDegenerateSegments(bool exact) {
1845    // We need to step over anything that will not move the current draw point
1846    // forward before the next move is seen
1847    const uint8_t* lastMoveVerb = 0;
1848    const SkPoint* lastMovePt = 0;
1849    const SkScalar* lastMoveWeight = nullptr;
1850    SkPoint lastPt = fLastPt;
1851    while (fVerbs != fVerbStop) {
1852        unsigned verb = *(fVerbs - 1); // fVerbs is one beyond the current verb
1853        switch (verb) {
1854            case kMove_Verb:
1855                // Keep a record of this most recent move
1856                lastMoveVerb = fVerbs;
1857                lastMovePt = fPts;
1858                lastMoveWeight = fConicWeights;
1859                lastPt = fPts[0];
1860                fVerbs--;
1861                fPts++;
1862                break;
1863
1864            case kClose_Verb:
1865                // A close when we are in a segment is always valid except when it
1866                // follows a move which follows a segment.
1867                if (fSegmentState == kAfterPrimitive_SegmentState && !lastMoveVerb) {
1868                    return;
1869                }
1870                // A close at any other time must be ignored
1871                fVerbs--;
1872                break;
1873
1874            case kLine_Verb:
1875                if (!IsLineDegenerate(lastPt, fPts[0], exact)) {
1876                    if (lastMoveVerb) {
1877                        fVerbs = lastMoveVerb;
1878                        fPts = lastMovePt;
1879                        fConicWeights = lastMoveWeight;
1880                        return;
1881                    }
1882                    return;
1883                }
1884                // Ignore this line and continue
1885                fVerbs--;
1886                fPts++;
1887                break;
1888
1889            case kConic_Verb:
1890            case kQuad_Verb:
1891                if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1], exact)) {
1892                    if (lastMoveVerb) {
1893                        fVerbs = lastMoveVerb;
1894                        fPts = lastMovePt;
1895                        fConicWeights = lastMoveWeight;
1896                        return;
1897                    }
1898                    return;
1899                }
1900                // Ignore this line and continue
1901                fVerbs--;
1902                fPts += 2;
1903                fConicWeights += (kConic_Verb == verb);
1904                break;
1905
1906            case kCubic_Verb:
1907                if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2], exact)) {
1908                    if (lastMoveVerb) {
1909                        fVerbs = lastMoveVerb;
1910                        fPts = lastMovePt;
1911                        fConicWeights = lastMoveWeight;
1912                        return;
1913                    }
1914                    return;
1915                }
1916                // Ignore this line and continue
1917                fVerbs--;
1918                fPts += 3;
1919                break;
1920
1921            default:
1922                SkDEBUGFAIL("Should never see kDone_Verb");
1923        }
1924    }
1925}
1926
1927SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
1928    SkASSERT(ptsParam);
1929
1930    if (fVerbs == fVerbStop) {
1931        // Close the curve if requested and if there is some curve to close
1932        if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
1933            if (kLine_Verb == this->autoClose(ptsParam)) {
1934                return kLine_Verb;
1935            }
1936            fNeedClose = false;
1937            return kClose_Verb;
1938        }
1939        return kDone_Verb;
1940    }
1941
1942    // fVerbs is one beyond the current verb, decrement first
1943    unsigned verb = *(--fVerbs);
1944    const SkPoint* SK_RESTRICT srcPts = fPts;
1945    SkPoint* SK_RESTRICT       pts = ptsParam;
1946
1947    switch (verb) {
1948        case kMove_Verb:
1949            if (fNeedClose) {
1950                fVerbs++; // move back one verb
1951                verb = this->autoClose(pts);
1952                if (verb == kClose_Verb) {
1953                    fNeedClose = false;
1954                }
1955                return (Verb)verb;
1956            }
1957            if (fVerbs == fVerbStop) {    // might be a trailing moveto
1958                return kDone_Verb;
1959            }
1960            fMoveTo = *srcPts;
1961            pts[0] = *srcPts;
1962            srcPts += 1;
1963            fSegmentState = kAfterMove_SegmentState;
1964            fLastPt = fMoveTo;
1965            fNeedClose = fForceClose;
1966            break;
1967        case kLine_Verb:
1968            pts[0] = this->cons_moveTo();
1969            pts[1] = srcPts[0];
1970            fLastPt = srcPts[0];
1971            fCloseLine = false;
1972            srcPts += 1;
1973            break;
1974        case kConic_Verb:
1975            fConicWeights += 1;
1976            // fall-through
1977        case kQuad_Verb:
1978            pts[0] = this->cons_moveTo();
1979            memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
1980            fLastPt = srcPts[1];
1981            srcPts += 2;
1982            break;
1983        case kCubic_Verb:
1984            pts[0] = this->cons_moveTo();
1985            memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
1986            fLastPt = srcPts[2];
1987            srcPts += 3;
1988            break;
1989        case kClose_Verb:
1990            verb = this->autoClose(pts);
1991            if (verb == kLine_Verb) {
1992                fVerbs++; // move back one verb
1993            } else {
1994                fNeedClose = false;
1995                fSegmentState = kEmptyContour_SegmentState;
1996            }
1997            fLastPt = fMoveTo;
1998            break;
1999    }
2000    fPts = srcPts;
2001    return (Verb)verb;
2002}
2003
2004///////////////////////////////////////////////////////////////////////////////
2005
2006/*
2007    Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]]
2008*/
2009
2010size_t SkPath::writeToMemory(void* storage) const {
2011    SkDEBUGCODE(this->validate();)
2012
2013    if (nullptr == storage) {
2014        const int byteCount = sizeof(int32_t) * 2 + fPathRef->writeSize();
2015        return SkAlign4(byteCount);
2016    }
2017
2018    SkWBuffer   buffer(storage);
2019
2020    int32_t packed = (fConvexity << kConvexity_SerializationShift) |
2021                     (fFillType << kFillType_SerializationShift) |
2022                     (fFirstDirection << kDirection_SerializationShift) |
2023                     (fIsVolatile << kIsVolatile_SerializationShift) |
2024                     kCurrent_Version;
2025
2026    buffer.write32(packed);
2027    buffer.write32(fLastMoveToIndex);
2028
2029    fPathRef->writeToBuffer(&buffer);
2030
2031    buffer.padToAlign4();
2032    return buffer.pos();
2033}
2034
2035size_t SkPath::readFromMemory(const void* storage, size_t length) {
2036    SkRBufferWithSizeCheck buffer(storage, length);
2037
2038    int32_t packed;
2039    if (!buffer.readS32(&packed)) {
2040        return 0;
2041    }
2042
2043    unsigned version = packed & 0xFF;
2044    if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) {
2045        return 0;
2046    }
2047
2048    fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
2049    fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
2050    uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
2051    fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1;
2052    SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer);
2053    if (!pathRef) {
2054        return 0;
2055    }
2056
2057    fPathRef.reset(pathRef);
2058    SkDEBUGCODE(this->validate();)
2059    buffer.skipToAlign4();
2060
2061    // compatibility check
2062    if (version < kPathPrivFirstDirection_Version) {
2063        switch (dir) {  // old values
2064            case 0:
2065                fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2066                break;
2067            case 1:
2068                fFirstDirection = SkPathPriv::kCW_FirstDirection;
2069                break;
2070            case 2:
2071                fFirstDirection = SkPathPriv::kCCW_FirstDirection;
2072                break;
2073            default:
2074                SkASSERT(false);
2075        }
2076    } else {
2077        fFirstDirection = dir;
2078    }
2079
2080    return buffer.pos();
2081}
2082
2083///////////////////////////////////////////////////////////////////////////////
2084
2085#include "SkStringUtils.h"
2086#include "SkStream.h"
2087
2088static void append_params(SkString* str, const char label[], const SkPoint pts[],
2089                          int count, SkScalarAsStringType strType, SkScalar conicWeight = -1) {
2090    str->append(label);
2091    str->append("(");
2092
2093    const SkScalar* values = &pts[0].fX;
2094    count *= 2;
2095
2096    for (int i = 0; i < count; ++i) {
2097        SkAppendScalar(str, values[i], strType);
2098        if (i < count - 1) {
2099            str->append(", ");
2100        }
2101    }
2102    if (conicWeight >= 0) {
2103        str->append(", ");
2104        SkAppendScalar(str, conicWeight, strType);
2105    }
2106    str->append(");");
2107    if (kHex_SkScalarAsStringType == strType) {
2108        str->append("  // ");
2109        for (int i = 0; i < count; ++i) {
2110            SkAppendScalarDec(str, values[i]);
2111            if (i < count - 1) {
2112                str->append(", ");
2113            }
2114        }
2115        if (conicWeight >= 0) {
2116            str->append(", ");
2117            SkAppendScalarDec(str, conicWeight);
2118        }
2119    }
2120    str->append("\n");
2121}
2122
2123void SkPath::dump(SkWStream* wStream, bool forceClose, bool dumpAsHex) const {
2124    SkScalarAsStringType asType = dumpAsHex ? kHex_SkScalarAsStringType : kDec_SkScalarAsStringType;
2125    Iter    iter(*this, forceClose);
2126    SkPoint pts[4];
2127    Verb    verb;
2128
2129    if (!wStream) {
2130        SkDebugf("path: forceClose=%s\n", forceClose ? "true" : "false");
2131    }
2132    SkString builder;
2133
2134    while ((verb = iter.next(pts, false)) != kDone_Verb) {
2135        switch (verb) {
2136            case kMove_Verb:
2137                append_params(&builder, "path.moveTo", &pts[0], 1, asType);
2138                break;
2139            case kLine_Verb:
2140                append_params(&builder, "path.lineTo", &pts[1], 1, asType);
2141                break;
2142            case kQuad_Verb:
2143                append_params(&builder, "path.quadTo", &pts[1], 2, asType);
2144                break;
2145            case kConic_Verb:
2146                append_params(&builder, "path.conicTo", &pts[1], 2, asType, iter.conicWeight());
2147                break;
2148            case kCubic_Verb:
2149                append_params(&builder, "path.cubicTo", &pts[1], 3, asType);
2150                break;
2151            case kClose_Verb:
2152                builder.append("path.close();\n");
2153                break;
2154            default:
2155                SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
2156                verb = kDone_Verb;  // stop the loop
2157                break;
2158        }
2159        if (!wStream && builder.size()) {
2160            SkDebugf("%s", builder.c_str());
2161            builder.reset();
2162        }
2163    }
2164    if (wStream) {
2165        wStream->writeText(builder.c_str());
2166    }
2167}
2168
2169void SkPath::dump() const {
2170    this->dump(nullptr, false, false);
2171}
2172
2173void SkPath::dumpHex() const {
2174    this->dump(nullptr, false, true);
2175}
2176
2177#ifdef SK_DEBUG
2178void SkPath::validate() const {
2179    SkASSERT((fFillType & ~3) == 0);
2180
2181#ifdef SK_DEBUG_PATH
2182    if (!fBoundsIsDirty) {
2183        SkRect bounds;
2184
2185        bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
2186        SkASSERT(SkToBool(fIsFinite) == isFinite);
2187
2188        if (fPathRef->countPoints() <= 1) {
2189            // if we're empty, fBounds may be empty but translated, so we can't
2190            // necessarily compare to bounds directly
2191            // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
2192            // be [2, 2, 2, 2]
2193            SkASSERT(bounds.isEmpty());
2194            SkASSERT(fBounds.isEmpty());
2195        } else {
2196            if (bounds.isEmpty()) {
2197                SkASSERT(fBounds.isEmpty());
2198            } else {
2199                if (!fBounds.isEmpty()) {
2200                    SkASSERT(fBounds.contains(bounds));
2201                }
2202            }
2203        }
2204    }
2205#endif // SK_DEBUG_PATH
2206}
2207#endif // SK_DEBUG
2208
2209///////////////////////////////////////////////////////////////////////////////
2210
2211static int sign(SkScalar x) { return x < 0; }
2212#define kValueNeverReturnedBySign   2
2213
2214enum DirChange {
2215    kLeft_DirChange,
2216    kRight_DirChange,
2217    kStraight_DirChange,
2218    kBackwards_DirChange,
2219
2220    kInvalid_DirChange
2221};
2222
2223
2224static bool almost_equal(SkScalar compA, SkScalar compB) {
2225    // The error epsilon was empirically derived; worse case round rects
2226    // with a mid point outset by 2x float epsilon in tests had an error
2227    // of 12.
2228    const int epsilon = 16;
2229    if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2230        return false;
2231    }
2232    // no need to check for small numbers because SkPath::Iter has removed degenerate values
2233    int aBits = SkFloatAs2sCompliment(compA);
2234    int bBits = SkFloatAs2sCompliment(compB);
2235    return aBits < bBits + epsilon && bBits < aBits + epsilon;
2236}
2237
2238static bool approximately_zero_when_compared_to(double x, double y) {
2239    return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
2240}
2241
2242
2243// only valid for a single contour
2244struct Convexicator {
2245    Convexicator()
2246    : fPtCount(0)
2247    , fConvexity(SkPath::kConvex_Convexity)
2248    , fFirstDirection(SkPathPriv::kUnknown_FirstDirection)
2249    , fIsFinite(true)
2250    , fIsCurve(false) {
2251        fExpectedDir = kInvalid_DirChange;
2252        // warnings
2253        fLastPt.set(0, 0);
2254        fCurrPt.set(0, 0);
2255        fLastVec.set(0, 0);
2256        fFirstVec.set(0, 0);
2257
2258        fDx = fDy = 0;
2259        fSx = fSy = kValueNeverReturnedBySign;
2260    }
2261
2262    SkPath::Convexity getConvexity() const { return fConvexity; }
2263
2264    /** The direction returned is only valid if the path is determined convex */
2265    SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirection; }
2266
2267    void addPt(const SkPoint& pt) {
2268        if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) {
2269            return;
2270        }
2271
2272        if (0 == fPtCount) {
2273            fCurrPt = pt;
2274            ++fPtCount;
2275        } else {
2276            SkVector vec = pt - fCurrPt;
2277            SkScalar lengthSqd = vec.lengthSqd();
2278            if (!SkScalarIsFinite(lengthSqd)) {
2279                fIsFinite = false;
2280            } else if (lengthSqd) {
2281                fPriorPt = fLastPt;
2282                fLastPt = fCurrPt;
2283                fCurrPt = pt;
2284                if (++fPtCount == 2) {
2285                    fFirstVec = fLastVec = vec;
2286                } else {
2287                    SkASSERT(fPtCount > 2);
2288                    this->addVec(vec);
2289                }
2290
2291                int sx = sign(vec.fX);
2292                int sy = sign(vec.fY);
2293                fDx += (sx != fSx);
2294                fDy += (sy != fSy);
2295                fSx = sx;
2296                fSy = sy;
2297
2298                if (fDx > 3 || fDy > 3) {
2299                    fConvexity = SkPath::kConcave_Convexity;
2300                }
2301            }
2302        }
2303    }
2304
2305    void close() {
2306        if (fPtCount > 2) {
2307            this->addVec(fFirstVec);
2308        }
2309    }
2310
2311    DirChange directionChange(const SkVector& curVec) {
2312        SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec);
2313
2314        SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY)));
2315        SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY)));
2316        largest = SkTMax(largest, -smallest);
2317
2318        if (!almost_equal(largest, largest + cross)) {
2319            int sign = SkScalarSignAsInt(cross);
2320            if (sign) {
2321                return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2322            }
2323        }
2324
2325        if (cross) {
2326            double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX);
2327            double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY);
2328            double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX);
2329            double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY);
2330            double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX;
2331            if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) {
2332                int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross));
2333                if (sign) {
2334                    return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2335                }
2336            }
2337        }
2338
2339        if (!SkScalarNearlyZero(fLastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
2340            !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
2341            fLastVec.dot(curVec) < 0.0f) {
2342            return kBackwards_DirChange;
2343        }
2344
2345        return kStraight_DirChange;
2346    }
2347
2348
2349    bool isFinite() const {
2350        return fIsFinite;
2351    }
2352
2353    void setCurve(bool isCurve) {
2354        fIsCurve = isCurve;
2355    }
2356
2357private:
2358    void addVec(const SkVector& vec) {
2359        SkASSERT(vec.fX || vec.fY);
2360        DirChange dir = this->directionChange(vec);
2361        switch (dir) {
2362            case kLeft_DirChange:       // fall through
2363            case kRight_DirChange:
2364                if (kInvalid_DirChange == fExpectedDir) {
2365                    fExpectedDir = dir;
2366                    fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kCW_FirstDirection
2367                                                                : SkPathPriv::kCCW_FirstDirection;
2368                } else if (dir != fExpectedDir) {
2369                    fConvexity = SkPath::kConcave_Convexity;
2370                    fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2371                }
2372                fLastVec = vec;
2373                break;
2374            case kStraight_DirChange:
2375                break;
2376            case kBackwards_DirChange:
2377                if (fIsCurve) {
2378                    fConvexity = SkPath::kConcave_Convexity;
2379                    fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2380                }
2381                fLastVec = vec;
2382                break;
2383            case kInvalid_DirChange:
2384                SkFAIL("Use of invalid direction change flag");
2385                break;
2386        }
2387    }
2388
2389    SkPoint             fPriorPt;
2390    SkPoint             fLastPt;
2391    SkPoint             fCurrPt;
2392    // fLastVec does not necessarily start at fLastPt. We only advance it when the cross product
2393    // value with the current vec is deemed to be of a significant value.
2394    SkVector            fLastVec, fFirstVec;
2395    int                 fPtCount;   // non-degenerate points
2396    DirChange           fExpectedDir;
2397    SkPath::Convexity   fConvexity;
2398    SkPathPriv::FirstDirection   fFirstDirection;
2399    int                 fDx, fDy, fSx, fSy;
2400    bool                fIsFinite;
2401    bool                fIsCurve;
2402};
2403
2404SkPath::Convexity SkPath::internalGetConvexity() const {
2405    SkASSERT(kUnknown_Convexity == fConvexity);
2406    SkPoint         pts[4];
2407    SkPath::Verb    verb;
2408    SkPath::Iter    iter(*this, true);
2409
2410    int             contourCount = 0;
2411    int             count;
2412    Convexicator    state;
2413
2414    if (!isFinite()) {
2415        return kUnknown_Convexity;
2416    }
2417    while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) {
2418        switch (verb) {
2419            case kMove_Verb:
2420                if (++contourCount > 1) {
2421                    fConvexity = kConcave_Convexity;
2422                    return kConcave_Convexity;
2423                }
2424                pts[1] = pts[0];
2425                // fall through
2426            case kLine_Verb:
2427                count = 1;
2428                state.setCurve(false);
2429                break;
2430            case kQuad_Verb:
2431                // fall through
2432            case kConic_Verb:
2433                // fall through
2434            case kCubic_Verb:
2435                count = 2 + (kCubic_Verb == verb);
2436                // As an additional enhancement, this could set curve true only
2437                // if the curve is nonlinear
2438                state.setCurve(true);
2439                break;
2440            case kClose_Verb:
2441                state.setCurve(false);
2442                state.close();
2443                count = 0;
2444                break;
2445            default:
2446                SkDEBUGFAIL("bad verb");
2447                fConvexity = kConcave_Convexity;
2448                return kConcave_Convexity;
2449        }
2450
2451        for (int i = 1; i <= count; i++) {
2452            state.addPt(pts[i]);
2453        }
2454        // early exit
2455        if (!state.isFinite()) {
2456            return kUnknown_Convexity;
2457        }
2458        if (kConcave_Convexity == state.getConvexity()) {
2459            fConvexity = kConcave_Convexity;
2460            return kConcave_Convexity;
2461        }
2462    }
2463    fConvexity = state.getConvexity();
2464    if (kConvex_Convexity == fConvexity && SkPathPriv::kUnknown_FirstDirection == fFirstDirection) {
2465        fFirstDirection = state.getFirstDirection();
2466    }
2467    return static_cast<Convexity>(fConvexity);
2468}
2469
2470///////////////////////////////////////////////////////////////////////////////
2471
2472class ContourIter {
2473public:
2474    ContourIter(const SkPathRef& pathRef);
2475
2476    bool done() const { return fDone; }
2477    // if !done() then these may be called
2478    int count() const { return fCurrPtCount; }
2479    const SkPoint* pts() const { return fCurrPt; }
2480    void next();
2481
2482private:
2483    int fCurrPtCount;
2484    const SkPoint* fCurrPt;
2485    const uint8_t* fCurrVerb;
2486    const uint8_t* fStopVerbs;
2487    const SkScalar* fCurrConicWeight;
2488    bool fDone;
2489    SkDEBUGCODE(int fContourCounter;)
2490};
2491
2492ContourIter::ContourIter(const SkPathRef& pathRef) {
2493    fStopVerbs = pathRef.verbsMemBegin();
2494    fDone = false;
2495    fCurrPt = pathRef.points();
2496    fCurrVerb = pathRef.verbs();
2497    fCurrConicWeight = pathRef.conicWeights();
2498    fCurrPtCount = 0;
2499    SkDEBUGCODE(fContourCounter = 0;)
2500    this->next();
2501}
2502
2503void ContourIter::next() {
2504    if (fCurrVerb <= fStopVerbs) {
2505        fDone = true;
2506    }
2507    if (fDone) {
2508        return;
2509    }
2510
2511    // skip pts of prev contour
2512    fCurrPt += fCurrPtCount;
2513
2514    SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
2515    int ptCount = 1;    // moveTo
2516    const uint8_t* verbs = fCurrVerb;
2517
2518    for (--verbs; verbs > fStopVerbs; --verbs) {
2519        switch (verbs[~0]) {
2520            case SkPath::kMove_Verb:
2521                goto CONTOUR_END;
2522            case SkPath::kLine_Verb:
2523                ptCount += 1;
2524                break;
2525            case SkPath::kConic_Verb:
2526                fCurrConicWeight += 1;
2527                // fall-through
2528            case SkPath::kQuad_Verb:
2529                ptCount += 2;
2530                break;
2531            case SkPath::kCubic_Verb:
2532                ptCount += 3;
2533                break;
2534            case SkPath::kClose_Verb:
2535                break;
2536            default:
2537                SkDEBUGFAIL("unexpected verb");
2538                break;
2539        }
2540    }
2541CONTOUR_END:
2542    fCurrPtCount = ptCount;
2543    fCurrVerb = verbs;
2544    SkDEBUGCODE(++fContourCounter;)
2545}
2546
2547// returns cross product of (p1 - p0) and (p2 - p0)
2548static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
2549    SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
2550    // We may get 0 when the above subtracts underflow. We expect this to be
2551    // very rare and lazily promote to double.
2552    if (0 == cross) {
2553        double p0x = SkScalarToDouble(p0.fX);
2554        double p0y = SkScalarToDouble(p0.fY);
2555
2556        double p1x = SkScalarToDouble(p1.fX);
2557        double p1y = SkScalarToDouble(p1.fY);
2558
2559        double p2x = SkScalarToDouble(p2.fX);
2560        double p2y = SkScalarToDouble(p2.fY);
2561
2562        cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
2563                                 (p1y - p0y) * (p2x - p0x));
2564
2565    }
2566    return cross;
2567}
2568
2569// Returns the first pt with the maximum Y coordinate
2570static int find_max_y(const SkPoint pts[], int count) {
2571    SkASSERT(count > 0);
2572    SkScalar max = pts[0].fY;
2573    int firstIndex = 0;
2574    for (int i = 1; i < count; ++i) {
2575        SkScalar y = pts[i].fY;
2576        if (y > max) {
2577            max = y;
2578            firstIndex = i;
2579        }
2580    }
2581    return firstIndex;
2582}
2583
2584static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
2585    int i = index;
2586    for (;;) {
2587        i = (i + inc) % n;
2588        if (i == index) {   // we wrapped around, so abort
2589            break;
2590        }
2591        if (pts[index] != pts[i]) { // found a different point, success!
2592            break;
2593        }
2594    }
2595    return i;
2596}
2597
2598/**
2599 *  Starting at index, and moving forward (incrementing), find the xmin and
2600 *  xmax of the contiguous points that have the same Y.
2601 */
2602static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
2603                               int* maxIndexPtr) {
2604    const SkScalar y = pts[index].fY;
2605    SkScalar min = pts[index].fX;
2606    SkScalar max = min;
2607    int minIndex = index;
2608    int maxIndex = index;
2609    for (int i = index + 1; i < n; ++i) {
2610        if (pts[i].fY != y) {
2611            break;
2612        }
2613        SkScalar x = pts[i].fX;
2614        if (x < min) {
2615            min = x;
2616            minIndex = i;
2617        } else if (x > max) {
2618            max = x;
2619            maxIndex = i;
2620        }
2621    }
2622    *maxIndexPtr = maxIndex;
2623    return minIndex;
2624}
2625
2626static void crossToDir(SkScalar cross, SkPathPriv::FirstDirection* dir) {
2627    *dir = cross > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
2628}
2629
2630/*
2631 *  We loop through all contours, and keep the computed cross-product of the
2632 *  contour that contained the global y-max. If we just look at the first
2633 *  contour, we may find one that is wound the opposite way (correctly) since
2634 *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2635 *  that is outer most (or at least has the global y-max) before we can consider
2636 *  its cross product.
2637 */
2638bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* dir) {
2639    if (kUnknown_FirstDirection != path.fFirstDirection.load()) {
2640        *dir = static_cast<FirstDirection>(path.fFirstDirection.load());
2641        return true;
2642    }
2643
2644    // don't want to pay the cost for computing this if it
2645    // is unknown, so we don't call isConvex()
2646    if (SkPath::kConvex_Convexity == path.getConvexityOrUnknown()) {
2647        SkASSERT(kUnknown_FirstDirection == path.fFirstDirection);
2648        *dir = static_cast<FirstDirection>(path.fFirstDirection.load());
2649        return false;
2650    }
2651
2652    ContourIter iter(*path.fPathRef.get());
2653
2654    // initialize with our logical y-min
2655    SkScalar ymax = path.getBounds().fTop;
2656    SkScalar ymaxCross = 0;
2657
2658    for (; !iter.done(); iter.next()) {
2659        int n = iter.count();
2660        if (n < 3) {
2661            continue;
2662        }
2663
2664        const SkPoint* pts = iter.pts();
2665        SkScalar cross = 0;
2666        int index = find_max_y(pts, n);
2667        if (pts[index].fY < ymax) {
2668            continue;
2669        }
2670
2671        // If there is more than 1 distinct point at the y-max, we take the
2672        // x-min and x-max of them and just subtract to compute the dir.
2673        if (pts[(index + 1) % n].fY == pts[index].fY) {
2674            int maxIndex;
2675            int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2676            if (minIndex == maxIndex) {
2677                goto TRY_CROSSPROD;
2678            }
2679            SkASSERT(pts[minIndex].fY == pts[index].fY);
2680            SkASSERT(pts[maxIndex].fY == pts[index].fY);
2681            SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2682            // we just subtract the indices, and let that auto-convert to
2683            // SkScalar, since we just want - or + to signal the direction.
2684            cross = minIndex - maxIndex;
2685        } else {
2686            TRY_CROSSPROD:
2687            // Find a next and prev index to use for the cross-product test,
2688            // but we try to find pts that form non-zero vectors from pts[index]
2689            //
2690            // Its possible that we can't find two non-degenerate vectors, so
2691            // we have to guard our search (e.g. all the pts could be in the
2692            // same place).
2693
2694            // we pass n - 1 instead of -1 so we don't foul up % operator by
2695            // passing it a negative LH argument.
2696            int prev = find_diff_pt(pts, index, n, n - 1);
2697            if (prev == index) {
2698                // completely degenerate, skip to next contour
2699                continue;
2700            }
2701            int next = find_diff_pt(pts, index, n, 1);
2702            SkASSERT(next != index);
2703            cross = cross_prod(pts[prev], pts[index], pts[next]);
2704            // if we get a zero and the points are horizontal, then we look at the spread in
2705            // x-direction. We really should continue to walk away from the degeneracy until
2706            // there is a divergence.
2707            if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
2708                // construct the subtract so we get the correct Direction below
2709                cross = pts[index].fX - pts[next].fX;
2710            }
2711        }
2712
2713        if (cross) {
2714            // record our best guess so far
2715            ymax = pts[index].fY;
2716            ymaxCross = cross;
2717        }
2718    }
2719    if (ymaxCross) {
2720        crossToDir(ymaxCross, dir);
2721        path.fFirstDirection = *dir;
2722        return true;
2723    } else {
2724        return false;
2725    }
2726}
2727
2728///////////////////////////////////////////////////////////////////////////////
2729
2730static bool between(SkScalar a, SkScalar b, SkScalar c) {
2731    SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
2732            || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c)));
2733    return (a - b) * (c - b) <= 0;
2734}
2735
2736static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
2737                                 SkScalar D, SkScalar t) {
2738    return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
2739}
2740
2741static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
2742                               SkScalar t) {
2743    SkScalar A = c3 + 3*(c1 - c2) - c0;
2744    SkScalar B = 3*(c2 - c1 - c1 + c0);
2745    SkScalar C = 3*(c1 - c0);
2746    SkScalar D = c0;
2747    return eval_cubic_coeff(A, B, C, D, t);
2748}
2749
2750template <size_t N> static void find_minmax(const SkPoint pts[],
2751                                            SkScalar* minPtr, SkScalar* maxPtr) {
2752    SkScalar min, max;
2753    min = max = pts[0].fX;
2754    for (size_t i = 1; i < N; ++i) {
2755        min = SkMinScalar(min, pts[i].fX);
2756        max = SkMaxScalar(max, pts[i].fX);
2757    }
2758    *minPtr = min;
2759    *maxPtr = max;
2760}
2761
2762static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) {
2763    if (start.fY == end.fY) {
2764        return between(start.fX, x, end.fX) && x != end.fX;
2765    } else {
2766        return x == start.fX && y == start.fY;
2767    }
2768}
2769
2770static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2771    SkScalar y0 = pts[0].fY;
2772    SkScalar y3 = pts[3].fY;
2773
2774    int dir = 1;
2775    if (y0 > y3) {
2776        SkTSwap(y0, y3);
2777        dir = -1;
2778    }
2779    if (y < y0 || y > y3) {
2780        return 0;
2781    }
2782    if (checkOnCurve(x, y, pts[0], pts[3])) {
2783        *onCurveCount += 1;
2784        return 0;
2785    }
2786    if (y == y3) {
2787        return 0;
2788    }
2789
2790    // quickreject or quickaccept
2791    SkScalar min, max;
2792    find_minmax<4>(pts, &min, &max);
2793    if (x < min) {
2794        return 0;
2795    }
2796    if (x > max) {
2797        return dir;
2798    }
2799
2800    // compute the actual x(t) value
2801    SkScalar t;
2802    SkAssertResult(SkCubicClipper::ChopMonoAtY(pts, y, &t));
2803    SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
2804    if (SkScalarNearlyEqual(xt, x)) {
2805        if (x != pts[3].fX || y != pts[3].fY) {  // don't test end points; they're start points
2806            *onCurveCount += 1;
2807            return 0;
2808        }
2809    }
2810    return xt < x ? dir : 0;
2811}
2812
2813static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2814    SkPoint dst[10];
2815    int n = SkChopCubicAtYExtrema(pts, dst);
2816    int w = 0;
2817    for (int i = 0; i <= n; ++i) {
2818        w += winding_mono_cubic(&dst[i * 3], x, y, onCurveCount);
2819    }
2820    return w;
2821}
2822
2823static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) {
2824    SkASSERT(src);
2825    SkASSERT(t >= 0 && t <= 1);
2826    SkScalar src2w = src[2] * w;
2827    SkScalar C = src[0];
2828    SkScalar A = src[4] - 2 * src2w + C;
2829    SkScalar B = 2 * (src2w - C);
2830    return (A * t + B) * t + C;
2831}
2832
2833
2834static double conic_eval_denominator(SkScalar w, SkScalar t) {
2835    SkScalar B = 2 * (w - 1);
2836    SkScalar C = 1;
2837    SkScalar A = -B;
2838    return (A * t + B) * t + C;
2839}
2840
2841static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) {
2842    const SkPoint* pts = conic.fPts;
2843    SkScalar y0 = pts[0].fY;
2844    SkScalar y2 = pts[2].fY;
2845
2846    int dir = 1;
2847    if (y0 > y2) {
2848        SkTSwap(y0, y2);
2849        dir = -1;
2850    }
2851    if (y < y0 || y > y2) {
2852        return 0;
2853    }
2854    if (checkOnCurve(x, y, pts[0], pts[2])) {
2855        *onCurveCount += 1;
2856        return 0;
2857    }
2858    if (y == y2) {
2859        return 0;
2860    }
2861
2862    SkScalar roots[2];
2863    SkScalar A = pts[2].fY;
2864    SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y;
2865    SkScalar C = pts[0].fY;
2866    A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
2867    B -= C;  // B = b*w - w * yCept + yCept - a
2868    C -= y;
2869    int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
2870    SkASSERT(n <= 1);
2871    SkScalar xt;
2872    if (0 == n) {
2873        // zero roots are returned only when y0 == y
2874        // Need [0] if dir == 1
2875        // and  [2] if dir == -1
2876        xt = pts[1 - dir].fX;
2877    } else {
2878        SkScalar t = roots[0];
2879        xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t);
2880    }
2881    if (SkScalarNearlyEqual(xt, x)) {
2882        if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
2883            *onCurveCount += 1;
2884            return 0;
2885        }
2886    }
2887    return xt < x ? dir : 0;
2888}
2889
2890static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) {
2891    //    return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0;
2892    if (y0 == y1) {
2893        return true;
2894    }
2895    if (y0 < y1) {
2896        return y1 <= y2;
2897    } else {
2898        return y1 >= y2;
2899    }
2900}
2901
2902static int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight,
2903                         int* onCurveCount) {
2904    SkConic conic(pts, weight);
2905    SkConic chopped[2];
2906    // If the data points are very large, the conic may not be monotonic but may also
2907    // fail to chop. Then, the chopper does not split the original conic in two.
2908    bool isMono = is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped);
2909    int w = winding_mono_conic(isMono ? conic : chopped[0], x, y, onCurveCount);
2910    if (!isMono) {
2911        w += winding_mono_conic(chopped[1], x, y, onCurveCount);
2912    }
2913    return w;
2914}
2915
2916static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2917    SkScalar y0 = pts[0].fY;
2918    SkScalar y2 = pts[2].fY;
2919
2920    int dir = 1;
2921    if (y0 > y2) {
2922        SkTSwap(y0, y2);
2923        dir = -1;
2924    }
2925    if (y < y0 || y > y2) {
2926        return 0;
2927    }
2928    if (checkOnCurve(x, y, pts[0], pts[2])) {
2929        *onCurveCount += 1;
2930        return 0;
2931    }
2932    if (y == y2) {
2933        return 0;
2934    }
2935    // bounds check on X (not required. is it faster?)
2936#if 0
2937    if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) {
2938        return 0;
2939    }
2940#endif
2941
2942    SkScalar roots[2];
2943    int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
2944                                2 * (pts[1].fY - pts[0].fY),
2945                                pts[0].fY - y,
2946                                roots);
2947    SkASSERT(n <= 1);
2948    SkScalar xt;
2949    if (0 == n) {
2950        // zero roots are returned only when y0 == y
2951        // Need [0] if dir == 1
2952        // and  [2] if dir == -1
2953        xt = pts[1 - dir].fX;
2954    } else {
2955        SkScalar t = roots[0];
2956        SkScalar C = pts[0].fX;
2957        SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
2958        SkScalar B = 2 * (pts[1].fX - C);
2959        xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
2960    }
2961    if (SkScalarNearlyEqual(xt, x)) {
2962        if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
2963            *onCurveCount += 1;
2964            return 0;
2965        }
2966    }
2967    return xt < x ? dir : 0;
2968}
2969
2970static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2971    SkPoint dst[5];
2972    int     n = 0;
2973
2974    if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) {
2975        n = SkChopQuadAtYExtrema(pts, dst);
2976        pts = dst;
2977    }
2978    int w = winding_mono_quad(pts, x, y, onCurveCount);
2979    if (n > 0) {
2980        w += winding_mono_quad(&pts[2], x, y, onCurveCount);
2981    }
2982    return w;
2983}
2984
2985static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2986    SkScalar x0 = pts[0].fX;
2987    SkScalar y0 = pts[0].fY;
2988    SkScalar x1 = pts[1].fX;
2989    SkScalar y1 = pts[1].fY;
2990
2991    SkScalar dy = y1 - y0;
2992
2993    int dir = 1;
2994    if (y0 > y1) {
2995        SkTSwap(y0, y1);
2996        dir = -1;
2997    }
2998    if (y < y0 || y > y1) {
2999        return 0;
3000    }
3001    if (checkOnCurve(x, y, pts[0], pts[1])) {
3002        *onCurveCount += 1;
3003        return 0;
3004    }
3005    if (y == y1) {
3006        return 0;
3007    }
3008    SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x0);
3009
3010    if (!cross) {
3011        // zero cross means the point is on the line, and since the case where
3012        // y of the query point is at the end point is handled above, we can be
3013        // sure that we're on the line (excluding the end point) here
3014        if (x != x1 || y != pts[1].fY) {
3015            *onCurveCount += 1;
3016        }
3017        dir = 0;
3018    } else if (SkScalarSignAsInt(cross) == dir) {
3019        dir = 0;
3020    }
3021    return dir;
3022}
3023
3024static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y,
3025        SkTDArray<SkVector>* tangents) {
3026    if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)
3027             && !between(pts[2].fY, y, pts[3].fY)) {
3028        return;
3029    }
3030    if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)
3031             && !between(pts[2].fX, x, pts[3].fX)) {
3032        return;
3033    }
3034    SkPoint dst[10];
3035    int n = SkChopCubicAtYExtrema(pts, dst);
3036    for (int i = 0; i <= n; ++i) {
3037        SkPoint* c = &dst[i * 3];
3038        SkScalar t;
3039        SkAssertResult(SkCubicClipper::ChopMonoAtY(c, y, &t));
3040        SkScalar xt = eval_cubic_pts(c[0].fX, c[1].fX, c[2].fX, c[3].fX, t);
3041        if (!SkScalarNearlyEqual(x, xt)) {
3042            continue;
3043        }
3044        SkVector tangent;
3045        SkEvalCubicAt(c, t, nullptr, &tangent, nullptr);
3046        tangents->push(tangent);
3047    }
3048}
3049
3050static void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w,
3051            SkTDArray<SkVector>* tangents) {
3052    if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
3053        return;
3054    }
3055    if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
3056        return;
3057    }
3058    SkScalar roots[2];
3059    SkScalar A = pts[2].fY;
3060    SkScalar B = pts[1].fY * w - y * w + y;
3061    SkScalar C = pts[0].fY;
3062    A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
3063    B -= C;  // B = b*w - w * yCept + yCept - a
3064    C -= y;
3065    int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
3066    for (int index = 0; index < n; ++index) {
3067        SkScalar t = roots[index];
3068        SkScalar xt = conic_eval_numerator(&pts[0].fX, w, t) / conic_eval_denominator(w, t);
3069        if (!SkScalarNearlyEqual(x, xt)) {
3070            continue;
3071        }
3072        SkConic conic(pts, w);
3073        tangents->push(conic.evalTangentAt(t));
3074    }
3075}
3076
3077static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y,
3078        SkTDArray<SkVector>* tangents) {
3079    if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
3080        return;
3081    }
3082    if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
3083        return;
3084    }
3085    SkScalar roots[2];
3086    int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
3087                                2 * (pts[1].fY - pts[0].fY),
3088                                pts[0].fY - y,
3089                                roots);
3090    for (int index = 0; index < n; ++index) {
3091        SkScalar t = roots[index];
3092        SkScalar C = pts[0].fX;
3093        SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
3094        SkScalar B = 2 * (pts[1].fX - C);
3095        SkScalar xt = (A * t + B) * t + C;
3096        if (!SkScalarNearlyEqual(x, xt)) {
3097            continue;
3098        }
3099        tangents->push(SkEvalQuadTangentAt(pts, t));
3100    }
3101}
3102
3103static void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y,
3104        SkTDArray<SkVector>* tangents) {
3105    SkScalar y0 = pts[0].fY;
3106    SkScalar y1 = pts[1].fY;
3107    if (!between(y0, y, y1)) {
3108        return;
3109    }
3110    SkScalar x0 = pts[0].fX;
3111    SkScalar x1 = pts[1].fX;
3112    if (!between(x0, x, x1)) {
3113        return;
3114    }
3115    SkScalar dx = x1 - x0;
3116    SkScalar dy = y1 - y0;
3117    if (!SkScalarNearlyEqual((x - x0) * dy, dx * (y - y0))) {
3118        return;
3119    }
3120    SkVector v;
3121    v.set(dx, dy);
3122    tangents->push(v);
3123}
3124
3125static bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) {
3126    return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom;
3127}
3128
3129bool SkPath::contains(SkScalar x, SkScalar y) const {
3130    bool isInverse = this->isInverseFillType();
3131    if (this->isEmpty()) {
3132        return isInverse;
3133    }
3134
3135    if (!contains_inclusive(this->getBounds(), x, y)) {
3136        return isInverse;
3137    }
3138
3139    SkPath::Iter iter(*this, true);
3140    bool done = false;
3141    int w = 0;
3142    int onCurveCount = 0;
3143    do {
3144        SkPoint pts[4];
3145        switch (iter.next(pts, false)) {
3146            case SkPath::kMove_Verb:
3147            case SkPath::kClose_Verb:
3148                break;
3149            case SkPath::kLine_Verb:
3150                w += winding_line(pts, x, y, &onCurveCount);
3151                break;
3152            case SkPath::kQuad_Verb:
3153                w += winding_quad(pts, x, y, &onCurveCount);
3154                break;
3155            case SkPath::kConic_Verb:
3156                w += winding_conic(pts, x, y, iter.conicWeight(), &onCurveCount);
3157                break;
3158            case SkPath::kCubic_Verb:
3159                w += winding_cubic(pts, x, y, &onCurveCount);
3160                break;
3161            case SkPath::kDone_Verb:
3162                done = true;
3163                break;
3164       }
3165    } while (!done);
3166    bool evenOddFill = SkPath::kEvenOdd_FillType == this->getFillType()
3167            || SkPath::kInverseEvenOdd_FillType == this->getFillType();
3168    if (evenOddFill) {
3169        w &= 1;
3170    }
3171    if (w) {
3172        return !isInverse;
3173    }
3174    if (onCurveCount <= 1) {
3175        return SkToBool(onCurveCount) ^ isInverse;
3176    }
3177    if ((onCurveCount & 1) || evenOddFill) {
3178        return SkToBool(onCurveCount & 1) ^ isInverse;
3179    }
3180    // If the point touches an even number of curves, and the fill is winding, check for
3181    // coincidence. Count coincidence as places where the on curve points have identical tangents.
3182    iter.setPath(*this, true);
3183    done = false;
3184    SkTDArray<SkVector> tangents;
3185    do {
3186        SkPoint pts[4];
3187        int oldCount = tangents.count();
3188        switch (iter.next(pts, false)) {
3189            case SkPath::kMove_Verb:
3190            case SkPath::kClose_Verb:
3191                break;
3192            case SkPath::kLine_Verb:
3193                tangent_line(pts, x, y, &tangents);
3194                break;
3195            case SkPath::kQuad_Verb:
3196                tangent_quad(pts, x, y, &tangents);
3197                break;
3198            case SkPath::kConic_Verb:
3199                tangent_conic(pts, x, y, iter.conicWeight(), &tangents);
3200                break;
3201            case SkPath::kCubic_Verb:
3202                tangent_cubic(pts, x, y, &tangents);
3203                break;
3204            case SkPath::kDone_Verb:
3205                done = true;
3206                break;
3207       }
3208       if (tangents.count() > oldCount) {
3209            int last = tangents.count() - 1;
3210            const SkVector& tangent = tangents[last];
3211            if (SkScalarNearlyZero(tangent.lengthSqd())) {
3212                tangents.remove(last);
3213            } else {
3214                for (int index = 0; index < last; ++index) {
3215                    const SkVector& test = tangents[index];
3216                    if (SkScalarNearlyZero(test.cross(tangent))
3217                            && SkScalarSignAsInt(tangent.fX * test.fX) <= 0
3218                            && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) {
3219                        tangents.remove(last);
3220                        tangents.removeShuffle(index);
3221                        break;
3222                    }
3223                }
3224            }
3225        }
3226    } while (!done);
3227    return SkToBool(tangents.count()) ^ isInverse;
3228}
3229
3230int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3231                                SkScalar w, SkPoint pts[], int pow2) {
3232    const SkConic conic(p0, p1, p2, w);
3233    return conic.chopIntoQuadsPOW2(pts, pow2);
3234}
3235