1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkPath.h"
11#include "SkReader32.h"
12#include "SkWriter32.h"
13#include "SkMath.h"
14
15////////////////////////////////////////////////////////////////////////////
16
17/**
18 *  Path.bounds is defined to be the bounds of all the control points.
19 *  If we called bounds.join(r) we would skip r if r was empty, which breaks
20 *  our promise. Hence we have a custom joiner that doesn't look at emptiness
21 */
22static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
23    dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
24    dst->fTop = SkMinScalar(dst->fTop, src.fTop);
25    dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
26    dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
27}
28
29static bool is_degenerate(const SkPath& path) {
30    SkPath::Iter iter(path, false);
31    SkPoint pts[4];
32    return SkPath::kDone_Verb == iter.next(pts);
33}
34
35/*  This guy's constructor/destructor bracket a path editing operation. It is
36    used when we know the bounds of the amount we are going to add to the path
37    (usually a new contour, but not required).
38
39    It captures some state about the path up front (i.e. if it already has a
40    cached bounds), and the if it can, it updates the cache bounds explicitly,
41    avoiding the need to revisit all of the points in getBounds().
42
43    It also notes if the path was originally degenerate, and if so, sets
44    isConvex to true. Thus it can only be used if the contour being added is
45    convex.
46 */
47class SkAutoPathBoundsUpdate {
48public:
49    SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
50        this->init(path);
51    }
52
53    SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
54                           SkScalar right, SkScalar bottom) {
55        fRect.set(left, top, right, bottom);
56        this->init(path);
57    }
58
59    ~SkAutoPathBoundsUpdate() {
60        fPath->setIsConvex(fDegenerate);
61        if (fEmpty) {
62            fPath->fBounds = fRect;
63            fPath->fBoundsIsDirty = false;
64        } else if (!fDirty) {
65            joinNoEmptyChecks(&fPath->fBounds, fRect);
66            fPath->fBoundsIsDirty = false;
67        }
68    }
69
70private:
71    SkPath* fPath;
72    SkRect  fRect;
73    bool    fDirty;
74    bool    fDegenerate;
75    bool    fEmpty;
76
77    // returns true if we should proceed
78    void init(SkPath* path) {
79        fPath = path;
80        fDirty = SkToBool(path->fBoundsIsDirty);
81        fDegenerate = is_degenerate(*path);
82        fEmpty = path->isEmpty();
83        // Cannot use fRect for our bounds unless we know it is sorted
84        fRect.sort();
85    }
86};
87
88static void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
89    if (pts.count() <= 1) {  // we ignore just 1 point (moveto)
90        bounds->set(0, 0, 0, 0);
91    } else {
92        bounds->set(pts.begin(), pts.count());
93//        SkDebugf("------- compute bounds %p %d", &pts, pts.count());
94    }
95}
96
97////////////////////////////////////////////////////////////////////////////
98
99/*
100    Stores the verbs and points as they are given to us, with exceptions:
101    - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic
102    - we insert a Move(0,0) if Line | Quad | Cubic is our first command
103
104    The iterator does more cleanup, especially if forceClose == true
105    1. If we encounter degenerate segments, remove them
106    2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
107    3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
108    4. if we encounter Line | Quad | Cubic after Close, cons up a Move
109*/
110
111////////////////////////////////////////////////////////////////////////////
112
113// flag to require a moveTo if we begin with something else, like lineTo etc.
114#define INITIAL_LASTMOVETOINDEX_VALUE   ~0
115
116SkPath::SkPath()
117    : fFillType(kWinding_FillType)
118    , fBoundsIsDirty(true) {
119    fConvexity = kUnknown_Convexity;
120    fSegmentMask = 0;
121    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
122#ifdef SK_BUILD_FOR_ANDROID
123    fGenerationID = 0;
124    fSourcePath = NULL;
125#endif
126}
127
128SkPath::SkPath(const SkPath& src) {
129    SkDEBUGCODE(src.validate();)
130    *this = src;
131#ifdef SK_BUILD_FOR_ANDROID
132    // the assignment operator above increments the ID so correct for that here
133    fGenerationID = src.fGenerationID;
134    fSourcePath = NULL;
135#endif
136}
137
138SkPath::~SkPath() {
139    SkDEBUGCODE(this->validate();)
140}
141
142SkPath& SkPath::operator=(const SkPath& src) {
143    SkDEBUGCODE(src.validate();)
144
145    if (this != &src) {
146        fBounds         = src.fBounds;
147        fPts            = src.fPts;
148        fVerbs          = src.fVerbs;
149        fFillType       = src.fFillType;
150        fBoundsIsDirty  = src.fBoundsIsDirty;
151        fConvexity      = src.fConvexity;
152        fSegmentMask    = src.fSegmentMask;
153        fLastMoveToIndex = src.fLastMoveToIndex;
154        GEN_ID_INC;
155    }
156    SkDEBUGCODE(this->validate();)
157    return *this;
158}
159
160bool operator==(const SkPath& a, const SkPath& b) {
161    // note: don't need to look at isConvex or bounds, since just comparing the
162    // raw data is sufficient.
163
164    // We explicitly check fSegmentMask as a quick-reject. We could skip it,
165    // since it is only a cache of info in the fVerbs, but its a fast way to
166    // notice a difference
167
168    return &a == &b ||
169        (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
170         a.fVerbs == b.fVerbs && a.fPts == b.fPts);
171}
172
173void SkPath::swap(SkPath& other) {
174    SkASSERT(&other != NULL);
175
176    if (this != &other) {
177        SkTSwap<SkRect>(fBounds, other.fBounds);
178        fPts.swap(other.fPts);
179        fVerbs.swap(other.fVerbs);
180        SkTSwap<uint8_t>(fFillType, other.fFillType);
181        SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
182        SkTSwap<uint8_t>(fConvexity, other.fConvexity);
183        SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
184        SkTSwap<int>(fLastMoveToIndex, other.fLastMoveToIndex);
185        GEN_ID_INC;
186    }
187}
188
189#ifdef SK_BUILD_FOR_ANDROID
190uint32_t SkPath::getGenerationID() const {
191    return fGenerationID;
192}
193
194const SkPath* SkPath::getSourcePath() const {
195    return fSourcePath;
196}
197
198void SkPath::setSourcePath(const SkPath* path) {
199    fSourcePath = path;
200}
201#endif
202
203void SkPath::reset() {
204    SkDEBUGCODE(this->validate();)
205
206    fPts.reset();
207    fVerbs.reset();
208    GEN_ID_INC;
209    fBoundsIsDirty = true;
210    fConvexity = kUnknown_Convexity;
211    fSegmentMask = 0;
212    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
213}
214
215void SkPath::rewind() {
216    SkDEBUGCODE(this->validate();)
217
218    fPts.rewind();
219    fVerbs.rewind();
220    GEN_ID_INC;
221    fConvexity = kUnknown_Convexity;
222    fBoundsIsDirty = true;
223    fSegmentMask = 0;
224    fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
225}
226
227bool SkPath::isEmpty() const {
228    SkDEBUGCODE(this->validate();)
229    return 0 == fVerbs.count();
230}
231
232/*
233 Determines if path is a rect by keeping track of changes in direction
234 and looking for a loop either clockwise or counterclockwise.
235
236 The direction is computed such that:
237  0: vertical up
238  1: horizontal right
239  2: vertical down
240  3: horizontal left
241
242A rectangle cycles up/right/down/left or up/left/down/right.
243
244The test fails if:
245  The path is closed, and followed by a line.
246  A second move creates a new endpoint.
247  A diagonal line is parsed.
248  There's more than four changes of direction.
249  There's a discontinuity on the line (e.g., a move in the middle)
250  The line reverses direction.
251  The rectangle doesn't complete a cycle.
252  The path contains a quadratic or cubic.
253  The path contains fewer than four points.
254  The final point isn't equal to the first point.
255
256It's OK if the path has:
257  Several colinear line segments composing a rectangle side.
258  Single points on the rectangle side.
259
260The direction takes advantage of the corners found since opposite sides
261must travel in opposite directions.
262
263FIXME: Allow colinear quads and cubics to be treated like lines.
264FIXME: If the API passes fill-only, return true if the filled stroke
265       is a rectangle, though the caller failed to close the path.
266 */
267bool SkPath::isRect(SkRect* rect) const {
268    SkDEBUGCODE(this->validate();)
269
270    int corners = 0;
271    SkPoint first, last;
272    first.set(0, 0);
273    last.set(0, 0);
274    int firstDirection = 0;
275    int lastDirection = 0;
276    int nextDirection = 0;
277    bool closedOrMoved = false;
278    bool autoClose = false;
279    const uint8_t* verbs = fVerbs.begin();
280    const uint8_t* verbStop = fVerbs.end();
281    const SkPoint* pts = fPts.begin();
282    while (verbs != verbStop) {
283        switch (*verbs++) {
284            case kClose_Verb:
285                pts = fPts.begin();
286                autoClose = true;
287            case kLine_Verb: {
288                SkScalar left = last.fX;
289                SkScalar top = last.fY;
290                SkScalar right = pts->fX;
291                SkScalar bottom = pts->fY;
292                ++pts;
293                if (left != right && top != bottom) {
294                    return false; // diagonal
295                }
296                if (left == right && top == bottom) {
297                    break; // single point on side OK
298                }
299                nextDirection = (left != right) << 0 |
300                    (left < right || top < bottom) << 1;
301                if (0 == corners) {
302                    firstDirection = nextDirection;
303                    first = last;
304                    last = pts[-1];
305                    corners = 1;
306                    closedOrMoved = false;
307                    break;
308                }
309                if (closedOrMoved) {
310                    return false; // closed followed by a line
311                }
312                closedOrMoved = autoClose;
313                if (lastDirection != nextDirection) {
314                    if (++corners > 4) {
315                        return false; // too many direction changes
316                    }
317                }
318                last = pts[-1];
319                if (lastDirection == nextDirection) {
320                    break; // colinear segment
321                }
322                // Possible values for corners are 2, 3, and 4.
323                // When corners == 3, nextDirection opposes firstDirection.
324                // Otherwise, nextDirection at corner 2 opposes corner 4.
325                int turn = firstDirection ^ (corners - 1);
326                int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
327                if ((directionCycle ^ turn) != nextDirection) {
328                    return false; // direction didn't follow cycle
329                }
330                break;
331            }
332            case kQuad_Verb:
333            case kCubic_Verb:
334                return false; // quadratic, cubic not allowed
335            case kMove_Verb:
336                last = *pts++;
337                closedOrMoved = true;
338                break;
339        }
340        lastDirection = nextDirection;
341    }
342    // Success if 4 corners and first point equals last
343    bool result = 4 == corners && first == last;
344    if (result && rect) {
345        *rect = getBounds();
346    }
347    return result;
348}
349
350int SkPath::getPoints(SkPoint copy[], int max) const {
351    SkDEBUGCODE(this->validate();)
352
353    SkASSERT(max >= 0);
354    int count = fPts.count();
355    if (copy && max > 0 && count > 0) {
356        memcpy(copy, fPts.begin(), sizeof(SkPoint) * SkMin32(max, count));
357    }
358    return count;
359}
360
361SkPoint SkPath::getPoint(int index) const {
362    if ((unsigned)index < (unsigned)fPts.count()) {
363        return fPts[index];
364    }
365    return SkPoint::Make(0, 0);
366}
367
368bool SkPath::getLastPt(SkPoint* lastPt) const {
369    SkDEBUGCODE(this->validate();)
370
371    int count = fPts.count();
372    if (count > 0) {
373        if (lastPt) {
374            *lastPt = fPts[count - 1];
375        }
376        return true;
377    }
378    if (lastPt) {
379        lastPt->set(0, 0);
380    }
381    return false;
382}
383
384void SkPath::setLastPt(SkScalar x, SkScalar y) {
385    SkDEBUGCODE(this->validate();)
386
387    int count = fPts.count();
388    if (count == 0) {
389        this->moveTo(x, y);
390    } else {
391        fPts[count - 1].set(x, y);
392        GEN_ID_INC;
393    }
394}
395
396void SkPath::computeBounds() const {
397    SkDEBUGCODE(this->validate();)
398    SkASSERT(fBoundsIsDirty);
399
400    fBoundsIsDirty = false;
401    compute_pt_bounds(&fBounds, fPts);
402}
403
404void SkPath::setConvexity(Convexity c) {
405    if (fConvexity != c) {
406        fConvexity = c;
407        GEN_ID_INC;
408    }
409}
410
411//////////////////////////////////////////////////////////////////////////////
412//  Construction methods
413
414#define DIRTY_AFTER_EDIT                 \
415    do {                                 \
416        fBoundsIsDirty = true;           \
417        fConvexity = kUnknown_Convexity; \
418    } while (0)
419
420#define DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE    \
421    do {                                        \
422        fBoundsIsDirty = true;                  \
423    } while (0)
424
425void SkPath::incReserve(U16CPU inc) {
426    SkDEBUGCODE(this->validate();)
427
428    fVerbs.setReserve(fVerbs.count() + inc);
429    fPts.setReserve(fPts.count() + inc);
430
431    SkDEBUGCODE(this->validate();)
432}
433
434void SkPath::moveTo(SkScalar x, SkScalar y) {
435    SkDEBUGCODE(this->validate();)
436
437    int      vc = fVerbs.count();
438    SkPoint* pt;
439
440    // remember our index
441    fLastMoveToIndex = fPts.count();
442
443    pt = fPts.append();
444    *fVerbs.append() = kMove_Verb;
445    pt->set(x, y);
446
447    GEN_ID_INC;
448    DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE;
449}
450
451void SkPath::rMoveTo(SkScalar x, SkScalar y) {
452    SkPoint pt;
453    this->getLastPt(&pt);
454    this->moveTo(pt.fX + x, pt.fY + y);
455}
456
457void SkPath::injectMoveToIfNeeded() {
458    if (fLastMoveToIndex < 0) {
459        SkScalar x, y;
460        if (fVerbs.count() == 0) {
461            x = y = 0;
462        } else {
463            const SkPoint& pt = fPts[~fLastMoveToIndex];
464            x = pt.fX;
465            y = pt.fY;
466        }
467        this->moveTo(x, y);
468    }
469}
470
471void SkPath::lineTo(SkScalar x, SkScalar y) {
472    SkDEBUGCODE(this->validate();)
473
474    this->injectMoveToIfNeeded();
475
476    fPts.append()->set(x, y);
477    *fVerbs.append() = kLine_Verb;
478    fSegmentMask |= kLine_SegmentMask;
479
480    GEN_ID_INC;
481    DIRTY_AFTER_EDIT;
482}
483
484void SkPath::rLineTo(SkScalar x, SkScalar y) {
485    SkPoint pt;
486    this->getLastPt(&pt);
487    this->lineTo(pt.fX + x, pt.fY + y);
488}
489
490void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
491    SkDEBUGCODE(this->validate();)
492
493    this->injectMoveToIfNeeded();
494
495    SkPoint* pts = fPts.append(2);
496    pts[0].set(x1, y1);
497    pts[1].set(x2, y2);
498    *fVerbs.append() = kQuad_Verb;
499    fSegmentMask |= kQuad_SegmentMask;
500
501    GEN_ID_INC;
502    DIRTY_AFTER_EDIT;
503}
504
505void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
506    SkPoint pt;
507    this->getLastPt(&pt);
508    this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
509}
510
511void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
512                     SkScalar x3, SkScalar y3) {
513    SkDEBUGCODE(this->validate();)
514
515    this->injectMoveToIfNeeded();
516
517    SkPoint* pts = fPts.append(3);
518    pts[0].set(x1, y1);
519    pts[1].set(x2, y2);
520    pts[2].set(x3, y3);
521    *fVerbs.append() = kCubic_Verb;
522    fSegmentMask |= kCubic_SegmentMask;
523
524    GEN_ID_INC;
525    DIRTY_AFTER_EDIT;
526}
527
528void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
529                      SkScalar x3, SkScalar y3) {
530    SkPoint pt;
531    this->getLastPt(&pt);
532    this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
533                  pt.fX + x3, pt.fY + y3);
534}
535
536void SkPath::close() {
537    SkDEBUGCODE(this->validate();)
538
539    int count = fVerbs.count();
540    if (count > 0) {
541        switch (fVerbs[count - 1]) {
542            case kLine_Verb:
543            case kQuad_Verb:
544            case kCubic_Verb:
545            case kMove_Verb:
546                *fVerbs.append() = kClose_Verb;
547                GEN_ID_INC;
548                break;
549            default:
550                // don't add a close if it's the first verb or a repeat
551                break;
552        }
553    }
554
555    // signal that we need a moveTo to follow us (unless we're done)
556#if 0
557    if (fLastMoveToIndex >= 0) {
558        fLastMoveToIndex = ~fLastMoveToIndex;
559    }
560#else
561    fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
562#endif
563}
564
565///////////////////////////////////////////////////////////////////////////////
566
567void SkPath::addRect(const SkRect& rect, Direction dir) {
568    this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
569}
570
571void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
572                     SkScalar bottom, Direction dir) {
573    SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom);
574
575    this->incReserve(5);
576
577    this->moveTo(left, top);
578    if (dir == kCCW_Direction) {
579        this->lineTo(left, bottom);
580        this->lineTo(right, bottom);
581        this->lineTo(right, top);
582    } else {
583        this->lineTo(right, top);
584        this->lineTo(right, bottom);
585        this->lineTo(left, bottom);
586    }
587    this->close();
588}
589
590#define CUBIC_ARC_FACTOR    ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
591
592void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
593                          Direction dir) {
594    SkScalar    w = rect.width();
595    SkScalar    halfW = SkScalarHalf(w);
596    SkScalar    h = rect.height();
597    SkScalar    halfH = SkScalarHalf(h);
598
599    if (halfW <= 0 || halfH <= 0) {
600        return;
601    }
602
603    bool skip_hori = rx >= halfW;
604    bool skip_vert = ry >= halfH;
605
606    if (skip_hori && skip_vert) {
607        this->addOval(rect, dir);
608        return;
609    }
610
611    SkAutoPathBoundsUpdate apbu(this, rect);
612
613    if (skip_hori) {
614        rx = halfW;
615    } else if (skip_vert) {
616        ry = halfH;
617    }
618
619    SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
620    SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
621
622    this->incReserve(17);
623    this->moveTo(rect.fRight - rx, rect.fTop);
624    if (dir == kCCW_Direction) {
625        if (!skip_hori) {
626            this->lineTo(rect.fLeft + rx, rect.fTop);       // top
627        }
628        this->cubicTo(rect.fLeft + rx - sx, rect.fTop,
629                      rect.fLeft, rect.fTop + ry - sy,
630                      rect.fLeft, rect.fTop + ry);          // top-left
631        if (!skip_vert) {
632            this->lineTo(rect.fLeft, rect.fBottom - ry);        // left
633        }
634        this->cubicTo(rect.fLeft, rect.fBottom - ry + sy,
635                      rect.fLeft + rx - sx, rect.fBottom,
636                      rect.fLeft + rx, rect.fBottom);       // bot-left
637        if (!skip_hori) {
638            this->lineTo(rect.fRight - rx, rect.fBottom);   // bottom
639        }
640        this->cubicTo(rect.fRight - rx + sx, rect.fBottom,
641                      rect.fRight, rect.fBottom - ry + sy,
642                      rect.fRight, rect.fBottom - ry);      // bot-right
643        if (!skip_vert) {
644            this->lineTo(rect.fRight, rect.fTop + ry);
645        }
646        this->cubicTo(rect.fRight, rect.fTop + ry - sy,
647                      rect.fRight - rx + sx, rect.fTop,
648                      rect.fRight - rx, rect.fTop);         // top-right
649    } else {
650        this->cubicTo(rect.fRight - rx + sx, rect.fTop,
651                      rect.fRight, rect.fTop + ry - sy,
652                      rect.fRight, rect.fTop + ry);         // top-right
653        if (!skip_vert) {
654            this->lineTo(rect.fRight, rect.fBottom - ry);
655        }
656        this->cubicTo(rect.fRight, rect.fBottom - ry + sy,
657                      rect.fRight - rx + sx, rect.fBottom,
658                      rect.fRight - rx, rect.fBottom);      // bot-right
659        if (!skip_hori) {
660            this->lineTo(rect.fLeft + rx, rect.fBottom);    // bottom
661        }
662        this->cubicTo(rect.fLeft + rx - sx, rect.fBottom,
663                      rect.fLeft, rect.fBottom - ry + sy,
664                      rect.fLeft, rect.fBottom - ry);       // bot-left
665        if (!skip_vert) {
666            this->lineTo(rect.fLeft, rect.fTop + ry);       // left
667        }
668        this->cubicTo(rect.fLeft, rect.fTop + ry - sy,
669                      rect.fLeft + rx - sx, rect.fTop,
670                      rect.fLeft + rx, rect.fTop);          // top-left
671        if (!skip_hori) {
672            this->lineTo(rect.fRight - rx, rect.fTop);      // top
673        }
674    }
675    this->close();
676}
677
678static void add_corner_arc(SkPath* path, const SkRect& rect,
679                           SkScalar rx, SkScalar ry, int startAngle,
680                           SkPath::Direction dir, bool forceMoveTo) {
681    rx = SkMinScalar(SkScalarHalf(rect.width()), rx);
682    ry = SkMinScalar(SkScalarHalf(rect.height()), ry);
683
684    SkRect   r;
685    r.set(-rx, -ry, rx, ry);
686
687    switch (startAngle) {
688        case   0:
689            r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom);
690            break;
691        case  90:
692            r.offset(rect.fLeft - r.fLeft,   rect.fBottom - r.fBottom);
693            break;
694        case 180: r.offset(rect.fLeft - r.fLeft,   rect.fTop - r.fTop); break;
695        case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break;
696        default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc");
697    }
698
699    SkScalar start = SkIntToScalar(startAngle);
700    SkScalar sweep = SkIntToScalar(90);
701    if (SkPath::kCCW_Direction == dir) {
702        start += sweep;
703        sweep = -sweep;
704    }
705
706    path->arcTo(r, start, sweep, forceMoveTo);
707}
708
709void SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[],
710                          Direction dir) {
711    // abort before we invoke SkAutoPathBoundsUpdate()
712    if (rect.isEmpty()) {
713        return;
714    }
715
716    SkAutoPathBoundsUpdate apbu(this, rect);
717
718    if (kCW_Direction == dir) {
719        add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
720        add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
721        add_corner_arc(this, rect, rad[4], rad[5],   0, dir, false);
722        add_corner_arc(this, rect, rad[6], rad[7],  90, dir, false);
723    } else {
724        add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
725        add_corner_arc(this, rect, rad[6], rad[7],  90, dir, false);
726        add_corner_arc(this, rect, rad[4], rad[5],   0, dir, false);
727        add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
728    }
729    this->close();
730}
731
732void SkPath::addOval(const SkRect& oval, Direction dir) {
733    SkAutoPathBoundsUpdate apbu(this, oval);
734
735    SkScalar    cx = oval.centerX();
736    SkScalar    cy = oval.centerY();
737    SkScalar    rx = SkScalarHalf(oval.width());
738    SkScalar    ry = SkScalarHalf(oval.height());
739#if 0   // these seem faster than using quads (1/2 the number of edges)
740    SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
741    SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
742
743    this->incReserve(13);
744    this->moveTo(cx + rx, cy);
745    if (dir == kCCW_Direction) {
746        this->cubicTo(cx + rx, cy - sy, cx + sx, cy - ry, cx, cy - ry);
747        this->cubicTo(cx - sx, cy - ry, cx - rx, cy - sy, cx - rx, cy);
748        this->cubicTo(cx - rx, cy + sy, cx - sx, cy + ry, cx, cy + ry);
749        this->cubicTo(cx + sx, cy + ry, cx + rx, cy + sy, cx + rx, cy);
750    } else {
751        this->cubicTo(cx + rx, cy + sy, cx + sx, cy + ry, cx, cy + ry);
752        this->cubicTo(cx - sx, cy + ry, cx - rx, cy + sy, cx - rx, cy);
753        this->cubicTo(cx - rx, cy - sy, cx - sx, cy - ry, cx, cy - ry);
754        this->cubicTo(cx + sx, cy - ry, cx + rx, cy - sy, cx + rx, cy);
755    }
756#else
757    SkScalar    sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
758    SkScalar    sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
759    SkScalar    mx = SkScalarMul(rx, SK_ScalarRoot2Over2);
760    SkScalar    my = SkScalarMul(ry, SK_ScalarRoot2Over2);
761
762    /*
763        To handle imprecision in computing the center and radii, we revert to
764        the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx)
765        to ensure that we don't exceed the oval's bounds *ever*, since we want
766        to use oval for our fast-bounds, rather than have to recompute it.
767    */
768    const SkScalar L = oval.fLeft;      // cx - rx
769    const SkScalar T = oval.fTop;       // cy - ry
770    const SkScalar R = oval.fRight;     // cx + rx
771    const SkScalar B = oval.fBottom;    // cy + ry
772
773    this->incReserve(17);   // 8 quads + close
774    this->moveTo(R, cy);
775    if (dir == kCCW_Direction) {
776        this->quadTo(      R, cy - sy, cx + mx, cy - my);
777        this->quadTo(cx + sx,       T, cx     ,       T);
778        this->quadTo(cx - sx,       T, cx - mx, cy - my);
779        this->quadTo(      L, cy - sy,       L, cy     );
780        this->quadTo(      L, cy + sy, cx - mx, cy + my);
781        this->quadTo(cx - sx,       B, cx     ,       B);
782        this->quadTo(cx + sx,       B, cx + mx, cy + my);
783        this->quadTo(      R, cy + sy,       R, cy     );
784    } else {
785        this->quadTo(      R, cy + sy, cx + mx, cy + my);
786        this->quadTo(cx + sx,       B, cx     ,       B);
787        this->quadTo(cx - sx,       B, cx - mx, cy + my);
788        this->quadTo(      L, cy + sy,       L, cy     );
789        this->quadTo(      L, cy - sy, cx - mx, cy - my);
790        this->quadTo(cx - sx,       T, cx     ,       T);
791        this->quadTo(cx + sx,       T, cx + mx, cy - my);
792        this->quadTo(      R, cy - sy,       R, cy     );
793    }
794#endif
795    this->close();
796}
797
798void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
799    if (r > 0) {
800        SkRect  rect;
801        rect.set(x - r, y - r, x + r, y + r);
802        this->addOval(rect, dir);
803    }
804}
805
806#include "SkGeometry.h"
807
808static int build_arc_points(const SkRect& oval, SkScalar startAngle,
809                            SkScalar sweepAngle,
810                            SkPoint pts[kSkBuildQuadArcStorage]) {
811    SkVector start, stop;
812
813    start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX);
814    stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle),
815                             &stop.fX);
816
817    /*  If the sweep angle is nearly (but less than) 360, then due to precision
818        loss in radians-conversion and/or sin/cos, we may end up with coincident
819        vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead
820        of drawing a nearly complete circle (good).
821             e.g. canvas.drawArc(0, 359.99, ...)
822             -vs- canvas.drawArc(0, 359.9, ...)
823        We try to detect this edge case, and tweak the stop vector
824     */
825    if (start == stop) {
826        SkScalar sw = SkScalarAbs(sweepAngle);
827        if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
828            SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
829            // make a guess at a tiny angle (in radians) to tweak by
830            SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
831            // not sure how much will be enough, so we use a loop
832            do {
833                stopRad -= deltaRad;
834                stop.fY = SkScalarSinCos(stopRad, &stop.fX);
835            } while (start == stop);
836        }
837    }
838
839    SkMatrix    matrix;
840
841    matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
842    matrix.postTranslate(oval.centerX(), oval.centerY());
843
844    return SkBuildQuadArc(start, stop,
845          sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection,
846                          &matrix, pts);
847}
848
849void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
850                   bool forceMoveTo) {
851    if (oval.width() < 0 || oval.height() < 0) {
852        return;
853    }
854
855    SkPoint pts[kSkBuildQuadArcStorage];
856    int count = build_arc_points(oval, startAngle, sweepAngle, pts);
857    SkASSERT((count & 1) == 1);
858
859    if (fVerbs.count() == 0) {
860        forceMoveTo = true;
861    }
862    this->incReserve(count);
863    forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]);
864    for (int i = 1; i < count; i += 2) {
865        this->quadTo(pts[i], pts[i+1]);
866    }
867}
868
869void SkPath::addArc(const SkRect& oval, SkScalar startAngle,
870                    SkScalar sweepAngle) {
871    if (oval.isEmpty() || 0 == sweepAngle) {
872        return;
873    }
874
875    const SkScalar kFullCircleAngle = SkIntToScalar(360);
876
877    if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
878        this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction);
879        return;
880    }
881
882    SkPoint pts[kSkBuildQuadArcStorage];
883    int count = build_arc_points(oval, startAngle, sweepAngle, pts);
884
885    this->incReserve(count);
886    this->moveTo(pts[0]);
887    for (int i = 1; i < count; i += 2) {
888        this->quadTo(pts[i], pts[i+1]);
889    }
890}
891
892/*
893    Need to handle the case when the angle is sharp, and our computed end-points
894    for the arc go behind pt1 and/or p2...
895*/
896void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
897                   SkScalar radius) {
898    SkVector    before, after;
899
900    // need to know our prev pt so we can construct tangent vectors
901    {
902        SkPoint start;
903        this->getLastPt(&start);
904        // Handle degenerate cases by adding a line to the first point and
905        // bailing out.
906        if ((x1 == start.fX && y1 == start.fY) ||
907            (x1 == x2 && y1 == y2) ||
908            radius == 0) {
909            this->lineTo(x1, y1);
910            return;
911        }
912        before.setNormalize(x1 - start.fX, y1 - start.fY);
913        after.setNormalize(x2 - x1, y2 - y1);
914    }
915
916    SkScalar cosh = SkPoint::DotProduct(before, after);
917    SkScalar sinh = SkPoint::CrossProduct(before, after);
918
919    if (SkScalarNearlyZero(sinh)) {   // angle is too tight
920        this->lineTo(x1, y1);
921        return;
922    }
923
924    SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh);
925    if (dist < 0) {
926        dist = -dist;
927    }
928
929    SkScalar xx = x1 - SkScalarMul(dist, before.fX);
930    SkScalar yy = y1 - SkScalarMul(dist, before.fY);
931    SkRotationDirection arcDir;
932
933    // now turn before/after into normals
934    if (sinh > 0) {
935        before.rotateCCW();
936        after.rotateCCW();
937        arcDir = kCW_SkRotationDirection;
938    } else {
939        before.rotateCW();
940        after.rotateCW();
941        arcDir = kCCW_SkRotationDirection;
942    }
943
944    SkMatrix    matrix;
945    SkPoint     pts[kSkBuildQuadArcStorage];
946
947    matrix.setScale(radius, radius);
948    matrix.postTranslate(xx - SkScalarMul(radius, before.fX),
949                         yy - SkScalarMul(radius, before.fY));
950
951    int count = SkBuildQuadArc(before, after, arcDir, &matrix, pts);
952
953    this->incReserve(count);
954    // [xx,yy] == pts[0]
955    this->lineTo(xx, yy);
956    for (int i = 1; i < count; i += 2) {
957        this->quadTo(pts[i], pts[i+1]);
958    }
959}
960
961///////////////////////////////////////////////////////////////////////////////
962
963void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
964    SkMatrix matrix;
965
966    matrix.setTranslate(dx, dy);
967    this->addPath(path, matrix);
968}
969
970void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
971    this->incReserve(path.fPts.count());
972
973    RawIter iter(path);
974    SkPoint pts[4];
975    Verb    verb;
976
977    SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
978
979    while ((verb = iter.next(pts)) != kDone_Verb) {
980        switch (verb) {
981            case kMove_Verb:
982                proc(matrix, &pts[0], &pts[0], 1);
983                this->moveTo(pts[0]);
984                break;
985            case kLine_Verb:
986                proc(matrix, &pts[1], &pts[1], 1);
987                this->lineTo(pts[1]);
988                break;
989            case kQuad_Verb:
990                proc(matrix, &pts[1], &pts[1], 2);
991                this->quadTo(pts[1], pts[2]);
992                break;
993            case kCubic_Verb:
994                proc(matrix, &pts[1], &pts[1], 3);
995                this->cubicTo(pts[1], pts[2], pts[3]);
996                break;
997            case kClose_Verb:
998                this->close();
999                break;
1000            default:
1001                SkDEBUGFAIL("unknown verb");
1002        }
1003    }
1004}
1005
1006///////////////////////////////////////////////////////////////////////////////
1007
1008static const uint8_t gPtsInVerb[] = {
1009    1,  // kMove
1010    1,  // kLine
1011    2,  // kQuad
1012    3,  // kCubic
1013    0,  // kClose
1014    0   // kDone
1015};
1016
1017// ignore the initial moveto, and stop when the 1st contour ends
1018void SkPath::pathTo(const SkPath& path) {
1019    int i, vcount = path.fVerbs.count();
1020    if (vcount == 0) {
1021        return;
1022    }
1023
1024    this->incReserve(vcount);
1025
1026    const uint8_t*  verbs = path.fVerbs.begin();
1027    const SkPoint*  pts = path.fPts.begin() + 1;    // 1 for the initial moveTo
1028
1029    SkASSERT(verbs[0] == kMove_Verb);
1030    for (i = 1; i < vcount; i++) {
1031        switch (verbs[i]) {
1032            case kLine_Verb:
1033                this->lineTo(pts[0].fX, pts[0].fY);
1034                break;
1035            case kQuad_Verb:
1036                this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
1037                break;
1038            case kCubic_Verb:
1039                this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY,
1040                              pts[2].fX, pts[2].fY);
1041                break;
1042            case kClose_Verb:
1043                return;
1044        }
1045        pts += gPtsInVerb[verbs[i]];
1046    }
1047}
1048
1049// ignore the last point of the 1st contour
1050void SkPath::reversePathTo(const SkPath& path) {
1051    int i, vcount = path.fVerbs.count();
1052    if (vcount == 0) {
1053        return;
1054    }
1055
1056    this->incReserve(vcount);
1057
1058    const uint8_t*  verbs = path.fVerbs.begin();
1059    const SkPoint*  pts = path.fPts.begin();
1060
1061    SkASSERT(verbs[0] == kMove_Verb);
1062    for (i = 1; i < vcount; i++) {
1063        int n = gPtsInVerb[verbs[i]];
1064        if (n == 0) {
1065            break;
1066        }
1067        pts += n;
1068    }
1069
1070    while (--i > 0) {
1071        switch (verbs[i]) {
1072            case kLine_Verb:
1073                this->lineTo(pts[-1].fX, pts[-1].fY);
1074                break;
1075            case kQuad_Verb:
1076                this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
1077                break;
1078            case kCubic_Verb:
1079                this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY,
1080                              pts[-3].fX, pts[-3].fY);
1081                break;
1082            default:
1083                SkDEBUGFAIL("bad verb");
1084                break;
1085        }
1086        pts -= gPtsInVerb[verbs[i]];
1087    }
1088}
1089
1090void SkPath::reverseAddPath(const SkPath& src) {
1091    this->incReserve(src.fPts.count());
1092
1093    const SkPoint* startPts = src.fPts.begin();
1094    const SkPoint* pts = src.fPts.end();
1095    const uint8_t* startVerbs = src.fVerbs.begin();
1096    const uint8_t* verbs = src.fVerbs.end();
1097
1098    bool needMove = true;
1099    bool needClose = false;
1100    while (verbs > startVerbs) {
1101        uint8_t v = *--verbs;
1102        int n = gPtsInVerb[v];
1103
1104        if (needMove) {
1105            --pts;
1106            this->moveTo(pts->fX, pts->fY);
1107            needMove = false;
1108        }
1109        pts -= n;
1110        switch (v) {
1111            case kMove_Verb:
1112                if (needClose) {
1113                    this->close();
1114                    needClose = false;
1115                }
1116                needMove = true;
1117                pts += 1;   // so we see the point in "if (needMove)" above
1118                break;
1119            case kLine_Verb:
1120                this->lineTo(pts[0]);
1121                break;
1122            case kQuad_Verb:
1123                this->quadTo(pts[1], pts[0]);
1124                break;
1125            case kCubic_Verb:
1126                this->cubicTo(pts[2], pts[1], pts[0]);
1127                break;
1128            case kClose_Verb:
1129                needClose = true;
1130                break;
1131            default:
1132                SkASSERT(!"unexpected verb");
1133        }
1134    }
1135}
1136
1137///////////////////////////////////////////////////////////////////////////////
1138
1139void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
1140    SkMatrix    matrix;
1141
1142    matrix.setTranslate(dx, dy);
1143    this->transform(matrix, dst);
1144}
1145
1146#include "SkGeometry.h"
1147
1148static void subdivide_quad_to(SkPath* path, const SkPoint pts[3],
1149                              int level = 2) {
1150    if (--level >= 0) {
1151        SkPoint tmp[5];
1152
1153        SkChopQuadAtHalf(pts, tmp);
1154        subdivide_quad_to(path, &tmp[0], level);
1155        subdivide_quad_to(path, &tmp[2], level);
1156    } else {
1157        path->quadTo(pts[1], pts[2]);
1158    }
1159}
1160
1161static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
1162                               int level = 2) {
1163    if (--level >= 0) {
1164        SkPoint tmp[7];
1165
1166        SkChopCubicAtHalf(pts, tmp);
1167        subdivide_cubic_to(path, &tmp[0], level);
1168        subdivide_cubic_to(path, &tmp[3], level);
1169    } else {
1170        path->cubicTo(pts[1], pts[2], pts[3]);
1171    }
1172}
1173
1174void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
1175    SkDEBUGCODE(this->validate();)
1176    if (dst == NULL) {
1177        dst = (SkPath*)this;
1178    }
1179
1180    if (matrix.hasPerspective()) {
1181        SkPath  tmp;
1182        tmp.fFillType = fFillType;
1183
1184        SkPath::Iter    iter(*this, false);
1185        SkPoint         pts[4];
1186        SkPath::Verb    verb;
1187
1188        while ((verb = iter.next(pts)) != kDone_Verb) {
1189            switch (verb) {
1190                case kMove_Verb:
1191                    tmp.moveTo(pts[0]);
1192                    break;
1193                case kLine_Verb:
1194                    tmp.lineTo(pts[1]);
1195                    break;
1196                case kQuad_Verb:
1197                    subdivide_quad_to(&tmp, pts);
1198                    break;
1199                case kCubic_Verb:
1200                    subdivide_cubic_to(&tmp, pts);
1201                    break;
1202                case kClose_Verb:
1203                    tmp.close();
1204                    break;
1205                default:
1206                    SkDEBUGFAIL("unknown verb");
1207                    break;
1208            }
1209        }
1210
1211        // swap() will increment the gen id if needed
1212        dst->swap(tmp);
1213        matrix.mapPoints(dst->fPts.begin(), dst->fPts.count());
1214    } else {
1215        // remember that dst might == this, so be sure to check
1216        // fBoundsIsDirty before we set it
1217        if (!fBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) {
1218            // if we're empty, fastbounds should not be mapped
1219            matrix.mapRect(&dst->fBounds, fBounds);
1220            dst->fBoundsIsDirty = false;
1221        } else {
1222            dst->fBoundsIsDirty = true;
1223        }
1224
1225        if (this != dst) {
1226            dst->fVerbs = fVerbs;
1227            dst->fPts.setCount(fPts.count());
1228            dst->fFillType = fFillType;
1229            dst->fSegmentMask = fSegmentMask;
1230            dst->fConvexity = fConvexity;
1231        }
1232
1233        if (!matrix.isIdentity()) {
1234            GEN_ID_PTR_INC(dst);
1235        }
1236        matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
1237
1238        SkDEBUGCODE(dst->validate();)
1239    }
1240}
1241
1242///////////////////////////////////////////////////////////////////////////////
1243///////////////////////////////////////////////////////////////////////////////
1244
1245enum SegmentState {
1246    kEmptyContour_SegmentState,   // The current contour is empty. We may be
1247                                  // starting processing or we may have just
1248                                  // closed a contour.
1249    kAfterMove_SegmentState,      // We have seen a move, but nothing else.
1250    kAfterPrimitive_SegmentState  // We have seen a primitive but not yet
1251                                  // closed the path. Also the initial state.
1252};
1253
1254SkPath::Iter::Iter() {
1255#ifdef SK_DEBUG
1256    fPts = NULL;
1257    fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1258    fForceClose = fCloseLine = false;
1259    fSegmentState = kEmptyContour_SegmentState;
1260#endif
1261    // need to init enough to make next() harmlessly return kDone_Verb
1262    fVerbs = NULL;
1263    fVerbStop = NULL;
1264    fNeedClose = false;
1265}
1266
1267SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
1268    this->setPath(path, forceClose);
1269}
1270
1271void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
1272    fPts = path.fPts.begin();
1273    fVerbs = path.fVerbs.begin();
1274    fVerbStop = path.fVerbs.end();
1275    fLastPt.fX = fLastPt.fY = 0;
1276    fMoveTo.fX = fMoveTo.fY = 0;
1277    fForceClose = SkToU8(forceClose);
1278    fNeedClose = false;
1279    fSegmentState = kEmptyContour_SegmentState;
1280}
1281
1282bool SkPath::Iter::isClosedContour() const {
1283    if (fVerbs == NULL || fVerbs == fVerbStop) {
1284        return false;
1285    }
1286    if (fForceClose) {
1287        return true;
1288    }
1289
1290    const uint8_t* verbs = fVerbs;
1291    const uint8_t* stop = fVerbStop;
1292
1293    if (kMove_Verb == *verbs) {
1294        verbs += 1; // skip the initial moveto
1295    }
1296
1297    while (verbs < stop) {
1298        unsigned v = *verbs++;
1299        if (kMove_Verb == v) {
1300            break;
1301        }
1302        if (kClose_Verb == v) {
1303            return true;
1304        }
1305    }
1306    return false;
1307}
1308
1309SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
1310    if (fLastPt != fMoveTo) {
1311        // A special case: if both points are NaN, SkPoint::operation== returns
1312        // false, but the iterator expects that they are treated as the same.
1313        // (consider SkPoint is a 2-dimension float point).
1314        if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
1315            SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
1316            return kClose_Verb;
1317        }
1318
1319        if (pts) {
1320            pts[0] = fLastPt;
1321            pts[1] = fMoveTo;
1322        }
1323        fLastPt = fMoveTo;
1324        fCloseLine = true;
1325        return kLine_Verb;
1326    } else {
1327        pts[0] = fMoveTo;
1328        return kClose_Verb;
1329    }
1330}
1331
1332bool SkPath::Iter::cons_moveTo(SkPoint pts[1]) {
1333    if (fSegmentState == kAfterMove_SegmentState) {
1334        // Set the first return pt to the move pt
1335        if (pts) {
1336            *pts = fMoveTo;
1337        }
1338        fSegmentState = kAfterPrimitive_SegmentState;
1339    } else {
1340        SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
1341         // Set the first return pt to the last pt of the previous primitive.
1342        if (pts) {
1343            *pts = fPts[-1];
1344        }
1345    }
1346    return false;
1347}
1348
1349void SkPath::Iter::consumeDegenerateSegments() {
1350    // We need to step over anything that will not move the current draw point
1351    // forward before the next move is seen
1352    const uint8_t* lastMoveVerb = 0;
1353    const SkPoint* lastMovePt = 0;
1354    SkPoint lastPt = fLastPt;
1355    while (fVerbs != fVerbStop) {
1356        unsigned verb = *fVerbs;
1357        switch (verb) {
1358            case kMove_Verb:
1359                // Keep a record of this most recent move
1360                lastMoveVerb = fVerbs;
1361                lastMovePt = fPts;
1362                lastPt = fPts[0];
1363                fVerbs++;
1364                fPts++;
1365                break;
1366
1367            case kClose_Verb:
1368                // A close when we are in a segment is always valid
1369                if (fSegmentState == kAfterPrimitive_SegmentState) {
1370                    return;
1371                }
1372                // A close at any other time must be ignored
1373                fVerbs++;
1374                break;
1375
1376            case kLine_Verb:
1377                if (!IsLineDegenerate(lastPt, fPts[0])) {
1378                    if (lastMoveVerb) {
1379                        fVerbs = lastMoveVerb;
1380                        fPts = lastMovePt;
1381                        return;
1382                    }
1383                    return;
1384                }
1385                // Ignore this line and continue
1386                fVerbs++;
1387                fPts++;
1388                break;
1389
1390            case kQuad_Verb:
1391                if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
1392                    if (lastMoveVerb) {
1393                        fVerbs = lastMoveVerb;
1394                        fPts = lastMovePt;
1395                        return;
1396                    }
1397                    return;
1398                }
1399                // Ignore this line and continue
1400                fVerbs++;
1401                fPts += 2;
1402                break;
1403
1404            case kCubic_Verb:
1405                if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) {
1406                    if (lastMoveVerb) {
1407                        fVerbs = lastMoveVerb;
1408                        fPts = lastMovePt;
1409                        return;
1410                    }
1411                    return;
1412                }
1413                // Ignore this line and continue
1414                fVerbs++;
1415                fPts += 3;
1416                break;
1417
1418            default:
1419                SkDEBUGFAIL("Should never see kDone_Verb");
1420        }
1421    }
1422}
1423
1424SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
1425    this->consumeDegenerateSegments();
1426
1427    if (fVerbs == fVerbStop) {
1428        // Close the curve if requested and if there is some curve to close
1429        if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
1430            if (kLine_Verb == this->autoClose(pts)) {
1431                return kLine_Verb;
1432            }
1433            fNeedClose = false;
1434            return kClose_Verb;
1435        }
1436        return kDone_Verb;
1437    }
1438
1439    unsigned        verb = *fVerbs++;
1440    const SkPoint*  srcPts = fPts;
1441
1442    switch (verb) {
1443        case kMove_Verb:
1444            if (fNeedClose) {
1445                fVerbs -= 1;
1446                verb = this->autoClose(pts);
1447                if (verb == kClose_Verb) {
1448                    fNeedClose = false;
1449                }
1450                return (Verb)verb;
1451            }
1452            if (fVerbs == fVerbStop) {    // might be a trailing moveto
1453                return kDone_Verb;
1454            }
1455            fMoveTo = *srcPts;
1456            if (pts) {
1457                pts[0] = *srcPts;
1458            }
1459            srcPts += 1;
1460            fSegmentState = kAfterMove_SegmentState;
1461            fLastPt = fMoveTo;
1462            fNeedClose = fForceClose;
1463            break;
1464        case kLine_Verb:
1465            if (this->cons_moveTo(pts)) {
1466                return kMove_Verb;
1467            }
1468            if (pts) {
1469                pts[1] = srcPts[0];
1470            }
1471            fLastPt = srcPts[0];
1472            fCloseLine = false;
1473            srcPts += 1;
1474            break;
1475        case kQuad_Verb:
1476            if (this->cons_moveTo(pts)) {
1477                return kMove_Verb;
1478            }
1479            if (pts) {
1480                memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
1481            }
1482            fLastPt = srcPts[1];
1483            srcPts += 2;
1484            break;
1485        case kCubic_Verb:
1486            if (this->cons_moveTo(pts)) {
1487                return kMove_Verb;
1488            }
1489            if (pts) {
1490                memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
1491            }
1492            fLastPt = srcPts[2];
1493            srcPts += 3;
1494            break;
1495        case kClose_Verb:
1496            verb = this->autoClose(pts);
1497            if (verb == kLine_Verb) {
1498                fVerbs -= 1;
1499            } else {
1500                fNeedClose = false;
1501                fSegmentState = kEmptyContour_SegmentState;
1502            }
1503            fLastPt = fMoveTo;
1504            break;
1505    }
1506    fPts = srcPts;
1507    return (Verb)verb;
1508}
1509
1510///////////////////////////////////////////////////////////////////////////////
1511
1512SkPath::RawIter::RawIter() {
1513#ifdef SK_DEBUG
1514    fPts = NULL;
1515    fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1516#endif
1517    // need to init enough to make next() harmlessly return kDone_Verb
1518    fVerbs = NULL;
1519    fVerbStop = NULL;
1520}
1521
1522SkPath::RawIter::RawIter(const SkPath& path) {
1523    this->setPath(path);
1524}
1525
1526void SkPath::RawIter::setPath(const SkPath& path) {
1527    fPts = path.fPts.begin();
1528    fVerbs = path.fVerbs.begin();
1529    fVerbStop = path.fVerbs.end();
1530    fMoveTo.fX = fMoveTo.fY = 0;
1531    fLastPt.fX = fLastPt.fY = 0;
1532}
1533
1534SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
1535    if (fVerbs == fVerbStop) {
1536        return kDone_Verb;
1537    }
1538
1539    unsigned        verb = *fVerbs++;
1540    const SkPoint*  srcPts = fPts;
1541
1542    switch (verb) {
1543        case kMove_Verb:
1544            if (pts) {
1545                pts[0] = *srcPts;
1546            }
1547            fMoveTo = srcPts[0];
1548            fLastPt = fMoveTo;
1549            srcPts += 1;
1550            break;
1551        case kLine_Verb:
1552            if (pts) {
1553                pts[0] = fLastPt;
1554                pts[1] = srcPts[0];
1555            }
1556            fLastPt = srcPts[0];
1557            srcPts += 1;
1558            break;
1559        case kQuad_Verb:
1560            if (pts) {
1561                pts[0] = fLastPt;
1562                memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
1563            }
1564            fLastPt = srcPts[1];
1565            srcPts += 2;
1566            break;
1567        case kCubic_Verb:
1568            if (pts) {
1569                pts[0] = fLastPt;
1570                memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
1571            }
1572            fLastPt = srcPts[2];
1573            srcPts += 3;
1574            break;
1575        case kClose_Verb:
1576            fLastPt = fMoveTo;
1577            if (pts) {
1578                pts[0] = fMoveTo;
1579            }
1580            break;
1581    }
1582    fPts = srcPts;
1583    return (Verb)verb;
1584}
1585
1586///////////////////////////////////////////////////////////////////////////////
1587
1588/*
1589    Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]]
1590*/
1591
1592void SkPath::flatten(SkWriter32& buffer) const {
1593    SkDEBUGCODE(this->validate();)
1594
1595    buffer.write32(fPts.count());
1596    buffer.write32(fVerbs.count());
1597    buffer.write32((fFillType << 8) | fSegmentMask);
1598    buffer.writeMul4(fPts.begin(), sizeof(SkPoint) * fPts.count());
1599    buffer.writePad(fVerbs.begin(), fVerbs.count());
1600}
1601
1602void SkPath::unflatten(SkReader32& buffer) {
1603    fPts.setCount(buffer.readS32());
1604    fVerbs.setCount(buffer.readS32());
1605    uint32_t packed = buffer.readS32();
1606    fFillType = packed >> 8;
1607    fSegmentMask = packed & 0xFF;
1608    buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
1609    buffer.read(fVerbs.begin(), fVerbs.count());
1610
1611    GEN_ID_INC;
1612    DIRTY_AFTER_EDIT;
1613
1614    SkDEBUGCODE(this->validate();)
1615}
1616
1617///////////////////////////////////////////////////////////////////////////////
1618
1619void SkPath::dump(bool forceClose, const char title[]) const {
1620    Iter    iter(*this, forceClose);
1621    SkPoint pts[4];
1622    Verb    verb;
1623
1624    SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false",
1625             title ? title : "");
1626
1627    while ((verb = iter.next(pts)) != kDone_Verb) {
1628        switch (verb) {
1629            case kMove_Verb:
1630#ifdef SK_CAN_USE_FLOAT
1631                SkDebugf("  path: moveTo [%g %g]\n",
1632                        SkScalarToFloat(pts[0].fX), SkScalarToFloat(pts[0].fY));
1633#else
1634                SkDebugf("  path: moveTo [%x %x]\n", pts[0].fX, pts[0].fY);
1635#endif
1636                break;
1637            case kLine_Verb:
1638#ifdef SK_CAN_USE_FLOAT
1639                SkDebugf("  path: lineTo [%g %g]\n",
1640                        SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY));
1641#else
1642                SkDebugf("  path: lineTo [%x %x]\n", pts[1].fX, pts[1].fY);
1643#endif
1644                break;
1645            case kQuad_Verb:
1646#ifdef SK_CAN_USE_FLOAT
1647                SkDebugf("  path: quadTo [%g %g] [%g %g]\n",
1648                        SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
1649                        SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY));
1650#else
1651                SkDebugf("  path: quadTo [%x %x] [%x %x]\n",
1652                         pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
1653#endif
1654                break;
1655            case kCubic_Verb:
1656#ifdef SK_CAN_USE_FLOAT
1657                SkDebugf("  path: cubeTo [%g %g] [%g %g] [%g %g]\n",
1658                        SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
1659                        SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY),
1660                        SkScalarToFloat(pts[3].fX), SkScalarToFloat(pts[3].fY));
1661#else
1662                SkDebugf("  path: cubeTo [%x %x] [%x %x] [%x %x]\n",
1663                         pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
1664                         pts[3].fX, pts[3].fY);
1665#endif
1666                break;
1667            case kClose_Verb:
1668                SkDebugf("  path: close\n");
1669                break;
1670            default:
1671                SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
1672                verb = kDone_Verb;  // stop the loop
1673                break;
1674        }
1675    }
1676    SkDebugf("path: done %s\n", title ? title : "");
1677}
1678
1679void SkPath::dump() const {
1680    this->dump(false);
1681}
1682
1683#ifdef SK_DEBUG
1684void SkPath::validate() const {
1685    SkASSERT(this != NULL);
1686    SkASSERT((fFillType & ~3) == 0);
1687    fPts.validate();
1688    fVerbs.validate();
1689
1690    if (!fBoundsIsDirty) {
1691        SkRect bounds;
1692        compute_pt_bounds(&bounds, fPts);
1693        if (fPts.count() <= 1) {
1694            // if we're empty, fBounds may be empty but translated, so we can't
1695            // necessarily compare to bounds directly
1696            // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
1697            // be [2, 2, 2, 2]
1698            SkASSERT(bounds.isEmpty());
1699            SkASSERT(fBounds.isEmpty());
1700        } else {
1701            if (bounds.isEmpty()) {
1702                SkASSERT(fBounds.isEmpty());
1703            } else {
1704                if (!fBounds.isEmpty()) {
1705                    SkASSERT(fBounds.contains(bounds));
1706                }
1707            }
1708        }
1709    }
1710
1711    uint32_t mask = 0;
1712    for (int i = 0; i < fVerbs.count(); i++) {
1713        switch (fVerbs[i]) {
1714            case kLine_Verb:
1715                mask |= kLine_SegmentMask;
1716                break;
1717            case kQuad_Verb:
1718                mask |= kQuad_SegmentMask;
1719                break;
1720            case kCubic_Verb:
1721                mask |= kCubic_SegmentMask;
1722        }
1723    }
1724    SkASSERT(mask == fSegmentMask);
1725}
1726#endif
1727
1728///////////////////////////////////////////////////////////////////////////////
1729
1730static int sign(SkScalar x) { return x < 0; }
1731#define kValueNeverReturnedBySign   2
1732
1733static int CrossProductSign(const SkVector& a, const SkVector& b) {
1734    return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
1735}
1736
1737// only valid for a single contour
1738struct Convexicator {
1739    Convexicator() : fPtCount(0), fConvexity(SkPath::kConvex_Convexity) {
1740        fSign = 0;
1741        // warnings
1742        fCurrPt.set(0, 0);
1743        fVec0.set(0, 0);
1744        fVec1.set(0, 0);
1745        fFirstVec.set(0, 0);
1746
1747        fDx = fDy = 0;
1748        fSx = fSy = kValueNeverReturnedBySign;
1749    }
1750
1751    SkPath::Convexity getConvexity() const { return fConvexity; }
1752
1753    void addPt(const SkPoint& pt) {
1754        if (SkPath::kConcave_Convexity == fConvexity) {
1755            return;
1756        }
1757
1758        if (0 == fPtCount) {
1759            fCurrPt = pt;
1760            ++fPtCount;
1761        } else {
1762            SkVector vec = pt - fCurrPt;
1763            if (vec.fX || vec.fY) {
1764                fCurrPt = pt;
1765                if (++fPtCount == 2) {
1766                    fFirstVec = fVec1 = vec;
1767                } else {
1768                    SkASSERT(fPtCount > 2);
1769                    this->addVec(vec);
1770                }
1771
1772                int sx = sign(vec.fX);
1773                int sy = sign(vec.fY);
1774                fDx += (sx != fSx);
1775                fDy += (sy != fSy);
1776                fSx = sx;
1777                fSy = sy;
1778
1779                if (fDx > 3 || fDy > 3) {
1780                    fConvexity = SkPath::kConcave_Convexity;
1781                }
1782            }
1783        }
1784    }
1785
1786    void close() {
1787        if (fPtCount > 2) {
1788            this->addVec(fFirstVec);
1789        }
1790    }
1791
1792private:
1793    void addVec(const SkVector& vec) {
1794        SkASSERT(vec.fX || vec.fY);
1795        fVec0 = fVec1;
1796        fVec1 = vec;
1797        int sign = CrossProductSign(fVec0, fVec1);
1798        if (0 == fSign) {
1799            fSign = sign;
1800        } else if (sign) {
1801            if (fSign != sign) {
1802                fConvexity = SkPath::kConcave_Convexity;
1803            }
1804        }
1805    }
1806
1807    SkPoint             fCurrPt;
1808    SkVector            fVec0, fVec1, fFirstVec;
1809    int                 fPtCount;   // non-degenerate points
1810    int                 fSign;
1811    SkPath::Convexity   fConvexity;
1812    int                 fDx, fDy, fSx, fSy;
1813};
1814
1815SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) {
1816    SkPoint         pts[4];
1817    SkPath::Verb    verb;
1818    SkPath::Iter    iter(path, true);
1819
1820    int             contourCount = 0;
1821    int             count;
1822    Convexicator    state;
1823
1824    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
1825        switch (verb) {
1826            case kMove_Verb:
1827                if (++contourCount > 1) {
1828                    return kConcave_Convexity;
1829                }
1830                pts[1] = pts[0];
1831                count = 1;
1832                break;
1833            case kLine_Verb: count = 1; break;
1834            case kQuad_Verb: count = 2; break;
1835            case kCubic_Verb: count = 3; break;
1836            case kClose_Verb:
1837                state.close();
1838                count = 0;
1839                break;
1840            default:
1841                SkDEBUGFAIL("bad verb");
1842                return kConcave_Convexity;
1843        }
1844
1845        for (int i = 1; i <= count; i++) {
1846            state.addPt(pts[i]);
1847        }
1848        // early exit
1849        if (kConcave_Convexity == state.getConvexity()) {
1850            return kConcave_Convexity;
1851        }
1852    }
1853    return state.getConvexity();
1854}
1855
1856///////////////////////////////////////////////////////////////////////////////
1857
1858class ContourIter {
1859public:
1860    ContourIter(const SkTDArray<uint8_t>& verbs, const SkTDArray<SkPoint>& pts);
1861
1862    bool done() const { return fDone; }
1863    // if !done() then these may be called
1864    int count() const { return fCurrPtCount; }
1865    const SkPoint* pts() const { return fCurrPt; }
1866    void next();
1867
1868private:
1869    int fCurrPtCount;
1870    const SkPoint* fCurrPt;
1871    const uint8_t* fCurrVerb;
1872    const uint8_t* fStopVerbs;
1873    bool fDone;
1874    SkDEBUGCODE(int fContourCounter;)
1875};
1876
1877ContourIter::ContourIter(const SkTDArray<uint8_t>& verbs,
1878                         const SkTDArray<SkPoint>& pts) {
1879    fStopVerbs = verbs.begin() + verbs.count();
1880
1881    fDone = false;
1882    fCurrPt = pts.begin();
1883    fCurrVerb = verbs.begin();
1884    fCurrPtCount = 0;
1885    SkDEBUGCODE(fContourCounter = 0;)
1886    this->next();
1887}
1888
1889void ContourIter::next() {
1890    if (fCurrVerb >= fStopVerbs) {
1891        fDone = true;
1892    }
1893    if (fDone) {
1894        return;
1895    }
1896
1897    // skip pts of prev contour
1898    fCurrPt += fCurrPtCount;
1899
1900    SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
1901    int ptCount = 1;    // moveTo
1902    const uint8_t* verbs = fCurrVerb;
1903
1904    for (++verbs; verbs < fStopVerbs; ++verbs) {
1905        switch (*verbs) {
1906            case SkPath::kMove_Verb:
1907                goto CONTOUR_END;
1908            case SkPath::kLine_Verb:
1909                ptCount += 1;
1910                break;
1911            case SkPath::kQuad_Verb:
1912                ptCount += 2;
1913                break;
1914            case SkPath::kCubic_Verb:
1915                ptCount += 3;
1916                break;
1917            default:    // kClose_Verb, just keep going
1918                break;
1919        }
1920    }
1921CONTOUR_END:
1922    fCurrPtCount = ptCount;
1923    fCurrVerb = verbs;
1924    SkDEBUGCODE(++fContourCounter;)
1925}
1926
1927// returns cross product of (p1 - p0) and (p2 - p0)
1928static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
1929    SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
1930    // We may get 0 when the above subtracts underflow. We expect this to be
1931    // very rare and lazily promote to double.
1932    if (0 == cross) {
1933        double p0x = SkScalarToDouble(p0.fX);
1934        double p0y = SkScalarToDouble(p0.fY);
1935
1936        double p1x = SkScalarToDouble(p1.fX);
1937        double p1y = SkScalarToDouble(p1.fY);
1938
1939        double p2x = SkScalarToDouble(p2.fX);
1940        double p2y = SkScalarToDouble(p2.fY);
1941
1942        cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
1943                                 (p1y - p0y) * (p2x - p0x));
1944
1945    }
1946    return cross;
1947}
1948
1949// Returns the first pt with the maximum Y coordinate
1950static int find_max_y(const SkPoint pts[], int count) {
1951    SkASSERT(count > 0);
1952    SkScalar max = pts[0].fY;
1953    int firstIndex = 0;
1954    for (int i = 1; i < count; ++i) {
1955        SkScalar y = pts[i].fY;
1956        if (y > max) {
1957            max = y;
1958            firstIndex = i;
1959        }
1960    }
1961    return firstIndex;
1962}
1963
1964static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
1965    int i = index;
1966    for (;;) {
1967        i = (i + inc) % n;
1968        if (i == index) {   // we wrapped around, so abort
1969            break;
1970        }
1971        if (pts[index] != pts[i]) { // found a different point, success!
1972            break;
1973        }
1974    }
1975    return i;
1976}
1977
1978/**
1979 *  Starting at index, and moving forward (incrementing), find the xmin and
1980 *  xmax of the contiguous points that have the same Y.
1981 */
1982static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
1983                               int* maxIndexPtr) {
1984    const SkScalar y = pts[index].fY;
1985    SkScalar min = pts[index].fX;
1986    SkScalar max = min;
1987    int minIndex = index;
1988    int maxIndex = index;
1989    for (int i = index + 1; i < n; ++i) {
1990        if (pts[i].fY != y) {
1991            break;
1992        }
1993        SkScalar x = pts[i].fX;
1994        if (x < min) {
1995            min = x;
1996            minIndex = i;
1997        } else if (x > max) {
1998            max = x;
1999            maxIndex = i;
2000        }
2001    }
2002    *maxIndexPtr = maxIndex;
2003    return minIndex;
2004}
2005
2006static bool crossToDir(SkScalar cross, SkPath::Direction* dir) {
2007    if (dir) {
2008        *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2009    }
2010    return true;
2011}
2012
2013#if 0
2014#include "SkString.h"
2015#include "../utils/SkParsePath.h"
2016static void dumpPath(const SkPath& path) {
2017    SkString str;
2018    SkParsePath::ToSVGString(path, &str);
2019    SkDebugf("%s\n", str.c_str());
2020}
2021#endif
2022
2023/*
2024 *  We loop through all contours, and keep the computed cross-product of the
2025 *  contour that contained the global y-max. If we just look at the first
2026 *  contour, we may find one that is wound the opposite way (correctly) since
2027 *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2028 *  that is outer most (or at least has the global y-max) before we can consider
2029 *  its cross product.
2030 */
2031bool SkPath::cheapComputeDirection(Direction* dir) const {
2032//    dumpPath(*this);
2033    // don't want to pay the cost for computing this if it
2034    // is unknown, so we don't call isConvex()
2035    const Convexity conv = this->getConvexityOrUnknown();
2036
2037    ContourIter iter(fVerbs, fPts);
2038
2039    // initialize with our logical y-min
2040    SkScalar ymax = this->getBounds().fTop;
2041    SkScalar ymaxCross = 0;
2042
2043    for (; !iter.done(); iter.next()) {
2044        int n = iter.count();
2045        if (n < 3) {
2046            continue;
2047        }
2048
2049        const SkPoint* pts = iter.pts();
2050        SkScalar cross = 0;
2051        if (kConvex_Convexity == conv) {
2052            // we loop, skipping over degenerate or flat segments that will
2053            // return 0 for the cross-product
2054            for (int i = 0; i < n - 2; ++i) {
2055                cross = cross_prod(pts[i], pts[i + 1], pts[i + 2]);
2056                if (cross) {
2057                    // early-exit, as kConvex is assumed to have only 1
2058                    // non-degenerate contour
2059                    return crossToDir(cross, dir);
2060                }
2061            }
2062        } else {
2063            int index = find_max_y(pts, n);
2064            if (pts[index].fY < ymax) {
2065                continue;
2066            }
2067
2068            // If there is more than 1 distinct point at the y-max, we take the
2069            // x-min and x-max of them and just subtract to compute the dir.
2070            if (pts[(index + 1) % n].fY == pts[index].fY) {
2071                int maxIndex;
2072                int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2073                if (minIndex == maxIndex) {
2074                    goto TRY_CROSSPROD;
2075                }
2076                SkASSERT(pts[minIndex].fY == pts[index].fY);
2077                SkASSERT(pts[maxIndex].fY == pts[index].fY);
2078                SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2079                // we just subtract the indices, and let that auto-convert to
2080                // SkScalar, since we just want - or + to signal the direction.
2081                cross = minIndex - maxIndex;
2082            } else {
2083                TRY_CROSSPROD:
2084                // Find a next and prev index to use for the cross-product test,
2085                // but we try to find pts that form non-zero vectors from pts[index]
2086                //
2087                // Its possible that we can't find two non-degenerate vectors, so
2088                // we have to guard our search (e.g. all the pts could be in the
2089                // same place).
2090
2091                // we pass n - 1 instead of -1 so we don't foul up % operator by
2092                // passing it a negative LH argument.
2093                int prev = find_diff_pt(pts, index, n, n - 1);
2094                if (prev == index) {
2095                    // completely degenerate, skip to next contour
2096                    continue;
2097                }
2098                int next = find_diff_pt(pts, index, n, 1);
2099                SkASSERT(next != index);
2100                cross = cross_prod(pts[prev], pts[index], pts[next]);
2101                // if we get a zero, but the pts aren't on top of each other, then
2102                // we can just look at the direction
2103                if (0 == cross) {
2104                    // construct the subtract so we get the correct Direction below
2105                    cross = pts[index].fX - pts[next].fX;
2106                }
2107            }
2108
2109            if (cross) {
2110                // record our best guess so far
2111                ymax = pts[index].fY;
2112                ymaxCross = cross;
2113            }
2114        }
2115    }
2116
2117    return ymaxCross ? crossToDir(ymaxCross, dir) : false;
2118}
2119