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