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