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