• 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(std::string & desc,int depth) const2192 void SkPath::dump(std::string &desc, int depth) const {
2193     std::string split(depth, '\t');
2194     desc += split + "\n SkPath:{ \n";
2195     Iter    iter(*this, false);
2196     SkPoint points[4];
2197     Verb    verb;
2198 
2199     SkString descSk;
2200     char const * const gFillTypeStrs[] = {
2201         "Winding",
2202         "EvenOdd",
2203         "InverseWinding",
2204         "InverseEvenOdd",
2205     };
2206     descSk.printf("path.setFillType(SkPath::k%s_FillType);\n", gFillTypeStrs[(int) this->getFillType()]);
2207     while ((verb = iter.next(points)) != kDone_Verb) {
2208         switch (verb) {
2209             case kMove_Verb:
2210                 append_params(&descSk, "path.moveTo", &points[0], 1, kDec_SkScalarAsStringType);
2211                 break;
2212             case kLine_Verb:
2213                 append_params(&descSk, "path.lineTo", &points[1], 1, kDec_SkScalarAsStringType);
2214                 break;
2215             case kQuad_Verb:
2216                 append_params(&descSk, "path.quadTo", &points[1], 2, kDec_SkScalarAsStringType);
2217                 break;
2218             case kConic_Verb:
2219                 append_params(&descSk, "path.conicTo", &points[1], 2, kDec_SkScalarAsStringType, iter.conicWeight());
2220                 break;
2221             case kCubic_Verb:
2222                 append_params(&descSk, "path.cubicTo", &points[1], 3, kDec_SkScalarAsStringType);
2223                 break;
2224             case kClose_Verb:
2225                 descSk.append("path.close();\n");
2226                 break;
2227             default:
2228                 verb = kDone_Verb;  // stop the loop
2229                 break;
2230         }
2231         if (descSk.size()) {
2232             desc += split + std::string(descSk.c_str());
2233             descSk.reset();
2234         }
2235     }
2236     desc += split + "}\n";
2237 }
2238 
dump() const2239 void SkPath::dump() const {
2240     this->dump(nullptr, false, false);
2241 }
2242 
dumpHex() const2243 void SkPath::dumpHex() const {
2244     this->dump(nullptr, false, true);
2245 }
2246 
2247 
isValidImpl() const2248 bool SkPath::isValidImpl() const {
2249     if ((fFillType & ~3) != 0) {
2250         return false;
2251     }
2252 
2253 #ifdef SK_DEBUG_PATH
2254     if (!fBoundsIsDirty) {
2255         SkRect bounds;
2256 
2257         bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
2258         if (SkToBool(fIsFinite) != isFinite) {
2259             return false;
2260         }
2261 
2262         if (fPathRef->countPoints() <= 1) {
2263             // if we're empty, fBounds may be empty but translated, so we can't
2264             // necessarily compare to bounds directly
2265             // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
2266             // be [2, 2, 2, 2]
2267             if (!bounds.isEmpty() || !fBounds.isEmpty()) {
2268                 return false;
2269             }
2270         } else {
2271             if (bounds.isEmpty()) {
2272                 if (!fBounds.isEmpty()) {
2273                     return false;
2274                 }
2275             } else {
2276                 if (!fBounds.isEmpty()) {
2277                     if (!fBounds.contains(bounds)) {
2278                         return false;
2279                     }
2280                 }
2281             }
2282         }
2283     }
2284 #endif // SK_DEBUG_PATH
2285     return true;
2286 }
2287 
2288 ///////////////////////////////////////////////////////////////////////////////
2289 
2290 #ifdef SK_LEGACY_PATH_CONVEXITY  // for rebaselining Chrome
2291 
sign(SkScalar x)2292 static int sign(SkScalar x) { return x < 0; }
2293 #define kValueNeverReturnedBySign   2
2294 
2295 enum DirChange {
2296     kLeft_DirChange,
2297     kRight_DirChange,
2298     kStraight_DirChange,
2299     kBackwards_DirChange,
2300 
2301     kInvalid_DirChange
2302 };
2303 
2304 
almost_equal(SkScalar compA,SkScalar compB)2305 static bool almost_equal(SkScalar compA, SkScalar compB) {
2306     // The error epsilon was empirically derived; worse case round rects
2307     // with a mid point outset by 2x float epsilon in tests had an error
2308     // of 12.
2309     const int epsilon = 16;
2310     if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2311         return false;
2312     }
2313     // no need to check for small numbers because SkPath::Iter has removed degenerate values
2314     int aBits = SkFloatAs2sCompliment(compA);
2315     int bBits = SkFloatAs2sCompliment(compB);
2316     return aBits < bBits + epsilon && bBits < aBits + epsilon;
2317 }
2318 
2319 // only valid for a single contour
2320 struct Convexicator {
ConvexicatorConvexicator2321     Convexicator()
2322     : fPtCount(0)
2323     , fConvexity(SkPath::kConvex_Convexity)
2324     , fFirstDirection(SkPathPriv::kUnknown_FirstDirection)
2325     , fIsFinite(true)
2326     , fIsCurve(false)
2327     , fBackwards(false) {
2328         fExpectedDir = kInvalid_DirChange;
2329         // warnings
2330         fPriorPt.set(0,0);
2331         fLastPt.set(0, 0);
2332         fCurrPt.set(0, 0);
2333         fLastVec.set(0, 0);
2334         fFirstVec.set(0, 0);
2335 
2336         fDx = fDy = 0;
2337         fSx = fSy = kValueNeverReturnedBySign;
2338     }
2339 
getConvexityConvexicator2340     SkPath::Convexity getConvexity() const { return fConvexity; }
2341 
2342     /** The direction returned is only valid if the path is determined convex */
getFirstDirectionConvexicator2343     SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirection; }
2344 
addPtConvexicator2345     void addPt(const SkPoint& pt) {
2346         if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) {
2347             return;
2348         }
2349 
2350         if (0 == fPtCount) {
2351             fCurrPt = pt;
2352             ++fPtCount;
2353         } else {
2354             SkVector vec = pt - fCurrPt;
2355             SkScalar lengthSqd = SkPointPriv::LengthSqd(vec);
2356             if (!SkScalarIsFinite(lengthSqd)) {
2357                 fIsFinite = false;
2358             } else if (lengthSqd) {
2359                 fPriorPt = fLastPt;
2360                 fLastPt = fCurrPt;
2361                 fCurrPt = pt;
2362                 if (++fPtCount == 2) {
2363                     fFirstVec = fLastVec = vec;
2364                 } else {
2365                     SkASSERT(fPtCount > 2);
2366                     this->addVec(vec);
2367                 }
2368 
2369                 int sx = sign(vec.fX);
2370                 int sy = sign(vec.fY);
2371                 fDx += (sx != fSx);
2372                 fDy += (sy != fSy);
2373                 fSx = sx;
2374                 fSy = sy;
2375 
2376                 if (fDx > 3 || fDy > 3) {
2377                     fConvexity = SkPath::kConcave_Convexity;
2378                 }
2379             }
2380         }
2381     }
2382 
closeConvexicator2383     void close() {
2384         if (fPtCount > 2) {
2385             this->addVec(fFirstVec);
2386         }
2387     }
2388 
directionChangeConvexicator2389     DirChange directionChange(const SkVector& curVec) {
2390         SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec);
2391 
2392         SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY)));
2393         SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY)));
2394         largest = SkTMax(largest, -smallest);
2395 
2396         if (!almost_equal(largest, largest + cross)) {
2397             int sign = SkScalarSignAsInt(cross);
2398             if (sign) {
2399                 return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2400             }
2401         }
2402 
2403         if (cross) {
2404             double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX);
2405             double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY);
2406             double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX);
2407             double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY);
2408             double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX;
2409             if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) {
2410                 int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross));
2411                 if (sign) {
2412                     return (1 == sign) ? kRight_DirChange : kLeft_DirChange;
2413                 }
2414             }
2415         }
2416 
2417         if (!SkScalarNearlyZero(SkPointPriv::LengthSqd(fLastVec),
2418                                 SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
2419             !SkScalarNearlyZero(SkPointPriv::LengthSqd(curVec),
2420                                 SK_ScalarNearlyZero*SK_ScalarNearlyZero) &&
2421             fLastVec.dot(curVec) < 0.0f) {
2422             return kBackwards_DirChange;
2423         }
2424 
2425         return kStraight_DirChange;
2426     }
2427 
hasBackwardsConvexicator2428     bool hasBackwards() const {
2429         return fBackwards;
2430     }
2431 
isFiniteConvexicator2432     bool isFinite() const {
2433         return fIsFinite;
2434     }
2435 
setCurveConvexicator2436     void setCurve(bool isCurve) {
2437         fIsCurve = isCurve;
2438     }
2439 
2440 private:
addVecConvexicator2441     void addVec(const SkVector& vec) {
2442         SkASSERT(vec.fX || vec.fY);
2443         DirChange dir = this->directionChange(vec);
2444         switch (dir) {
2445             case kLeft_DirChange:       // fall through
2446             case kRight_DirChange:
2447                 if (kInvalid_DirChange == fExpectedDir) {
2448                     fExpectedDir = dir;
2449                     fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kCW_FirstDirection
2450                                                                 : SkPathPriv::kCCW_FirstDirection;
2451                 } else if (dir != fExpectedDir) {
2452                     fConvexity = SkPath::kConcave_Convexity;
2453                     fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2454                 }
2455                 fLastVec = vec;
2456                 break;
2457             case kStraight_DirChange:
2458                 break;
2459             case kBackwards_DirChange:
2460                 if (fIsCurve) {
2461                     // If any of the subsequent dir is non-backward, it'll be concave.
2462                     // Otherwise, it's still convex.
2463                     fExpectedDir = dir;
2464                 }
2465                 fLastVec = vec;
2466                 fBackwards = true;
2467                 break;
2468             case kInvalid_DirChange:
2469                 SK_ABORT("Use of invalid direction change flag");
2470                 break;
2471         }
2472     }
2473 
2474     SkPoint             fPriorPt;
2475     SkPoint             fLastPt;
2476     SkPoint             fCurrPt;
2477     // fLastVec does not necessarily start at fLastPt. We only advance it when the cross product
2478     // value with the current vec is deemed to be of a significant value.
2479     SkVector            fLastVec, fFirstVec;
2480     int                 fPtCount;   // non-degenerate points
2481     DirChange           fExpectedDir;
2482     SkPath::Convexity   fConvexity;
2483     SkPathPriv::FirstDirection   fFirstDirection;
2484     int                 fDx, fDy, fSx, fSy;
2485     bool                fIsFinite;
2486     bool                fIsCurve;
2487     bool                fBackwards;
2488 };
2489 
internalGetConvexity() const2490 SkPath::Convexity SkPath::internalGetConvexity() const {
2491     // Sometimes we think we need to calculate convexity but another thread already did.
2492     auto c = this->getConvexityOrUnknown();
2493     if (c != kUnknown_Convexity) {
2494         return c;
2495     }
2496 
2497     SkPoint         pts[4];
2498     SkPath::Verb    verb;
2499     SkPath::Iter    iter(*this, true);
2500 
2501     int             contourCount = 0;
2502     int             count;
2503     Convexicator    state;
2504 
2505     if (!isFinite()) {
2506         return kUnknown_Convexity;
2507     }
2508     while ((verb = iter.next(pts, false, false)) != SkPath::kDone_Verb) {
2509         switch (verb) {
2510             case kMove_Verb:
2511                 if (++contourCount > 1) {
2512                     this->setConvexity(kConcave_Convexity);
2513                     return kConcave_Convexity;
2514                 }
2515                 pts[1] = pts[0];
2516                 // fall through
2517             case kLine_Verb:
2518                 count = 1;
2519                 state.setCurve(false);
2520                 break;
2521             case kQuad_Verb:
2522                 // fall through
2523             case kConic_Verb:
2524                 // fall through
2525             case kCubic_Verb:
2526                 count = 2 + (kCubic_Verb == verb);
2527                 // As an additional enhancement, this could set curve true only
2528                 // if the curve is nonlinear
2529                 state.setCurve(true);
2530                 break;
2531             case kClose_Verb:
2532                 state.setCurve(false);
2533                 state.close();
2534                 count = 0;
2535                 break;
2536             default:
2537                 SkDEBUGFAIL("bad verb");
2538                 this->setConvexity(kConcave_Convexity);
2539                 return kConcave_Convexity;
2540         }
2541 
2542         for (int i = 1; i <= count; i++) {
2543             state.addPt(pts[i]);
2544         }
2545         // early exit
2546         if (!state.isFinite()) {
2547             return kUnknown_Convexity;
2548         }
2549         if (kConcave_Convexity == state.getConvexity()) {
2550             this->setConvexity(kConcave_Convexity);
2551             return kConcave_Convexity;
2552         }
2553     }
2554     this->setConvexity(state.getConvexity());
2555 
2556     if (this->getConvexityOrUnknown() == kConvex_Convexity &&
2557             this->getFirstDirection() == SkPathPriv::kUnknown_FirstDirection) {
2558 
2559         if (state.getFirstDirection() == SkPathPriv::kUnknown_FirstDirection
2560                 && !this->getBounds().isEmpty()
2561                 && !state.hasBackwards()) {
2562             this->setConvexity(Convexity::kConcave_Convexity);
2563         } else {
2564             this->setFirstDirection(state.getFirstDirection());
2565         }
2566     }
2567     return this->getConvexityOrUnknown();
2568 }
2569 
2570 #else
2571 
sign(SkScalar x)2572 static int sign(SkScalar x) { return x < 0; }
2573 #define kValueNeverReturnedBySign   2
2574 
2575 enum DirChange {
2576     kUnknown_DirChange,
2577     kLeft_DirChange,
2578     kRight_DirChange,
2579     kStraight_DirChange,
2580     kBackwards_DirChange, // if double back, allow simple lines to be convex
2581     kInvalid_DirChange
2582 };
2583 
2584 
almost_equal(SkScalar compA,SkScalar compB)2585 static bool almost_equal(SkScalar compA, SkScalar compB) {
2586     // The error epsilon was empirically derived; worse case round rects
2587     // with a mid point outset by 2x float epsilon in tests had an error
2588     // of 12.
2589     const int epsilon = 16;
2590     if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2591         return false;
2592     }
2593     // no need to check for small numbers because SkPath::Iter has removed degenerate values
2594     int aBits = SkFloatAs2sCompliment(compA);
2595     int bBits = SkFloatAs2sCompliment(compB);
2596     return aBits < bBits + epsilon && bBits < aBits + epsilon;
2597 }
2598 
2599 // only valid for a single contour
2600 struct Convexicator {
2601 
2602     /** The direction returned is only valid if the path is determined convex */
getFirstDirectionConvexicator2603     SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirection; }
2604 
setMovePtConvexicator2605     void setMovePt(const SkPoint& pt) {
2606         fPriorPt = fLastPt = fCurrPt = pt;
2607     }
2608 
addPtConvexicator2609     bool addPt(const SkPoint& pt) {
2610         if (fCurrPt == pt) {
2611             return true;
2612         }
2613         fCurrPt = pt;
2614         if (fPriorPt == fLastPt) {  // should only be true for first non-zero vector
2615             fLastVec = fCurrPt - fLastPt;
2616             fFirstPt = pt;
2617         } else if (!this->addVec(fCurrPt - fLastPt)) {
2618             return false;
2619         }
2620         fPriorPt = fLastPt;
2621         fLastPt = fCurrPt;
2622         return true;
2623     }
2624 
BySignConvexicator2625     static SkPath::Convexity BySign(const SkPoint points[], int count) {
2626         const SkPoint* last = points + count;
2627         SkPoint currPt = *points++;
2628         SkPoint firstPt = currPt;
2629         int dxes = 0;
2630         int dyes = 0;
2631         int lastSx = kValueNeverReturnedBySign;
2632         int lastSy = kValueNeverReturnedBySign;
2633         for (int outerLoop = 0; outerLoop < 2; ++outerLoop ) {
2634             while (points != last) {
2635                 SkVector vec = *points - currPt;
2636                 if (!vec.isZero()) {
2637                     // give up if vector construction failed
2638                     if (!vec.isFinite()) {
2639                         return SkPath::kUnknown_Convexity;
2640                     }
2641                     int sx = sign(vec.fX);
2642                     int sy = sign(vec.fY);
2643                     dxes += (sx != lastSx);
2644                     dyes += (sy != lastSy);
2645                     if (dxes > 3 || dyes > 3) {
2646                         return SkPath::kConcave_Convexity;
2647                     }
2648                     lastSx = sx;
2649                     lastSy = sy;
2650                 }
2651                 currPt = *points++;
2652                 if (outerLoop) {
2653                     break;
2654                 }
2655             }
2656             points = &firstPt;
2657         }
2658         return SkPath::kConvex_Convexity;  // that is, it may be convex, don't know yet
2659     }
2660 
closeConvexicator2661     bool close() {
2662         return this->addPt(fFirstPt);
2663     }
2664 
isFiniteConvexicator2665     bool isFinite() const {
2666         return fIsFinite;
2667     }
2668 
reversalsConvexicator2669     int reversals() const {
2670         return fReversals;
2671     }
2672 
2673 private:
directionChangeConvexicator2674     DirChange directionChange(const SkVector& curVec) {
2675         SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec);
2676         if (!SkScalarIsFinite(cross)) {
2677                 return kUnknown_DirChange;
2678         }
2679         SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY)));
2680         SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY)));
2681         largest = SkTMax(largest, -smallest);
2682 
2683         if (almost_equal(largest, largest + cross)) {
2684             return fLastVec.dot(curVec) < 0 ? kBackwards_DirChange : kStraight_DirChange;
2685         }
2686         return 1 == SkScalarSignAsInt(cross) ? kRight_DirChange : kLeft_DirChange;
2687     }
2688 
addVecConvexicator2689     bool addVec(const SkVector& curVec) {
2690         DirChange dir = this->directionChange(curVec);
2691         switch (dir) {
2692             case kLeft_DirChange:       // fall through
2693             case kRight_DirChange:
2694                 if (kInvalid_DirChange == fExpectedDir) {
2695                     fExpectedDir = dir;
2696                     fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kCW_FirstDirection
2697                                                                 : SkPathPriv::kCCW_FirstDirection;
2698                 } else if (dir != fExpectedDir) {
2699                     fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
2700                     return false;
2701                 }
2702                 fLastVec = curVec;
2703                 break;
2704             case kStraight_DirChange:
2705                 break;
2706             case kBackwards_DirChange:
2707                 //  allow path to reverse direction twice
2708                 //    Given path.moveTo(0, 0); path.lineTo(1, 1);
2709                 //    - 1st reversal: direction change formed by line (0,0 1,1), line (1,1 0,0)
2710                 //    - 2nd reversal: direction change formed by line (1,1 0,0), line (0,0 1,1)
2711                 fLastVec = curVec;
2712                 return ++fReversals < 3;
2713             case kUnknown_DirChange:
2714                 return (fIsFinite = false);
2715             case kInvalid_DirChange:
2716                 SK_ABORT("Use of invalid direction change flag");
2717                 break;
2718         }
2719         return true;
2720     }
2721 
2722     SkPoint             fFirstPt {0, 0};
2723     SkPoint             fPriorPt {0, 0};
2724     SkPoint             fLastPt {0, 0};
2725     SkPoint             fCurrPt {0, 0};
2726     SkVector            fLastVec {0, 0};
2727     DirChange           fExpectedDir { kInvalid_DirChange };
2728     SkPathPriv::FirstDirection   fFirstDirection { SkPathPriv::kUnknown_FirstDirection };
2729     int                 fReversals { 0 };
2730     bool                fIsFinite { true };
2731 };
2732 
internalGetConvexity() const2733 SkPath::Convexity SkPath::internalGetConvexity() const {
2734     SkPoint         pts[4];
2735     SkPath::Verb    verb;
2736     SkPath::Iter    iter(*this, true);
2737     auto setComputedConvexity = [=](Convexity convexity){
2738         SkASSERT(kUnknown_Convexity != convexity);
2739         this->setConvexity(convexity);
2740         return convexity;
2741     };
2742 
2743     // Check to see if path changes direction more than three times as quick concave test
2744     int pointCount = this->countPoints();
2745     // last moveTo index may exceed point count if data comes from fuzzer (via SkImageFilter)
2746     if (0 < fLastMoveToIndex && fLastMoveToIndex < pointCount) {
2747         pointCount = fLastMoveToIndex;
2748     }
2749     if (pointCount > 3) {
2750         const SkPoint* points = fPathRef->points();
2751         const SkPoint* last = &points[pointCount];
2752         // only consider the last of the initial move tos
2753         while (SkPath::kMove_Verb == iter.next(pts)) {
2754             ++points;
2755         }
2756         --points;
2757         SkPath::Convexity convexity = Convexicator::BySign(points, (int) (last - points));
2758         if (SkPath::kConcave_Convexity == convexity) {
2759             return setComputedConvexity(SkPath::kConcave_Convexity);
2760         } else if (SkPath::kUnknown_Convexity == convexity) {
2761             return SkPath::kUnknown_Convexity;
2762         }
2763         iter.setPath(*this, true);
2764     } else if (!this->isFinite()) {
2765         return kUnknown_Convexity;
2766     }
2767 
2768     int             contourCount = 0;
2769     int             count;
2770     Convexicator    state;
2771     auto setFail = [=](){
2772         if (!state.isFinite()) {
2773             return SkPath::kUnknown_Convexity;
2774         }
2775         return setComputedConvexity(SkPath::kConcave_Convexity);
2776     };
2777 
2778     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
2779         switch (verb) {
2780             case kMove_Verb:
2781                 if (++contourCount > 1) {
2782                     return setComputedConvexity(kConcave_Convexity);
2783                 }
2784                 state.setMovePt(pts[0]);
2785                 count = 0;
2786                 break;
2787             case kLine_Verb:
2788                 count = 1;
2789                 break;
2790             case kQuad_Verb:
2791                 // fall through
2792             case kConic_Verb:
2793                 count = 2;
2794                 break;
2795             case kCubic_Verb:
2796                 count = 3;
2797                 break;
2798             case kClose_Verb:
2799                 if (!state.close()) {
2800                     return setFail();
2801                 }
2802                 count = 0;
2803                 break;
2804             default:
2805                 SkDEBUGFAIL("bad verb");
2806                 return setComputedConvexity(kConcave_Convexity);
2807         }
2808         for (int i = 1; i <= count; i++) {
2809             if (!state.addPt(pts[i])) {
2810                 return setFail();
2811             }
2812         }
2813     }
2814 
2815     if (this->getFirstDirection() == SkPathPriv::kUnknown_FirstDirection) {
2816         if (state.getFirstDirection() == SkPathPriv::kUnknown_FirstDirection
2817                 && !this->getBounds().isEmpty()) {
2818             return setComputedConvexity(state.reversals() < 3 ?
2819                     kConvex_Convexity : kConcave_Convexity);
2820         }
2821         this->setFirstDirection(state.getFirstDirection());
2822     }
2823     return setComputedConvexity(kConvex_Convexity);
2824 }
2825 
IsConvex(const SkPoint points[],int count)2826 bool SkPathPriv::IsConvex(const SkPoint points[], int count) {
2827     SkPath::Convexity convexity = Convexicator::BySign(points, count);
2828     if (SkPath::kConvex_Convexity != convexity) {
2829         return false;
2830     }
2831     Convexicator state;
2832     state.setMovePt(points[0]);
2833     for (int i = 1; i < count; i++) {
2834         if (!state.addPt(points[i])) {
2835             return false;
2836         }
2837     }
2838     if (!state.addPt(points[0])) {
2839         return false;
2840     }
2841     if (!state.close()) {
2842         return false;
2843     }
2844     return state.getFirstDirection() != SkPathPriv::kUnknown_FirstDirection
2845             || state.reversals() < 3;
2846 }
2847 
2848 #endif
2849 
2850 ///////////////////////////////////////////////////////////////////////////////
2851 
2852 class ContourIter {
2853 public:
2854     ContourIter(const SkPathRef& pathRef);
2855 
done() const2856     bool done() const { return fDone; }
2857     // if !done() then these may be called
count() const2858     int count() const { return fCurrPtCount; }
pts() const2859     const SkPoint* pts() const { return fCurrPt; }
2860     void next();
2861 
2862 private:
2863     int fCurrPtCount;
2864     const SkPoint* fCurrPt;
2865     const uint8_t* fCurrVerb;
2866     const uint8_t* fStopVerbs;
2867     const SkScalar* fCurrConicWeight;
2868     bool fDone;
2869     SkDEBUGCODE(int fContourCounter;)
2870 };
2871 
ContourIter(const SkPathRef & pathRef)2872 ContourIter::ContourIter(const SkPathRef& pathRef) {
2873     fStopVerbs = pathRef.verbsMemBegin();
2874     fDone = false;
2875     fCurrPt = pathRef.points();
2876     fCurrVerb = pathRef.verbs();
2877     fCurrConicWeight = pathRef.conicWeights();
2878     fCurrPtCount = 0;
2879     SkDEBUGCODE(fContourCounter = 0;)
2880     this->next();
2881 }
2882 
next()2883 void ContourIter::next() {
2884     if (fCurrVerb <= fStopVerbs) {
2885         fDone = true;
2886     }
2887     if (fDone) {
2888         return;
2889     }
2890 
2891     // skip pts of prev contour
2892     fCurrPt += fCurrPtCount;
2893 
2894     SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
2895     int ptCount = 1;    // moveTo
2896     const uint8_t* verbs = fCurrVerb;
2897 
2898     for (--verbs; verbs > fStopVerbs; --verbs) {
2899         switch (verbs[~0]) {
2900             case SkPath::kMove_Verb:
2901                 goto CONTOUR_END;
2902             case SkPath::kLine_Verb:
2903                 ptCount += 1;
2904                 break;
2905             case SkPath::kConic_Verb:
2906                 fCurrConicWeight += 1;
2907                 // fall-through
2908             case SkPath::kQuad_Verb:
2909                 ptCount += 2;
2910                 break;
2911             case SkPath::kCubic_Verb:
2912                 ptCount += 3;
2913                 break;
2914             case SkPath::kClose_Verb:
2915                 break;
2916             default:
2917                 SkDEBUGFAIL("unexpected verb");
2918                 break;
2919         }
2920     }
2921 CONTOUR_END:
2922     fCurrPtCount = ptCount;
2923     fCurrVerb = verbs;
2924     SkDEBUGCODE(++fContourCounter;)
2925 }
2926 
2927 // returns cross product of (p1 - p0) and (p2 - p0)
cross_prod(const SkPoint & p0,const SkPoint & p1,const SkPoint & p2)2928 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
2929     SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
2930     // We may get 0 when the above subtracts underflow. We expect this to be
2931     // very rare and lazily promote to double.
2932     if (0 == cross) {
2933         double p0x = SkScalarToDouble(p0.fX);
2934         double p0y = SkScalarToDouble(p0.fY);
2935 
2936         double p1x = SkScalarToDouble(p1.fX);
2937         double p1y = SkScalarToDouble(p1.fY);
2938 
2939         double p2x = SkScalarToDouble(p2.fX);
2940         double p2y = SkScalarToDouble(p2.fY);
2941 
2942         cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
2943                                  (p1y - p0y) * (p2x - p0x));
2944 
2945     }
2946     return cross;
2947 }
2948 
2949 // Returns the first pt with the maximum Y coordinate
find_max_y(const SkPoint pts[],int count)2950 static int find_max_y(const SkPoint pts[], int count) {
2951     SkASSERT(count > 0);
2952     SkScalar max = pts[0].fY;
2953     int firstIndex = 0;
2954     for (int i = 1; i < count; ++i) {
2955         SkScalar y = pts[i].fY;
2956         if (y > max) {
2957             max = y;
2958             firstIndex = i;
2959         }
2960     }
2961     return firstIndex;
2962 }
2963 
find_diff_pt(const SkPoint pts[],int index,int n,int inc)2964 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
2965     int i = index;
2966     for (;;) {
2967         i = (i + inc) % n;
2968         if (i == index) {   // we wrapped around, so abort
2969             break;
2970         }
2971         if (pts[index] != pts[i]) { // found a different point, success!
2972             break;
2973         }
2974     }
2975     return i;
2976 }
2977 
2978 /**
2979  *  Starting at index, and moving forward (incrementing), find the xmin and
2980  *  xmax of the contiguous points that have the same Y.
2981  */
find_min_max_x_at_y(const SkPoint pts[],int index,int n,int * maxIndexPtr)2982 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
2983                                int* maxIndexPtr) {
2984     const SkScalar y = pts[index].fY;
2985     SkScalar min = pts[index].fX;
2986     SkScalar max = min;
2987     int minIndex = index;
2988     int maxIndex = index;
2989     for (int i = index + 1; i < n; ++i) {
2990         if (pts[i].fY != y) {
2991             break;
2992         }
2993         SkScalar x = pts[i].fX;
2994         if (x < min) {
2995             min = x;
2996             minIndex = i;
2997         } else if (x > max) {
2998             max = x;
2999             maxIndex = i;
3000         }
3001     }
3002     *maxIndexPtr = maxIndex;
3003     return minIndex;
3004 }
3005 
crossToDir(SkScalar cross,SkPathPriv::FirstDirection * dir)3006 static void crossToDir(SkScalar cross, SkPathPriv::FirstDirection* dir) {
3007     *dir = cross > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
3008 }
3009 
3010 /*
3011  *  We loop through all contours, and keep the computed cross-product of the
3012  *  contour that contained the global y-max. If we just look at the first
3013  *  contour, we may find one that is wound the opposite way (correctly) since
3014  *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
3015  *  that is outer most (or at least has the global y-max) before we can consider
3016  *  its cross product.
3017  */
CheapComputeFirstDirection(const SkPath & path,FirstDirection * dir)3018 bool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* dir) {
3019     auto d = path.getFirstDirection();
3020     if (d != kUnknown_FirstDirection) {
3021         *dir = static_cast<FirstDirection>(d);
3022         return true;
3023     }
3024 
3025     // We don't want to pay the cost for computing convexity if it is unknown,
3026     // so we call getConvexityOrUnknown() instead of isConvex().
3027     if (path.getConvexityOrUnknown() == SkPath::kConvex_Convexity) {
3028         SkASSERT(path.getFirstDirection() == kUnknown_FirstDirection);
3029         *dir = static_cast<FirstDirection>(path.getFirstDirection());
3030         return false;
3031     }
3032 
3033     ContourIter iter(*path.fPathRef.get());
3034 
3035     // initialize with our logical y-min
3036     SkScalar ymax = path.getBounds().fTop;
3037     SkScalar ymaxCross = 0;
3038 
3039     for (; !iter.done(); iter.next()) {
3040         int n = iter.count();
3041         if (n < 3) {
3042             continue;
3043         }
3044 
3045         const SkPoint* pts = iter.pts();
3046         SkScalar cross = 0;
3047         int index = find_max_y(pts, n);
3048         if (pts[index].fY < ymax) {
3049             continue;
3050         }
3051 
3052         // If there is more than 1 distinct point at the y-max, we take the
3053         // x-min and x-max of them and just subtract to compute the dir.
3054         if (pts[(index + 1) % n].fY == pts[index].fY) {
3055             int maxIndex;
3056             int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
3057             if (minIndex == maxIndex) {
3058                 goto TRY_CROSSPROD;
3059             }
3060             SkASSERT(pts[minIndex].fY == pts[index].fY);
3061             SkASSERT(pts[maxIndex].fY == pts[index].fY);
3062             SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
3063             // we just subtract the indices, and let that auto-convert to
3064             // SkScalar, since we just want - or + to signal the direction.
3065             cross = minIndex - maxIndex;
3066         } else {
3067             TRY_CROSSPROD:
3068             // Find a next and prev index to use for the cross-product test,
3069             // but we try to find pts that form non-zero vectors from pts[index]
3070             //
3071             // Its possible that we can't find two non-degenerate vectors, so
3072             // we have to guard our search (e.g. all the pts could be in the
3073             // same place).
3074 
3075             // we pass n - 1 instead of -1 so we don't foul up % operator by
3076             // passing it a negative LH argument.
3077             int prev = find_diff_pt(pts, index, n, n - 1);
3078             if (prev == index) {
3079                 // completely degenerate, skip to next contour
3080                 continue;
3081             }
3082             int next = find_diff_pt(pts, index, n, 1);
3083             SkASSERT(next != index);
3084             cross = cross_prod(pts[prev], pts[index], pts[next]);
3085             // if we get a zero and the points are horizontal, then we look at the spread in
3086             // x-direction. We really should continue to walk away from the degeneracy until
3087             // there is a divergence.
3088             if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
3089                 // construct the subtract so we get the correct Direction below
3090                 cross = pts[index].fX - pts[next].fX;
3091             }
3092         }
3093 
3094         if (cross) {
3095             // record our best guess so far
3096             ymax = pts[index].fY;
3097             ymaxCross = cross;
3098         }
3099     }
3100     if (ymaxCross) {
3101         crossToDir(ymaxCross, dir);
3102         path.setFirstDirection(*dir);
3103         return true;
3104     } else {
3105         return false;
3106     }
3107 }
3108 
3109 ///////////////////////////////////////////////////////////////////////////////
3110 
between(SkScalar a,SkScalar b,SkScalar c)3111 static bool between(SkScalar a, SkScalar b, SkScalar c) {
3112     SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
3113             || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c)));
3114     return (a - b) * (c - b) <= 0;
3115 }
3116 
eval_cubic_pts(SkScalar c0,SkScalar c1,SkScalar c2,SkScalar c3,SkScalar t)3117 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
3118                                SkScalar t) {
3119     SkScalar A = c3 + 3*(c1 - c2) - c0;
3120     SkScalar B = 3*(c2 - c1 - c1 + c0);
3121     SkScalar C = 3*(c1 - c0);
3122     SkScalar D = c0;
3123     return poly_eval(A, B, C, D, t);
3124 }
3125 
find_minmax(const SkPoint pts[],SkScalar * minPtr,SkScalar * maxPtr)3126 template <size_t N> static void find_minmax(const SkPoint pts[],
3127                                             SkScalar* minPtr, SkScalar* maxPtr) {
3128     SkScalar min, max;
3129     min = max = pts[0].fX;
3130     for (size_t i = 1; i < N; ++i) {
3131         min = SkMinScalar(min, pts[i].fX);
3132         max = SkMaxScalar(max, pts[i].fX);
3133     }
3134     *minPtr = min;
3135     *maxPtr = max;
3136 }
3137 
checkOnCurve(SkScalar x,SkScalar y,const SkPoint & start,const SkPoint & end)3138 static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) {
3139     if (start.fY == end.fY) {
3140         return between(start.fX, x, end.fX) && x != end.fX;
3141     } else {
3142         return x == start.fX && y == start.fY;
3143     }
3144 }
3145 
winding_mono_cubic(const SkPoint pts[],SkScalar x,SkScalar y,int * onCurveCount)3146 static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
3147     SkScalar y0 = pts[0].fY;
3148     SkScalar y3 = pts[3].fY;
3149 
3150     int dir = 1;
3151     if (y0 > y3) {
3152         using std::swap;
3153         swap(y0, y3);
3154         dir = -1;
3155     }
3156     if (y < y0 || y > y3) {
3157         return 0;
3158     }
3159     if (checkOnCurve(x, y, pts[0], pts[3])) {
3160         *onCurveCount += 1;
3161         return 0;
3162     }
3163     if (y == y3) {
3164         return 0;
3165     }
3166 
3167     // quickreject or quickaccept
3168     SkScalar min, max;
3169     find_minmax<4>(pts, &min, &max);
3170     if (x < min) {
3171         return 0;
3172     }
3173     if (x > max) {
3174         return dir;
3175     }
3176 
3177     // compute the actual x(t) value
3178     SkScalar t;
3179     if (!SkCubicClipper::ChopMonoAtY(pts, y, &t)) {
3180         return 0;
3181     }
3182     SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
3183     if (SkScalarNearlyEqual(xt, x)) {
3184         if (x != pts[3].fX || y != pts[3].fY) {  // don't test end points; they're start points
3185             *onCurveCount += 1;
3186             return 0;
3187         }
3188     }
3189     return xt < x ? dir : 0;
3190 }
3191 
winding_cubic(const SkPoint pts[],SkScalar x,SkScalar y,int * onCurveCount)3192 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
3193     SkPoint dst[10];
3194     int n = SkChopCubicAtYExtrema(pts, dst);
3195     int w = 0;
3196     for (int i = 0; i <= n; ++i) {
3197         w += winding_mono_cubic(&dst[i * 3], x, y, onCurveCount);
3198     }
3199     return w;
3200 }
3201 
conic_eval_numerator(const SkScalar src[],SkScalar w,SkScalar t)3202 static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) {
3203     SkASSERT(src);
3204     SkASSERT(t >= 0 && t <= 1);
3205     SkScalar src2w = src[2] * w;
3206     SkScalar C = src[0];
3207     SkScalar A = src[4] - 2 * src2w + C;
3208     SkScalar B = 2 * (src2w - C);
3209     return poly_eval(A, B, C, t);
3210 }
3211 
3212 
conic_eval_denominator(SkScalar w,SkScalar t)3213 static double conic_eval_denominator(SkScalar w, SkScalar t) {
3214     SkScalar B = 2 * (w - 1);
3215     SkScalar C = 1;
3216     SkScalar A = -B;
3217     return poly_eval(A, B, C, t);
3218 }
3219 
winding_mono_conic(const SkConic & conic,SkScalar x,SkScalar y,int * onCurveCount)3220 static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) {
3221     const SkPoint* pts = conic.fPts;
3222     SkScalar y0 = pts[0].fY;
3223     SkScalar y2 = pts[2].fY;
3224 
3225     int dir = 1;
3226     if (y0 > y2) {
3227         using std::swap;
3228         swap(y0, y2);
3229         dir = -1;
3230     }
3231     if (y < y0 || y > y2) {
3232         return 0;
3233     }
3234     if (checkOnCurve(x, y, pts[0], pts[2])) {
3235         *onCurveCount += 1;
3236         return 0;
3237     }
3238     if (y == y2) {
3239         return 0;
3240     }
3241 
3242     SkScalar roots[2];
3243     SkScalar A = pts[2].fY;
3244     SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y;
3245     SkScalar C = pts[0].fY;
3246     A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
3247     B -= C;  // B = b*w - w * yCept + yCept - a
3248     C -= y;
3249     int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
3250     SkASSERT(n <= 1);
3251     SkScalar xt;
3252     if (0 == n) {
3253         // zero roots are returned only when y0 == y
3254         // Need [0] if dir == 1
3255         // and  [2] if dir == -1
3256         xt = pts[1 - dir].fX;
3257     } else {
3258         SkScalar t = roots[0];
3259         xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t);
3260     }
3261     if (SkScalarNearlyEqual(xt, x)) {
3262         if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
3263             *onCurveCount += 1;
3264             return 0;
3265         }
3266     }
3267     return xt < x ? dir : 0;
3268 }
3269 
is_mono_quad(SkScalar y0,SkScalar y1,SkScalar y2)3270 static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) {
3271     //    return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0;
3272     if (y0 == y1) {
3273         return true;
3274     }
3275     if (y0 < y1) {
3276         return y1 <= y2;
3277     } else {
3278         return y1 >= y2;
3279     }
3280 }
3281 
winding_conic(const SkPoint pts[],SkScalar x,SkScalar y,SkScalar weight,int * onCurveCount)3282 static int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight,
3283                          int* onCurveCount) {
3284     SkConic conic(pts, weight);
3285     SkConic chopped[2];
3286     // If the data points are very large, the conic may not be monotonic but may also
3287     // fail to chop. Then, the chopper does not split the original conic in two.
3288     bool isMono = is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped);
3289     int w = winding_mono_conic(isMono ? conic : chopped[0], x, y, onCurveCount);
3290     if (!isMono) {
3291         w += winding_mono_conic(chopped[1], x, y, onCurveCount);
3292     }
3293     return w;
3294 }
3295 
winding_mono_quad(const SkPoint pts[],SkScalar x,SkScalar y,int * onCurveCount)3296 static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
3297     SkScalar y0 = pts[0].fY;
3298     SkScalar y2 = pts[2].fY;
3299 
3300     int dir = 1;
3301     if (y0 > y2) {
3302         using std::swap;
3303         swap(y0, y2);
3304         dir = -1;
3305     }
3306     if (y < y0 || y > y2) {
3307         return 0;
3308     }
3309     if (checkOnCurve(x, y, pts[0], pts[2])) {
3310         *onCurveCount += 1;
3311         return 0;
3312     }
3313     if (y == y2) {
3314         return 0;
3315     }
3316     // bounds check on X (not required. is it faster?)
3317 #if 0
3318     if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) {
3319         return 0;
3320     }
3321 #endif
3322 
3323     SkScalar roots[2];
3324     int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
3325                                 2 * (pts[1].fY - pts[0].fY),
3326                                 pts[0].fY - y,
3327                                 roots);
3328     SkASSERT(n <= 1);
3329     SkScalar xt;
3330     if (0 == n) {
3331         // zero roots are returned only when y0 == y
3332         // Need [0] if dir == 1
3333         // and  [2] if dir == -1
3334         xt = pts[1 - dir].fX;
3335     } else {
3336         SkScalar t = roots[0];
3337         SkScalar C = pts[0].fX;
3338         SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
3339         SkScalar B = 2 * (pts[1].fX - C);
3340         xt = poly_eval(A, B, C, t);
3341     }
3342     if (SkScalarNearlyEqual(xt, x)) {
3343         if (x != pts[2].fX || y != pts[2].fY) {  // don't test end points; they're start points
3344             *onCurveCount += 1;
3345             return 0;
3346         }
3347     }
3348     return xt < x ? dir : 0;
3349 }
3350 
winding_quad(const SkPoint pts[],SkScalar x,SkScalar y,int * onCurveCount)3351 static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
3352     SkPoint dst[5];
3353     int     n = 0;
3354 
3355     if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) {
3356         n = SkChopQuadAtYExtrema(pts, dst);
3357         pts = dst;
3358     }
3359     int w = winding_mono_quad(pts, x, y, onCurveCount);
3360     if (n > 0) {
3361         w += winding_mono_quad(&pts[2], x, y, onCurveCount);
3362     }
3363     return w;
3364 }
3365 
winding_line(const SkPoint pts[],SkScalar x,SkScalar y,int * onCurveCount)3366 static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
3367     SkScalar x0 = pts[0].fX;
3368     SkScalar y0 = pts[0].fY;
3369     SkScalar x1 = pts[1].fX;
3370     SkScalar y1 = pts[1].fY;
3371 
3372     SkScalar dy = y1 - y0;
3373 
3374     int dir = 1;
3375     if (y0 > y1) {
3376         using std::swap;
3377         swap(y0, y1);
3378         dir = -1;
3379     }
3380     if (y < y0 || y > y1) {
3381         return 0;
3382     }
3383     if (checkOnCurve(x, y, pts[0], pts[1])) {
3384         *onCurveCount += 1;
3385         return 0;
3386     }
3387     if (y == y1) {
3388         return 0;
3389     }
3390     SkScalar cross = (x1 - x0) * (y - pts[0].fY) - dy * (x - x0);
3391 
3392     if (!cross) {
3393         // zero cross means the point is on the line, and since the case where
3394         // y of the query point is at the end point is handled above, we can be
3395         // sure that we're on the line (excluding the end point) here
3396         if (x != x1 || y != pts[1].fY) {
3397             *onCurveCount += 1;
3398         }
3399         dir = 0;
3400     } else if (SkScalarSignAsInt(cross) == dir) {
3401         dir = 0;
3402     }
3403     return dir;
3404 }
3405 
tangent_cubic(const SkPoint pts[],SkScalar x,SkScalar y,SkTDArray<SkVector> * tangents)3406 static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y,
3407         SkTDArray<SkVector>* tangents) {
3408     if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)
3409              && !between(pts[2].fY, y, pts[3].fY)) {
3410         return;
3411     }
3412     if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)
3413              && !between(pts[2].fX, x, pts[3].fX)) {
3414         return;
3415     }
3416     SkPoint dst[10];
3417     int n = SkChopCubicAtYExtrema(pts, dst);
3418     for (int i = 0; i <= n; ++i) {
3419         SkPoint* c = &dst[i * 3];
3420         SkScalar t;
3421         if (!SkCubicClipper::ChopMonoAtY(c, y, &t)) {
3422             continue;
3423         }
3424         SkScalar xt = eval_cubic_pts(c[0].fX, c[1].fX, c[2].fX, c[3].fX, t);
3425         if (!SkScalarNearlyEqual(x, xt)) {
3426             continue;
3427         }
3428         SkVector tangent;
3429         SkEvalCubicAt(c, t, nullptr, &tangent, nullptr);
3430         tangents->push_back(tangent);
3431     }
3432 }
3433 
tangent_conic(const SkPoint pts[],SkScalar x,SkScalar y,SkScalar w,SkTDArray<SkVector> * tangents)3434 static void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w,
3435             SkTDArray<SkVector>* tangents) {
3436     if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
3437         return;
3438     }
3439     if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
3440         return;
3441     }
3442     SkScalar roots[2];
3443     SkScalar A = pts[2].fY;
3444     SkScalar B = pts[1].fY * w - y * w + y;
3445     SkScalar C = pts[0].fY;
3446     A += C - 2 * B;  // A = a + c - 2*(b*w - yCept*w + yCept)
3447     B -= C;  // B = b*w - w * yCept + yCept - a
3448     C -= y;
3449     int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
3450     for (int index = 0; index < n; ++index) {
3451         SkScalar t = roots[index];
3452         SkScalar xt = conic_eval_numerator(&pts[0].fX, w, t) / conic_eval_denominator(w, t);
3453         if (!SkScalarNearlyEqual(x, xt)) {
3454             continue;
3455         }
3456         SkConic conic(pts, w);
3457         tangents->push_back(conic.evalTangentAt(t));
3458     }
3459 }
3460 
tangent_quad(const SkPoint pts[],SkScalar x,SkScalar y,SkTDArray<SkVector> * tangents)3461 static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y,
3462         SkTDArray<SkVector>* tangents) {
3463     if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) {
3464         return;
3465     }
3466     if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) {
3467         return;
3468     }
3469     SkScalar roots[2];
3470     int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
3471                                 2 * (pts[1].fY - pts[0].fY),
3472                                 pts[0].fY - y,
3473                                 roots);
3474     for (int index = 0; index < n; ++index) {
3475         SkScalar t = roots[index];
3476         SkScalar C = pts[0].fX;
3477         SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
3478         SkScalar B = 2 * (pts[1].fX - C);
3479         SkScalar xt = poly_eval(A, B, C, t);
3480         if (!SkScalarNearlyEqual(x, xt)) {
3481             continue;
3482         }
3483         tangents->push_back(SkEvalQuadTangentAt(pts, t));
3484     }
3485 }
3486 
tangent_line(const SkPoint pts[],SkScalar x,SkScalar y,SkTDArray<SkVector> * tangents)3487 static void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y,
3488         SkTDArray<SkVector>* tangents) {
3489     SkScalar y0 = pts[0].fY;
3490     SkScalar y1 = pts[1].fY;
3491     if (!between(y0, y, y1)) {
3492         return;
3493     }
3494     SkScalar x0 = pts[0].fX;
3495     SkScalar x1 = pts[1].fX;
3496     if (!between(x0, x, x1)) {
3497         return;
3498     }
3499     SkScalar dx = x1 - x0;
3500     SkScalar dy = y1 - y0;
3501     if (!SkScalarNearlyEqual((x - x0) * dy, dx * (y - y0))) {
3502         return;
3503     }
3504     SkVector v;
3505     v.set(dx, dy);
3506     tangents->push_back(v);
3507 }
3508 
contains_inclusive(const SkRect & r,SkScalar x,SkScalar y)3509 static bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) {
3510     return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom;
3511 }
3512 
contains(SkScalar x,SkScalar y) const3513 bool SkPath::contains(SkScalar x, SkScalar y) const {
3514     bool isInverse = this->isInverseFillType();
3515     if (this->isEmpty()) {
3516         return isInverse;
3517     }
3518 
3519     if (!contains_inclusive(this->getBounds(), x, y)) {
3520         return isInverse;
3521     }
3522 
3523     SkPath::Iter iter(*this, true);
3524     bool done = false;
3525     int w = 0;
3526     int onCurveCount = 0;
3527     do {
3528         SkPoint pts[4];
3529         switch (iter.next(pts)) {
3530             case SkPath::kMove_Verb:
3531             case SkPath::kClose_Verb:
3532                 break;
3533             case SkPath::kLine_Verb:
3534                 w += winding_line(pts, x, y, &onCurveCount);
3535                 break;
3536             case SkPath::kQuad_Verb:
3537                 w += winding_quad(pts, x, y, &onCurveCount);
3538                 break;
3539             case SkPath::kConic_Verb:
3540                 w += winding_conic(pts, x, y, iter.conicWeight(), &onCurveCount);
3541                 break;
3542             case SkPath::kCubic_Verb:
3543                 w += winding_cubic(pts, x, y, &onCurveCount);
3544                 break;
3545             case SkPath::kDone_Verb:
3546                 done = true;
3547                 break;
3548        }
3549     } while (!done);
3550     bool evenOddFill = SkPath::kEvenOdd_FillType == this->getFillType()
3551             || SkPath::kInverseEvenOdd_FillType == this->getFillType();
3552     if (evenOddFill) {
3553         w &= 1;
3554     }
3555     if (w) {
3556         return !isInverse;
3557     }
3558     if (onCurveCount <= 1) {
3559         return SkToBool(onCurveCount) ^ isInverse;
3560     }
3561     if ((onCurveCount & 1) || evenOddFill) {
3562         return SkToBool(onCurveCount & 1) ^ isInverse;
3563     }
3564     // If the point touches an even number of curves, and the fill is winding, check for
3565     // coincidence. Count coincidence as places where the on curve points have identical tangents.
3566     iter.setPath(*this, true);
3567     done = false;
3568     SkTDArray<SkVector> tangents;
3569     do {
3570         SkPoint pts[4];
3571         int oldCount = tangents.count();
3572         switch (iter.next(pts)) {
3573             case SkPath::kMove_Verb:
3574             case SkPath::kClose_Verb:
3575                 break;
3576             case SkPath::kLine_Verb:
3577                 tangent_line(pts, x, y, &tangents);
3578                 break;
3579             case SkPath::kQuad_Verb:
3580                 tangent_quad(pts, x, y, &tangents);
3581                 break;
3582             case SkPath::kConic_Verb:
3583                 tangent_conic(pts, x, y, iter.conicWeight(), &tangents);
3584                 break;
3585             case SkPath::kCubic_Verb:
3586                 tangent_cubic(pts, x, y, &tangents);
3587                 break;
3588             case SkPath::kDone_Verb:
3589                 done = true;
3590                 break;
3591        }
3592        if (tangents.count() > oldCount) {
3593             int last = tangents.count() - 1;
3594             const SkVector& tangent = tangents[last];
3595             if (SkScalarNearlyZero(SkPointPriv::LengthSqd(tangent))) {
3596                 tangents.remove(last);
3597             } else {
3598                 for (int index = 0; index < last; ++index) {
3599                     const SkVector& test = tangents[index];
3600                     if (SkScalarNearlyZero(test.cross(tangent))
3601                             && SkScalarSignAsInt(tangent.fX * test.fX) <= 0
3602                             && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) {
3603                         tangents.remove(last);
3604                         tangents.removeShuffle(index);
3605                         break;
3606                     }
3607                 }
3608             }
3609         }
3610     } while (!done);
3611     return SkToBool(tangents.count()) ^ isInverse;
3612 }
3613 
ConvertConicToQuads(const SkPoint & p0,const SkPoint & p1,const SkPoint & p2,SkScalar w,SkPoint pts[],int pow2)3614 int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
3615                                 SkScalar w, SkPoint pts[], int pow2) {
3616     const SkConic conic(p0, p1, p2, w);
3617     return conic.chopIntoQuadsPOW2(pts, pow2);
3618 }
3619 
IsSimpleClosedRect(const SkPath & path,SkRect * rect,SkPath::Direction * direction,unsigned * start)3620 bool SkPathPriv::IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction,
3621                                     unsigned* start) {
3622     if (path.getSegmentMasks() != SkPath::kLine_SegmentMask) {
3623         return false;
3624     }
3625     SkPath::RawIter iter(path);
3626     SkPoint verbPts[4];
3627     SkPath::Verb v;
3628     SkPoint rectPts[5];
3629     int rectPtCnt = 0;
3630     while ((v = iter.next(verbPts)) != SkPath::kDone_Verb) {
3631         switch (v) {
3632             case SkPath::kMove_Verb:
3633                 if (0 != rectPtCnt) {
3634                     return false;
3635                 }
3636                 rectPts[0] = verbPts[0];
3637                 ++rectPtCnt;
3638                 break;
3639             case SkPath::kLine_Verb:
3640                 if (5 == rectPtCnt) {
3641                     return false;
3642                 }
3643                 rectPts[rectPtCnt] = verbPts[1];
3644                 ++rectPtCnt;
3645                 break;
3646             case SkPath::kClose_Verb:
3647                 if (4 == rectPtCnt) {
3648                     rectPts[4] = rectPts[0];
3649                     rectPtCnt = 5;
3650                 }
3651                 break;
3652             default:
3653                 return false;
3654         }
3655     }
3656     if (rectPtCnt < 5) {
3657         return false;
3658     }
3659     if (rectPts[0] != rectPts[4]) {
3660         return false;
3661     }
3662     // Check for two cases of rectangles: pts 0 and 3 form a vertical edge or a horizontal edge (
3663     // and pts 1 and 2 the opposite vertical or horizontal edge).
3664     bool vec03IsVertical;
3665     if (rectPts[0].fX == rectPts[3].fX && rectPts[1].fX == rectPts[2].fX &&
3666         rectPts[0].fY == rectPts[1].fY && rectPts[3].fY == rectPts[2].fY) {
3667         // Make sure it has non-zero width and height
3668         if (rectPts[0].fX == rectPts[1].fX || rectPts[0].fY == rectPts[3].fY) {
3669             return false;
3670         }
3671         vec03IsVertical = true;
3672     } else if (rectPts[0].fY == rectPts[3].fY && rectPts[1].fY == rectPts[2].fY &&
3673                rectPts[0].fX == rectPts[1].fX && rectPts[3].fX == rectPts[2].fX) {
3674         // Make sure it has non-zero width and height
3675         if (rectPts[0].fY == rectPts[1].fY || rectPts[0].fX == rectPts[3].fX) {
3676             return false;
3677         }
3678         vec03IsVertical = false;
3679     } else {
3680         return false;
3681     }
3682     // Set sortFlags so that it has the low bit set if pt index 0 is on right edge and second bit
3683     // set if it is on the bottom edge.
3684     unsigned sortFlags =
3685             ((rectPts[0].fX < rectPts[2].fX) ? 0b00 : 0b01) |
3686             ((rectPts[0].fY < rectPts[2].fY) ? 0b00 : 0b10);
3687     switch (sortFlags) {
3688         case 0b00:
3689             rect->set(rectPts[0].fX, rectPts[0].fY, rectPts[2].fX, rectPts[2].fY);
3690             *direction = vec03IsVertical ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
3691             *start = 0;
3692             break;
3693         case 0b01:
3694             rect->set(rectPts[2].fX, rectPts[0].fY, rectPts[0].fX, rectPts[2].fY);
3695             *direction = vec03IsVertical ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
3696             *start = 1;
3697             break;
3698         case 0b10:
3699             rect->set(rectPts[0].fX, rectPts[2].fY, rectPts[2].fX, rectPts[0].fY);
3700             *direction = vec03IsVertical ? SkPath::kCCW_Direction : SkPath::kCW_Direction;
3701             *start = 3;
3702             break;
3703         case 0b11:
3704             rect->set(rectPts[2].fX, rectPts[2].fY, rectPts[0].fX, rectPts[0].fY);
3705             *direction = vec03IsVertical ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
3706             *start = 2;
3707             break;
3708     }
3709     return true;
3710 }
3711 
DrawArcIsConvex(SkScalar sweepAngle,bool useCenter,bool isFillNoPathEffect)3712 bool SkPathPriv::DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
3713     if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
3714         // This gets converted to an oval.
3715         return true;
3716     }
3717     if (useCenter) {
3718         // This is a pie wedge. It's convex if the angle is <= 180.
3719         return SkScalarAbs(sweepAngle) <= 180.f;
3720     }
3721     // When the angle exceeds 360 this wraps back on top of itself. Otherwise it is a circle clipped
3722     // to a secant, i.e. convex.
3723     return SkScalarAbs(sweepAngle) <= 360.f;
3724 }
3725 
CreateDrawArcPath(SkPath * path,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,bool isFillNoPathEffect)3726 void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
3727                                    SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
3728     SkASSERT(!oval.isEmpty());
3729     SkASSERT(sweepAngle);
3730 
3731     path->reset();
3732     path->setIsVolatile(true);
3733     path->setFillType(SkPath::kWinding_FillType);
3734     if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
3735         path->addOval(oval);
3736         SkASSERT(path->isConvex() && DrawArcIsConvex(sweepAngle, false, isFillNoPathEffect));
3737         return;
3738     }
3739     if (useCenter) {
3740         path->moveTo(oval.centerX(), oval.centerY());
3741     }
3742     auto firstDir =
3743             sweepAngle > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
3744     bool convex = DrawArcIsConvex(sweepAngle, useCenter, isFillNoPathEffect);
3745     // Arc to mods at 360 and drawArc is not supposed to.
3746     bool forceMoveTo = !useCenter;
3747     while (sweepAngle <= -360.f) {
3748         path->arcTo(oval, startAngle, -180.f, forceMoveTo);
3749         startAngle -= 180.f;
3750         path->arcTo(oval, startAngle, -180.f, false);
3751         startAngle -= 180.f;
3752         forceMoveTo = false;
3753         sweepAngle += 360.f;
3754     }
3755     while (sweepAngle >= 360.f) {
3756         path->arcTo(oval, startAngle, 180.f, forceMoveTo);
3757         startAngle += 180.f;
3758         path->arcTo(oval, startAngle, 180.f, false);
3759         startAngle += 180.f;
3760         forceMoveTo = false;
3761         sweepAngle -= 360.f;
3762     }
3763     path->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
3764     if (useCenter) {
3765         path->close();
3766     }
3767     path->setConvexity(convex ? SkPath::kConvex_Convexity : SkPath::kConcave_Convexity);
3768     path->setFirstDirection(firstDir);
3769 }
3770 
3771 ///////////////////////////////////////////////////////////////////////////////////////////////////
3772 #include "include/private/SkNx.h"
3773 
compute_quad_extremas(const SkPoint src[3],SkPoint extremas[3])3774 static int compute_quad_extremas(const SkPoint src[3], SkPoint extremas[3]) {
3775     SkScalar ts[2];
3776     int n  = SkFindQuadExtrema(src[0].fX, src[1].fX, src[2].fX, ts);
3777         n += SkFindQuadExtrema(src[0].fY, src[1].fY, src[2].fY, &ts[n]);
3778     SkASSERT(n >= 0 && n <= 2);
3779     for (int i = 0; i < n; ++i) {
3780         extremas[i] = SkEvalQuadAt(src, ts[i]);
3781     }
3782     extremas[n] = src[2];
3783     return n + 1;
3784 }
3785 
compute_conic_extremas(const SkPoint src[3],SkScalar w,SkPoint extremas[3])3786 static int compute_conic_extremas(const SkPoint src[3], SkScalar w, SkPoint extremas[3]) {
3787     SkConic conic(src[0], src[1], src[2], w);
3788     SkScalar ts[2];
3789     int n  = conic.findXExtrema(ts);
3790         n += conic.findYExtrema(&ts[n]);
3791     SkASSERT(n >= 0 && n <= 2);
3792     for (int i = 0; i < n; ++i) {
3793         extremas[i] = conic.evalAt(ts[i]);
3794     }
3795     extremas[n] = src[2];
3796     return n + 1;
3797 }
3798 
compute_cubic_extremas(const SkPoint src[4],SkPoint extremas[5])3799 static int compute_cubic_extremas(const SkPoint src[4], SkPoint extremas[5]) {
3800     SkScalar ts[4];
3801     int n  = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX, src[3].fX, ts);
3802         n += SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, src[3].fY, &ts[n]);
3803     SkASSERT(n >= 0 && n <= 4);
3804     for (int i = 0; i < n; ++i) {
3805         SkEvalCubicAt(src, ts[i], &extremas[i], nullptr, nullptr);
3806     }
3807     extremas[n] = src[3];
3808     return n + 1;
3809 }
3810 
computeTightBounds() const3811 SkRect SkPath::computeTightBounds() const {
3812     if (0 == this->countVerbs()) {
3813         return SkRect::MakeEmpty();
3814     }
3815 
3816     if (this->getSegmentMasks() == SkPath::kLine_SegmentMask) {
3817         return this->getBounds();
3818     }
3819 
3820     SkPoint extremas[5]; // big enough to hold worst-case curve type (cubic) extremas + 1
3821     SkPoint pts[4];
3822     SkPath::RawIter iter(*this);
3823 
3824     // initial with the first MoveTo, so we don't have to check inside the switch
3825     Sk2s min, max;
3826     min = max = from_point(this->getPoint(0));
3827     for (;;) {
3828         int count = 0;
3829         switch (iter.next(pts)) {
3830             case SkPath::kMove_Verb:
3831                 extremas[0] = pts[0];
3832                 count = 1;
3833                 break;
3834             case SkPath::kLine_Verb:
3835                 extremas[0] = pts[1];
3836                 count = 1;
3837                 break;
3838             case SkPath::kQuad_Verb:
3839                 count = compute_quad_extremas(pts, extremas);
3840                 break;
3841             case SkPath::kConic_Verb:
3842                 count = compute_conic_extremas(pts, iter.conicWeight(), extremas);
3843                 break;
3844             case SkPath::kCubic_Verb:
3845                 count = compute_cubic_extremas(pts, extremas);
3846                 break;
3847             case SkPath::kClose_Verb:
3848                 break;
3849             case SkPath::kDone_Verb:
3850                 goto DONE;
3851         }
3852         for (int i = 0; i < count; ++i) {
3853             Sk2s tmp = from_point(extremas[i]);
3854             min = Sk2s::Min(min, tmp);
3855             max = Sk2s::Max(max, tmp);
3856         }
3857     }
3858 DONE:
3859     SkRect bounds;
3860     min.store((SkPoint*)&bounds.fLeft);
3861     max.store((SkPoint*)&bounds.fRight);
3862     return bounds;
3863 }
3864 
IsLineDegenerate(const SkPoint & p1,const SkPoint & p2,bool exact)3865 bool SkPath::IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact) {
3866     return exact ? p1 == p2 : SkPointPriv::EqualsWithinTolerance(p1, p2);
3867 }
3868 
IsQuadDegenerate(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3,bool exact)3869 bool SkPath::IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
3870                                 const SkPoint& p3, bool exact) {
3871     return exact ? p1 == p2 && p2 == p3 : SkPointPriv::EqualsWithinTolerance(p1, p2) &&
3872             SkPointPriv::EqualsWithinTolerance(p2, p3);
3873 }
3874 
IsCubicDegenerate(const SkPoint & p1,const SkPoint & p2,const SkPoint & p3,const SkPoint & p4,bool exact)3875 bool SkPath::IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
3876                                 const SkPoint& p3, const SkPoint& p4, bool exact) {
3877     return exact ? p1 == p2 && p2 == p3 && p3 == p4 :
3878             SkPointPriv::EqualsWithinTolerance(p1, p2) &&
3879             SkPointPriv::EqualsWithinTolerance(p2, p3) &&
3880             SkPointPriv::EqualsWithinTolerance(p3, p4);
3881 }
3882