Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include <cmath>
      9 #include "SkBuffer.h"
     10 #include "SkCubicClipper.h"
     11 #include "SkData.h"
     12 #include "SkGeometry.h"
     13 #include "SkMath.h"
     14 #include "SkMatrixPriv.h"
     15 #include "SkPathPriv.h"
     16 #include "SkPathRef.h"
     17 #include "SkPointPriv.h"
     18 #include "SkRRect.h"
     19 #include "SkSafeMath.h"
     20 
     21 static float poly_eval(float A, float B, float C, float t) {
     22     return (A * t + B) * t + C;
     23 }
     24 
     25 static float poly_eval(float A, float B, float C, float D, float t) {
     26     return ((A * t + B) * t + C) * t + D;
     27 }
     28 
     29 ////////////////////////////////////////////////////////////////////////////
     30 
     31 /**
     32  *  Path.bounds is defined to be the bounds of all the control points.
     33  *  If we called bounds.join(r) we would skip r if r was empty, which breaks
     34  *  our promise. Hence we have a custom joiner that doesn't look at emptiness
     35  */
     36 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
     37     dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
     38     dst->fTop = SkMinScalar(dst->fTop, src.fTop);
     39     dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
     40     dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
     41 }
     42 
     43 static bool is_degenerate(const SkPath& path) {
     44     SkPath::Iter iter(path, false);
     45     SkPoint pts[4];
     46     return SkPath::kDone_Verb == iter.next(pts);
     47 }
     48 
     49 class SkAutoDisableDirectionCheck {
     50 public:
     51     SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) {
     52         fSaved = static_cast<SkPathPriv::FirstDirection>(fPath->fFirstDirection.load());
     53     }
     54 
     55     ~SkAutoDisableDirectionCheck() {
     56         fPath->fFirstDirection = fSaved;
     57     }
     58 
     59 private:
     60     SkPath*                     fPath;
     61     SkPathPriv::FirstDirection  fSaved;
     62 };
     63 #define SkAutoDisableDirectionCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableDirectionCheck)
     64 
     65 /*  This guy's constructor/destructor bracket a path editing operation. It is
     66     used when we know the bounds of the amount we are going to add to the path
     67     (usually a new contour, but not required).
     68 
     69     It captures some state about the path up front (i.e. if it already has a
     70     cached bounds), and then if it can, it updates the cache bounds explicitly,
     71     avoiding the need to revisit all of the points in getBounds().
     72 
     73     It also notes if the path was originally degenerate, and if so, sets
     74     isConvex to true. Thus it can only be used if the contour being added is
     75     convex.
     76  */
     77 class SkAutoPathBoundsUpdate {
     78 public:
     79     SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
     80         this->init(path);
     81     }
     82 
     83     SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
     84                            SkScalar right, SkScalar bottom) {
     85         fRect.set(left, top, right, bottom);
     86         this->init(path);
     87     }
     88 
     89     ~SkAutoPathBoundsUpdate() {
     90         fPath->setConvexity(fDegenerate ? SkPath::kConvex_Convexity
     91                                         : SkPath::kUnknown_Convexity);
     92         if ((fEmpty || fHasValidBounds) && fRect.isFinite()) {
     93             fPath->setBounds(fRect);
     94         }
     95     }
     96 
     97 private:
     98     SkPath* fPath;
     99     SkRect  fRect;
    100     bool    fHasValidBounds;
    101     bool    fDegenerate;
    102     bool    fEmpty;
    103 
    104     void init(SkPath* path) {
    105         // Cannot use fRect for our bounds unless we know it is sorted
    106         fRect.sort();
    107         fPath = path;
    108         // Mark the path's bounds as dirty if (1) they are, or (2) the path
    109         // is non-finite, and therefore its bounds are not meaningful
    110         fHasValidBounds = path->hasComputedBounds() && path->isFinite();
    111         fEmpty = path->isEmpty();
    112         if (fHasValidBounds && !fEmpty) {
    113             joinNoEmptyChecks(&fRect, fPath->getBounds());
    114         }
    115         fDegenerate = is_degenerate(*path);
    116     }
    117 };
    118 #define SkAutoPathBoundsUpdate(...) SK_REQUIRE_LOCAL_VAR(SkAutoPathBoundsUpdate)
    119 
    120 ////////////////////////////////////////////////////////////////////////////
    121 
    122 /*
    123     Stores the verbs and points as they are given to us, with exceptions:
    124     - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic
    125     - we insert a Move(0,0) if Line | Quad | Cubic is our first command
    126 
    127     The iterator does more cleanup, especially if forceClose == true
    128     1. If we encounter degenerate segments, remove them
    129     2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
    130     3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
    131     4. if we encounter Line | Quad | Cubic after Close, cons up a Move
    132 */
    133 
    134 ////////////////////////////////////////////////////////////////////////////
    135 
    136 // flag to require a moveTo if we begin with something else, like lineTo etc.
    137 #define INITIAL_LASTMOVETOINDEX_VALUE   ~0
    138 
    139 SkPath::SkPath()
    140     : fPathRef(SkPathRef::CreateEmpty()) {
    141     this->resetFields();
    142     fIsVolatile = false;
    143 }
    144 
    145 void SkPath::resetFields() {
    146     //fPathRef is assumed to have been emptied by the caller.
    147     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
    148     fFillType = kWinding_FillType;
    149     fConvexity = kUnknown_Convexity;
    150     fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
    151 
    152     // We don't touch Android's fSourcePath.  It's used to track texture garbage collection, so we
    153     // don't want to muck with it if it's been set to something non-nullptr.
    154 }
    155 
    156 SkPath::SkPath(const SkPath& that)
    157     : fPathRef(SkRef(that.fPathRef.get())) {
    158     this->copyFields(that);
    159     SkDEBUGCODE(that.validate();)
    160 }
    161 
    162 SkPath::~SkPath() {
    163     SkDEBUGCODE(this->validate();)
    164 }
    165 
    166 SkPath& SkPath::operator=(const SkPath& that) {
    167     SkDEBUGCODE(that.validate();)
    168 
    169     if (this != &that) {
    170         fPathRef.reset(SkRef(that.fPathRef.get()));
    171         this->copyFields(that);
    172     }
    173     SkDEBUGCODE(this->validate();)
    174     return *this;
    175 }
    176 
    177 void SkPath::copyFields(const SkPath& that) {
    178     //fPathRef is assumed to have been set by the caller.
    179     fLastMoveToIndex = that.fLastMoveToIndex;
    180     fFillType        = that.fFillType;
    181     fIsVolatile      = that.fIsVolatile;
    182 
    183     // Non-atomic assignment of atomic values.
    184     fConvexity     .store(that.fConvexity     .load());
    185     fFirstDirection.store(that.fFirstDirection.load());
    186 }
    187 
    188 bool operator==(const SkPath& a, const SkPath& b) {
    189     // note: don't need to look at isConvex or bounds, since just comparing the
    190     // raw data is sufficient.
    191     return &a == &b ||
    192         (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get());
    193 }
    194 
    195 void SkPath::swap(SkPath& that) {
    196     if (this != &that) {
    197         fPathRef.swap(that.fPathRef);
    198         SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex);
    199         SkTSwap<uint8_t>(fFillType, that.fFillType);
    200         SkTSwap<SkBool8>(fIsVolatile, that.fIsVolatile);
    201 
    202         // Non-atomic swaps of atomic values.
    203         Convexity c = fConvexity.load();
    204         fConvexity.store(that.fConvexity.load());
    205         that.fConvexity.store(c);
    206 
    207         uint8_t fd = fFirstDirection.load();
    208         fFirstDirection.store(that.fFirstDirection.load());
    209         that.fFirstDirection.store(fd);
    210     }
    211 }
    212 
    213 bool SkPath::isInterpolatable(const SkPath& compare) const {
    214     int count = fPathRef->countVerbs();
    215     if (count != compare.fPathRef->countVerbs()) {
    216         return false;
    217     }
    218     if (!count) {
    219         return true;
    220     }
    221     if (memcmp(fPathRef->verbsMemBegin(), compare.fPathRef->verbsMemBegin(),
    222                count)) {
    223         return false;
    224     }
    225     return !fPathRef->countWeights() ||
    226             !SkToBool(memcmp(fPathRef->conicWeights(), compare.fPathRef->conicWeights(),
    227             fPathRef->countWeights() * sizeof(*fPathRef->conicWeights())));
    228 }
    229 
    230 bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
    231     int verbCount = fPathRef->countVerbs();
    232     if (verbCount != ending.fPathRef->countVerbs()) {
    233         return false;
    234     }
    235     if (!verbCount) {
    236         return true;
    237     }
    238     out->reset();
    239     out->addPath(*this);
    240     fPathRef->interpolate(*ending.fPathRef, weight, out->fPathRef.get());
    241     return true;
    242 }
    243 
    244 static inline bool check_edge_against_rect(const SkPoint& p0,
    245                                            const SkPoint& p1,
    246                                            const SkRect& rect,
    247                                            SkPathPriv::FirstDirection dir) {
    248     const SkPoint* edgeBegin;
    249     SkVector v;
    250     if (SkPathPriv::kCW_FirstDirection == dir) {
    251         v = p1 - p0;
    252         edgeBegin = &p0;
    253     } else {
    254         v = p0 - p1;
    255         edgeBegin = &p1;
    256     }
    257     if (v.fX || v.fY) {
    258         // check the cross product of v with the vec from edgeBegin to each rect corner
    259         SkScalar yL = v.fY * (rect.fLeft - edgeBegin->fX);
    260         SkScalar xT = v.fX * (rect.fTop - edgeBegin->fY);
    261         SkScalar yR = v.fY * (rect.fRight - edgeBegin->fX);
    262         SkScalar xB = v.fX * (rect.fBottom - edgeBegin->fY);
    263         if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) {
    264             return false;
    265         }
    266     }
    267     return true;
    268 }
    269 
    270 bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
    271     // This only handles non-degenerate convex paths currently.
    272     if (kConvex_Convexity != this->getConvexity()) {
    273         return false;
    274     }
    275 
    276     SkPathPriv::FirstDirection direction;
    277     if (!SkPathPriv::CheapComputeFirstDirection(*this, &direction)) {
    278         return false;
    279     }
    280 
    281     SkPoint firstPt;
    282     SkPoint prevPt;
    283     SkPath::Iter iter(*this, true);
    284     SkPath::Verb verb;
    285     SkPoint pts[4];
    286     int segmentCount = 0;
    287     SkDEBUGCODE(int moveCnt = 0;)
    288     SkDEBUGCODE(int closeCount = 0;)
    289 
    290     while ((verb = iter.next(pts, true, true)) != kDone_Verb) {
    291         int nextPt = -1;
    292         switch (verb) {
    293             case kMove_Verb:
    294                 SkASSERT(!segmentCount && !closeCount);
    295                 SkDEBUGCODE(++moveCnt);
    296                 firstPt = prevPt = pts[0];
    297                 break;
    298             case kLine_Verb:
    299                 nextPt = 1;
    300                 SkASSERT(moveCnt && !closeCount);
    301                 ++segmentCount;
    302                 break;
    303             case kQuad_Verb:
    304             case kConic_Verb:
    305                 SkASSERT(moveCnt && !closeCount);
    306                 ++segmentCount;
    307                 nextPt = 2;
    308                 break;
    309             case kCubic_Verb:
    310                 SkASSERT(moveCnt && !closeCount);
    311                 ++segmentCount;
    312                 nextPt = 3;
    313                 break;
    314             case kClose_Verb:
    315                 SkDEBUGCODE(++closeCount;)
    316                 break;
    317             default:
    318                 SkDEBUGFAIL("unknown verb");
    319         }
    320         if (-1 != nextPt) {
    321             if (SkPath::kConic_Verb == verb) {
    322                 SkConic orig;
    323                 orig.set(pts, iter.conicWeight());
    324                 SkPoint quadPts[5];
    325                 int count = orig.chopIntoQuadsPOW2(quadPts, 1);
    326                 SkASSERT_RELEASE(2 == count);
    327 
    328                 if (!check_edge_against_rect(quadPts[0], quadPts[2], rect, direction)) {
    329                     return false;
    330                 }
    331                 if (!check_edge_against_rect(quadPts[2], quadPts[4], rect, direction)) {
    332                     return false;
    333                 }
    334             } else {
    335                 if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) {
    336                     return false;
    337                 }
    338             }
    339             prevPt = pts[nextPt];
    340         }
    341     }
    342 
    343     if (segmentCount) {
    344         return check_edge_against_rect(prevPt, firstPt, rect, direction);
    345     }
    346     return false;
    347 }
    348 
    349 uint32_t SkPath::getGenerationID() const {
    350     uint32_t genID = fPathRef->genID();
    351 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    352     SkASSERT((unsigned)fFillType < (1 << (32 - SkPathPriv::kPathRefGenIDBitCnt)));
    353     genID |= static_cast<uint32_t>(fFillType) << SkPathPriv::kPathRefGenIDBitCnt;
    354 #endif
    355     return genID;
    356 }
    357 
    358 void SkPath::reset() {
    359     SkDEBUGCODE(this->validate();)
    360 
    361     fPathRef.reset(SkPathRef::CreateEmpty());
    362     this->resetFields();
    363 }
    364 
    365 void SkPath::rewind() {
    366     SkDEBUGCODE(this->validate();)
    367 
    368     SkPathRef::Rewind(&fPathRef);
    369     this->resetFields();
    370 }
    371 
    372 bool SkPath::isLastContourClosed() const {
    373     int verbCount = fPathRef->countVerbs();
    374     if (0 == verbCount) {
    375         return false;
    376     }
    377     return kClose_Verb == fPathRef->atVerb(verbCount - 1);
    378 }
    379 
    380 bool SkPath::isLine(SkPoint line[2]) const {
    381     int verbCount = fPathRef->countVerbs();
    382 
    383     if (2 == verbCount) {
    384         SkASSERT(kMove_Verb == fPathRef->atVerb(0));
    385         if (kLine_Verb == fPathRef->atVerb(1)) {
    386             SkASSERT(2 == fPathRef->countPoints());
    387             if (line) {
    388                 const SkPoint* pts = fPathRef->points();
    389                 line[0] = pts[0];
    390                 line[1] = pts[1];
    391             }
    392             return true;
    393         }
    394     }
    395     return false;
    396 }
    397 
    398 /*
    399  Determines if path is a rect by keeping track of changes in direction
    400  and looking for a loop either clockwise or counterclockwise.
    401 
    402  The direction is computed such that:
    403   0: vertical up
    404   1: horizontal left
    405   2: vertical down
    406   3: horizontal right
    407 
    408 A rectangle cycles up/right/down/left or up/left/down/right.
    409 
    410 The test fails if:
    411   The path is closed, and followed by a line.
    412   A second move creates a new endpoint.
    413   A diagonal line is parsed.
    414   There's more than four changes of direction.
    415   There's a discontinuity on the line (e.g., a move in the middle)
    416   The line reverses direction.
    417   The path contains a quadratic or cubic.
    418   The path contains fewer than four points.
    419  *The rectangle doesn't complete a cycle.
    420  *The final point isn't equal to the first point.
    421 
    422   *These last two conditions we relax if we have a 3-edge path that would
    423    form a rectangle if it were closed (as we do when we fill a path)
    424 
    425 It's OK if the path has:
    426   Several colinear line segments composing a rectangle side.
    427   Single points on the rectangle side.
    428 
    429 The direction takes advantage of the corners found since opposite sides
    430 must travel in opposite directions.
    431 
    432 FIXME: Allow colinear quads and cubics to be treated like lines.
    433 FIXME: If the API passes fill-only, return true if the filled stroke
    434        is a rectangle, though the caller failed to close the path.
    435 
    436  first,last,next direction state-machine:
    437     0x1 is set if the segment is horizontal
    438     0x2 is set if the segment is moving to the right or down
    439  thus:
    440     two directions are opposites iff (dirA ^ dirB) == 0x2
    441     two directions are perpendicular iff (dirA ^ dirB) == 0x1
    442 
    443  */
    444 static int rect_make_dir(SkScalar dx, SkScalar dy) {
    445     return ((0 != dx) << 0) | ((dx > 0 || dy > 0) << 1);
    446 }
    447 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr,
    448         bool* isClosed, Direction* direction) const {
    449     int corners = 0;
    450     SkPoint first, last;
    451     const SkPoint* pts = *ptsPtr;
    452     const SkPoint* savePts = nullptr;
    453     first.set(0, 0);
    454     last.set(0, 0);
    455     int firstDirection = 0;
    456     int lastDirection = 0;
    457     int nextDirection = 0;
    458     bool closedOrMoved = false;
    459     bool autoClose = false;
    460     bool insertClose = false;
    461     int verbCnt = fPathRef->countVerbs();
    462     while (*currVerb < verbCnt && (!allowPartial || !autoClose)) {
    463         uint8_t verb = insertClose ? (uint8_t) kClose_Verb : fPathRef->atVerb(*currVerb);
    464         switch (verb) {
    465             case kClose_Verb:
    466                 savePts = pts;
    467                 pts = *ptsPtr;
    468                 autoClose = true;
    469                 insertClose = false;
    470             case kLine_Verb: {
    471                 SkScalar left = last.fX;
    472                 SkScalar top = last.fY;
    473                 SkScalar right = pts->fX;
    474                 SkScalar bottom = pts->fY;
    475                 ++pts;
    476                 if (left != right && top != bottom) {
    477                     return false; // diagonal
    478                 }
    479                 if (left == right && top == bottom) {
    480                     break; // single point on side OK
    481                 }
    482                 nextDirection = rect_make_dir(right - left, bottom - top);
    483                 if (0 == corners) {
    484                     firstDirection = nextDirection;
    485                     first = last;
    486                     last = pts[-1];
    487                     corners = 1;
    488                     closedOrMoved = false;
    489                     break;
    490                 }
    491                 if (closedOrMoved) {
    492                     return false; // closed followed by a line
    493                 }
    494                 if (autoClose && nextDirection == firstDirection) {
    495                     break; // colinear with first
    496                 }
    497                 closedOrMoved = autoClose;
    498                 if (lastDirection != nextDirection) {
    499                     if (++corners > 4) {
    500                         return false; // too many direction changes
    501                     }
    502                 }
    503                 last = pts[-1];
    504                 if (lastDirection == nextDirection) {
    505                     break; // colinear segment
    506                 }
    507                 // Possible values for corners are 2, 3, and 4.
    508                 // When corners == 3, nextDirection opposes firstDirection.
    509                 // Otherwise, nextDirection at corner 2 opposes corner 4.
    510                 int turn = firstDirection ^ (corners - 1);
    511                 int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
    512                 if ((directionCycle ^ turn) != nextDirection) {
    513                     return false; // direction didn't follow cycle
    514                 }
    515                 break;
    516             }
    517             case kQuad_Verb:
    518             case kConic_Verb:
    519             case kCubic_Verb:
    520                 return false; // quadratic, cubic not allowed
    521             case kMove_Verb:
    522                 if (allowPartial && !autoClose && firstDirection) {
    523                     insertClose = true;
    524                     *currVerb -= 1;  // try move again afterwards
    525                     goto addMissingClose;
    526                 }
    527                 last = *pts++;
    528                 closedOrMoved = true;
    529                 break;
    530             default:
    531                 SkDEBUGFAIL("unexpected verb");
    532                 break;
    533         }
    534         *currVerb += 1;
    535         lastDirection = nextDirection;
    536 addMissingClose:
    537         ;
    538     }
    539     // Success if 4 corners and first point equals last
    540     bool result = 4 == corners && (first == last || autoClose);
    541     if (!result) {
    542         // check if we are just an incomplete rectangle, in which case we can
    543         // return true, but not claim to be closed.
    544         // e.g.
    545         //    3 sided rectangle
    546         //    4 sided but the last edge is not long enough to reach the start
    547         //
    548         SkScalar closeX = first.x() - last.x();
    549         SkScalar closeY = first.y() - last.y();
    550         if (closeX && closeY) {
    551             return false;   // we're diagonal, abort (can we ever reach this?)
    552         }
    553         int closeDirection = rect_make_dir(closeX, closeY);
    554         // make sure the close-segment doesn't double-back on itself
    555         if (3 == corners || (4 == corners && closeDirection == lastDirection)) {
    556             result = true;
    557             autoClose = false;  // we are not closed
    558         }
    559     }
    560     if (savePts) {
    561         *ptsPtr = savePts;
    562     }
    563     if (result && isClosed) {
    564         *isClosed = autoClose;
    565     }
    566     if (result && direction) {
    567         *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Direction : kCW_Direction;
    568     }
    569     return result;
    570 }
    571 
    572 bool SkPath::isRect(SkRect* rect, bool* isClosed, Direction* direction) const {
    573     SkDEBUGCODE(this->validate();)
    574     int currVerb = 0;
    575     const SkPoint* pts = fPathRef->points();
    576     const SkPoint* first = pts;
    577     if (!this->isRectContour(false, &currVerb, &pts, isClosed, direction)) {
    578         return false;
    579     }
    580     if (rect) {
    581         int32_t num = SkToS32(pts - first);
    582         if (num) {
    583             rect->set(first, num);
    584         } else {
    585             // 'pts' isn't updated for open rects
    586             *rect = this->getBounds();
    587         }
    588     }
    589     return true;
    590 }
    591 
    592 bool SkPath::isNestedFillRects(SkRect rects[2], Direction dirs[2]) const {
    593     SkDEBUGCODE(this->validate();)
    594     int currVerb = 0;
    595     const SkPoint* pts = fPathRef->points();
    596     const SkPoint* first = pts;
    597     Direction testDirs[2];
    598     if (!isRectContour(true, &currVerb, &pts, nullptr, &testDirs[0])) {
    599         return false;
    600     }
    601     const SkPoint* last = pts;
    602     SkRect testRects[2];
    603     bool isClosed;
    604     if (isRectContour(false, &currVerb, &pts, &isClosed, &testDirs[1])) {
    605         testRects[0].set(first, SkToS32(last - first));
    606         if (!isClosed) {
    607             pts = fPathRef->points() + fPathRef->countPoints();
    608         }
    609         testRects[1].set(last, SkToS32(pts - last));
    610         if (testRects[0].contains(testRects[1])) {
    611             if (rects) {
    612                 rects[0] = testRects[0];
    613                 rects[1] = testRects[1];
    614             }
    615             if (dirs) {
    616                 dirs[0] = testDirs[0];
    617                 dirs[1] = testDirs[1];
    618             }
    619             return true;
    620         }
    621         if (testRects[1].contains(testRects[0])) {
    622             if (rects) {
    623                 rects[0] = testRects[1];
    624                 rects[1] = testRects[0];
    625             }
    626             if (dirs) {
    627                 dirs[0] = testDirs[1];
    628                 dirs[1] = testDirs[0];
    629             }
    630             return true;
    631         }
    632     }
    633     return false;
    634 }
    635 
    636 bool SkPath::isOval(SkRect* bounds) const {
    637     return SkPathPriv::IsOval(*this, bounds, nullptr, nullptr);
    638 }
    639 
    640 bool SkPath::isRRect(SkRRect* rrect) const {
    641     return SkPathPriv::IsRRect(*this, rrect, nullptr, nullptr);
    642 }
    643 
    644 int SkPath::countPoints() const {
    645     return fPathRef->countPoints();
    646 }
    647 
    648 int SkPath::getPoints(SkPoint dst[], int max) const {
    649     SkDEBUGCODE(this->validate();)
    650 
    651     SkASSERT(max >= 0);
    652     SkASSERT(!max || dst);
    653     int count = SkMin32(max, fPathRef->countPoints());
    654     sk_careful_memcpy(dst, fPathRef->points(), count * sizeof(SkPoint));
    655     return fPathRef->countPoints();
    656 }
    657 
    658 SkPoint SkPath::getPoint(int index) const {
    659     if ((unsigned)index < (unsigned)fPathRef->countPoints()) {
    660         return fPathRef->atPoint(index);
    661     }
    662     return SkPoint::Make(0, 0);
    663 }
    664 
    665 int SkPath::countVerbs() const {
    666     return fPathRef->countVerbs();
    667 }
    668 
    669 static inline void copy_verbs_reverse(uint8_t* inorderDst,
    670                                       const uint8_t* reversedSrc,
    671                                       int count) {
    672     for (int i = 0; i < count; ++i) {
    673         inorderDst[i] = reversedSrc[~i];
    674     }
    675 }
    676 
    677 int SkPath::getVerbs(uint8_t dst[], int max) const {
    678     SkDEBUGCODE(this->validate();)
    679 
    680     SkASSERT(max >= 0);
    681     SkASSERT(!max || dst);
    682     int count = SkMin32(max, fPathRef->countVerbs());
    683     copy_verbs_reverse(dst, fPathRef->verbs(), count);
    684     return fPathRef->countVerbs();
    685 }
    686 
    687 bool SkPath::getLastPt(SkPoint* lastPt) const {
    688     SkDEBUGCODE(this->validate();)
    689 
    690     int count = fPathRef->countPoints();
    691     if (count > 0) {
    692         if (lastPt) {
    693             *lastPt = fPathRef->atPoint(count - 1);
    694         }
    695         return true;
    696     }
    697     if (lastPt) {
    698         lastPt->set(0, 0);
    699     }
    700     return false;
    701 }
    702 
    703 void SkPath::setPt(int index, SkScalar x, SkScalar y) {
    704     SkDEBUGCODE(this->validate();)
    705 
    706     int count = fPathRef->countPoints();
    707     if (count <= index) {
    708         return;
    709     } else {
    710         SkPathRef::Editor ed(&fPathRef);
    711         ed.atPoint(index)->set(x, y);
    712     }
    713 }
    714 
    715 void SkPath::setLastPt(SkScalar x, SkScalar y) {
    716     SkDEBUGCODE(this->validate();)
    717 
    718     int count = fPathRef->countPoints();
    719     if (count == 0) {
    720         this->moveTo(x, y);
    721     } else {
    722         SkPathRef::Editor ed(&fPathRef);
    723         ed.atPoint(count-1)->set(x, y);
    724     }
    725 }
    726 
    727 void SkPath::setConvexity(Convexity c) {
    728     if (fConvexity != c) {
    729         fConvexity = c;
    730     }
    731 }
    732 
    733 //////////////////////////////////////////////////////////////////////////////
    734 //  Construction methods
    735 
    736 #define DIRTY_AFTER_EDIT                                        \
    737     do {                                                        \
    738         fConvexity = kUnknown_Convexity;                        \
    739         fFirstDirection = SkPathPriv::kUnknown_FirstDirection;  \
    740     } while (0)
    741 
    742 void SkPath::incReserve(U16CPU inc) {
    743     SkDEBUGCODE(this->validate();)
    744     SkPathRef::Editor(&fPathRef, inc, inc);
    745     SkDEBUGCODE(this->validate();)
    746 }
    747 
    748 void SkPath::moveTo(SkScalar x, SkScalar y) {
    749     SkDEBUGCODE(this->validate();)
    750 
    751     SkPathRef::Editor ed(&fPathRef);
    752 
    753     // remember our index
    754     fLastMoveToIndex = fPathRef->countPoints();
    755 
    756     ed.growForVerb(kMove_Verb)->set(x, y);
    757 
    758     DIRTY_AFTER_EDIT;
    759 }
    760 
    761 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
    762     SkPoint pt;
    763     this->getLastPt(&pt);
    764     this->moveTo(pt.fX + x, pt.fY + y);
    765 }
    766 
    767 void SkPath::injectMoveToIfNeeded() {
    768     if (fLastMoveToIndex < 0) {
    769         SkScalar x, y;
    770         if (fPathRef->countVerbs() == 0) {
    771             x = y = 0;
    772         } else {
    773             const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex);
    774             x = pt.fX;
    775             y = pt.fY;
    776         }
    777         this->moveTo(x, y);
    778     }
    779 }
    780 
    781 void SkPath::lineTo(SkScalar x, SkScalar y) {
    782     SkDEBUGCODE(this->validate();)
    783 
    784     this->injectMoveToIfNeeded();
    785 
    786     SkPathRef::Editor ed(&fPathRef);
    787     ed.growForVerb(kLine_Verb)->set(x, y);
    788 
    789     DIRTY_AFTER_EDIT;
    790 }
    791 
    792 void SkPath::rLineTo(SkScalar x, SkScalar y) {
    793     this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
    794     SkPoint pt;
    795     this->getLastPt(&pt);
    796     this->lineTo(pt.fX + x, pt.fY + y);
    797 }
    798 
    799 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
    800     SkDEBUGCODE(this->validate();)
    801 
    802     this->injectMoveToIfNeeded();
    803 
    804     SkPathRef::Editor ed(&fPathRef);
    805     SkPoint* pts = ed.growForVerb(kQuad_Verb);
    806     pts[0].set(x1, y1);
    807     pts[1].set(x2, y2);
    808 
    809     DIRTY_AFTER_EDIT;
    810 }
    811 
    812 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
    813     this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
    814     SkPoint pt;
    815     this->getLastPt(&pt);
    816     this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
    817 }
    818 
    819 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
    820                      SkScalar w) {
    821     // check for <= 0 or NaN with this test
    822     if (!(w > 0)) {
    823         this->lineTo(x2, y2);
    824     } else if (!SkScalarIsFinite(w)) {
    825         this->lineTo(x1, y1);
    826         this->lineTo(x2, y2);
    827     } else if (SK_Scalar1 == w) {
    828         this->quadTo(x1, y1, x2, y2);
    829     } else {
    830         SkDEBUGCODE(this->validate();)
    831 
    832         this->injectMoveToIfNeeded();
    833 
    834         SkPathRef::Editor ed(&fPathRef);
    835         SkPoint* pts = ed.growForVerb(kConic_Verb, w);
    836         pts[0].set(x1, y1);
    837         pts[1].set(x2, y2);
    838 
    839         DIRTY_AFTER_EDIT;
    840     }
    841 }
    842 
    843 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
    844                       SkScalar w) {
    845     this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
    846     SkPoint pt;
    847     this->getLastPt(&pt);
    848     this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w);
    849 }
    850 
    851 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
    852                      SkScalar x3, SkScalar y3) {
    853     SkDEBUGCODE(this->validate();)
    854 
    855     this->injectMoveToIfNeeded();
    856 
    857     SkPathRef::Editor ed(&fPathRef);
    858     SkPoint* pts = ed.growForVerb(kCubic_Verb);
    859     pts[0].set(x1, y1);
    860     pts[1].set(x2, y2);
    861     pts[2].set(x3, y3);
    862 
    863     DIRTY_AFTER_EDIT;
    864 }
    865 
    866 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
    867                       SkScalar x3, SkScalar y3) {
    868     this->injectMoveToIfNeeded();  // This can change the result of this->getLastPt().
    869     SkPoint pt;
    870     this->getLastPt(&pt);
    871     this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
    872                   pt.fX + x3, pt.fY + y3);
    873 }
    874 
    875 void SkPath::close() {
    876     SkDEBUGCODE(this->validate();)
    877 
    878     int count = fPathRef->countVerbs();
    879     if (count > 0) {
    880         switch (fPathRef->atVerb(count - 1)) {
    881             case kLine_Verb:
    882             case kQuad_Verb:
    883             case kConic_Verb:
    884             case kCubic_Verb:
    885             case kMove_Verb: {
    886                 SkPathRef::Editor ed(&fPathRef);
    887                 ed.growForVerb(kClose_Verb);
    888                 break;
    889             }
    890             case kClose_Verb:
    891                 // don't add a close if it's the first verb or a repeat
    892                 break;
    893             default:
    894                 SkDEBUGFAIL("unexpected verb");
    895                 break;
    896         }
    897     }
    898 
    899     // signal that we need a moveTo to follow us (unless we're done)
    900 #if 0
    901     if (fLastMoveToIndex >= 0) {
    902         fLastMoveToIndex = ~fLastMoveToIndex;
    903     }
    904 #else
    905     fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
    906 #endif
    907 }
    908 
    909 ///////////////////////////////////////////////////////////////////////////////
    910 
    911 namespace {
    912 
    913 template <unsigned N>
    914 class PointIterator {
    915 public:
    916     PointIterator(SkPath::Direction dir, unsigned startIndex)
    917         : fCurrent(startIndex % N)
    918         , fAdvance(dir == SkPath::kCW_Direction ? 1 : N - 1) { }
    919 
    920     const SkPoint& current() const {
    921         SkASSERT(fCurrent < N);
    922         return fPts[fCurrent];
    923     }
    924 
    925     const SkPoint& next() {
    926         fCurrent = (fCurrent + fAdvance) % N;
    927         return this->current();
    928     }
    929 
    930 protected:
    931     SkPoint fPts[N];
    932 
    933 private:
    934     unsigned fCurrent;
    935     unsigned fAdvance;
    936 };
    937 
    938 class RectPointIterator : public PointIterator<4> {
    939 public:
    940     RectPointIterator(const SkRect& rect, SkPath::Direction dir, unsigned startIndex)
    941         : PointIterator(dir, startIndex) {
    942 
    943         fPts[0] = SkPoint::Make(rect.fLeft, rect.fTop);
    944         fPts[1] = SkPoint::Make(rect.fRight, rect.fTop);
    945         fPts[2] = SkPoint::Make(rect.fRight, rect.fBottom);
    946         fPts[3] = SkPoint::Make(rect.fLeft, rect.fBottom);
    947     }
    948 };
    949 
    950 class OvalPointIterator : public PointIterator<4> {
    951 public:
    952     OvalPointIterator(const SkRect& oval, SkPath::Direction dir, unsigned startIndex)
    953         : PointIterator(dir, startIndex) {
    954 
    955         const SkScalar cx = oval.centerX();
    956         const SkScalar cy = oval.centerY();
    957 
    958         fPts[0] = SkPoint::Make(cx, oval.fTop);
    959         fPts[1] = SkPoint::Make(oval.fRight, cy);
    960         fPts[2] = SkPoint::Make(cx, oval.fBottom);
    961         fPts[3] = SkPoint::Make(oval.fLeft, cy);
    962     }
    963 };
    964 
    965 class RRectPointIterator : public PointIterator<8> {
    966 public:
    967     RRectPointIterator(const SkRRect& rrect, SkPath::Direction dir, unsigned startIndex)
    968         : PointIterator(dir, startIndex) {
    969 
    970         const SkRect& bounds = rrect.getBounds();
    971         const SkScalar L = bounds.fLeft;
    972         const SkScalar T = bounds.fTop;
    973         const SkScalar R = bounds.fRight;
    974         const SkScalar B = bounds.fBottom;
    975 
    976         fPts[0] = SkPoint::Make(L + rrect.radii(SkRRect::kUpperLeft_Corner).fX, T);
    977         fPts[1] = SkPoint::Make(R - rrect.radii(SkRRect::kUpperRight_Corner).fX, T);
    978         fPts[2] = SkPoint::Make(R, T + rrect.radii(SkRRect::kUpperRight_Corner).fY);
    979         fPts[3] = SkPoint::Make(R, B - rrect.radii(SkRRect::kLowerRight_Corner).fY);
    980         fPts[4] = SkPoint::Make(R - rrect.radii(SkRRect::kLowerRight_Corner).fX, B);
    981         fPts[5] = SkPoint::Make(L + rrect.radii(SkRRect::kLowerLeft_Corner).fX, B);
    982         fPts[6] = SkPoint::Make(L, B - rrect.radii(SkRRect::kLowerLeft_Corner).fY);
    983         fPts[7] = SkPoint::Make(L, T + rrect.radii(SkRRect::kUpperLeft_Corner).fY);
    984     }
    985 };
    986 
    987 } // anonymous namespace
    988 
    989 static void assert_known_direction(int dir) {
    990     SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir);
    991 }
    992 
    993 void SkPath::addRect(const SkRect& rect, Direction dir) {
    994     this->addRect(rect, dir, 0);
    995 }
    996 
    997 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
    998                      SkScalar bottom, Direction dir) {
    999     this->addRect(SkRect::MakeLTRB(left, top, right, bottom), dir, 0);
   1000 }
   1001 
   1002 void SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) {
   1003     assert_known_direction(dir);
   1004     fFirstDirection = this->hasOnlyMoveTos() ?
   1005         (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
   1006     SkAutoDisableDirectionCheck addc(this);
   1007     SkAutoPathBoundsUpdate apbu(this, rect);
   1008 
   1009     SkDEBUGCODE(int initialVerbCount = this->countVerbs());
   1010 
   1011     const int kVerbs = 5; // moveTo + 3x lineTo + close
   1012     this->incReserve(kVerbs);
   1013 
   1014     RectPointIterator iter(rect, dir, startIndex);
   1015 
   1016     this->moveTo(iter.current());
   1017     this->lineTo(iter.next());
   1018     this->lineTo(iter.next());
   1019     this->lineTo(iter.next());
   1020     this->close();
   1021 
   1022     SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
   1023 }
   1024 
   1025 void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
   1026     SkDEBUGCODE(this->validate();)
   1027     if (count <= 0) {
   1028         return;
   1029     }
   1030 
   1031     fLastMoveToIndex = fPathRef->countPoints();
   1032 
   1033     // +close makes room for the extra kClose_Verb
   1034     SkPathRef::Editor ed(&fPathRef, count+close, count);
   1035 
   1036     ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY);
   1037     if (count > 1) {
   1038         SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1);
   1039         memcpy(p, &pts[1], (count-1) * sizeof(SkPoint));
   1040     }
   1041 
   1042     if (close) {
   1043         ed.growForVerb(kClose_Verb);
   1044         fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
   1045     }
   1046 
   1047     DIRTY_AFTER_EDIT;
   1048     SkDEBUGCODE(this->validate();)
   1049 }
   1050 
   1051 #include "SkGeometry.h"
   1052 
   1053 static bool arc_is_lone_point(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
   1054                               SkPoint* pt) {
   1055     if (0 == sweepAngle && (0 == startAngle || SkIntToScalar(360) == startAngle)) {
   1056         // Chrome uses this path to move into and out of ovals. If not
   1057         // treated as a special case the moves can distort the oval's
   1058         // bounding box (and break the circle special case).
   1059         pt->set(oval.fRight, oval.centerY());
   1060         return true;
   1061     } else if (0 == oval.width() && 0 == oval.height()) {
   1062         // Chrome will sometimes create 0 radius round rects. Having degenerate
   1063         // quad segments in the path prevents the path from being recognized as
   1064         // a rect.
   1065         // TODO: optimizing the case where only one of width or height is zero
   1066         // should also be considered. This case, however, doesn't seem to be
   1067         // as common as the single point case.
   1068         pt->set(oval.fRight, oval.fTop);
   1069         return true;
   1070     }
   1071     return false;
   1072 }
   1073 
   1074 // Return the unit vectors pointing at the start/stop points for the given start/sweep angles
   1075 //
   1076 static void angles_to_unit_vectors(SkScalar startAngle, SkScalar sweepAngle,
   1077                                    SkVector* startV, SkVector* stopV, SkRotationDirection* dir) {
   1078     startV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &startV->fX);
   1079     stopV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), &stopV->fX);
   1080 
   1081     /*  If the sweep angle is nearly (but less than) 360, then due to precision
   1082      loss in radians-conversion and/or sin/cos, we may end up with coincident
   1083      vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead
   1084      of drawing a nearly complete circle (good).
   1085      e.g. canvas.drawArc(0, 359.99, ...)
   1086      -vs- canvas.drawArc(0, 359.9, ...)
   1087      We try to detect this edge case, and tweak the stop vector
   1088      */
   1089     if (*startV == *stopV) {
   1090         SkScalar sw = SkScalarAbs(sweepAngle);
   1091         if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
   1092             SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
   1093             // make a guess at a tiny angle (in radians) to tweak by
   1094             SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
   1095             // not sure how much will be enough, so we use a loop
   1096             do {
   1097                 stopRad -= deltaRad;
   1098                 stopV->fY = SkScalarSinCos(stopRad, &stopV->fX);
   1099             } while (*startV == *stopV);
   1100         }
   1101     }
   1102     *dir = sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection;
   1103 }
   1104 
   1105 /**
   1106  *  If this returns 0, then the caller should just line-to the singlePt, else it should
   1107  *  ignore singlePt and append the specified number of conics.
   1108  */
   1109 static int build_arc_conics(const SkRect& oval, const SkVector& start, const SkVector& stop,
   1110                             SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc],
   1111                             SkPoint* singlePt) {
   1112     SkMatrix    matrix;
   1113 
   1114     matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
   1115     matrix.postTranslate(oval.centerX(), oval.centerY());
   1116 
   1117     int count = SkConic::BuildUnitArc(start, stop, dir, &matrix, conics);
   1118     if (0 == count) {
   1119         matrix.mapXY(stop.x(), stop.y(), singlePt);
   1120     }
   1121     return count;
   1122 }
   1123 
   1124 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
   1125                           Direction dir) {
   1126     SkRRect rrect;
   1127     rrect.setRectRadii(rect, (const SkVector*) radii);
   1128     this->addRRect(rrect, dir);
   1129 }
   1130 
   1131 void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
   1132     // legacy start indices: 6 (CW) and 7(CCW)
   1133     this->addRRect(rrect, dir, dir == kCW_Direction ? 6 : 7);
   1134 }
   1135 
   1136 void SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex) {
   1137         assert_known_direction(dir);
   1138 
   1139         bool isRRect = hasOnlyMoveTos();
   1140         const SkRect& bounds = rrect.getBounds();
   1141 
   1142         if (rrect.isRect() || rrect.isEmpty()) {
   1143             // degenerate(rect) => radii points are collapsing
   1144             this->addRect(bounds, dir, (startIndex + 1) / 2);
   1145         } else if (rrect.isOval()) {
   1146             // degenerate(oval) => line points are collapsing
   1147             this->addOval(bounds, dir, startIndex / 2);
   1148         } else {
   1149             fFirstDirection = this->hasOnlyMoveTos() ?
   1150                                 (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection;
   1151 
   1152             SkAutoPathBoundsUpdate apbu(this, bounds);
   1153             SkAutoDisableDirectionCheck addc(this);
   1154 
   1155             // we start with a conic on odd indices when moving CW vs. even indices when moving CCW
   1156             const bool startsWithConic = ((startIndex & 1) == (dir == kCW_Direction));
   1157             const SkScalar weight = SK_ScalarRoot2Over2;
   1158 
   1159             SkDEBUGCODE(int initialVerbCount = this->countVerbs());
   1160             const int kVerbs = startsWithConic
   1161                 ? 9   // moveTo + 4x conicTo + 3x lineTo + close
   1162                 : 10; // moveTo + 4x lineTo + 4x conicTo + close
   1163             this->incReserve(kVerbs);
   1164 
   1165             RRectPointIterator rrectIter(rrect, dir, startIndex);
   1166             // Corner iterator indices follow the collapsed radii model,
   1167             // adjusted such that the start pt is "behind" the radii start pt.
   1168             const unsigned rectStartIndex = startIndex / 2 + (dir == kCW_Direction ? 0 : 1);
   1169             RectPointIterator rectIter(bounds, dir, rectStartIndex);
   1170 
   1171             this->moveTo(rrectIter.current());
   1172             if (startsWithConic) {
   1173                 for (unsigned i = 0; i < 3; ++i) {
   1174                     this->conicTo(rectIter.next(), rrectIter.next(), weight);
   1175                     this->lineTo(rrectIter.next());
   1176                 }
   1177                 this->conicTo(rectIter.next(), rrectIter.next(), weight);
   1178                 // final lineTo handled by close().
   1179             } else {
   1180                 for (unsigned i = 0; i < 4; ++i) {
   1181                     this->lineTo(rrectIter.next());
   1182                     this->conicTo(rectIter.next(), rrectIter.next(), weight);
   1183                 }
   1184             }
   1185             this->close();
   1186 
   1187             SkPathRef::Editor ed(&fPathRef);
   1188             ed.setIsRRect(isRRect, dir, startIndex % 8);
   1189 
   1190             SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
   1191         }
   1192 
   1193         SkDEBUGCODE(fPathRef->validate();)
   1194 }
   1195 
   1196 bool SkPath::hasOnlyMoveTos() const {
   1197     int count = fPathRef->countVerbs();
   1198     const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin();
   1199     for (int i = 0; i < count; ++i) {
   1200         if (*verbs == kLine_Verb ||
   1201             *verbs == kQuad_Verb ||
   1202             *verbs == kConic_Verb ||
   1203             *verbs == kCubic_Verb) {
   1204             return false;
   1205         }
   1206         ++verbs;
   1207     }
   1208     return true;
   1209 }
   1210 
   1211 bool SkPath::isZeroLengthSincePoint(int startPtIndex) const {
   1212     int count = fPathRef->countPoints() - startPtIndex;
   1213     if (count < 2) {
   1214         return true;
   1215     }
   1216     const SkPoint* pts = fPathRef.get()->points() + startPtIndex;
   1217     const SkPoint& first = *pts;
   1218     for (int index = 1; index < count; ++index) {
   1219         if (first != pts[index]) {
   1220             return false;
   1221         }
   1222     }
   1223     return true;
   1224 }
   1225 
   1226 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
   1227                           Direction dir) {
   1228     assert_known_direction(dir);
   1229 
   1230     if (rx < 0 || ry < 0) {
   1231         return;
   1232     }
   1233 
   1234     SkRRect rrect;
   1235     rrect.setRectXY(rect, rx, ry);
   1236     this->addRRect(rrect, dir);
   1237 }
   1238 
   1239 void SkPath::addOval(const SkRect& oval, Direction dir) {
   1240     // legacy start index: 1
   1241     this->addOval(oval, dir, 1);
   1242 }
   1243 
   1244 void SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex) {
   1245     assert_known_direction(dir);
   1246 
   1247     /* If addOval() is called after previous moveTo(),
   1248        this path is still marked as an oval. This is used to
   1249        fit into WebKit's calling sequences.
   1250        We can't simply check isEmpty() in this case, as additional
   1251        moveTo() would mark the path non empty.
   1252      */
   1253     bool isOval = hasOnlyMoveTos();
   1254     if (isOval) {
   1255         fFirstDirection = (SkPathPriv::FirstDirection)dir;
   1256     } else {
   1257         fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
   1258     }
   1259 
   1260     SkAutoDisableDirectionCheck addc(this);
   1261     SkAutoPathBoundsUpdate apbu(this, oval);
   1262 
   1263     SkDEBUGCODE(int initialVerbCount = this->countVerbs());
   1264     const int kVerbs = 6; // moveTo + 4x conicTo + close
   1265     this->incReserve(kVerbs);
   1266 
   1267     OvalPointIterator ovalIter(oval, dir, startPointIndex);
   1268     // The corner iterator pts are tracking "behind" the oval/radii pts.
   1269     RectPointIterator rectIter(oval, dir, startPointIndex + (dir == kCW_Direction ? 0 : 1));
   1270     const SkScalar weight = SK_ScalarRoot2Over2;
   1271 
   1272     this->moveTo(ovalIter.current());
   1273     for (unsigned i = 0; i < 4; ++i) {
   1274         this->conicTo(rectIter.next(), ovalIter.next(), weight);
   1275     }
   1276     this->close();
   1277 
   1278     SkASSERT(this->countVerbs() == initialVerbCount + kVerbs);
   1279 
   1280     SkPathRef::Editor ed(&fPathRef);
   1281 
   1282     ed.setIsOval(isOval, kCCW_Direction == dir, startPointIndex % 4);
   1283 }
   1284 
   1285 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
   1286     if (r > 0) {
   1287         this->addOval(SkRect::MakeLTRB(x - r, y - r, x + r, y + r), dir);
   1288     }
   1289 }
   1290 
   1291 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
   1292                    bool forceMoveTo) {
   1293     if (oval.width() < 0 || oval.height() < 0) {
   1294         return;
   1295     }
   1296 
   1297     if (fPathRef->countVerbs() == 0) {
   1298         forceMoveTo = true;
   1299     }
   1300 
   1301     SkPoint lonePt;
   1302     if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) {
   1303         forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt);
   1304         return;
   1305     }
   1306 
   1307     SkVector startV, stopV;
   1308     SkRotationDirection dir;
   1309     angles_to_unit_vectors(startAngle, sweepAngle, &startV, &stopV, &dir);
   1310 
   1311     SkPoint singlePt;
   1312 
   1313     // Adds a move-to to 'pt' if forceMoveTo is true. Otherwise a lineTo unless we're sufficiently
   1314     // close to 'pt' currently. This prevents spurious lineTos when adding a series of contiguous
   1315     // arcs from the same oval.
   1316     auto addPt = [&forceMoveTo, this](const SkPoint& pt) {
   1317         SkPoint lastPt;
   1318 #ifdef SK_DISABLE_ARC_TO_LINE_TO_CHECK
   1319         static constexpr bool kSkipLineToCheck = true;
   1320 #else
   1321         static constexpr bool kSkipLineToCheck = false;
   1322 #endif
   1323         if (forceMoveTo) {
   1324             this->moveTo(pt);
   1325         } else if (kSkipLineToCheck || !this->getLastPt(&lastPt) ||
   1326                    !SkScalarNearlyEqual(lastPt.fX, pt.fX) ||
   1327                    !SkScalarNearlyEqual(lastPt.fY, pt.fY)) {
   1328             this->lineTo(pt);
   1329         }
   1330     };
   1331 
   1332     // At this point, we know that the arc is not a lone point, but startV == stopV
   1333     // indicates that the sweepAngle is too small such that angles_to_unit_vectors
   1334     // cannot handle it.
   1335     if (startV == stopV) {
   1336         SkScalar endAngle = SkDegreesToRadians(startAngle + sweepAngle);
   1337         SkScalar radiusX = oval.width() / 2;
   1338         SkScalar radiusY = oval.height() / 2;
   1339         // We cannot use SkScalarSinCos function in the next line because
   1340         // SkScalarSinCos has a threshold *SkScalarNearlyZero*. When sin(startAngle)
   1341         // is 0 and sweepAngle is very small and radius is huge, the expected
   1342         // behavior here is to draw a line. But calling SkScalarSinCos will
   1343         // make sin(endAngle) to be 0 which will then draw a dot.
   1344         singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle),
   1345             oval.centerY() + radiusY * sk_float_sin(endAngle));
   1346         addPt(singlePt);
   1347         return;
   1348     }
   1349 
   1350     SkConic conics[SkConic::kMaxConicsForArc];
   1351     int count = build_arc_conics(oval, startV, stopV, dir, conics, &singlePt);
   1352     if (count) {
   1353         this->incReserve(count * 2 + 1);
   1354         const SkPoint& pt = conics[0].fPts[0];
   1355         addPt(pt);
   1356         for (int i = 0; i < count; ++i) {
   1357             this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
   1358         }
   1359     } else {
   1360         addPt(singlePt);
   1361     }
   1362 }
   1363 
   1364 // This converts the SVG arc to conics.
   1365 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
   1366 // Then transcribed from webkit/chrome's SVGPathNormalizer::decomposeArcToCubic()
   1367 // See also SVG implementation notes:
   1368 // http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
   1369 // Note that arcSweep bool value is flipped from the original implementation.
   1370 void SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arcLarge,
   1371                    SkPath::Direction arcSweep, SkScalar x, SkScalar y) {
   1372     this->injectMoveToIfNeeded();
   1373     SkPoint srcPts[2];
   1374     this->getLastPt(&srcPts[0]);
   1375     // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto")
   1376     // joining the endpoints.
   1377     // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
   1378     if (!rx || !ry) {
   1379         this->lineTo(x, y);
   1380         return;
   1381     }
   1382     // If the current point and target point for the arc are identical, it should be treated as a
   1383     // zero length path. This ensures continuity in animations.
   1384     srcPts[1].set(x, y);
   1385     if (srcPts[0] == srcPts[1]) {
   1386         this->lineTo(x, y);
   1387         return;
   1388     }
   1389     rx = SkScalarAbs(rx);
   1390     ry = SkScalarAbs(ry);
   1391     SkVector midPointDistance = srcPts[0] - srcPts[1];
   1392     midPointDistance *= 0.5f;
   1393 
   1394     SkMatrix pointTransform;
   1395     pointTransform.setRotate(-angle);
   1396 
   1397     SkPoint transformedMidPoint;
   1398     pointTransform.mapPoints(&transformedMidPoint, &midPointDistance, 1);
   1399     SkScalar squareRx = rx * rx;
   1400     SkScalar squareRy = ry * ry;
   1401     SkScalar squareX = transformedMidPoint.fX * transformedMidPoint.fX;
   1402     SkScalar squareY = transformedMidPoint.fY * transformedMidPoint.fY;
   1403 
   1404     // Check if the radii are big enough to draw the arc, scale radii if not.
   1405     // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
   1406     SkScalar radiiScale = squareX / squareRx + squareY / squareRy;
   1407     if (radiiScale > 1) {
   1408         radiiScale = SkScalarSqrt(radiiScale);
   1409         rx *= radiiScale;
   1410         ry *= radiiScale;
   1411     }
   1412 
   1413     pointTransform.setScale(1 / rx, 1 / ry);
   1414     pointTransform.preRotate(-angle);
   1415 
   1416     SkPoint unitPts[2];
   1417     pointTransform.mapPoints(unitPts, srcPts, (int) SK_ARRAY_COUNT(unitPts));
   1418     SkVector delta = unitPts[1] - unitPts[0];
   1419 
   1420     SkScalar d = delta.fX * delta.fX + delta.fY * delta.fY;
   1421     SkScalar scaleFactorSquared = SkTMax(1 / d - 0.25f, 0.f);
   1422 
   1423     SkScalar scaleFactor = SkScalarSqrt(scaleFactorSquared);
   1424     if (SkToBool(arcSweep) != SkToBool(arcLarge)) {  // flipped from the original implementation
   1425         scaleFactor = -scaleFactor;
   1426     }
   1427     delta.scale(scaleFactor);
   1428     SkPoint centerPoint = unitPts[0] + unitPts[1];
   1429     centerPoint *= 0.5f;
   1430     centerPoint.offset(-delta.fY, delta.fX);
   1431     unitPts[0] -= centerPoint;
   1432     unitPts[1] -= centerPoint;
   1433     SkScalar theta1 = SkScalarATan2(unitPts[0].fY, unitPts[0].fX);
   1434     SkScalar theta2 = SkScalarATan2(unitPts[1].fY, unitPts[1].fX);
   1435     SkScalar thetaArc = theta2 - theta1;
   1436     if (thetaArc < 0 && !arcSweep) {  // arcSweep flipped from the original implementation
   1437         thetaArc += SK_ScalarPI * 2;
   1438     } else if (thetaArc > 0 && arcSweep) {  // arcSweep flipped from the original implementation
   1439         thetaArc -= SK_ScalarPI * 2;
   1440     }
   1441     pointTransform.setRotate(angle);
   1442     pointTransform.preScale(rx, ry);
   1443 
   1444 #ifdef SK_SUPPORT_LEGACY_SVG_ARC_TO
   1445     int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (SK_ScalarPI / 2)));
   1446 #else
   1447     // the arc may be slightly bigger than 1/4 circle, so allow up to 1/3rd
   1448     int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (2 * SK_ScalarPI / 3)));
   1449 #endif
   1450     SkScalar thetaWidth = thetaArc / segments;
   1451     SkScalar t = SkScalarTan(0.5f * thetaWidth);
   1452     if (!SkScalarIsFinite(t)) {
   1453         return;
   1454     }
   1455     SkScalar startTheta = theta1;
   1456     SkScalar w = SkScalarSqrt(SK_ScalarHalf + SkScalarCos(thetaWidth) * SK_ScalarHalf);
   1457 #ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO
   1458     auto scalar_is_integer = [](SkScalar scalar) -> bool {
   1459         return scalar == SkScalarFloorToScalar(scalar);
   1460     };
   1461     bool expectIntegers = SkScalarNearlyZero(SK_ScalarPI/2 - SkScalarAbs(thetaWidth)) &&
   1462         scalar_is_integer(rx) && scalar_is_integer(ry) &&
   1463         scalar_is_integer(x) && scalar_is_integer(y);
   1464 #endif
   1465     for (int i = 0; i < segments; ++i) {
   1466         SkScalar endTheta = startTheta + thetaWidth;
   1467         SkScalar cosEndTheta, sinEndTheta = SkScalarSinCos(endTheta, &cosEndTheta);
   1468 
   1469         unitPts[1].set(cosEndTheta, sinEndTheta);
   1470         unitPts[1] += centerPoint;
   1471         unitPts[0] = unitPts[1];
   1472         unitPts[0].offset(t * sinEndTheta, -t * cosEndTheta);
   1473         SkPoint mapped[2];
   1474         pointTransform.mapPoints(mapped, unitPts, (int) SK_ARRAY_COUNT(unitPts));
   1475         /*
   1476         Computing the arc width introduces rounding errors that cause arcs to start
   1477         outside their marks. A round rect may lose convexity as a result. If the input
   1478         values are on integers, place the conic on integers as well.
   1479          */
   1480 #ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO
   1481         if (expectIntegers) {
   1482             SkScalar* mappedScalars = &mapped[0].fX;
   1483             for (unsigned index = 0; index < sizeof(mapped) / sizeof(SkScalar); ++index) {
   1484                 mappedScalars[index] = SkScalarRoundToScalar(mappedScalars[index]);
   1485             }
   1486         }
   1487 #endif
   1488         this->conicTo(mapped[0], mapped[1], w);
   1489         startTheta = endTheta;
   1490     }
   1491 }
   1492 
   1493 void SkPath::rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, SkPath::ArcSize largeArc,
   1494                     SkPath::Direction sweep, SkScalar dx, SkScalar dy) {
   1495     SkPoint currentPoint;
   1496     this->getLastPt(&currentPoint);
   1497     this->arcTo(rx, ry, xAxisRotate, largeArc, sweep, currentPoint.fX + dx, currentPoint.fY + dy);
   1498 }
   1499 
   1500 void SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) {
   1501     if (oval.isEmpty() || 0 == sweepAngle) {
   1502         return;
   1503     }
   1504 
   1505     const SkScalar kFullCircleAngle = SkIntToScalar(360);
   1506 
   1507     if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
   1508         // We can treat the arc as an oval if it begins at one of our legal starting positions.
   1509         // See SkPath::addOval() docs.
   1510         SkScalar startOver90 = startAngle / 90.f;
   1511         SkScalar startOver90I = SkScalarRoundToScalar(startOver90);
   1512         SkScalar error = startOver90 - startOver90I;
   1513         if (SkScalarNearlyEqual(error, 0)) {
   1514             // Index 1 is at startAngle == 0.
   1515             SkScalar startIndex = std::fmod(startOver90I + 1.f, 4.f);
   1516             startIndex = startIndex < 0 ? startIndex + 4.f : startIndex;
   1517             this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction,
   1518                           (unsigned) startIndex);
   1519             return;
   1520         }
   1521     }
   1522     this->arcTo(oval, startAngle, sweepAngle, true);
   1523 }
   1524 
   1525 /*
   1526     Need to handle the case when the angle is sharp, and our computed end-points
   1527     for the arc go behind pt1 and/or p2...
   1528 */
   1529 void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) {
   1530     if (radius == 0) {
   1531         this->lineTo(x1, y1);
   1532         return;
   1533     }
   1534 
   1535     SkVector before, after;
   1536 
   1537     // need to know our prev pt so we can construct tangent vectors
   1538     {
   1539         SkPoint start;
   1540         this->getLastPt(&start);
   1541         // Handle degenerate cases by adding a line to the first point and
   1542         // bailing out.
   1543         before.setNormalize(x1 - start.fX, y1 - start.fY);
   1544         after.setNormalize(x2 - x1, y2 - y1);
   1545     }
   1546 
   1547     SkScalar cosh = SkPoint::DotProduct(before, after);
   1548     SkScalar sinh = SkPoint::CrossProduct(before, after);
   1549 
   1550     if (SkScalarNearlyZero(sinh)) {   // angle is too tight
   1551         this->lineTo(x1, y1);
   1552         return;
   1553     }
   1554 
   1555     SkScalar dist = SkScalarAbs(radius * (1 - cosh) / sinh);
   1556 
   1557     SkScalar xx = x1 - dist * before.fX;
   1558     SkScalar yy = y1 - dist * before.fY;
   1559     after.setLength(dist);
   1560     this->lineTo(xx, yy);
   1561     SkScalar weight = SkScalarSqrt(SK_ScalarHalf + cosh * SK_ScalarHalf);
   1562     this->conicTo(x1, y1, x1 + after.fX, y1 + after.fY, weight);
   1563 }
   1564 
   1565 ///////////////////////////////////////////////////////////////////////////////
   1566 
   1567 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy, AddPathMode mode) {
   1568     SkMatrix matrix;
   1569 
   1570     matrix.setTranslate(dx, dy);
   1571     this->addPath(path, matrix, mode);
   1572 }
   1573 
   1574 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix, AddPathMode mode) {
   1575     SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
   1576 
   1577     RawIter iter(path);
   1578     SkPoint pts[4];
   1579     Verb    verb;
   1580 
   1581     SkMatrixPriv::MapPtsProc proc = SkMatrixPriv::GetMapPtsProc(matrix);
   1582     bool firstVerb = true;
   1583     while ((verb = iter.next(pts)) != kDone_Verb) {
   1584         switch (verb) {
   1585             case kMove_Verb:
   1586                 proc(matrix, &pts[0], &pts[0], 1);
   1587                 if (firstVerb && mode == kExtend_AddPathMode && !isEmpty()) {
   1588                     injectMoveToIfNeeded(); // In case last contour is closed
   1589                     this->lineTo(pts[0]);
   1590                 } else {
   1591                     this->moveTo(pts[0]);
   1592                 }
   1593                 break;
   1594             case kLine_Verb:
   1595                 proc(matrix, &pts[1], &pts[1], 1);
   1596                 this->lineTo(pts[1]);
   1597                 break;
   1598             case kQuad_Verb:
   1599                 proc(matrix, &pts[1], &pts[1], 2);
   1600                 this->quadTo(pts[1], pts[2]);
   1601                 break;
   1602             case kConic_Verb:
   1603                 proc(matrix, &pts[1], &pts[1], 2);
   1604                 this->conicTo(pts[1], pts[2], iter.conicWeight());
   1605                 break;
   1606             case kCubic_Verb:
   1607                 proc(matrix, &pts[1], &pts[1], 3);
   1608                 this->cubicTo(pts[1], pts[2], pts[3]);
   1609                 break;
   1610             case kClose_Verb:
   1611                 this->close();
   1612                 break;
   1613             default:
   1614                 SkDEBUGFAIL("unknown verb");
   1615         }
   1616         firstVerb = false;
   1617     }
   1618 }
   1619 
   1620 ///////////////////////////////////////////////////////////////////////////////
   1621 
   1622 static int pts_in_verb(unsigned verb) {
   1623     static const uint8_t gPtsInVerb[] = {
   1624         1,  // kMove
   1625         1,  // kLine
   1626         2,  // kQuad
   1627         2,  // kConic
   1628         3,  // kCubic
   1629         0,  // kClose
   1630         0   // kDone
   1631     };
   1632 
   1633     SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
   1634     return gPtsInVerb[verb];
   1635 }
   1636 
   1637 // ignore the last point of the 1st contour
   1638 void SkPath::reversePathTo(const SkPath& path) {
   1639     const uint8_t* verbs = path.fPathRef->verbsMemBegin(); // points at the last verb
   1640     if (!verbs) {  // empty path returns nullptr
   1641         return;
   1642     }
   1643     const uint8_t* verbsEnd = path.fPathRef->verbs() - 1; // points just past the first verb
   1644     SkASSERT(verbsEnd[0] == kMove_Verb);
   1645     const SkPoint*  pts = path.fPathRef->pointsEnd() - 1;
   1646     const SkScalar* conicWeights = path.fPathRef->conicWeightsEnd();
   1647 
   1648     while (verbs < verbsEnd) {
   1649         uint8_t v = *verbs++;
   1650         pts -= pts_in_verb(v);
   1651         switch (v) {
   1652             case kMove_Verb:
   1653                 // if the path has multiple contours, stop after reversing the last
   1654                 return;
   1655             case kLine_Verb:
   1656                 this->lineTo(pts[0]);
   1657                 break;
   1658             case kQuad_Verb:
   1659                 this->quadTo(pts[1], pts[0]);
   1660                 break;
   1661             case kConic_Verb:
   1662                 this->conicTo(pts[1], pts[0], *--conicWeights);
   1663                 break;
   1664             case kCubic_Verb:
   1665                 this->cubicTo(pts[2], pts[1], pts[0]);
   1666                 break;
   1667             case kClose_Verb:
   1668                 SkASSERT(verbs - path.fPathRef->verbsMemBegin() == 1);
   1669                 break;
   1670             default:
   1671                 SkDEBUGFAIL("bad verb");
   1672                 break;
   1673         }
   1674     }
   1675 }
   1676 
   1677 void SkPath::reverseAddPath(const SkPath& src) {
   1678     SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs());
   1679 
   1680     const SkPoint* pts = src.fPathRef->pointsEnd();
   1681     // we will iterator through src's verbs backwards
   1682     const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
   1683     const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb
   1684     const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
   1685 
   1686     bool needMove = true;
   1687     bool needClose = false;
   1688     while (verbs < verbsEnd) {
   1689         uint8_t v = *(verbs++);
   1690         int n = pts_in_verb(v);
   1691 
   1692         if (needMove) {
   1693             --pts;
   1694             this->moveTo(pts->fX, pts->fY);
   1695             needMove = false;
   1696         }
   1697         pts -= n;
   1698         switch (v) {
   1699             case kMove_Verb:
   1700                 if (needClose) {
   1701                     this->close();
   1702                     needClose = false;
   1703                 }
   1704                 needMove = true;
   1705                 pts += 1;   // so we see the point in "if (needMove)" above
   1706                 break;
   1707             case kLine_Verb:
   1708                 this->lineTo(pts[0]);
   1709                 break;
   1710             case kQuad_Verb:
   1711                 this->quadTo(pts[1], pts[0]);
   1712                 break;
   1713             case kConic_Verb:
   1714                 this->conicTo(pts[1], pts[0], *--conicWeights);
   1715                 break;
   1716             case kCubic_Verb:
   1717                 this->cubicTo(pts[2], pts[1], pts[0]);
   1718                 break;
   1719             case kClose_Verb:
   1720                 needClose = true;
   1721                 break;
   1722             default:
   1723                 SkDEBUGFAIL("unexpected verb");
   1724         }
   1725     }
   1726 }
   1727 
   1728 ///////////////////////////////////////////////////////////////////////////////
   1729 
   1730 void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
   1731     SkMatrix    matrix;
   1732 
   1733     matrix.setTranslate(dx, dy);
   1734     this->transform(matrix, dst);
   1735 }
   1736 
   1737 static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
   1738                                int level = 2) {
   1739     if (--level >= 0) {
   1740         SkPoint tmp[7];
   1741 
   1742         SkChopCubicAtHalf(pts, tmp);
   1743         subdivide_cubic_to(path, &tmp[0], level);
   1744         subdivide_cubic_to(path, &tmp[3], level);
   1745     } else {
   1746         path->cubicTo(pts[1], pts[2], pts[3]);
   1747     }
   1748 }
   1749 
   1750 void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
   1751     SkDEBUGCODE(this->validate();)
   1752     if (dst == nullptr) {
   1753         dst = (SkPath*)this;
   1754     }
   1755 
   1756     if (matrix.hasPerspective()) {
   1757         SkPath  tmp;
   1758         tmp.fFillType = fFillType;
   1759 
   1760         SkPath::Iter    iter(*this, false);
   1761         SkPoint         pts[4];
   1762         SkPath::Verb    verb;
   1763 
   1764         while ((verb = iter.next(pts, false)) != kDone_Verb) {
   1765             switch (verb) {
   1766                 case kMove_Verb:
   1767                     tmp.moveTo(pts[0]);
   1768                     break;
   1769                 case kLine_Verb:
   1770                     tmp.lineTo(pts[1]);
   1771                     break;
   1772                 case kQuad_Verb:
   1773                     // promote the quad to a conic
   1774                     tmp.conicTo(pts[1], pts[2],
   1775                                 SkConic::TransformW(pts, SK_Scalar1, matrix));
   1776                     break;
   1777                 case kConic_Verb:
   1778                     tmp.conicTo(pts[1], pts[2],
   1779                                 SkConic::TransformW(pts, iter.conicWeight(), matrix));
   1780                     break;
   1781                 case kCubic_Verb:
   1782                     subdivide_cubic_to(&tmp, pts);
   1783                     break;
   1784                 case kClose_Verb:
   1785                     tmp.close();
   1786                     break;
   1787                 default:
   1788                     SkDEBUGFAIL("unknown verb");
   1789                     break;
   1790             }
   1791         }
   1792 
   1793         dst->swap(tmp);
   1794         SkPathRef::Editor ed(&dst->fPathRef);
   1795         matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
   1796         dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
   1797     } else {
   1798         SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix);
   1799 
   1800         if (this != dst) {
   1801             dst->fFillType = fFillType;
   1802             dst->fConvexity.store(fConvexity);
   1803             dst->fIsVolatile = fIsVolatile;
   1804         }
   1805 
   1806         if (SkPathPriv::kUnknown_FirstDirection == fFirstDirection) {
   1807             dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
   1808         } else {
   1809             SkScalar det2x2 =
   1810                 matrix.get(SkMatrix::kMScaleX) * matrix.get(SkMatrix::kMScaleY) -
   1811                 matrix.get(SkMatrix::kMSkewX)  * matrix.get(SkMatrix::kMSkewY);
   1812             if (det2x2 < 0) {
   1813                 dst->fFirstDirection = SkPathPriv::OppositeFirstDirection(
   1814                         (SkPathPriv::FirstDirection)fFirstDirection.load());
   1815             } else if (det2x2 > 0) {
   1816                 dst->fFirstDirection = fFirstDirection.load();
   1817             } else {
   1818                 dst->fConvexity = kUnknown_Convexity;
   1819                 dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
   1820             }
   1821         }
   1822 
   1823         SkDEBUGCODE(dst->validate();)
   1824     }
   1825 }
   1826 
   1827 ///////////////////////////////////////////////////////////////////////////////
   1828 ///////////////////////////////////////////////////////////////////////////////
   1829 
   1830 enum SegmentState {
   1831     kEmptyContour_SegmentState,   // The current contour is empty. We may be
   1832                                   // starting processing or we may have just
   1833                                   // closed a contour.
   1834     kAfterMove_SegmentState,      // We have seen a move, but nothing else.
   1835     kAfterPrimitive_SegmentState  // We have seen a primitive but not yet
   1836                                   // closed the path. Also the initial state.
   1837 };
   1838 
   1839 SkPath::Iter::Iter() {
   1840 #ifdef SK_DEBUG
   1841     fPts = nullptr;
   1842     fConicWeights = nullptr;
   1843     fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
   1844     fForceClose = fCloseLine = false;
   1845     fSegmentState = kEmptyContour_SegmentState;
   1846 #endif
   1847     // need to init enough to make next() harmlessly return kDone_Verb
   1848     fVerbs = nullptr;
   1849     fVerbStop = nullptr;
   1850     fNeedClose = false;
   1851 }
   1852 
   1853 SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
   1854     this->setPath(path, forceClose);
   1855 }
   1856 
   1857 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
   1858     fPts = path.fPathRef->points();
   1859     fVerbs = path.fPathRef->verbs();
   1860     fVerbStop = path.fPathRef->verbsMemBegin();
   1861     fConicWeights = path.fPathRef->conicWeights();
   1862     if (fConicWeights) {
   1863       fConicWeights -= 1;  // begin one behind
   1864     }
   1865     fLastPt.fX = fLastPt.fY = 0;
   1866     fMoveTo.fX = fMoveTo.fY = 0;
   1867     fForceClose = SkToU8(forceClose);
   1868     fNeedClose = false;
   1869     fSegmentState = kEmptyContour_SegmentState;
   1870 }
   1871 
   1872 bool SkPath::Iter::isClosedContour() const {
   1873     if (fVerbs == nullptr || fVerbs == fVerbStop) {
   1874         return false;
   1875     }
   1876     if (fForceClose) {
   1877         return true;
   1878     }
   1879 
   1880     const uint8_t* verbs = fVerbs;
   1881     const uint8_t* stop = fVerbStop;
   1882 
   1883     if (kMove_Verb == *(verbs - 1)) {
   1884         verbs -= 1; // skip the initial moveto
   1885     }
   1886 
   1887     while (verbs > stop) {
   1888         // verbs points one beyond the current verb, decrement first.
   1889         unsigned v = *(--verbs);
   1890         if (kMove_Verb == v) {
   1891             break;
   1892         }
   1893         if (kClose_Verb == v) {
   1894             return true;
   1895         }
   1896     }
   1897     return false;
   1898 }
   1899 
   1900 SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
   1901     SkASSERT(pts);
   1902     if (fLastPt != fMoveTo) {
   1903         // A special case: if both points are NaN, SkPoint::operation== returns
   1904         // false, but the iterator expects that they are treated as the same.
   1905         // (consider SkPoint is a 2-dimension float point).
   1906         if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
   1907             SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
   1908             return kClose_Verb;
   1909         }
   1910 
   1911         pts[0] = fLastPt;
   1912         pts[1] = fMoveTo;
   1913         fLastPt = fMoveTo;
   1914         fCloseLine = true;
   1915         return kLine_Verb;
   1916     } else {
   1917         pts[0] = fMoveTo;
   1918         return kClose_Verb;
   1919     }
   1920 }
   1921 
   1922 const SkPoint& SkPath::Iter::cons_moveTo() {
   1923     if (fSegmentState == kAfterMove_SegmentState) {
   1924         // Set the first return pt to the move pt
   1925         fSegmentState = kAfterPrimitive_SegmentState;
   1926         return fMoveTo;
   1927     } else {
   1928         SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
   1929          // Set the first return pt to the last pt of the previous primitive.
   1930         return fPts[-1];
   1931     }
   1932 }
   1933 
   1934 void SkPath::Iter::consumeDegenerateSegments(bool exact) {
   1935     // We need to step over anything that will not move the current draw point
   1936     // forward before the next move is seen
   1937     const uint8_t* lastMoveVerb = nullptr;
   1938     const SkPoint* lastMovePt = nullptr;
   1939     const SkScalar* lastMoveWeight = nullptr;
   1940     SkPoint lastPt = fLastPt;
   1941     while (fVerbs != fVerbStop) {
   1942         unsigned verb = *(fVerbs - 1); // fVerbs is one beyond the current verb
   1943         switch (verb) {
   1944             case kMove_Verb:
   1945                 // Keep a record of this most recent move
   1946                 lastMoveVerb = fVerbs;
   1947                 lastMovePt = fPts;
   1948                 lastMoveWeight = fConicWeights;
   1949                 lastPt = fPts[0];
   1950                 fVerbs--;
   1951                 fPts++;
   1952                 break;
   1953 
   1954             case kClose_Verb:
   1955                 // A close when we are in a segment is always valid except when it
   1956                 // follows a move which follows a segment.
   1957                 if (fSegmentState == kAfterPrimitive_SegmentState && !lastMoveVerb) {
   1958                     return;
   1959                 }
   1960                 // A close at any other time must be ignored
   1961                 fVerbs--;
   1962                 break;
   1963 
   1964             case kLine_Verb:
   1965                 if (!IsLineDegenerate(lastPt, fPts[0], exact)) {
   1966                     if (lastMoveVerb) {
   1967                         fVerbs = lastMoveVerb;
   1968                         fPts = lastMovePt;
   1969                         fConicWeights = lastMoveWeight;
   1970                         return;
   1971                     }
   1972                     return;
   1973                 }
   1974                 // Ignore this line and continue
   1975                 fVerbs--;
   1976                 fPts++;
   1977                 break;
   1978 
   1979             case kConic_Verb:
   1980             case kQuad_Verb:
   1981                 if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1], exact)) {
   1982                     if (lastMoveVerb) {
   1983                         fVerbs = lastMoveVerb;
   1984                         fPts = lastMovePt;
   1985                         fConicWeights = lastMoveWeight;
   1986                         return;
   1987                     }
   1988                     return;
   1989                 }
   1990                 // Ignore this line and continue
   1991                 fVerbs--;
   1992                 fPts += 2;
   1993                 fConicWeights += (kConic_Verb == verb);
   1994                 break;
   1995 
   1996             case kCubic_Verb:
   1997                 if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2], exact)) {
   1998                     if (lastMoveVerb) {
   1999                         fVerbs = lastMoveVerb;
   2000                         fPts = lastMovePt;
   2001                         fConicWeights = lastMoveWeight;
   2002                         return;
   2003                     }
   2004                     return;
   2005                 }
   2006                 // Ignore this line and continue
   2007                 fVerbs--;
   2008                 fPts += 3;
   2009                 break;
   2010 
   2011             default:
   2012                 SkDEBUGFAIL("Should never see kDone_Verb");
   2013         }
   2014     }
   2015 }
   2016 
   2017 SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
   2018     SkASSERT(ptsParam);
   2019 
   2020     if (fVerbs == fVerbStop) {
   2021         // Close the curve if requested and if there is some curve to close
   2022         if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
   2023             if (kLine_Verb == this->autoClose(ptsParam)) {
   2024                 return kLine_Verb;
   2025             }
   2026             fNeedClose = false;
   2027             return kClose_Verb;
   2028         }
   2029         return kDone_Verb;
   2030     }
   2031 
   2032     // fVerbs is one beyond the current verb, decrement first
   2033     unsigned verb = *(--fVerbs);
   2034     const SkPoint* SK_RESTRICT srcPts = fPts;
   2035     SkPoint* SK_RESTRICT       pts = ptsParam;
   2036 
   2037     switch (verb) {
   2038         case kMove_Verb:
   2039             if (fNeedClose) {
   2040                 fVerbs++; // move back one verb
   2041                 verb = this->autoClose(pts);
   2042                 if (verb == kClose_Verb) {
   2043                     fNeedClose = false;
   2044                 }
   2045                 return (Verb)verb;
   2046             }
   2047             if (fVerbs == fVerbStop) {    // might be a trailing moveto
   2048                 return kDone_Verb;
   2049             }
   2050             fMoveTo = *srcPts;
   2051             pts[0] = *srcPts;
   2052             srcPts += 1;
   2053             fSegmentState = kAfterMove_SegmentState;
   2054             fLastPt = fMoveTo;
   2055             fNeedClose = fForceClose;
   2056             break;
   2057         case kLine_Verb:
   2058             pts[0] = this->cons_moveTo();
   2059             pts[1] = srcPts[0];
   2060             fLastPt = srcPts[0];
   2061             fCloseLine = false;
   2062             srcPts += 1;
   2063             break;
   2064         case kConic_Verb:
   2065             fConicWeights += 1;
   2066             // fall-through
   2067         case kQuad_Verb:
   2068             pts[0] = this->cons_moveTo();
   2069             memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
   2070             fLastPt = srcPts[1];
   2071             srcPts += 2;
   2072             break;
   2073         case kCubic_Verb:
   2074             pts[0] = this->cons_moveTo();
   2075             memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
   2076             fLastPt = srcPts[2];
   2077             srcPts += 3;
   2078             break;
   2079         case kClose_Verb:
   2080             verb = this->autoClose(pts);
   2081             if (verb == kLine_Verb) {
   2082                 fVerbs++; // move back one verb
   2083             } else {
   2084                 fNeedClose = false;
   2085                 fSegmentState = kEmptyContour_SegmentState;
   2086             }
   2087             fLastPt = fMoveTo;
   2088             break;
   2089     }
   2090     fPts = srcPts;
   2091     return (Verb)verb;
   2092 }
   2093 
   2094 ///////////////////////////////////////////////////////////////////////////////
   2095 
   2096 #include "SkString.h"
   2097 #include "SkStringUtils.h"
   2098 #include "SkStream.h"
   2099 
   2100 static void append_params(SkString* str, const char label[], const SkPoint pts[],
   2101                           int count, SkScalarAsStringType strType, SkScalar conicWeight = -12345) {
   2102     str->append(label);
   2103     str->append("(");
   2104 
   2105     const SkScalar* values = &pts[0].fX;
   2106     count *= 2;
   2107 
   2108     for (int i = 0; i < count; ++i) {
   2109         SkAppendScalar(str, values[i], strType);
   2110         if (i < count - 1) {
   2111             str->append(", ");
   2112         }
   2113     }
   2114     if (conicWeight != -12345) {
   2115         str->append(", ");
   2116         SkAppendScalar(str, conicWeight, strType);
   2117     }
   2118     str->append(");");
   2119     if (kHex_SkScalarAsStringType == strType) {
   2120         str->append("  // ");
   2121         for (int i = 0; i < count; ++i) {
   2122             SkAppendScalarDec(str, values[i]);
   2123             if (i < count - 1) {
   2124                 str->append(", ");
   2125             }
   2126         }
   2127         if (conicWeight >= 0) {
   2128             str->append(", ");
   2129             SkAppendScalarDec(str, conicWeight);
   2130         }
   2131     }
   2132     str->append("\n");
   2133 }
   2134 
   2135 void SkPath::dump(SkWStream* wStream, bool forceClose, bool dumpAsHex) const {
   2136     SkScalarAsStringType asType = dumpAsHex ? kHex_SkScalarAsStringType : kDec_SkScalarAsStringType;
   2137     Iter    iter(*this, forceClose);
   2138     SkPoint pts[4];
   2139     Verb    verb;
   2140 
   2141     SkString builder;
   2142     char const * const gFillTypeStrs[] = {
   2143         "Winding",
   2144         "EvenOdd",
   2145         "InverseWinding",
   2146         "InverseEvenOdd",
   2147     };
   2148     builder.printf("path.setFillType(SkPath::k%s_FillType);\n",
   2149             gFillTypeStrs[(int) this->getFillType()]);
   2150     while ((verb = iter.next(pts, false)) != kDone_Verb) {
   2151         switch (verb) {
   2152             case kMove_Verb:
   2153                 append_params(&builder, "path.moveTo", &pts[0], 1, asType);
   2154                 break;
   2155             case kLine_Verb:
   2156                 append_params(&builder, "path.lineTo", &pts[1], 1, asType);
   2157                 break;
   2158             case kQuad_Verb:
   2159                 append_params(&builder, "path.quadTo", &pts[1], 2, asType);
   2160                 break;
   2161             case kConic_Verb:
   2162                 append_params(&builder, "path.conicTo", &pts[1], 2, asType, iter.conicWeight());
   2163                 break;
   2164             case kCubic_Verb:
   2165                 append_params(&builder, "path.cubicTo", &pts[1], 3, asType);
   2166                 break;
   2167             case kClose_Verb:
   2168                 builder.append("path.close();\n");
   2169                 break;
   2170             default:
   2171                 SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
   2172                 verb = kDone_Verb;  // stop the loop
   2173                 break;
   2174         }
   2175         if (!wStream && builder.size()) {
   2176             SkDebugf("%s", builder.c_str());
   2177             builder.reset();
   2178         }
   2179     }
   2180     if (wStream) {
   2181         wStream->writeText(builder.c_str());
   2182     }
   2183 }
   2184 
   2185 void SkPath::dump() const {
   2186     this->dump(nullptr, false, false);
   2187 }
   2188 
   2189 void SkPath::dumpHex() const {
   2190     this->dump(nullptr, false, true);
   2191 }
   2192 
   2193 
   2194 bool SkPath::isValidImpl() const {
   2195     if ((fFillType & ~3) != 0) {
   2196         return false;
   2197     }
   2198 
   2199 #ifdef SK_DEBUG_PATH
   2200     if (!fBoundsIsDirty) {
   2201         SkRect bounds;
   2202 
   2203         bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
   2204         if (SkToBool(fIsFinite) != isFinite) {
   2205             return false;
   2206         }
   2207 
   2208         if (fPathRef->countPoints() <= 1) {
   2209             // if we're empty, fBounds may be empty but translated, so we can't
   2210             // necessarily compare to bounds directly
   2211             // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
   2212             // be [2, 2, 2, 2]
   2213             if (!bounds.isEmpty() || !fBounds.isEmpty()) {
   2214                 return false;
   2215             }
   2216         } else {
   2217             if (bounds.isEmpty()) {
   2218                 if (!fBounds.isEmpty()) {
   2219                     return false;
   2220                 }
   2221             } else {
   2222                 if (!fBounds.isEmpty()) {
   2223                     if (!fBounds.contains(bounds)) {
   2224                         return false;
   2225                     }
   2226                 }
   2227             }
   2228         }
   2229     }
   2230 #endif // SK_DEBUG_PATH
   2231     return true;
   2232 }
   2233 
   2234 ///////////////////////////////////////////////////////////////////////////////
   2235 
   2236 static int sign(SkScalar x) { return x < 0; }
   2237 #define kValueNeverReturnedBySign   2
   2238 
   2239 enum DirChange {
   2240     kLeft_DirChange,
   2241     kRight_DirChange,
   2242     kStraight_DirChange,
   2243     kBackwards_DirChange,
   2244 
   2245     kInvalid_DirChange
   2246 };
   2247 
   2248 
   2249 static bool almost_equal(SkScalar compA, SkScalar compB) {
   2250     // The error epsilon was empirically derived; worse case round rects
   2251     // with a mid point outset by 2x float epsilon in tests had an error
   2252     // of 12.
   2253     const int epsilon = 16;
   2254     if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
   2255         return false;
   2256     }
   2257     // no need to check for small numbers because SkPath::Iter has removed degenerate values
   2258     int aBits = SkFloatAs2sCompliment(compA);
   2259     int bBits = SkFloatAs2sCompliment(compB);
   2260     return aBits < bBits + epsilon && bBits < aBits + epsilon;
   2261 }
   2262 
   2263 static bool approximately_zero_when_compared_to(double x, double y) {
   2264     return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
   2265 }
   2266 
   2267 
   2268 // only valid for a single contour
   2269 struct Convexicator {
   2270     Convexicator()
   2271     : fPtCount(0)
   2272     , fConvexity(SkPath::kConvex_Convexity)
   2273     , fFirstDirection(SkPathPriv::kUnknown_FirstDirection)
   2274     , fIsFinite(true)
   2275     , fIsCurve(false)
   2276     , fBackwards(false) {
   2277         fExpectedDir = kInvalid_DirChange;
   2278         // warnings
   2279         fPriorPt.set(0,0);
   2280         fLastPt.set(0, 0);
   2281         fCurrPt.set(0, 0);
   2282         fLastVec.set(0, 0);
   2283         fFirstVec.set(0, 0);
   2284 
   2285         fDx = fDy = 0;
   2286         fSx = fSy = kValueNeverReturnedBySign;
   2287     }
   2288 
   2289     SkPath::Convexity getConvexity() const { return fConvexity; }
   2290 
   2291     /** The direction returned is only valid if the path is determined convex */
   2292     SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirection; }
   2293 
   2294     void addPt(const SkPoint& pt) {
   2295         if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) {
   2296             return;
   2297         }
   2298 
   2299         if (0 == fPtCount) {
   2300             fCurrPt = pt;
   2301             ++fPtCount;
   2302         } else {
   2303             SkVector vec = pt - fCurrPt;
   2304             SkScalar lengthSqd = SkPointPriv::LengthSqd(vec);
   2305             if (!SkScalarIsFinite(lengthSqd)) {
   2306                 fIsFinite = false;
   2307             } else if (lengthSqd) {
   2308                 fPriorPt = fLastPt;
   2309                 fLastPt = fCurrPt;
   2310                 fCurrPt = pt;
   2311                 if (++fPtCount == 2) {
   2312                     fFirstVec = fLastVec = vec;
   2313                 } else {
   2314                     SkASSERT(fPtCount > 2);
   2315                     this->addVec(vec);
   2316                 }
   2317 
   2318                 int sx = sign(vec.fX);
   2319                 int sy = sign(vec.fY);
   2320                 fDx += (sx != fSx);
   2321                 fDy += (sy != fSy);
   2322                 fSx = sx;
   2323                 fSy = sy;
   2324 
   2325                 if (fDx > 3 || fDy > 3) {
   2326                     fConvexity = SkPath::kConcave_Convexity;
   2327                 }
   2328             }
   2329         }
   2330     }
   2331 
   2332     void close() {
   2333         if (fPtCount > 2) {
   2334             this->addVec(fFirstVec);
   2335         }
   2336     }
   2337 
   2338     DirChange directionChange(const SkVector& curVec) {
   2339         SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec);
   2340 
   2341         SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY)));
   2342         SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY)));
   2343         largest = SkTMax(largest, -smallest);
   2344 
   2345         if (!almost_equal(largest, largest + cross)) {
   2346             int sign = SkScalarSignAsInt(cross);
   2347             if (sign) {
   2348                 return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
   2349             }
   2350         }
   2351 
   2352         if (cross) {
   2353             double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX);
   2354             double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY);
   2355             double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX);
   2356             double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY);
   2357             double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX;
   2358             if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) {
   2359                 int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross));
   2360                 if (sign) {
   2361                     return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
   2362                 }
   2363             }
   2364         }
   2365 
   2366         if (!SkScalarNearlyZero(SkPointPriv::LengthSqd(fLastVec),
   2367                                 SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
   2368             !SkScalarNearlyZero(SkPointPriv::LengthSqd(curVec),
   2369                                 SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
   2370             fLastVec.dot(curVec) < 0.0f) {
   2371             return kBackwards_DirChange;
   2372         }
   2373 
   2374         return kStraight_DirChange;
   2375     }
   2376 
   2377     bool hasBackwards() const {
   2378         return fBackwards;
   2379     }
   2380 
   2381     bool isFinite() const {
   2382         return fIsFinite;
   2383     }
   2384 
   2385     void setCurve(bool isCurve) {
   2386         fIsCurve = isCurve;
   2387     }
   2388 
   2389 private:
   2390     void addVec(const SkVector& vec) {
   2391         SkASSERT(vec.fX || vec.fY);
   2392         DirChange dir = this->directionChange(vec);
   2393         switch (dir) {
   2394             case kLeft_DirChange:       // fall through
   2395             case kRight_DirChange:
   2396                 if (kInvalid_DirChange == fExpectedDir) {
   2397                     fExpectedDir = dir;
   2398                     fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kCW_FirstDirection
   2399                                                                 : SkPathPriv::kCCW_FirstDirection;
   2400                 } else if (dir != fExpectedDir) {
   2401                     fConvexity = SkPath::kConcave_Convexity;
   2402                     fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
   2403                 }
   2404                 fLastVec = vec;
   2405                 break;
   2406             case kStraight_DirChange:
   2407                 break;
   2408             case kBackwards_DirChange:
   2409                 if (fIsCurve) {
   2410                     // If any of the subsequent dir is non-backward, it'll be concave.
   2411                     // Otherwise, it's still convex.
   2412                     fExpectedDir = dir;
   2413                 }
   2414                 fLastVec = vec;
   2415                 fBackwards = true;
   2416                 break;
   2417             case kInvalid_DirChange:
   2418                 SK_ABORT("Use of invalid direction change flag");
   2419                 break;
   2420         }
   2421     }
   2422 
   2423     SkPoint             fPriorPt;
   2424     SkPoint             fLastPt;
   2425     SkPoint             fCurrPt;
   2426     // fLastVec does not necessarily start at fLastPt. We only advance it when the cross product
   2427     // value with the current vec is deemed to be of a significant value.
   2428     SkVector            fLastVec, fFirstVec;
   2429     int                 fPtCount;   // non-degenerate points
   2430     DirChange           fExpectedDir;
   2431     SkPath::Convexity   fConvexity;
   2432     SkPathPriv::FirstDirection   fFirstDirection;
   2433     int                 fDx, fDy, fSx, fSy;
   2434     bool                fIsFinite;
   2435     bool                fIsCurve;
   2436     bool                fBackwards;
   2437 };
   2438 
   2439 SkPath::Convexity SkPath::internalGetConvexity() const {
   2440     SkASSERT(kUnknown_Convexity == fConvexity);
   2441     SkPoint         pts[4];
   2442     SkPath::Verb    verb;
   2443     SkPath::Iter    iter(*this, true);
   2444 
   2445     int             contourCount = 0;
   2446     int             count;
   2447     Convexicator    state;
   2448 
   2449     if (!isFinite()) {
   2450         return kUnknown_Convexity;
   2451     }
   2452     while ((verb = iter.next(pts, false, false)) != SkPath::kDone_Verb) {
   2453         switch (verb) {
   2454             case kMove_Verb:
   2455                 if (++contourCount > 1) {
   2456                     fConvexity = kConcave_Convexity;
   2457                     return kConcave_Convexity;
   2458                 }
   2459                 pts[1] = pts[0];
   2460                 // fall through
   2461             case kLine_Verb:
   2462                 count = 1;
   2463                 state.setCurve(false);
   2464                 break;
   2465             case kQuad_Verb:
   2466                 // fall through
   2467             case kConic_Verb:
   2468                 // fall through
   2469             case kCubic_Verb:
   2470                 count = 2 + (kCubic_Verb == verb);
   2471                 // As an additional enhancement, this could set curve true only
   2472                 // if the curve is nonlinear
   2473                 state.setCurve(true);
   2474                 break;
   2475             case kClose_Verb:
   2476                 state.setCurve(false);
   2477                 state.close();
   2478                 count = 0;
   2479                 break;
   2480             default:
   2481                 SkDEBUGFAIL("bad verb");
   2482                 fConvexity = kConcave_Convexity;
   2483                 return kConcave_Convexity;
   2484         }
   2485 
   2486         for (int i = 1; i <= count; i++) {
   2487             state.addPt(pts[i]);
   2488         }
   2489         // early exit
   2490         if (!state.isFinite()) {
   2491             return kUnknown_Convexity;
   2492         }
   2493         if (kConcave_Convexity == state.getConvexity()) {
   2494             fConvexity = kConcave_Convexity;
   2495             return kConcave_Convexity;
   2496         }
   2497     }
   2498     fConvexity = state.getConvexity();
   2499     if (kConvex_Convexity == fConvexity && SkPathPriv::kUnknown_FirstDirection == fFirstDirection) {
   2500         if (SkPathPriv::kUnknown_FirstDirection == state.getFirstDirection() &&
   2501                 !this->getBounds().isEmpty() && !state.hasBackwards()) {
   2502             fConvexity = Convexity::kConcave_Convexity;
   2503         } else {
   2504             fFirstDirection = state.getFirstDirection();
   2505         }
   2506     }
   2507     return static_cast<Convexity>(fConvexity);
   2508 }
   2509 
   2510 ///////////////////////////////////////////////////////////////////////////////
   2511 
   2512 class ContourIter {
   2513 public:
   2514     ContourIter(const SkPathRef& pathRef);
   2515 
   2516     bool done() const { return fDone; }
   2517     // if !done() then these may be called
   2518     int count() const { return fCurrPtCount; }
   2519     const SkPoint* pts() const { return fCurrPt; }
   2520     void next();
   2521 
   2522 private:
   2523     int fCurrPtCount;
   2524     const SkPoint* fCurrPt;
   2525     const uint8_t* fCurrVerb;
   2526     const uint8_t* fStopVerbs;
   2527     const SkScalar* fCurrConicWeight;
   2528     bool fDone;
   2529     SkDEBUGCODE(int fContourCounter;)
   2530 };
   2531 
   2532 ContourIter::ContourIter(const SkPathRef& pathRef) {
   2533     fStopVerbs = pathRef.verbsMemBegin();
   2534     fDone = false;
   2535     fCurrPt = pathRef.points();
   2536     fCurrVerb = pathRef.verbs();
   2537     fCurrConicWeight = pathRef.conicWeights();
   2538     fCurrPtCount = 0;
   2539     SkDEBUGCODE(fContourCounter = 0;)
   2540     this->next();
   2541 }
   2542 
   2543 void ContourIter::next() {
   2544     if (fCurrVerb <= fStopVerbs) {
   2545         fDone = true;
   2546     }
   2547     if (fDone) {
   2548         return;
   2549     }
   2550 
   2551     // skip pts of prev contour
   2552     fCurrPt += fCurrPtCount;
   2553 
   2554     SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
   2555     int ptCount = 1;    // moveTo
   2556     const uint8_t* verbs = fCurrVerb;
   2557 
   2558     for (--verbs; verbs > fStopVerbs; --verbs) {
   2559         switch (verbs[~0]) {
   2560             case SkPath::kMove_Verb:
   2561                 goto CONTOUR_END;
   2562             case SkPath::kLine_Verb:
   2563                 ptCount += 1;
   2564                 break;
   2565             case SkPath::kConic_Verb:
   2566                 fCurrConicWeight += 1;
   2567                 // fall-through
   2568             case SkPath::kQuad_Verb:
   2569                 ptCount += 2;
   2570                 break;
   2571             case SkPath::kCubic_Verb:
   2572                 ptCount += 3;
   2573                 break;
   2574             case SkPath::kClose_Verb:
   2575                 break;
   2576             default:
   2577                 SkDEBUGFAIL("unexpected verb");
   2578                 break;
   2579         }
   2580     }
   2581 CONTOUR_END:
   2582     fCurrPtCount = ptCount;
   2583     fCurrVerb = verbs;
   2584     SkDEBUGCODE(++fContourCounter;)
   2585 }
   2586 
   2587 // returns cross product of (p1 - p0) and (p2 - p0)
   2588 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
   2589     SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
   2590     // We may get 0 when the above subtracts underflow. We expect this to be
   2591     // very rare and lazily promote to double.
   2592     if (0 == cross) {
   2593         double p0x = SkScalarToDouble(p0.fX);
   2594         double p0y = SkScalarToDouble(p0.fY);
   2595 
   2596         double p1x = SkScalarToDouble(p1.fX);
   2597         double p1y = SkScalarToDouble(p1.fY);
   2598 
   2599         double p2x = SkScalarToDouble(p2.fX);
   2600         double p2y = SkScalarToDouble(p2.fY);
   2601 
   2602         cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
   2603                                  (p1y - p0y) * (p2x - p0x));
   2604 
   2605     }
   2606     return cross;
   2607 }
   2608 
   2609 // Returns the first pt with the maximum Y coordinate
   2610 static int find_max_y(const SkPoint pts[], int count) {
   2611     SkASSERT(count > 0);
   2612     SkScalar max = pts[0].fY;
   2613     int firstIndex = 0;
   2614     for (int i = 1; i < count; ++i) {
   2615         SkScalar y = pts[i].fY;
   2616         if (y > max) {
   2617             max = y;
   2618             firstIndex = i;
   2619         }
   2620     }
   2621     return firstIndex;
   2622 }
   2623 
   2624 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
   2625     int i = index;
   2626     for (;;) {
   2627         i = (i + inc) % n;
   2628         if (i == index) {   // we wrapped around, so abort
   2629             break;
   2630         }
   2631         if (pts[index] != pts[i]) { // found a different point, success!
   2632             break;
   2633         }
   2634     }
   2635     return i;
   2636 }
   2637 
   2638 /**
   2639  *  Starting at index, and moving forward (incrementing), find the xmin and
   2640  *  xmax of the contiguous points that have the same Y.
   2641  */
   2642 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
   2643                                int* maxIndexPtr) {
   2644     const SkScalar y = pts[index].fY;
   2645     SkScalar min = pts[index].fX;
   2646     SkScalar max = min;
   2647     int minIndex = index;
   2648     int maxIndex = index;
   2649     for (int i = index + 1; i < n; ++i) {
   2650         if (pts[i].fY != y) {
   2651             break;
   2652         }
   2653         SkScalar x = pts[i].fX;
   2654         if (x < min) {
   2655             min = x;
   2656             minIndex = i;
   2657         } else if (x > max) {
   2658             max = x;
   2659             maxIndex = i;
   2660         }
   2661     }
   2662     *maxIndexPtr = maxIndex;
   2663     return minIndex;
   2664 }
   2665 
   2666 static void crossToDir(SkScalar cross, SkPathPriv::FirstDirection* dir) {
   2667     *dir = cross > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
   2668 }
   2669 
   2670 /*
   2671  *  We loop through all contours, and keep the computed cross-product of the
   2672  *  contour that contained the global y-max. If we just look at the first
   2673  *  contour, we may find one that is wound the opposite way (correctly) since
   2674  *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
   2675  *  that is outer most (or at least has the global y-max) before we can consider
   2676  *  its cross product.
   2677  */
   2678 bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* dir) {
   2679     if (kUnknown_FirstDirection != path.fFirstDirection.load()) {
   2680         *dir = static_cast<FirstDirection>(path.fFirstDirection.load());
   2681         return true;
   2682     }
   2683 
   2684     // don't want to pay the cost for computing this if it
   2685     // is unknown, so we don't call isConvex()
   2686     if (SkPath::kConvex_Convexity == path.getConvexityOrUnknown()) {
   2687         SkASSERT(kUnknown_FirstDirection == path.fFirstDirection);
   2688         *dir = static_cast<FirstDirection>(path.fFirstDirection.load());
   2689         return false;
   2690     }
   2691 
   2692     ContourIter iter(*path.fPathRef.get());
   2693 
   2694     // initialize with our logical y-min
   2695     SkScalar ymax = path.getBounds().fTop;
   2696     SkScalar ymaxCross = 0;
   2697 
   2698     for (; !iter.done(); iter.next()) {
   2699         int n = iter.count();
   2700         if (n < 3) {
   2701             continue;
   2702         }
   2703 
   2704         const SkPoint* pts = iter.pts();
   2705         SkScalar cross = 0;
   2706         int index = find_max_y(pts, n);
   2707         if (pts[index].fY < ymax) {
   2708             continue;
   2709         }
   2710 
   2711         // If there is more than 1 distinct point at the y-max, we take the
   2712         // x-min and x-max of them and just subtract to compute the dir.
   2713         if (pts[(index + 1) % n].fY == pts[index].fY) {
   2714             int maxIndex;
   2715             int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
   2716             if (minIndex == maxIndex) {
   2717                 goto TRY_CROSSPROD;
   2718             }
   2719             SkASSERT(pts[minIndex].fY == pts[index].fY);
   2720             SkASSERT(pts[maxIndex].fY == pts[index].fY);
   2721             SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
   2722             // we just subtract the indices, and let that auto-convert to
   2723             // SkScalar, since we just want - or + to signal the direction.
   2724             cross = minIndex - maxIndex;
   2725         } else {
   2726             TRY_CROSSPROD:
   2727             // Find a next and prev index to use for the cross-product test,
   2728             // but we try to find pts that form non-zero vectors from pts[index]
   2729             //
   2730             // Its possible that we can't find two non-degenerate vectors, so
   2731             // we have to guard our search (e.g. all the pts could be in the
   2732             // same place).
   2733 
   2734             // we pass n - 1 instead of -1 so we don't foul up % operator by
   2735             // passing it a negative LH argument.
   2736             int prev = find_diff_pt(pts, index, n, n - 1);
   2737             if (prev == index) {
   2738                 // completely degenerate, skip to next contour
   2739                 continue;
   2740             }
   2741             int next = find_diff_pt(pts, index, n, 1);
   2742             SkASSERT(next != index);
   2743             cross = cross_prod(pts[prev], pts[index], pts[next]);
   2744             // if we get a zero and the points are horizontal, then we look at the spread in
   2745             // x-direction. We really should continue to walk away from the degeneracy until
   2746             // there is a divergence.
   2747             if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
   2748                 // construct the subtract so we get the correct Direction below
   2749                 cross = pts[index].fX - pts[next].fX;
   2750             }
   2751         }
   2752 
   2753         if (cross) {
   2754             // record our best guess so far
   2755             ymax = pts[index].fY;
   2756             ymaxCross = cross;
   2757         }
   2758     }
   2759     if (ymaxCross) {
   2760         crossToDir(ymaxCross, dir);
   2761         path.fFirstDirection = *dir;
   2762         return true;
   2763     } else {
   2764         return false;
   2765     }
   2766 }
   2767 
   2768 ///////////////////////////////////////////////////////////////////////////////
   2769 
   2770 static bool between(SkScalar a, SkScalar b, SkScalar c) {
   2771     SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
   2772             || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c)));
   2773     return (a - b) * (c - b) <= 0;
   2774 }
   2775 
   2776 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
   2777                                SkScalar t) {
   2778     SkScalar A = c3 + 3*(c1 - c2) - c0;
   2779     SkScalar B = 3*(c2 - c1 - c1 + c0);
   2780     SkScalar C = 3*(c1 - c0);
   2781     SkScalar D = c0;
   2782     return poly_eval(A, B, C, D, t);
   2783 }
   2784 
   2785 template <size_t N> static void find_minmax(const SkPoint pts[],
   2786                                             SkScalar* minPtr, SkScalar* maxPtr) {
   2787     SkScalar min, max;
   2788     min = max = pts[0].fX;
   2789     for (size_t i = 1; i < N; ++i) {
   2790         min = SkMinScalar(min, pts[i].fX);
   2791         max = SkMaxScalar(max, pts[i].fX);
   2792     }
   2793     *minPtr = min;
   2794     *maxPtr = max;
   2795 }
   2796 
   2797 static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) {
   2798     if (start.fY == end.fY) {
   2799         return between(start.fX, x, end.fX) && x != end.fX;
   2800     } else {
   2801         return x == start.fX && y == start.fY;
   2802     }
   2803 }
   2804 
   2805 static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
   2806     SkScalar y0 = pts[0].fY;
   2807     SkScalar y3 = pts[3].fY;
   2808 
   2809     int dir = 1;
   2810     if (y0 > y3) {
   2811         SkTSwap(y0, y3);
   2812         dir = -1;
   2813     }
   2814     if (y < y0 || y > y3) {
   2815         return 0;
   2816     }
   2817     if (checkOnCurve(x, y, pts[0], pts[3])) {
   2818         *onCurveCount += 1;
   2819         return 0;
   2820     }
   2821     if (y == y3) {
   2822         return 0;
   2823     }
   2824 
   2825     // quickreject or quickaccept
   2826     SkScalar min, max;
   2827     find_minmax<4>(pts, &min, &max);
   2828     if (x < min) {
   2829         return 0;
   2830     }
   2831     if (x > max) {
   2832         return dir;
   2833     }
   2834 
   2835     // compute the actual x(t) value
   2836     SkScalar t;
   2837     if (!SkCubicClipper::ChopMonoAtY(pts, y, &t)) {
   2838         return 0;
   2839     }
   2840     SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
   2841     if (SkScalarNearlyEqual(xt, x)) {
   2842         if (x != pts[3].fX || y != pts[3].fY) {  // don't test end points; they're start points
   2843             *onCurveCount += 1;
   2844             return 0;
   2845         }
   2846     }
   2847     return xt < x ? dir : 0;
   2848 }
   2849 
   2850 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
   2851     SkPoint dst[10];
   2852     int n = SkChopCubicAtYExtrema(pts, dst);
   2853     int w = 0;
   2854     for (int i = 0; i <= n; ++i) {
   2855         w += winding_mono_cubic(&dst[i * 3], x, y, onCurveCount);
   2856     }
   2857     return w;
   2858 }
   2859 
   2860 static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) {
   2861     SkASSERT(src);
   2862     SkASSERT(t >= 0 && t <= 1);
   2863     SkScalar src2w = src[2] * w;
   2864     SkScalar C = src[0];
   2865     SkScalar A = src[4] - 2 * src2w + C;
   2866     SkScalar B = 2 * (src2w - C);
   2867     return poly_eval(A, B, C, t);
   2868 }
   2869 
   2870 
   2871 static double conic_eval_denominator(SkScalar w, SkScalar t) {
   2872     SkScalar B = 2 * (w - 1);
   2873     SkScalar C = 1;
   2874     SkScalar A = -B;
   2875     return poly_eval(A, B, C, t);
   2876 }
   2877 
   2878 static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) {
   2879     const SkPoint* pts = conic.fPts;
   2880     SkScalar y0 = pts[0].fY;
   2881     SkScalar y2 = pts[2].fY;
   2882 
   2883     int dir = 1;
   2884     if (y0 > y2) {
   2885         SkTSwap(y0, y2);
   2886         dir = -1;
   2887     }
   2888     if (y < y0 || y > y2) {
   2889         return 0;
   2890     }
   2891     if (checkOnCurve(x, y, pts[0], pts[2])) {
   2892         *onCurveCount += 1;
   2893         return 0;
   2894     }
   2895     if (y == y2) {
   2896         return 0;
   2897     }
   2898 
   2899     SkScalar roots[2];
   2900     SkScalar A = pts[2].fY;
   2901     SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y;
   2902     SkScalar C = pts[0].fY;
   2903     A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
   2904     B -= C;  // B = b*w - w * yCept + yCept - a
   2905     C -= y;
   2906     int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
   2907     SkASSERT(n <= 1);
   2908     SkScalar xt;
   2909     if (0 == n) {
   2910         // zero roots are returned only when y0 == y
   2911         // Need [0] if dir == 1
   2912         // and  [2] if dir == -1
   2913         xt = pts[1 - dir].fX;
   2914     } else {
   2915         SkScalar t = roots[0];
   2916         xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t);
   2917     }
   2918     if (SkScalarNearlyEqual(xt, x)) {
   2919         if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
   2920             *onCurveCount += 1;
   2921             return 0;
   2922         }
   2923     }
   2924     return xt < x ? dir : 0;
   2925 }
   2926 
   2927 static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) {
   2928     //    return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0;
   2929     if (y0 == y1) {
   2930         return true;
   2931     }
   2932     if (y0 < y1) {
   2933         return y1 <= y2;
   2934     } else {
   2935         return y1 >= y2;
   2936     }
   2937 }
   2938 
   2939 static int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight,
   2940                          int* onCurveCount) {
   2941     SkConic conic(pts, weight);
   2942     SkConic chopped[2];
   2943     // If the data points are very large, the conic may not be monotonic but may also
   2944     // fail to chop. Then, the chopper does not split the original conic in two.
   2945     bool isMono = is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped);
   2946     int w = winding_mono_conic(isMono ? conic : chopped[0], x, y, onCurveCount);
   2947     if (!isMono) {
   2948         w += winding_mono_conic(chopped[1], x, y, onCurveCount);
   2949     }
   2950     return w;
   2951 }
   2952 
   2953 static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
   2954     SkScalar y0 = pts[0].fY;
   2955     SkScalar y2 = pts[2].fY;
   2956 
   2957     int dir = 1;
   2958     if (y0 > y2) {
   2959         SkTSwap(y0, y2);
   2960         dir = -1;
   2961     }
   2962     if (y < y0 || y > y2) {
   2963         return 0;
   2964     }
   2965     if (checkOnCurve(x, y, pts[0], pts[2])) {
   2966         *onCurveCount += 1;
   2967         return 0;
   2968     }
   2969     if (y == y2) {
   2970         return 0;
   2971     }
   2972     // bounds check on X (not required. is it faster?)
   2973 #if 0
   2974     if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) {
   2975         return 0;
   2976     }
   2977 #endif
   2978 
   2979     SkScalar roots[2];
   2980     int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
   2981                                 2 * (pts[1].fY - pts[0].fY),
   2982                                 pts[0].fY - y,
   2983                                 roots);
   2984     SkASSERT(n <= 1);
   2985     SkScalar xt;
   2986     if (0 == n) {
   2987         // zero roots are returned only when y0 == y
   2988         // Need [0] if dir == 1
   2989         // and  [2] if dir == -1
   2990         xt = pts[1 - dir].fX;
   2991     } else {
   2992         SkScalar t = roots[0];
   2993         SkScalar C = pts[0].fX;
   2994         SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
   2995         SkScalar B = 2 * (pts[1].fX - C);
   2996         xt = poly_eval(A, B, C, t);
   2997     }
   2998     if (SkScalarNearlyEqual(xt, x)) {
   2999         if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
   3000             *onCurveCount += 1;
   3001             return 0;
   3002         }
   3003     }
   3004     return xt < x ? dir : 0;
   3005 }
   3006 
   3007 static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
   3008     SkPoint dst[5];
   3009     int     n = 0;
   3010 
   3011     if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) {
   3012         n = SkChopQuadAtYExtrema(pts, dst);
   3013         pts = dst;
   3014     }
   3015     int w = winding_mono_quad(pts, x, y, onCurveCount);
   3016     if (n > 0) {
   3017         w += winding_mono_quad(&pts[2], x, y, onCurveCount);
   3018     }
   3019     return w;
   3020 }
   3021 
   3022 static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
   3023     SkScalar x0 = pts[0].fX;
   3024     SkScalar y0 = pts[0].fY;
   3025     SkScalar x1 = pts[1].fX;
   3026     SkScalar y1 = pts[1].fY;
   3027 
   3028     SkScalar dy = y1 - y0;
   3029 
   3030     int dir = 1;
   3031     if (y0 > y1) {
   3032         SkTSwap(y0, y1);
   3033         dir = -1;
   3034     }
   3035     if (y < y0 || y > y1) {
   3036         return 0;
   3037     }
   3038     if (checkOnCurve(x, y, pts[0], pts[1])) {
   3039         *onCurveCount += 1;
   3040         return 0;
   3041     }
   3042     if (y == y1) {
   3043         return 0;
   3044     }
   3045     SkScalar cross = (x1 - x0) * (y - pts[0].fY) - dy * (x - x0);
   3046 
   3047     if (!cross) {
   3048         // zero cross means the point is on the line, and since the case where
   3049         // y of the query point is at the end point is handled above, we can be
   3050         // sure that we're on the line (excluding the end point) here
   3051         if (x != x1 || y != pts[1].fY) {
   3052             *onCurveCount += 1;
   3053         }
   3054         dir = 0;
   3055     } else if (SkScalarSignAsInt(cross) == dir) {
   3056         dir = 0;
   3057     }
   3058     return dir;
   3059 }
   3060 
   3061 static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y,
   3062         SkTDArray<SkVector>* tangents) {
   3063     if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)
   3064              && !between(pts[2].fY, y, pts[3].fY)) {
   3065         return;
   3066     }
   3067     if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)
   3068              && !between(pts[2].fX, x, pts[3].fX)) {
   3069         return;
   3070     }
   3071     SkPoint dst[10];
   3072     int n = SkChopCubicAtYExtrema(pts, dst);
   3073     for (int i = 0; i <= n; ++i) {
   3074         SkPoint* c = &dst[i * 3];
   3075         SkScalar t;
   3076         if (!SkCubicClipper::ChopMonoAtY(c, y, &t)) {
   3077             continue;
   3078         }
   3079         SkScalar xt = eval_cubic_pts(c[0].fX, c[1].fX, c[2].fX, c[3].fX, t);
   3080         if (!SkScalarNearlyEqual(x, xt)) {
   3081             continue;
   3082         }
   3083         SkVector tangent;
   3084         SkEvalCubicAt(c, t, nullptr, &tangent, nullptr);
   3085         tangents->push(tangent);
   3086     }
   3087 }
   3088 
   3089 static void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w,
   3090             SkTDArray<SkVector>* tangents) {
   3091     if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
   3092         return;
   3093     }
   3094     if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
   3095         return;
   3096     }
   3097     SkScalar roots[2];
   3098     SkScalar A = pts[2].fY;
   3099     SkScalar B = pts[1].fY * w - y * w + y;
   3100     SkScalar C = pts[0].fY;
   3101     A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
   3102     B -= C;  // B = b*w - w * yCept + yCept - a
   3103     C -= y;
   3104     int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
   3105     for (int index = 0; index < n; ++index) {
   3106         SkScalar t = roots[index];
   3107         SkScalar xt = conic_eval_numerator(&pts[0].fX, w, t) / conic_eval_denominator(w, t);
   3108         if (!SkScalarNearlyEqual(x, xt)) {
   3109             continue;
   3110         }
   3111         SkConic conic(pts, w);
   3112         tangents->push(conic.evalTangentAt(t));
   3113     }
   3114 }
   3115 
   3116 static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y,
   3117         SkTDArray<SkVector>* tangents) {
   3118     if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
   3119         return;
   3120     }
   3121     if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
   3122         return;
   3123     }
   3124     SkScalar roots[2];
   3125     int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
   3126                                 2 * (pts[1].fY - pts[0].fY),
   3127                                 pts[0].fY - y,
   3128                                 roots);
   3129     for (int index = 0; index < n; ++index) {
   3130         SkScalar t = roots[index];
   3131         SkScalar C = pts[0].fX;
   3132         SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
   3133         SkScalar B = 2 * (pts[1].fX - C);
   3134         SkScalar xt = poly_eval(A, B, C, t);
   3135         if (!SkScalarNearlyEqual(x, xt)) {
   3136             continue;
   3137         }
   3138         tangents->push(SkEvalQuadTangentAt(pts, t));
   3139     }
   3140 }
   3141 
   3142 static void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y,
   3143         SkTDArray<SkVector>* tangents) {
   3144     SkScalar y0 = pts[0].fY;
   3145     SkScalar y1 = pts[1].fY;
   3146     if (!between(y0, y, y1)) {
   3147         return;
   3148     }
   3149     SkScalar x0 = pts[0].fX;
   3150     SkScalar x1 = pts[1].fX;
   3151     if (!between(x0, x, x1)) {
   3152         return;
   3153     }
   3154     SkScalar dx = x1 - x0;
   3155     SkScalar dy = y1 - y0;
   3156     if (!SkScalarNearlyEqual((x - x0) * dy, dx * (y - y0))) {
   3157         return;
   3158     }
   3159     SkVector v;
   3160     v.set(dx, dy);
   3161     tangents->push(v);
   3162 }
   3163 
   3164 static bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) {
   3165     return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom;
   3166 }
   3167 
   3168 bool SkPath::contains(SkScalar x, SkScalar y) const {
   3169     bool isInverse = this->isInverseFillType();
   3170     if (this->isEmpty()) {
   3171         return isInverse;
   3172     }
   3173 
   3174     if (!contains_inclusive(this->getBounds(), x, y)) {
   3175         return isInverse;
   3176     }
   3177 
   3178     SkPath::Iter iter(*this, true);
   3179     bool done = false;
   3180     int w = 0;
   3181     int onCurveCount = 0;
   3182     do {
   3183         SkPoint pts[4];
   3184         switch (iter.next(pts, false)) {
   3185             case SkPath::kMove_Verb:
   3186             case SkPath::kClose_Verb:
   3187                 break;
   3188             case SkPath::kLine_Verb:
   3189                 w += winding_line(pts, x, y, &onCurveCount);
   3190                 break;
   3191             case SkPath::kQuad_Verb:
   3192                 w += winding_quad(pts, x, y, &onCurveCount);
   3193                 break;
   3194             case SkPath::kConic_Verb:
   3195                 w += winding_conic(pts, x, y, iter.conicWeight(), &onCurveCount);
   3196                 break;
   3197             case SkPath::kCubic_Verb:
   3198                 w += winding_cubic(pts, x, y, &onCurveCount);
   3199                 break;
   3200             case SkPath::kDone_Verb:
   3201                 done = true;
   3202                 break;
   3203        }
   3204     } while (!done);
   3205     bool evenOddFill = SkPath::kEvenOdd_FillType == this->getFillType()
   3206             || SkPath::kInverseEvenOdd_FillType == this->getFillType();
   3207     if (evenOddFill) {
   3208         w &= 1;
   3209     }
   3210     if (w) {
   3211         return !isInverse;
   3212     }
   3213     if (onCurveCount <= 1) {
   3214         return SkToBool(onCurveCount) ^ isInverse;
   3215     }
   3216     if ((onCurveCount & 1) || evenOddFill) {
   3217         return SkToBool(onCurveCount & 1) ^ isInverse;
   3218     }
   3219     // If the point touches an even number of curves, and the fill is winding, check for
   3220     // coincidence. Count coincidence as places where the on curve points have identical tangents.
   3221     iter.setPath(*this, true);
   3222     done = false;
   3223     SkTDArray<SkVector> tangents;
   3224     do {
   3225         SkPoint pts[4];
   3226         int oldCount = tangents.count();
   3227         switch (iter.next(pts, false)) {
   3228             case SkPath::kMove_Verb:
   3229             case SkPath::kClose_Verb:
   3230                 break;
   3231             case SkPath::kLine_Verb:
   3232                 tangent_line(pts, x, y, &tangents);
   3233                 break;
   3234             case SkPath::kQuad_Verb:
   3235                 tangent_quad(pts, x, y, &tangents);
   3236                 break;
   3237             case SkPath::kConic_Verb:
   3238                 tangent_conic(pts, x, y, iter.conicWeight(), &tangents);
   3239                 break;
   3240             case SkPath::kCubic_Verb:
   3241                 tangent_cubic(pts, x, y, &tangents);
   3242                 break;
   3243             case SkPath::kDone_Verb:
   3244                 done = true;
   3245                 break;
   3246        }
   3247        if (tangents.count() > oldCount) {
   3248             int last = tangents.count() - 1;
   3249             const SkVector& tangent = tangents[last];
   3250             if (SkScalarNearlyZero(SkPointPriv::LengthSqd(tangent))) {
   3251                 tangents.remove(last);
   3252             } else {
   3253                 for (int index = 0; index < last; ++index) {
   3254                     const SkVector& test = tangents[index];
   3255                     if (SkScalarNearlyZero(test.cross(tangent))
   3256                             && SkScalarSignAsInt(tangent.fX * test.fX) <= 0
   3257                             && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) {
   3258                         tangents.remove(last);
   3259                         tangents.removeShuffle(index);
   3260                         break;
   3261                     }
   3262                 }
   3263             }
   3264         }
   3265     } while (!done);
   3266     return SkToBool(tangents.count()) ^ isInverse;
   3267 }
   3268 
   3269 int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
   3270                                 SkScalar w, SkPoint pts[], int pow2) {
   3271     const SkConic conic(p0, p1, p2, w);
   3272     return conic.chopIntoQuadsPOW2(pts, pow2);
   3273 }
   3274 
   3275 bool SkPathPriv::IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction,
   3276                                     unsigned* start) {
   3277     if (path.getSegmentMasks() != SkPath::kLine_SegmentMask) {
   3278         return false;
   3279     }
   3280     SkPath::RawIter iter(path);
   3281     SkPoint verbPts[4];
   3282     SkPath::Verb v;
   3283     SkPoint rectPts[5];
   3284     int rectPtCnt = 0;
   3285     while ((v = iter.next(verbPts)) != SkPath::kDone_Verb) {
   3286         switch (v) {
   3287             case SkPath::kMove_Verb:
   3288                 if (0 != rectPtCnt) {
   3289                     return false;
   3290                 }
   3291                 rectPts[0] = verbPts[0];
   3292                 ++rectPtCnt;
   3293                 break;
   3294             case SkPath::kLine_Verb:
   3295                 if (5 == rectPtCnt) {
   3296                     return false;
   3297                 }
   3298                 rectPts[rectPtCnt] = verbPts[1];
   3299                 ++rectPtCnt;
   3300                 break;
   3301             case SkPath::kClose_Verb:
   3302                 if (4 == rectPtCnt) {
   3303                     rectPts[4] = rectPts[0];
   3304                     rectPtCnt = 5;
   3305                 }
   3306                 break;
   3307             default:
   3308                 return false;
   3309         }
   3310     }
   3311     if (rectPtCnt < 5) {
   3312         return false;
   3313     }
   3314     if (rectPts[0] != rectPts[4]) {
   3315         return false;
   3316     }
   3317     // Check for two cases of rectangles: pts 0 and 3 form a vertical edge or a horizontal edge (
   3318     // and pts 1 and 2 the opposite vertical or horizontal edge).
   3319     bool vec03IsVertical;
   3320     if (rectPts[0].fX == rectPts[3].fX && rectPts[1].fX == rectPts[2].fX &&
   3321         rectPts[0].fY == rectPts[1].fY && rectPts[3].fY == rectPts[2].fY) {
   3322         // Make sure it has non-zero width and height
   3323         if (rectPts[0].fX == rectPts[1].fX || rectPts[0].fY == rectPts[3].fY) {
   3324             return false;
   3325         }
   3326         vec03IsVertical = true;
   3327     } else if (rectPts[0].fY == rectPts[3].fY && rectPts[1].fY == rectPts[2].fY &&
   3328                rectPts[0].fX == rectPts[1].fX && rectPts[3].fX == rectPts[2].fX) {
   3329         // Make sure it has non-zero width and height
   3330         if (rectPts[0].fY == rectPts[1].fY || rectPts[0].fX == rectPts[3].fX) {
   3331             return false;
   3332         }
   3333         vec03IsVertical = false;
   3334     } else {
   3335         return false;
   3336     }
   3337     // Set sortFlags so that it has the low bit set if pt index 0 is on right edge and second bit
   3338     // set if it is on the bottom edge.
   3339     unsigned sortFlags =
   3340             ((rectPts[0].fX < rectPts[2].fX) ? 0b00 : 0b01) |
   3341             ((rectPts[0].fY < rectPts[2].fY) ? 0b00 : 0b10);
   3342     switch (sortFlags) {
   3343         case 0b00:
   3344             rect->set(rectPts[0].fX, rectPts[0].fY, rectPts[2].fX, rectPts[2].fY);
   3345             *direction = vec03IsVertical ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
   3346             *start = 0;
   3347             break;
   3348         case 0b01:
   3349             rect->set(rectPts[2].fX, rectPts[0].fY, rectPts[0].fX, rectPts[2].fY);
   3350             *direction = vec03IsVertical ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
   3351             *start = 1;
   3352             break;
   3353         case 0b10:
   3354             rect->set(rectPts[0].fX, rectPts[2].fY, rectPts[2].fX, rectPts[0].fY);
   3355             *direction = vec03IsVertical ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
   3356             *start = 3;
   3357             break;
   3358         case 0b11:
   3359             rect->set(rectPts[2].fX, rectPts[2].fY, rectPts[0].fX, rectPts[0].fY);
   3360             *direction = vec03IsVertical ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
   3361             *start = 2;
   3362             break;
   3363     }
   3364     return true;
   3365 }
   3366 
   3367 bool SkPathPriv::DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
   3368     if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
   3369         // This gets converted to an oval.
   3370         return true;
   3371     }
   3372     if (useCenter) {
   3373         // This is a pie wedge. It's convex if the angle is <= 180.
   3374         return SkScalarAbs(sweepAngle) <= 180.f;
   3375     }
   3376     // When the angle exceeds 360 this wraps back on top of itself. Otherwise it is a circle clipped
   3377     // to a secant, i.e. convex.
   3378     return SkScalarAbs(sweepAngle) <= 360.f;
   3379 }
   3380 
   3381 void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
   3382                                    SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
   3383     SkASSERT(!oval.isEmpty());
   3384     SkASSERT(sweepAngle);
   3385 
   3386     path->reset();
   3387     path->setIsVolatile(true);
   3388     path->setFillType(SkPath::kWinding_FillType);
   3389     if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
   3390         path->addOval(oval);
   3391         SkASSERT(path->isConvex() && DrawArcIsConvex(sweepAngle, false, isFillNoPathEffect));
   3392         return;
   3393     }
   3394     if (useCenter) {
   3395         path->moveTo(oval.centerX(), oval.centerY());
   3396     }
   3397     auto firstDir =
   3398             sweepAngle > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
   3399     bool convex = DrawArcIsConvex(sweepAngle, useCenter, isFillNoPathEffect);
   3400     // Arc to mods at 360 and drawArc is not supposed to.
   3401     bool forceMoveTo = !useCenter;
   3402     while (sweepAngle <= -360.f) {
   3403         path->arcTo(oval, startAngle, -180.f, forceMoveTo);
   3404         startAngle -= 180.f;
   3405         path->arcTo(oval, startAngle, -180.f, false);
   3406         startAngle -= 180.f;
   3407         forceMoveTo = false;
   3408         sweepAngle += 360.f;
   3409     }
   3410     while (sweepAngle >= 360.f) {
   3411         path->arcTo(oval, startAngle, 180.f, forceMoveTo);
   3412         startAngle += 180.f;
   3413         path->arcTo(oval, startAngle, 180.f, false);
   3414         startAngle += 180.f;
   3415         forceMoveTo = false;
   3416         sweepAngle -= 360.f;
   3417     }
   3418     path->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
   3419     if (useCenter) {
   3420         path->close();
   3421     }
   3422     path->setConvexity(convex ? SkPath::kConvex_Convexity : SkPath::kConcave_Convexity);
   3423     path->fFirstDirection.store(firstDir);
   3424 }
   3425 
   3426 ///////////////////////////////////////////////////////////////////////////////////////////////////
   3427 #include "SkNx.h"
   3428 
   3429 static int compute_quad_extremas(const SkPoint src[3], SkPoint extremas[3]) {
   3430     SkScalar ts[2];
   3431     int n  = SkFindQuadExtrema(src[0].fX, src[1].fX, src[2].fX, ts);
   3432         n += SkFindQuadExtrema(src[0].fY, src[1].fY, src[2].fY, &ts[n]);
   3433     SkASSERT(n >= 0 && n <= 2);
   3434     for (int i = 0; i < n; ++i) {
   3435         extremas[i] = SkEvalQuadAt(src, ts[i]);
   3436     }
   3437     extremas[n] = src[2];
   3438     return n + 1;
   3439 }
   3440 
   3441 static int compute_conic_extremas(const SkPoint src[3], SkScalar w, SkPoint extremas[3]) {
   3442     SkConic conic(src[0], src[1], src[2], w);
   3443     SkScalar ts[2];
   3444     int n  = conic.findXExtrema(ts);
   3445         n += conic.findYExtrema(&ts[n]);
   3446     SkASSERT(n >= 0 && n <= 2);
   3447     for (int i = 0; i < n; ++i) {
   3448         extremas[i] = conic.evalAt(ts[i]);
   3449     }
   3450     extremas[n] = src[2];
   3451     return n + 1;
   3452 }
   3453 
   3454 static int compute_cubic_extremas(const SkPoint src[3], SkPoint extremas[5]) {
   3455     SkScalar ts[4];
   3456     int n  = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX, src[3].fX, ts);
   3457         n += SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, src[3].fY, &ts[n]);
   3458     SkASSERT(n >= 0 && n <= 4);
   3459     for (int i = 0; i < n; ++i) {
   3460         SkEvalCubicAt(src, ts[i], &extremas[i], nullptr, nullptr);
   3461     }
   3462     extremas[n] = src[3];
   3463     return n + 1;
   3464 }
   3465 
   3466 SkRect SkPath::computeTightBounds() const {
   3467     if (0 == this->countVerbs()) {
   3468         return SkRect::MakeEmpty();
   3469     }
   3470 
   3471     if (this->getSegmentMasks() == SkPath::kLine_SegmentMask) {
   3472         return this->getBounds();
   3473     }
   3474 
   3475     SkPoint extremas[5]; // big enough to hold worst-case curve type (cubic) extremas + 1
   3476     SkPoint pts[4];
   3477     SkPath::RawIter iter(*this);
   3478 
   3479     // initial with the first MoveTo, so we don't have to check inside the switch
   3480     Sk2s min, max;
   3481     min = max = from_point(this->getPoint(0));
   3482     for (;;) {
   3483         int count = 0;
   3484         switch (iter.next(pts)) {
   3485             case SkPath::kMove_Verb:
   3486                 extremas[0] = pts[0];
   3487                 count = 1;
   3488                 break;
   3489             case SkPath::kLine_Verb:
   3490                 extremas[0] = pts[1];
   3491                 count = 1;
   3492                 break;
   3493             case SkPath::kQuad_Verb:
   3494                 count = compute_quad_extremas(pts, extremas);
   3495                 break;
   3496             case SkPath::kConic_Verb:
   3497                 count = compute_conic_extremas(pts, iter.conicWeight(), extremas);
   3498                 break;
   3499             case SkPath::kCubic_Verb:
   3500                 count = compute_cubic_extremas(pts, extremas);
   3501                 break;
   3502             case SkPath::kClose_Verb:
   3503                 break;
   3504             case SkPath::kDone_Verb:
   3505                 goto DONE;
   3506         }
   3507         for (int i = 0; i < count; ++i) {
   3508             Sk2s tmp = from_point(extremas[i]);
   3509             min = Sk2s::Min(min, tmp);
   3510             max = Sk2s::Max(max, tmp);
   3511         }
   3512     }
   3513 DONE:
   3514     SkRect bounds;
   3515     min.store((SkPoint*)&bounds.fLeft);
   3516     max.store((SkPoint*)&bounds.fRight);
   3517     return bounds;
   3518 }
   3519 
   3520 bool SkPath::IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact) {
   3521     return exact ? p1 == p2 : SkPointPriv::EqualsWithinTolerance(p1, p2);
   3522 }
   3523 
   3524 bool SkPath::IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
   3525                                 const SkPoint& p3, bool exact) {
   3526     return exact ? p1 == p2 && p2 == p3 : SkPointPriv::EqualsWithinTolerance(p1, p2) &&
   3527             SkPointPriv::EqualsWithinTolerance(p2, p3);
   3528 }
   3529 
   3530 bool SkPath::IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
   3531                                 const SkPoint& p3, const SkPoint& p4, bool exact) {
   3532     return exact ? p1 == p2 && p2 == p3 && p3 == p4 :
   3533             SkPointPriv::EqualsWithinTolerance(p1, p2) &&
   3534             SkPointPriv::EqualsWithinTolerance(p2, p3) &&
   3535             SkPointPriv::EqualsWithinTolerance(p3, p4);
   3536 }
   3537