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