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