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