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