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