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 "SkString.h"
2086#include "SkStringUtils.h"
2087#include "SkStream.h"
2088
2089static void append_params(SkString* str, const char label[], const SkPoint pts[],
2090                          int count, SkScalarAsStringType strType, SkScalar conicWeight = -1) {
2091    str->append(label);
2092    str->append("(");
2093
2094    const SkScalar* values = &pts[0].fX;
2095    count *= 2;
2096
2097    for (int i = 0; i < count; ++i) {
2098        SkAppendScalar(str, values[i], strType);
2099        if (i < count - 1) {
2100            str->append(", ");
2101        }
2102    }
2103    if (conicWeight >= 0) {
2104        str->append(", ");
2105        SkAppendScalar(str, conicWeight, strType);
2106    }
2107    str->append(");");
2108    if (kHex_SkScalarAsStringType == strType) {
2109        str->append("  // ");
2110        for (int i = 0; i < count; ++i) {
2111            SkAppendScalarDec(str, values[i]);
2112            if (i < count - 1) {
2113                str->append(", ");
2114            }
2115        }
2116        if (conicWeight >= 0) {
2117            str->append(", ");
2118            SkAppendScalarDec(str, conicWeight);
2119        }
2120    }
2121    str->append("\n");
2122}
2123
2124void SkPath::dump(SkWStream* wStream, bool forceClose, bool dumpAsHex) const {
2125    SkScalarAsStringType asType = dumpAsHex ? kHex_SkScalarAsStringType : kDec_SkScalarAsStringType;
2126    Iter    iter(*this, forceClose);
2127    SkPoint pts[4];
2128    Verb    verb;
2129
2130    if (!wStream) {
2131        SkDebugf("path: forceClose=%s\n", forceClose ? "true" : "false");
2132    }
2133    SkString builder;
2134
2135    while ((verb = iter.next(pts, false)) != kDone_Verb) {
2136        switch (verb) {
2137            case kMove_Verb:
2138                append_params(&builder, "path.moveTo", &pts[0], 1, asType);
2139                break;
2140            case kLine_Verb:
2141                append_params(&builder, "path.lineTo", &pts[1], 1, asType);
2142                break;
2143            case kQuad_Verb:
2144                append_params(&builder, "path.quadTo", &pts[1], 2, asType);
2145                break;
2146            case kConic_Verb:
2147                append_params(&builder, "path.conicTo", &pts[1], 2, asType, iter.conicWeight());
2148                break;
2149            case kCubic_Verb:
2150                append_params(&builder, "path.cubicTo", &pts[1], 3, asType);
2151                break;
2152            case kClose_Verb:
2153                builder.append("path.close();\n");
2154                break;
2155            default:
2156                SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
2157                verb = kDone_Verb;  // stop the loop
2158                break;
2159        }
2160        if (!wStream && builder.size()) {
2161            SkDebugf("%s", builder.c_str());
2162            builder.reset();
2163        }
2164    }
2165    if (wStream) {
2166        wStream->writeText(builder.c_str());
2167    }
2168}
2169
2170void SkPath::dump() const {
2171    this->dump(nullptr, false, false);
2172}
2173
2174void SkPath::dumpHex() const {
2175    this->dump(nullptr, false, true);
2176}
2177
2178#ifdef SK_DEBUG
2179void SkPath::validate() const {
2180    SkASSERT((fFillType & ~3) == 0);
2181
2182#ifdef SK_DEBUG_PATH
2183    if (!fBoundsIsDirty) {
2184        SkRect bounds;
2185
2186        bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
2187        SkASSERT(SkToBool(fIsFinite) == isFinite);
2188
2189        if (fPathRef->countPoints() <= 1) {
2190            // if we're empty, fBounds may be empty but translated, so we can't
2191            // necessarily compare to bounds directly
2192            // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
2193            // be [2, 2, 2, 2]
2194            SkASSERT(bounds.isEmpty());
2195            SkASSERT(fBounds.isEmpty());
2196        } else {
2197            if (bounds.isEmpty()) {
2198                SkASSERT(fBounds.isEmpty());
2199            } else {
2200                if (!fBounds.isEmpty()) {
2201                    SkASSERT(fBounds.contains(bounds));
2202                }
2203            }
2204        }
2205    }
2206#endif // SK_DEBUG_PATH
2207}
2208#endif // SK_DEBUG
2209
2210///////////////////////////////////////////////////////////////////////////////
2211
2212static int sign(SkScalar x) { return x < 0; }
2213#define kValueNeverReturnedBySign   2
2214
2215enum DirChange {
2216    kLeft_DirChange,
2217    kRight_DirChange,
2218    kStraight_DirChange,
2219    kBackwards_DirChange,
2220
2221    kInvalid_DirChange
2222};
2223
2224
2225static bool almost_equal(SkScalar compA, SkScalar compB) {
2226    // The error epsilon was empirically derived; worse case round rects
2227    // with a mid point outset by 2x float epsilon in tests had an error
2228    // of 12.
2229    const int epsilon = 16;
2230    if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2231        return false;
2232    }
2233    // no need to check for small numbers because SkPath::Iter has removed degenerate values
2234    int aBits = SkFloatAs2sCompliment(compA);
2235    int bBits = SkFloatAs2sCompliment(compB);
2236    return aBits < bBits + epsilon && bBits < aBits + epsilon;
2237}
2238
2239static bool approximately_zero_when_compared_to(double x, double y) {
2240    return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
2241}
2242
2243
2244// only valid for a single contour
2245struct Convexicator {
2246    Convexicator()
2247    : fPtCount(0)
2248    , fConvexity(SkPath::kConvex_Convexity)
2249    , fFirstDirection(SkPathPriv::kUnknown_FirstDirection)
2250    , fIsFinite(true)
2251    , fIsCurve(false) {
2252        fExpectedDir = kInvalid_DirChange;
2253        // warnings
2254        fLastPt.set(0, 0);
2255        fCurrPt.set(0, 0);
2256        fLastVec.set(0, 0);
2257        fFirstVec.set(0, 0);
2258
2259        fDx = fDy = 0;
2260        fSx = fSy = kValueNeverReturnedBySign;
2261    }
2262
2263    SkPath::Convexity getConvexity() const { return fConvexity; }
2264
2265    /** The direction returned is only valid if the path is determined convex */
2266    SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirection; }
2267
2268    void addPt(const SkPoint& pt) {
2269        if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) {
2270            return;
2271        }
2272
2273        if (0 == fPtCount) {
2274            fCurrPt = pt;
2275            ++fPtCount;
2276        } else {
2277            SkVector vec = pt - fCurrPt;
2278            SkScalar lengthSqd = vec.lengthSqd();
2279            if (!SkScalarIsFinite(lengthSqd)) {
2280                fIsFinite = false;
2281            } else if (lengthSqd) {
2282                fPriorPt = fLastPt;
2283                fLastPt = fCurrPt;
2284                fCurrPt = pt;
2285                if (++fPtCount == 2) {
2286                    fFirstVec = fLastVec = vec;
2287                } else {
2288                    SkASSERT(fPtCount > 2);
2289                    this->addVec(vec);
2290                }
2291
2292                int sx = sign(vec.fX);
2293                int sy = sign(vec.fY);
2294                fDx += (sx != fSx);
2295                fDy += (sy != fSy);
2296                fSx = sx;
2297                fSy = sy;
2298
2299                if (fDx > 3 || fDy > 3) {
2300                    fConvexity = SkPath::kConcave_Convexity;
2301                }
2302            }
2303        }
2304    }
2305
2306    void close() {
2307        if (fPtCount > 2) {
2308            this->addVec(fFirstVec);
2309        }
2310    }
2311
2312    DirChange directionChange(const SkVector& curVec) {
2313        SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec);
2314
2315        SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY)));
2316        SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY)));
2317        largest = SkTMax(largest, -smallest);
2318
2319        if (!almost_equal(largest, largest + cross)) {
2320            int sign = SkScalarSignAsInt(cross);
2321            if (sign) {
2322                return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2323            }
2324        }
2325
2326        if (cross) {
2327            double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX);
2328            double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY);
2329            double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX);
2330            double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY);
2331            double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX;
2332            if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) {
2333                int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross));
2334                if (sign) {
2335                    return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2336                }
2337            }
2338        }
2339
2340        if (!SkScalarNearlyZero(fLastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
2341            !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
2342            fLastVec.dot(curVec) < 0.0f) {
2343            return kBackwards_DirChange;
2344        }
2345
2346        return kStraight_DirChange;
2347    }
2348
2349
2350    bool isFinite() const {
2351        return fIsFinite;
2352    }
2353
2354    void setCurve(bool isCurve) {
2355        fIsCurve = isCurve;
2356    }
2357
2358private:
2359    void addVec(const SkVector& vec) {
2360        SkASSERT(vec.fX || vec.fY);
2361        DirChange dir = this->directionChange(vec);
2362        switch (dir) {
2363            case kLeft_DirChange:       // fall through
2364            case kRight_DirChange:
2365                if (kInvalid_DirChange == fExpectedDir) {
2366                    fExpectedDir = dir;
2367                    fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kCW_FirstDirection
2368                                                                : SkPathPriv::kCCW_FirstDirection;
2369                } else if (dir != fExpectedDir) {
2370                    fConvexity = SkPath::kConcave_Convexity;
2371                    fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2372                }
2373                fLastVec = vec;
2374                break;
2375            case kStraight_DirChange:
2376                break;
2377            case kBackwards_DirChange:
2378                if (fIsCurve) {
2379                    fConvexity = SkPath::kConcave_Convexity;
2380                    fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2381                }
2382                fLastVec = vec;
2383                break;
2384            case kInvalid_DirChange:
2385                SkFAIL("Use of invalid direction change flag");
2386                break;
2387        }
2388    }
2389
2390    SkPoint             fPriorPt;
2391    SkPoint             fLastPt;
2392    SkPoint             fCurrPt;
2393    // fLastVec does not necessarily start at fLastPt. We only advance it when the cross product
2394    // value with the current vec is deemed to be of a significant value.
2395    SkVector            fLastVec, fFirstVec;
2396    int                 fPtCount;   // non-degenerate points
2397    DirChange           fExpectedDir;
2398    SkPath::Convexity   fConvexity;
2399    SkPathPriv::FirstDirection   fFirstDirection;
2400    int                 fDx, fDy, fSx, fSy;
2401    bool                fIsFinite;
2402    bool                fIsCurve;
2403};
2404
2405SkPath::Convexity SkPath::internalGetConvexity() const {
2406    SkASSERT(kUnknown_Convexity == fConvexity);
2407    SkPoint         pts[4];
2408    SkPath::Verb    verb;
2409    SkPath::Iter    iter(*this, true);
2410
2411    int             contourCount = 0;
2412    int             count;
2413    Convexicator    state;
2414
2415    if (!isFinite()) {
2416        return kUnknown_Convexity;
2417    }
2418    while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) {
2419        switch (verb) {
2420            case kMove_Verb:
2421                if (++contourCount > 1) {
2422                    fConvexity = kConcave_Convexity;
2423                    return kConcave_Convexity;
2424                }
2425                pts[1] = pts[0];
2426                // fall through
2427            case kLine_Verb:
2428                count = 1;
2429                state.setCurve(false);
2430                break;
2431            case kQuad_Verb:
2432                // fall through
2433            case kConic_Verb:
2434                // fall through
2435            case kCubic_Verb:
2436                count = 2 + (kCubic_Verb == verb);
2437                // As an additional enhancement, this could set curve true only
2438                // if the curve is nonlinear
2439                state.setCurve(true);
2440                break;
2441            case kClose_Verb:
2442                state.setCurve(false);
2443                state.close();
2444                count = 0;
2445                break;
2446            default:
2447                SkDEBUGFAIL("bad verb");
2448                fConvexity = kConcave_Convexity;
2449                return kConcave_Convexity;
2450        }
2451
2452        for (int i = 1; i <= count; i++) {
2453            state.addPt(pts[i]);
2454        }
2455        // early exit
2456        if (!state.isFinite()) {
2457            return kUnknown_Convexity;
2458        }
2459        if (kConcave_Convexity == state.getConvexity()) {
2460            fConvexity = kConcave_Convexity;
2461            return kConcave_Convexity;
2462        }
2463    }
2464    fConvexity = state.getConvexity();
2465    if (kConvex_Convexity == fConvexity && SkPathPriv::kUnknown_FirstDirection == fFirstDirection) {
2466        fFirstDirection = state.getFirstDirection();
2467    }
2468    return static_cast<Convexity>(fConvexity);
2469}
2470
2471///////////////////////////////////////////////////////////////////////////////
2472
2473class ContourIter {
2474public:
2475    ContourIter(const SkPathRef& pathRef);
2476
2477    bool done() const { return fDone; }
2478    // if !done() then these may be called
2479    int count() const { return fCurrPtCount; }
2480    const SkPoint* pts() const { return fCurrPt; }
2481    void next();
2482
2483private:
2484    int fCurrPtCount;
2485    const SkPoint* fCurrPt;
2486    const uint8_t* fCurrVerb;
2487    const uint8_t* fStopVerbs;
2488    const SkScalar* fCurrConicWeight;
2489    bool fDone;
2490    SkDEBUGCODE(int fContourCounter;)
2491};
2492
2493ContourIter::ContourIter(const SkPathRef& pathRef) {
2494    fStopVerbs = pathRef.verbsMemBegin();
2495    fDone = false;
2496    fCurrPt = pathRef.points();
2497    fCurrVerb = pathRef.verbs();
2498    fCurrConicWeight = pathRef.conicWeights();
2499    fCurrPtCount = 0;
2500    SkDEBUGCODE(fContourCounter = 0;)
2501    this->next();
2502}
2503
2504void ContourIter::next() {
2505    if (fCurrVerb <= fStopVerbs) {
2506        fDone = true;
2507    }
2508    if (fDone) {
2509        return;
2510    }
2511
2512    // skip pts of prev contour
2513    fCurrPt += fCurrPtCount;
2514
2515    SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
2516    int ptCount = 1;    // moveTo
2517    const uint8_t* verbs = fCurrVerb;
2518
2519    for (--verbs; verbs > fStopVerbs; --verbs) {
2520        switch (verbs[~0]) {
2521            case SkPath::kMove_Verb:
2522                goto CONTOUR_END;
2523            case SkPath::kLine_Verb:
2524                ptCount += 1;
2525                break;
2526            case SkPath::kConic_Verb:
2527                fCurrConicWeight += 1;
2528                // fall-through
2529            case SkPath::kQuad_Verb:
2530                ptCount += 2;
2531                break;
2532            case SkPath::kCubic_Verb:
2533                ptCount += 3;
2534                break;
2535            case SkPath::kClose_Verb:
2536                break;
2537            default:
2538                SkDEBUGFAIL("unexpected verb");
2539                break;
2540        }
2541    }
2542CONTOUR_END:
2543    fCurrPtCount = ptCount;
2544    fCurrVerb = verbs;
2545    SkDEBUGCODE(++fContourCounter;)
2546}
2547
2548// returns cross product of (p1 - p0) and (p2 - p0)
2549static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
2550    SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
2551    // We may get 0 when the above subtracts underflow. We expect this to be
2552    // very rare and lazily promote to double.
2553    if (0 == cross) {
2554        double p0x = SkScalarToDouble(p0.fX);
2555        double p0y = SkScalarToDouble(p0.fY);
2556
2557        double p1x = SkScalarToDouble(p1.fX);
2558        double p1y = SkScalarToDouble(p1.fY);
2559
2560        double p2x = SkScalarToDouble(p2.fX);
2561        double p2y = SkScalarToDouble(p2.fY);
2562
2563        cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
2564                                 (p1y - p0y) * (p2x - p0x));
2565
2566    }
2567    return cross;
2568}
2569
2570// Returns the first pt with the maximum Y coordinate
2571static int find_max_y(const SkPoint pts[], int count) {
2572    SkASSERT(count > 0);
2573    SkScalar max = pts[0].fY;
2574    int firstIndex = 0;
2575    for (int i = 1; i < count; ++i) {
2576        SkScalar y = pts[i].fY;
2577        if (y > max) {
2578            max = y;
2579            firstIndex = i;
2580        }
2581    }
2582    return firstIndex;
2583}
2584
2585static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
2586    int i = index;
2587    for (;;) {
2588        i = (i + inc) % n;
2589        if (i == index) {   // we wrapped around, so abort
2590            break;
2591        }
2592        if (pts[index] != pts[i]) { // found a different point, success!
2593            break;
2594        }
2595    }
2596    return i;
2597}
2598
2599/**
2600 *  Starting at index, and moving forward (incrementing), find the xmin and
2601 *  xmax of the contiguous points that have the same Y.
2602 */
2603static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
2604                               int* maxIndexPtr) {
2605    const SkScalar y = pts[index].fY;
2606    SkScalar min = pts[index].fX;
2607    SkScalar max = min;
2608    int minIndex = index;
2609    int maxIndex = index;
2610    for (int i = index + 1; i < n; ++i) {
2611        if (pts[i].fY != y) {
2612            break;
2613        }
2614        SkScalar x = pts[i].fX;
2615        if (x < min) {
2616            min = x;
2617            minIndex = i;
2618        } else if (x > max) {
2619            max = x;
2620            maxIndex = i;
2621        }
2622    }
2623    *maxIndexPtr = maxIndex;
2624    return minIndex;
2625}
2626
2627static void crossToDir(SkScalar cross, SkPathPriv::FirstDirection* dir) {
2628    *dir = cross > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
2629}
2630
2631/*
2632 *  We loop through all contours, and keep the computed cross-product of the
2633 *  contour that contained the global y-max. If we just look at the first
2634 *  contour, we may find one that is wound the opposite way (correctly) since
2635 *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2636 *  that is outer most (or at least has the global y-max) before we can consider
2637 *  its cross product.
2638 */
2639bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* dir) {
2640    if (kUnknown_FirstDirection != path.fFirstDirection.load()) {
2641        *dir = static_cast<FirstDirection>(path.fFirstDirection.load());
2642        return true;
2643    }
2644
2645    // don't want to pay the cost for computing this if it
2646    // is unknown, so we don't call isConvex()
2647    if (SkPath::kConvex_Convexity == path.getConvexityOrUnknown()) {
2648        SkASSERT(kUnknown_FirstDirection == path.fFirstDirection);
2649        *dir = static_cast<FirstDirection>(path.fFirstDirection.load());
2650        return false;
2651    }
2652
2653    ContourIter iter(*path.fPathRef.get());
2654
2655    // initialize with our logical y-min
2656    SkScalar ymax = path.getBounds().fTop;
2657    SkScalar ymaxCross = 0;
2658
2659    for (; !iter.done(); iter.next()) {
2660        int n = iter.count();
2661        if (n < 3) {
2662            continue;
2663        }
2664
2665        const SkPoint* pts = iter.pts();
2666        SkScalar cross = 0;
2667        int index = find_max_y(pts, n);
2668        if (pts[index].fY < ymax) {
2669            continue;
2670        }
2671
2672        // If there is more than 1 distinct point at the y-max, we take the
2673        // x-min and x-max of them and just subtract to compute the dir.
2674        if (pts[(index + 1) % n].fY == pts[index].fY) {
2675            int maxIndex;
2676            int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2677            if (minIndex == maxIndex) {
2678                goto TRY_CROSSPROD;
2679            }
2680            SkASSERT(pts[minIndex].fY == pts[index].fY);
2681            SkASSERT(pts[maxIndex].fY == pts[index].fY);
2682            SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2683            // we just subtract the indices, and let that auto-convert to
2684            // SkScalar, since we just want - or + to signal the direction.
2685            cross = minIndex - maxIndex;
2686        } else {
2687            TRY_CROSSPROD:
2688            // Find a next and prev index to use for the cross-product test,
2689            // but we try to find pts that form non-zero vectors from pts[index]
2690            //
2691            // Its possible that we can't find two non-degenerate vectors, so
2692            // we have to guard our search (e.g. all the pts could be in the
2693            // same place).
2694
2695            // we pass n - 1 instead of -1 so we don't foul up % operator by
2696            // passing it a negative LH argument.
2697            int prev = find_diff_pt(pts, index, n, n - 1);
2698            if (prev == index) {
2699                // completely degenerate, skip to next contour
2700                continue;
2701            }
2702            int next = find_diff_pt(pts, index, n, 1);
2703            SkASSERT(next != index);
2704            cross = cross_prod(pts[prev], pts[index], pts[next]);
2705            // if we get a zero and the points are horizontal, then we look at the spread in
2706            // x-direction. We really should continue to walk away from the degeneracy until
2707            // there is a divergence.
2708            if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
2709                // construct the subtract so we get the correct Direction below
2710                cross = pts[index].fX - pts[next].fX;
2711            }
2712        }
2713
2714        if (cross) {
2715            // record our best guess so far
2716            ymax = pts[index].fY;
2717            ymaxCross = cross;
2718        }
2719    }
2720    if (ymaxCross) {
2721        crossToDir(ymaxCross, dir);
2722        path.fFirstDirection = *dir;
2723        return true;
2724    } else {
2725        return false;
2726    }
2727}
2728
2729///////////////////////////////////////////////////////////////////////////////
2730
2731static bool between(SkScalar a, SkScalar b, SkScalar c) {
2732    SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
2733            || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c)));
2734    return (a - b) * (c - b) <= 0;
2735}
2736
2737static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
2738                                 SkScalar D, SkScalar t) {
2739    return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
2740}
2741
2742static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
2743                               SkScalar t) {
2744    SkScalar A = c3 + 3*(c1 - c2) - c0;
2745    SkScalar B = 3*(c2 - c1 - c1 + c0);
2746    SkScalar C = 3*(c1 - c0);
2747    SkScalar D = c0;
2748    return eval_cubic_coeff(A, B, C, D, t);
2749}
2750
2751template <size_t N> static void find_minmax(const SkPoint pts[],
2752                                            SkScalar* minPtr, SkScalar* maxPtr) {
2753    SkScalar min, max;
2754    min = max = pts[0].fX;
2755    for (size_t i = 1; i < N; ++i) {
2756        min = SkMinScalar(min, pts[i].fX);
2757        max = SkMaxScalar(max, pts[i].fX);
2758    }
2759    *minPtr = min;
2760    *maxPtr = max;
2761}
2762
2763static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) {
2764    if (start.fY == end.fY) {
2765        return between(start.fX, x, end.fX) && x != end.fX;
2766    } else {
2767        return x == start.fX && y == start.fY;
2768    }
2769}
2770
2771static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2772    SkScalar y0 = pts[0].fY;
2773    SkScalar y3 = pts[3].fY;
2774
2775    int dir = 1;
2776    if (y0 > y3) {
2777        SkTSwap(y0, y3);
2778        dir = -1;
2779    }
2780    if (y < y0 || y > y3) {
2781        return 0;
2782    }
2783    if (checkOnCurve(x, y, pts[0], pts[3])) {
2784        *onCurveCount += 1;
2785        return 0;
2786    }
2787    if (y == y3) {
2788        return 0;
2789    }
2790
2791    // quickreject or quickaccept
2792    SkScalar min, max;
2793    find_minmax<4>(pts, &min, &max);
2794    if (x < min) {
2795        return 0;
2796    }
2797    if (x > max) {
2798        return dir;
2799    }
2800
2801    // compute the actual x(t) value
2802    SkScalar t;
2803    SkAssertResult(SkCubicClipper::ChopMonoAtY(pts, y, &t));
2804    SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
2805    if (SkScalarNearlyEqual(xt, x)) {
2806        if (x != pts[3].fX || y != pts[3].fY) {  // don't test end points; they're start points
2807            *onCurveCount += 1;
2808            return 0;
2809        }
2810    }
2811    return xt < x ? dir : 0;
2812}
2813
2814static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2815    SkPoint dst[10];
2816    int n = SkChopCubicAtYExtrema(pts, dst);
2817    int w = 0;
2818    for (int i = 0; i <= n; ++i) {
2819        w += winding_mono_cubic(&dst[i * 3], x, y, onCurveCount);
2820    }
2821    return w;
2822}
2823
2824static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) {
2825    SkASSERT(src);
2826    SkASSERT(t >= 0 && t <= 1);
2827    SkScalar src2w = src[2] * w;
2828    SkScalar C = src[0];
2829    SkScalar A = src[4] - 2 * src2w + C;
2830    SkScalar B = 2 * (src2w - C);
2831    return (A * t + B) * t + C;
2832}
2833
2834
2835static double conic_eval_denominator(SkScalar w, SkScalar t) {
2836    SkScalar B = 2 * (w - 1);
2837    SkScalar C = 1;
2838    SkScalar A = -B;
2839    return (A * t + B) * t + C;
2840}
2841
2842static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) {
2843    const SkPoint* pts = conic.fPts;
2844    SkScalar y0 = pts[0].fY;
2845    SkScalar y2 = pts[2].fY;
2846
2847    int dir = 1;
2848    if (y0 > y2) {
2849        SkTSwap(y0, y2);
2850        dir = -1;
2851    }
2852    if (y < y0 || y > y2) {
2853        return 0;
2854    }
2855    if (checkOnCurve(x, y, pts[0], pts[2])) {
2856        *onCurveCount += 1;
2857        return 0;
2858    }
2859    if (y == y2) {
2860        return 0;
2861    }
2862
2863    SkScalar roots[2];
2864    SkScalar A = pts[2].fY;
2865    SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y;
2866    SkScalar C = pts[0].fY;
2867    A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
2868    B -= C;  // B = b*w - w * yCept + yCept - a
2869    C -= y;
2870    int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
2871    SkASSERT(n <= 1);
2872    SkScalar xt;
2873    if (0 == n) {
2874        // zero roots are returned only when y0 == y
2875        // Need [0] if dir == 1
2876        // and  [2] if dir == -1
2877        xt = pts[1 - dir].fX;
2878    } else {
2879        SkScalar t = roots[0];
2880        xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t);
2881    }
2882    if (SkScalarNearlyEqual(xt, x)) {
2883        if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
2884            *onCurveCount += 1;
2885            return 0;
2886        }
2887    }
2888    return xt < x ? dir : 0;
2889}
2890
2891static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) {
2892    //    return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0;
2893    if (y0 == y1) {
2894        return true;
2895    }
2896    if (y0 < y1) {
2897        return y1 <= y2;
2898    } else {
2899        return y1 >= y2;
2900    }
2901}
2902
2903static int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight,
2904                         int* onCurveCount) {
2905    SkConic conic(pts, weight);
2906    SkConic chopped[2];
2907    // If the data points are very large, the conic may not be monotonic but may also
2908    // fail to chop. Then, the chopper does not split the original conic in two.
2909    bool isMono = is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped);
2910    int w = winding_mono_conic(isMono ? conic : chopped[0], x, y, onCurveCount);
2911    if (!isMono) {
2912        w += winding_mono_conic(chopped[1], x, y, onCurveCount);
2913    }
2914    return w;
2915}
2916
2917static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2918    SkScalar y0 = pts[0].fY;
2919    SkScalar y2 = pts[2].fY;
2920
2921    int dir = 1;
2922    if (y0 > y2) {
2923        SkTSwap(y0, y2);
2924        dir = -1;
2925    }
2926    if (y < y0 || y > y2) {
2927        return 0;
2928    }
2929    if (checkOnCurve(x, y, pts[0], pts[2])) {
2930        *onCurveCount += 1;
2931        return 0;
2932    }
2933    if (y == y2) {
2934        return 0;
2935    }
2936    // bounds check on X (not required. is it faster?)
2937#if 0
2938    if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) {
2939        return 0;
2940    }
2941#endif
2942
2943    SkScalar roots[2];
2944    int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
2945                                2 * (pts[1].fY - pts[0].fY),
2946                                pts[0].fY - y,
2947                                roots);
2948    SkASSERT(n <= 1);
2949    SkScalar xt;
2950    if (0 == n) {
2951        // zero roots are returned only when y0 == y
2952        // Need [0] if dir == 1
2953        // and  [2] if dir == -1
2954        xt = pts[1 - dir].fX;
2955    } else {
2956        SkScalar t = roots[0];
2957        SkScalar C = pts[0].fX;
2958        SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
2959        SkScalar B = 2 * (pts[1].fX - C);
2960        xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
2961    }
2962    if (SkScalarNearlyEqual(xt, x)) {
2963        if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
2964            *onCurveCount += 1;
2965            return 0;
2966        }
2967    }
2968    return xt < x ? dir : 0;
2969}
2970
2971static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2972    SkPoint dst[5];
2973    int     n = 0;
2974
2975    if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) {
2976        n = SkChopQuadAtYExtrema(pts, dst);
2977        pts = dst;
2978    }
2979    int w = winding_mono_quad(pts, x, y, onCurveCount);
2980    if (n > 0) {
2981        w += winding_mono_quad(&pts[2], x, y, onCurveCount);
2982    }
2983    return w;
2984}
2985
2986static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2987    SkScalar x0 = pts[0].fX;
2988    SkScalar y0 = pts[0].fY;
2989    SkScalar x1 = pts[1].fX;
2990    SkScalar y1 = pts[1].fY;
2991
2992    SkScalar dy = y1 - y0;
2993
2994    int dir = 1;
2995    if (y0 > y1) {
2996        SkTSwap(y0, y1);
2997        dir = -1;
2998    }
2999    if (y < y0 || y > y1) {
3000        return 0;
3001    }
3002    if (checkOnCurve(x, y, pts[0], pts[1])) {
3003        *onCurveCount += 1;
3004        return 0;
3005    }
3006    if (y == y1) {
3007        return 0;
3008    }
3009    SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x0);
3010
3011    if (!cross) {
3012        // zero cross means the point is on the line, and since the case where
3013        // y of the query point is at the end point is handled above, we can be
3014        // sure that we're on the line (excluding the end point) here
3015        if (x != x1 || y != pts[1].fY) {
3016            *onCurveCount += 1;
3017        }
3018        dir = 0;
3019    } else if (SkScalarSignAsInt(cross) == dir) {
3020        dir = 0;
3021    }
3022    return dir;
3023}
3024
3025static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y,
3026        SkTDArray<SkVector>* tangents) {
3027    if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)
3028             && !between(pts[2].fY, y, pts[3].fY)) {
3029        return;
3030    }
3031    if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)
3032             && !between(pts[2].fX, x, pts[3].fX)) {
3033        return;
3034    }
3035    SkPoint dst[10];
3036    int n = SkChopCubicAtYExtrema(pts, dst);
3037    for (int i = 0; i <= n; ++i) {
3038        SkPoint* c = &dst[i * 3];
3039        SkScalar t;
3040        SkAssertResult(SkCubicClipper::ChopMonoAtY(c, y, &t));
3041        SkScalar xt = eval_cubic_pts(c[0].fX, c[1].fX, c[2].fX, c[3].fX, t);
3042        if (!SkScalarNearlyEqual(x, xt)) {
3043            continue;
3044        }
3045        SkVector tangent;
3046        SkEvalCubicAt(c, t, nullptr, &tangent, nullptr);
3047        tangents->push(tangent);
3048    }
3049}
3050
3051static void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w,
3052            SkTDArray<SkVector>* tangents) {
3053    if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
3054        return;
3055    }
3056    if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
3057        return;
3058    }
3059    SkScalar roots[2];
3060    SkScalar A = pts[2].fY;
3061    SkScalar B = pts[1].fY * w - y * w + y;
3062    SkScalar C = pts[0].fY;
3063    A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
3064    B -= C;  // B = b*w - w * yCept + yCept - a
3065    C -= y;
3066    int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
3067    for (int index = 0; index < n; ++index) {
3068        SkScalar t = roots[index];
3069        SkScalar xt = conic_eval_numerator(&pts[0].fX, w, t) / conic_eval_denominator(w, t);
3070        if (!SkScalarNearlyEqual(x, xt)) {
3071            continue;
3072        }
3073        SkConic conic(pts, w);
3074        tangents->push(conic.evalTangentAt(t));
3075    }
3076}
3077
3078static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y,
3079        SkTDArray<SkVector>* tangents) {
3080    if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
3081        return;
3082    }
3083    if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
3084        return;
3085    }
3086    SkScalar roots[2];
3087    int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
3088                                2 * (pts[1].fY - pts[0].fY),
3089                                pts[0].fY - y,
3090                                roots);
3091    for (int index = 0; index < n; ++index) {
3092        SkScalar t = roots[index];
3093        SkScalar C = pts[0].fX;
3094        SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
3095        SkScalar B = 2 * (pts[1].fX - C);
3096        SkScalar xt = (A * t + B) * t + C;
3097        if (!SkScalarNearlyEqual(x, xt)) {
3098            continue;
3099        }
3100        tangents->push(SkEvalQuadTangentAt(pts, t));
3101    }
3102}
3103
3104static void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y,
3105        SkTDArray<SkVector>* tangents) {
3106    SkScalar y0 = pts[0].fY;
3107    SkScalar y1 = pts[1].fY;
3108    if (!between(y0, y, y1)) {
3109        return;
3110    }
3111    SkScalar x0 = pts[0].fX;
3112    SkScalar x1 = pts[1].fX;
3113    if (!between(x0, x, x1)) {
3114        return;
3115    }
3116    SkScalar dx = x1 - x0;
3117    SkScalar dy = y1 - y0;
3118    if (!SkScalarNearlyEqual((x - x0) * dy, dx * (y - y0))) {
3119        return;
3120    }
3121    SkVector v;
3122    v.set(dx, dy);
3123    tangents->push(v);
3124}
3125
3126static bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) {
3127    return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom;
3128}
3129
3130bool SkPath::contains(SkScalar x, SkScalar y) const {
3131    bool isInverse = this->isInverseFillType();
3132    if (this->isEmpty()) {
3133        return isInverse;
3134    }
3135
3136    if (!contains_inclusive(this->getBounds(), x, y)) {
3137        return isInverse;
3138    }
3139
3140    SkPath::Iter iter(*this, true);
3141    bool done = false;
3142    int w = 0;
3143    int onCurveCount = 0;
3144    do {
3145        SkPoint pts[4];
3146        switch (iter.next(pts, false)) {
3147            case SkPath::kMove_Verb:
3148            case SkPath::kClose_Verb:
3149                break;
3150            case SkPath::kLine_Verb:
3151                w += winding_line(pts, x, y, &onCurveCount);
3152                break;
3153            case SkPath::kQuad_Verb:
3154                w += winding_quad(pts, x, y, &onCurveCount);
3155                break;
3156            case SkPath::kConic_Verb:
3157                w += winding_conic(pts, x, y, iter.conicWeight(), &onCurveCount);
3158                break;
3159            case SkPath::kCubic_Verb:
3160                w += winding_cubic(pts, x, y, &onCurveCount);
3161                break;
3162            case SkPath::kDone_Verb:
3163                done = true;
3164                break;
3165       }
3166    } while (!done);
3167    bool evenOddFill = SkPath::kEvenOdd_FillType == this->getFillType()
3168            || SkPath::kInverseEvenOdd_FillType == this->getFillType();
3169    if (evenOddFill) {
3170        w &= 1;
3171    }
3172    if (w) {
3173        return !isInverse;
3174    }
3175    if (onCurveCount <= 1) {
3176        return SkToBool(onCurveCount) ^ isInverse;
3177    }
3178    if ((onCurveCount & 1) || evenOddFill) {
3179        return SkToBool(onCurveCount & 1) ^ isInverse;
3180    }
3181    // If the point touches an even number of curves, and the fill is winding, check for
3182    // coincidence. Count coincidence as places where the on curve points have identical tangents.
3183    iter.setPath(*this, true);
3184    done = false;
3185    SkTDArray<SkVector> tangents;
3186    do {
3187        SkPoint pts[4];
3188        int oldCount = tangents.count();
3189        switch (iter.next(pts, false)) {
3190            case SkPath::kMove_Verb:
3191            case SkPath::kClose_Verb:
3192                break;
3193            case SkPath::kLine_Verb:
3194                tangent_line(pts, x, y, &tangents);
3195                break;
3196            case SkPath::kQuad_Verb:
3197                tangent_quad(pts, x, y, &tangents);
3198                break;
3199            case SkPath::kConic_Verb:
3200                tangent_conic(pts, x, y, iter.conicWeight(), &tangents);
3201                break;
3202            case SkPath::kCubic_Verb:
3203                tangent_cubic(pts, x, y, &tangents);
3204                break;
3205            case SkPath::kDone_Verb:
3206                done = true;
3207                break;
3208       }
3209       if (tangents.count() > oldCount) {
3210            int last = tangents.count() - 1;
3211            const SkVector& tangent = tangents[last];
3212            if (SkScalarNearlyZero(tangent.lengthSqd())) {
3213                tangents.remove(last);
3214            } else {
3215                for (int index = 0; index < last; ++index) {
3216                    const SkVector& test = tangents[index];
3217                    if (SkScalarNearlyZero(test.cross(tangent))
3218                            && SkScalarSignAsInt(tangent.fX * test.fX) <= 0
3219                            && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) {
3220                        tangents.remove(last);
3221                        tangents.removeShuffle(index);
3222                        break;
3223                    }
3224                }
3225            }
3226        }
3227    } while (!done);
3228    return SkToBool(tangents.count()) ^ isInverse;
3229}
3230
3231int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3232                                SkScalar w, SkPoint pts[], int pow2) {
3233    const SkConic conic(p0, p1, p2, w);
3234    return conic.chopIntoQuadsPOW2(pts, pow2);
3235}
3236