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