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