• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkPath.h"
11 #include "SkBuffer.h"
12 #include "SkMath.h"
13 #include "SkPathRef.h"
14 #include "SkRRect.h"
15 #include "SkThread.h"
16 
17 ////////////////////////////////////////////////////////////////////////////
18 
19 #if SK_DEBUG_PATH_REF
20 
PathRefDebugRef(SkPath * owner)21 SkPath::PathRefDebugRef::PathRefDebugRef(SkPath* owner) : fOwner(owner) {}
22 
PathRefDebugRef(SkPathRef * pr,SkPath * owner)23 SkPath::PathRefDebugRef::PathRefDebugRef(SkPathRef* pr, SkPath* owner)
24 : fPathRef(pr)
25 , fOwner(owner) {
26     pr->addOwner(owner);
27 }
28 
~PathRefDebugRef()29 SkPath::PathRefDebugRef::~PathRefDebugRef() {
30     fPathRef->removeOwner(fOwner);
31 }
32 
reset(SkPathRef * ref)33 void SkPath::PathRefDebugRef::reset(SkPathRef* ref) {
34     bool diff = (ref != fPathRef.get());
35     if (diff && NULL != fPathRef.get()) {
36         fPathRef.get()->removeOwner(fOwner);
37     }
38     fPathRef.reset(ref);
39     if (diff && NULL != fPathRef.get()) {
40         fPathRef.get()->addOwner(fOwner);
41     }
42 }
43 
swap(SkPath::PathRefDebugRef * other)44 void SkPath::PathRefDebugRef::swap(SkPath::PathRefDebugRef* other) {
45     if (other->fPathRef.get() != fPathRef.get()) {
46         other->fPathRef->removeOwner(other->fOwner);
47         other->fPathRef->addOwner(fOwner);
48 
49         fPathRef->removeOwner(fOwner);
50         fPathRef->addOwner(other->fOwner);
51     }
52 
53     fPathRef.swap(&other->fPathRef);
54 }
55 
get() const56 SkPathRef* SkPath::PathRefDebugRef::get() const { return fPathRef.get(); }
57 
operator ->() const58 SkAutoTUnref<SkPathRef>::BlockRefType *SkPath::PathRefDebugRef::operator->() const {
59     return fPathRef.operator->();
60 }
61 
operator SkPathRef*()62 SkPath::PathRefDebugRef::operator SkPathRef*() {
63     return fPathRef.operator SkPathRef *();
64 }
65 
66 #endif
67 
68 ////////////////////////////////////////////////////////////////////////////
69 
70 
71 SK_DEFINE_INST_COUNT(SkPath);
72 
73 // This value is just made-up for now. When count is 4, calling memset was much
74 // slower than just writing the loop. This seems odd, and hopefully in the
75 // future this we appear to have been a fluke...
76 #define MIN_COUNT_FOR_MEMSET_TO_BE_FAST 16
77 
78 ////////////////////////////////////////////////////////////////////////////
79 
80 /**
81  *  Path.bounds is defined to be the bounds of all the control points.
82  *  If we called bounds.join(r) we would skip r if r was empty, which breaks
83  *  our promise. Hence we have a custom joiner that doesn't look at emptiness
84  */
joinNoEmptyChecks(SkRect * dst,const SkRect & src)85 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
86     dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
87     dst->fTop = SkMinScalar(dst->fTop, src.fTop);
88     dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
89     dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
90 }
91 
is_degenerate(const SkPath & path)92 static bool is_degenerate(const SkPath& path) {
93     SkPath::Iter iter(path, false);
94     SkPoint pts[4];
95     return SkPath::kDone_Verb == iter.next(pts);
96 }
97 
98 class SkAutoDisableOvalCheck {
99 public:
SkAutoDisableOvalCheck(SkPath * path)100     SkAutoDisableOvalCheck(SkPath* path) : fPath(path) {
101         fSaved = fPath->fIsOval;
102     }
103 
~SkAutoDisableOvalCheck()104     ~SkAutoDisableOvalCheck() {
105         fPath->fIsOval = fSaved;
106     }
107 
108 private:
109     SkPath* fPath;
110     bool    fSaved;
111 };
112 
113 class SkAutoDisableDirectionCheck {
114 public:
SkAutoDisableDirectionCheck(SkPath * path)115     SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) {
116         fSaved = static_cast<SkPath::Direction>(fPath->fDirection);
117     }
118 
~SkAutoDisableDirectionCheck()119     ~SkAutoDisableDirectionCheck() {
120         fPath->fDirection = fSaved;
121     }
122 
123 private:
124     SkPath*              fPath;
125     SkPath::Direction    fSaved;
126 };
127 
128 /*  This guy's constructor/destructor bracket a path editing operation. It is
129     used when we know the bounds of the amount we are going to add to the path
130     (usually a new contour, but not required).
131 
132     It captures some state about the path up front (i.e. if it already has a
133     cached bounds), and the if it can, it updates the cache bounds explicitly,
134     avoiding the need to revisit all of the points in getBounds().
135 
136     It also notes if the path was originally degenerate, and if so, sets
137     isConvex to true. Thus it can only be used if the contour being added is
138     convex.
139  */
140 class SkAutoPathBoundsUpdate {
141 public:
SkAutoPathBoundsUpdate(SkPath * path,const SkRect & r)142     SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
143         this->init(path);
144     }
145 
SkAutoPathBoundsUpdate(SkPath * path,SkScalar left,SkScalar top,SkScalar right,SkScalar bottom)146     SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
147                            SkScalar right, SkScalar bottom) {
148         fRect.set(left, top, right, bottom);
149         this->init(path);
150     }
151 
~SkAutoPathBoundsUpdate()152     ~SkAutoPathBoundsUpdate() {
153         fPath->setIsConvex(fDegenerate);
154         if (fEmpty) {
155             fPath->fBounds = fRect;
156             fPath->fBoundsIsDirty = false;
157             fPath->fIsFinite = fPath->fBounds.isFinite();
158         } else if (!fDirty) {
159             joinNoEmptyChecks(&fPath->fBounds, fRect);
160             fPath->fBoundsIsDirty = false;
161             fPath->fIsFinite = fPath->fBounds.isFinite();
162         }
163     }
164 
165 private:
166     SkPath* fPath;
167     SkRect  fRect;
168     bool    fDirty;
169     bool    fDegenerate;
170     bool    fEmpty;
171 
172     // returns true if we should proceed
init(SkPath * path)173     void init(SkPath* path) {
174         fPath = path;
175         // Mark the path's bounds as dirty if (1) they are, or (2) the path
176         // is non-finite, and therefore its bounds are not meaningful
177         fDirty = SkToBool(path->fBoundsIsDirty) || !path->fIsFinite;
178         fDegenerate = is_degenerate(*path);
179         fEmpty = path->isEmpty();
180         // Cannot use fRect for our bounds unless we know it is sorted
181         fRect.sort();
182     }
183 };
184 
185 // Return true if the computed bounds are finite.
compute_pt_bounds(SkRect * bounds,const SkPathRef & ref)186 static bool compute_pt_bounds(SkRect* bounds, const SkPathRef& ref) {
187     int count = ref.countPoints();
188     if (count <= 1) {  // we ignore just 1 point (moveto)
189         bounds->setEmpty();
190         return count ? ref.points()->isFinite() : true;
191     } else {
192         return bounds->setBoundsCheck(ref.points(), count);
193     }
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////
197 
198 /*
199     Stores the verbs and points as they are given to us, with exceptions:
200     - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic
201     - we insert a Move(0,0) if Line | Quad | Cubic is our first command
202 
203     The iterator does more cleanup, especially if forceClose == true
204     1. If we encounter degenerate segments, remove them
205     2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
206     3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
207     4. if we encounter Line | Quad | Cubic after Close, cons up a Move
208 */
209 
210 ////////////////////////////////////////////////////////////////////////////
211 
212 // flag to require a moveTo if we begin with something else, like lineTo etc.
213 #define INITIAL_LASTMOVETOINDEX_VALUE   ~0
214 
SkPath()215 SkPath::SkPath()
216 #if SK_DEBUG_PATH_REF
217     : fPathRef(SkPathRef::CreateEmpty(), this)
218 #else
219     : fPathRef(SkPathRef::CreateEmpty())
220 #endif
221     , fFillType(kWinding_FillType)
222     , fBoundsIsDirty(true) {
223     fConvexity = kUnknown_Convexity;
224     fDirection = kUnknown_Direction;
225     fSegmentMask = 0;
226     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
227     fIsOval = false;
228     fIsFinite = false;  // gets computed when we know our bounds
229 #ifdef SK_BUILD_FOR_ANDROID
230     fGenerationID = 0;
231     fSourcePath = NULL;
232 #endif
233 }
234 
SkPath(const SkPath & src)235 SkPath::SkPath(const SkPath& src)
236 #if SK_DEBUG_PATH_REF
237     : fPathRef(this)
238 #endif
239 {
240     SkDEBUGCODE(src.validate();)
241     src.fPathRef.get()->ref();
242     fPathRef.reset(src.fPathRef.get());
243     fBounds         = src.fBounds;
244     fFillType       = src.fFillType;
245     fBoundsIsDirty  = src.fBoundsIsDirty;
246     fConvexity      = src.fConvexity;
247     fDirection      = src.fDirection;
248     fIsFinite       = src.fIsFinite;
249     fSegmentMask    = src.fSegmentMask;
250     fLastMoveToIndex = src.fLastMoveToIndex;
251     fIsOval         = src.fIsOval;
252 #ifdef SK_BUILD_FOR_ANDROID
253     // the assignment operator above increments the ID so correct for that here
254     fGenerationID = src.fGenerationID;
255     fSourcePath = NULL;
256 #endif
257 }
258 
~SkPath()259 SkPath::~SkPath() {
260     SkDEBUGCODE(this->validate();)
261 }
262 
operator =(const SkPath & src)263 SkPath& SkPath::operator=(const SkPath& src) {
264     SkDEBUGCODE(src.validate();)
265 
266     if (this != &src) {
267         src.fPathRef.get()->ref();
268         fPathRef.reset(src.fPathRef.get());
269         fBounds         = src.fBounds;
270         fFillType       = src.fFillType;
271         fBoundsIsDirty  = src.fBoundsIsDirty;
272         fConvexity      = src.fConvexity;
273         fDirection      = src.fDirection;
274         fIsFinite       = src.fIsFinite;
275         fSegmentMask    = src.fSegmentMask;
276         fLastMoveToIndex = src.fLastMoveToIndex;
277         fIsOval         = src.fIsOval;
278         GEN_ID_INC;
279     }
280     SkDEBUGCODE(this->validate();)
281     return *this;
282 }
283 
operator ==(const SkPath & a,const SkPath & b)284 SK_API bool operator==(const SkPath& a, const SkPath& b) {
285     // note: don't need to look at isConvex or bounds, since just comparing the
286     // raw data is sufficient.
287 
288     // We explicitly check fSegmentMask as a quick-reject. We could skip it,
289     // since it is only a cache of info in the fVerbs, but its a fast way to
290     // notice a difference
291 
292     return &a == &b ||
293         (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
294          *a.fPathRef.get() == *b.fPathRef.get());
295 }
296 
swap(SkPath & other)297 void SkPath::swap(SkPath& other) {
298     SkASSERT(&other != NULL);
299 
300     if (this != &other) {
301         SkTSwap<SkRect>(fBounds, other.fBounds);
302         fPathRef.swap(&other.fPathRef);
303         SkTSwap<uint8_t>(fFillType, other.fFillType);
304         SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
305         SkTSwap<uint8_t>(fConvexity, other.fConvexity);
306         SkTSwap<uint8_t>(fDirection, other.fDirection);
307         SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
308         SkTSwap<int>(fLastMoveToIndex, other.fLastMoveToIndex);
309         SkTSwap<SkBool8>(fIsOval, other.fIsOval);
310         SkTSwap<SkBool8>(fIsFinite, other.fIsFinite);
311         GEN_ID_INC;
312     }
313 }
314 
check_edge_against_rect(const SkPoint & p0,const SkPoint & p1,const SkRect & rect,SkPath::Direction dir)315 static inline bool check_edge_against_rect(const SkPoint& p0,
316                                            const SkPoint& p1,
317                                            const SkRect& rect,
318                                            SkPath::Direction dir) {
319     const SkPoint* edgeBegin;
320     SkVector v;
321     if (SkPath::kCW_Direction == dir) {
322         v = p1 - p0;
323         edgeBegin = &p0;
324     } else {
325         v = p0 - p1;
326         edgeBegin = &p1;
327     }
328     if (v.fX || v.fY) {
329         // check the cross product of v with the vec from edgeBegin to each rect corner
330         SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX);
331         SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY);
332         SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX);
333         SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY);
334         if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) {
335             return false;
336         }
337     }
338     return true;
339 }
340 
conservativelyContainsRect(const SkRect & rect) const341 bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
342     // This only handles non-degenerate convex paths currently.
343     if (kConvex_Convexity != this->getConvexity()) {
344         return false;
345     }
346 
347     Direction direction;
348     if (!this->cheapComputeDirection(&direction)) {
349         return false;
350     }
351 
352     SkPoint firstPt;
353     SkPoint prevPt;
354     RawIter iter(*this);
355     SkPath::Verb verb;
356     SkPoint pts[4];
357     SkDEBUGCODE(int moveCnt = 0;)
358 
359     while ((verb = iter.next(pts)) != kDone_Verb) {
360         int nextPt = -1;
361         switch (verb) {
362             case kMove_Verb:
363                 SkASSERT(!moveCnt);
364                 SkDEBUGCODE(++moveCnt);
365                 firstPt = prevPt = pts[0];
366                 break;
367             case kLine_Verb:
368                 nextPt = 1;
369                 SkASSERT(moveCnt);
370                 break;
371             case kQuad_Verb:
372                 SkASSERT(moveCnt);
373                 nextPt = 2;
374                 break;
375             case kCubic_Verb:
376                 SkASSERT(moveCnt);
377                 nextPt = 3;
378                 break;
379             case kClose_Verb:
380                 break;
381             default:
382                 SkDEBUGFAIL("unknown verb");
383         }
384         if (-1 != nextPt) {
385             if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) {
386                 return false;
387             }
388             prevPt = pts[nextPt];
389         }
390     }
391 
392     return check_edge_against_rect(prevPt, firstPt, rect, direction);
393 }
394 
395 #ifdef SK_BUILD_FOR_ANDROID
getGenerationID() const396 uint32_t SkPath::getGenerationID() const {
397     return fGenerationID;
398 }
399 
getSourcePath() const400 const SkPath* SkPath::getSourcePath() const {
401     return fSourcePath;
402 }
403 
setSourcePath(const SkPath * path)404 void SkPath::setSourcePath(const SkPath* path) {
405     fSourcePath = path;
406 }
407 #endif
408 
reset()409 void SkPath::reset() {
410     SkDEBUGCODE(this->validate();)
411 
412     fPathRef.reset(SkPathRef::CreateEmpty());
413     GEN_ID_INC;
414     fBoundsIsDirty = true;
415     fConvexity = kUnknown_Convexity;
416     fDirection = kUnknown_Direction;
417     fSegmentMask = 0;
418     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
419     fIsOval = false;
420 }
421 
rewind()422 void SkPath::rewind() {
423     SkDEBUGCODE(this->validate();)
424 
425     SkPathRef::Rewind(&fPathRef);
426     GEN_ID_INC;
427     fConvexity = kUnknown_Convexity;
428     fBoundsIsDirty = true;
429     fSegmentMask = 0;
430     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
431     fIsOval = false;
432 }
433 
isEmpty() const434 bool SkPath::isEmpty() const {
435     SkDEBUGCODE(this->validate();)
436     return 0 == fPathRef->countVerbs();
437 }
438 
isLine(SkPoint line[2]) const439 bool SkPath::isLine(SkPoint line[2]) const {
440     int verbCount = fPathRef->countVerbs();
441     int ptCount = fPathRef->countVerbs();
442 
443     if (2 == verbCount && 2 == ptCount) {
444         if (kMove_Verb == fPathRef->atVerb(0) &&
445             kLine_Verb == fPathRef->atVerb(1)) {
446             if (line) {
447                 const SkPoint* pts = fPathRef->points();
448                 line[0] = pts[0];
449                 line[1] = pts[1];
450             }
451             return true;
452         }
453     }
454     return false;
455 }
456 
457 /*
458  Determines if path is a rect by keeping track of changes in direction
459  and looking for a loop either clockwise or counterclockwise.
460 
461  The direction is computed such that:
462   0: vertical up
463   1: horizontal left
464   2: vertical down
465   3: horizontal right
466 
467 A rectangle cycles up/right/down/left or up/left/down/right.
468 
469 The test fails if:
470   The path is closed, and followed by a line.
471   A second move creates a new endpoint.
472   A diagonal line is parsed.
473   There's more than four changes of direction.
474   There's a discontinuity on the line (e.g., a move in the middle)
475   The line reverses direction.
476   The rectangle doesn't complete a cycle.
477   The path contains a quadratic or cubic.
478   The path contains fewer than four points.
479   The final point isn't equal to the first point.
480 
481 It's OK if the path has:
482   Several colinear line segments composing a rectangle side.
483   Single points on the rectangle side.
484 
485 The direction takes advantage of the corners found since opposite sides
486 must travel in opposite directions.
487 
488 FIXME: Allow colinear quads and cubics to be treated like lines.
489 FIXME: If the API passes fill-only, return true if the filled stroke
490        is a rectangle, though the caller failed to close the path.
491  */
isRectContour(bool allowPartial,int * currVerb,const SkPoint ** ptsPtr,bool * isClosed,Direction * direction) const492 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr,
493         bool* isClosed, Direction* direction) const {
494     int corners = 0;
495     SkPoint first, last;
496     const SkPoint* pts = *ptsPtr;
497     const SkPoint* savePts = NULL;
498     first.set(0, 0);
499     last.set(0, 0);
500     int firstDirection = 0;
501     int lastDirection = 0;
502     int nextDirection = 0;
503     bool closedOrMoved = false;
504     bool autoClose = false;
505     int verbCnt = fPathRef->countVerbs();
506     while (*currVerb < verbCnt && (!allowPartial || !autoClose)) {
507         switch (fPathRef->atVerb(*currVerb)) {
508             case kClose_Verb:
509                 savePts = pts;
510                 pts = *ptsPtr;
511                 autoClose = true;
512             case kLine_Verb: {
513                 SkScalar left = last.fX;
514                 SkScalar top = last.fY;
515                 SkScalar right = pts->fX;
516                 SkScalar bottom = pts->fY;
517                 ++pts;
518                 if (left != right && top != bottom) {
519                     return false; // diagonal
520                 }
521                 if (left == right && top == bottom) {
522                     break; // single point on side OK
523                 }
524                 nextDirection = (left != right) << 0 |
525                     (left < right || top < bottom) << 1;
526                 if (0 == corners) {
527                     firstDirection = nextDirection;
528                     first = last;
529                     last = pts[-1];
530                     corners = 1;
531                     closedOrMoved = false;
532                     break;
533                 }
534                 if (closedOrMoved) {
535                     return false; // closed followed by a line
536                 }
537                 if (autoClose && nextDirection == firstDirection) {
538                     break; // colinear with first
539                 }
540                 closedOrMoved = autoClose;
541                 if (lastDirection != nextDirection) {
542                     if (++corners > 4) {
543                         return false; // too many direction changes
544                     }
545                 }
546                 last = pts[-1];
547                 if (lastDirection == nextDirection) {
548                     break; // colinear segment
549                 }
550                 // Possible values for corners are 2, 3, and 4.
551                 // When corners == 3, nextDirection opposes firstDirection.
552                 // Otherwise, nextDirection at corner 2 opposes corner 4.
553                 int turn = firstDirection ^ (corners - 1);
554                 int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
555                 if ((directionCycle ^ turn) != nextDirection) {
556                     return false; // direction didn't follow cycle
557                 }
558                 break;
559             }
560             case kQuad_Verb:
561             case kCubic_Verb:
562                 return false; // quadratic, cubic not allowed
563             case kMove_Verb:
564                 last = *pts++;
565                 closedOrMoved = true;
566                 break;
567         }
568         *currVerb += 1;
569         lastDirection = nextDirection;
570     }
571     // Success if 4 corners and first point equals last
572     bool result = 4 == corners && (first == last || autoClose);
573     if (savePts) {
574         *ptsPtr = savePts;
575     }
576     if (result && isClosed) {
577         *isClosed = autoClose;
578     }
579     if (result && direction) {
580         *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Direction : kCW_Direction;
581     }
582     return result;
583 }
584 
isRect(SkRect * rect) const585 bool SkPath::isRect(SkRect* rect) const {
586     SkDEBUGCODE(this->validate();)
587     int currVerb = 0;
588     const SkPoint* pts = fPathRef->points();
589     bool result = isRectContour(false, &currVerb, &pts, NULL, NULL);
590     if (result && rect) {
591         *rect = getBounds();
592     }
593     return result;
594 }
595 
isRect(bool * isClosed,Direction * direction) const596 bool SkPath::isRect(bool* isClosed, Direction* direction) const {
597     SkDEBUGCODE(this->validate();)
598     int currVerb = 0;
599     const SkPoint* pts = fPathRef->points();
600     return isRectContour(false, &currVerb, &pts, isClosed, direction);
601 }
602 
isNestedRects(SkRect rects[2]) const603 bool SkPath::isNestedRects(SkRect rects[2]) const {
604     SkDEBUGCODE(this->validate();)
605     int currVerb = 0;
606     const SkPoint* pts = fPathRef->points();
607     const SkPoint* first = pts;
608     if (!isRectContour(true, &currVerb, &pts, NULL, NULL)) {
609         return false;
610     }
611     const SkPoint* last = pts;
612     SkRect testRects[2];
613     if (isRectContour(false, &currVerb, &pts, NULL, NULL)) {
614         testRects[0].set(first, last - first);
615         testRects[1].set(last, pts - last);
616         if (testRects[0].contains(testRects[1])) {
617             if (rects) {
618                 rects[0] = testRects[0];
619                 rects[1] = testRects[1];
620             }
621             return true;
622         }
623         if (testRects[1].contains(testRects[0])) {
624             if (rects) {
625                 rects[0] = testRects[1];
626                 rects[1] = testRects[0];
627             }
628             return true;
629         }
630     }
631     return false;
632 }
633 
countPoints() const634 int SkPath::countPoints() const {
635     return fPathRef->countPoints();
636 }
637 
getPoints(SkPoint dst[],int max) const638 int SkPath::getPoints(SkPoint dst[], int max) const {
639     SkDEBUGCODE(this->validate();)
640 
641     SkASSERT(max >= 0);
642     SkASSERT(!max || dst);
643     int count = SkMin32(max, fPathRef->countPoints());
644     memcpy(dst, fPathRef->points(), count * sizeof(SkPoint));
645     return fPathRef->countPoints();
646 }
647 
getPoint(int index) const648 SkPoint SkPath::getPoint(int index) const {
649     if ((unsigned)index < (unsigned)fPathRef->countPoints()) {
650         return fPathRef->atPoint(index);
651     }
652     return SkPoint::Make(0, 0);
653 }
654 
countVerbs() const655 int SkPath::countVerbs() const {
656     return fPathRef->countVerbs();
657 }
658 
copy_verbs_reverse(uint8_t * inorderDst,const uint8_t * reversedSrc,int count)659 static inline void copy_verbs_reverse(uint8_t* inorderDst,
660                                       const uint8_t* reversedSrc,
661                                       int count) {
662     for (int i = 0; i < count; ++i) {
663         inorderDst[i] = reversedSrc[~i];
664     }
665 }
666 
getVerbs(uint8_t dst[],int max) const667 int SkPath::getVerbs(uint8_t dst[], int max) const {
668     SkDEBUGCODE(this->validate();)
669 
670     SkASSERT(max >= 0);
671     SkASSERT(!max || dst);
672     int count = SkMin32(max, fPathRef->countVerbs());
673     copy_verbs_reverse(dst, fPathRef->verbs(), count);
674     return fPathRef->countVerbs();
675 }
676 
getLastPt(SkPoint * lastPt) const677 bool SkPath::getLastPt(SkPoint* lastPt) const {
678     SkDEBUGCODE(this->validate();)
679 
680     int count = fPathRef->countPoints();
681     if (count > 0) {
682         if (lastPt) {
683             *lastPt = fPathRef->atPoint(count - 1);
684         }
685         return true;
686     }
687     if (lastPt) {
688         lastPt->set(0, 0);
689     }
690     return false;
691 }
692 
setLastPt(SkScalar x,SkScalar y)693 void SkPath::setLastPt(SkScalar x, SkScalar y) {
694     SkDEBUGCODE(this->validate();)
695 
696     int count = fPathRef->countPoints();
697     if (count == 0) {
698         this->moveTo(x, y);
699     } else {
700         fIsOval = false;
701         SkPathRef::Editor ed(&fPathRef);
702         ed.atPoint(count-1)->set(x, y);
703         GEN_ID_INC;
704     }
705 }
706 
computeBounds() const707 void SkPath::computeBounds() const {
708     SkDEBUGCODE(this->validate();)
709     SkASSERT(fBoundsIsDirty);
710 
711     fIsFinite = compute_pt_bounds(&fBounds, *fPathRef.get());
712     fBoundsIsDirty = false;
713 }
714 
setConvexity(Convexity c)715 void SkPath::setConvexity(Convexity c) {
716     if (fConvexity != c) {
717         fConvexity = c;
718         GEN_ID_INC;
719     }
720 }
721 
722 //////////////////////////////////////////////////////////////////////////////
723 //  Construction methods
724 
725 #define DIRTY_AFTER_EDIT                 \
726     do {                                 \
727         fBoundsIsDirty = true;           \
728         fConvexity = kUnknown_Convexity; \
729         fDirection = kUnknown_Direction; \
730         fIsOval = false;                 \
731     } while (0)
732 
733 #define DIRTY_AFTER_EDIT_NO_CONVEXITY_OR_DIRECTION_CHANGE   \
734     do {                                                    \
735         fBoundsIsDirty = true;                              \
736     } while (0)
737 
incReserve(U16CPU inc)738 void SkPath::incReserve(U16CPU inc) {
739     SkDEBUGCODE(this->validate();)
740     SkPathRef::Editor(&fPathRef, inc, inc);
741     SkDEBUGCODE(this->validate();)
742 }
743 
moveTo(SkScalar x,SkScalar y)744 void SkPath::moveTo(SkScalar x, SkScalar y) {
745     SkDEBUGCODE(this->validate();)
746 
747     SkPathRef::Editor ed(&fPathRef);
748 
749     // remember our index
750     fLastMoveToIndex = ed.pathRef()->countPoints();
751 
752     ed.growForVerb(kMove_Verb)->set(x, y);
753 
754     GEN_ID_INC;
755     DIRTY_AFTER_EDIT_NO_CONVEXITY_OR_DIRECTION_CHANGE;
756 }
757 
rMoveTo(SkScalar x,SkScalar y)758 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
759     SkPoint pt;
760     this->getLastPt(&pt);
761     this->moveTo(pt.fX + x, pt.fY + y);
762 }
763 
injectMoveToIfNeeded()764 void SkPath::injectMoveToIfNeeded() {
765     if (fLastMoveToIndex < 0) {
766         SkScalar x, y;
767         if (fPathRef->countVerbs() == 0) {
768             x = y = 0;
769         } else {
770             const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex);
771             x = pt.fX;
772             y = pt.fY;
773         }
774         this->moveTo(x, y);
775     }
776 }
777 
lineTo(SkScalar x,SkScalar y)778 void SkPath::lineTo(SkScalar x, SkScalar y) {
779     SkDEBUGCODE(this->validate();)
780 
781     this->injectMoveToIfNeeded();
782 
783     SkPathRef::Editor ed(&fPathRef);
784     ed.growForVerb(kLine_Verb)->set(x, y);
785     fSegmentMask |= kLine_SegmentMask;
786 
787     GEN_ID_INC;
788     DIRTY_AFTER_EDIT;
789 }
790 
rLineTo(SkScalar x,SkScalar y)791 void SkPath::rLineTo(SkScalar x, SkScalar y) {
792     SkPoint pt;
793     this->getLastPt(&pt);
794     this->lineTo(pt.fX + x, pt.fY + y);
795 }
796 
quadTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)797 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
798     SkDEBUGCODE(this->validate();)
799 
800     this->injectMoveToIfNeeded();
801 
802     SkPathRef::Editor ed(&fPathRef);
803     SkPoint* pts = ed.growForVerb(kQuad_Verb);
804     pts[0].set(x1, y1);
805     pts[1].set(x2, y2);
806     fSegmentMask |= kQuad_SegmentMask;
807 
808     GEN_ID_INC;
809     DIRTY_AFTER_EDIT;
810 }
811 
rQuadTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)812 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
813     SkPoint pt;
814     this->getLastPt(&pt);
815     this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
816 }
817 
cubicTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar x3,SkScalar y3)818 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
819                      SkScalar x3, SkScalar y3) {
820     SkDEBUGCODE(this->validate();)
821 
822     this->injectMoveToIfNeeded();
823 
824     SkPathRef::Editor ed(&fPathRef);
825     SkPoint* pts = ed.growForVerb(kCubic_Verb);
826     pts[0].set(x1, y1);
827     pts[1].set(x2, y2);
828     pts[2].set(x3, y3);
829     fSegmentMask |= kCubic_SegmentMask;
830 
831     GEN_ID_INC;
832     DIRTY_AFTER_EDIT;
833 }
834 
rCubicTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar x3,SkScalar y3)835 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
836                       SkScalar x3, SkScalar y3) {
837     SkPoint pt;
838     this->getLastPt(&pt);
839     this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
840                   pt.fX + x3, pt.fY + y3);
841 }
842 
close()843 void SkPath::close() {
844     SkDEBUGCODE(this->validate();)
845 
846     int count = fPathRef->countVerbs();
847     if (count > 0) {
848         switch (fPathRef->atVerb(count - 1)) {
849             case kLine_Verb:
850             case kQuad_Verb:
851             case kCubic_Verb:
852             case kMove_Verb: {
853                 SkPathRef::Editor ed(&fPathRef);
854                 ed.growForVerb(kClose_Verb);
855                 GEN_ID_INC;
856                 break;
857             }
858             default:
859                 // don't add a close if it's the first verb or a repeat
860                 break;
861         }
862     }
863 
864     // signal that we need a moveTo to follow us (unless we're done)
865 #if 0
866     if (fLastMoveToIndex >= 0) {
867         fLastMoveToIndex = ~fLastMoveToIndex;
868     }
869 #else
870     fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
871 #endif
872 }
873 
874 ///////////////////////////////////////////////////////////////////////////////
875 
assert_known_direction(int dir)876 static void assert_known_direction(int dir) {
877     SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir);
878 }
879 
addRect(const SkRect & rect,Direction dir)880 void SkPath::addRect(const SkRect& rect, Direction dir) {
881     this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
882 }
883 
addRect(SkScalar left,SkScalar top,SkScalar right,SkScalar bottom,Direction dir)884 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
885                      SkScalar bottom, Direction dir) {
886     assert_known_direction(dir);
887     fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
888     SkAutoDisableDirectionCheck addc(this);
889 
890     SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom);
891 
892     this->incReserve(5);
893 
894     this->moveTo(left, top);
895     if (dir == kCCW_Direction) {
896         this->lineTo(left, bottom);
897         this->lineTo(right, bottom);
898         this->lineTo(right, top);
899     } else {
900         this->lineTo(right, top);
901         this->lineTo(right, bottom);
902         this->lineTo(left, bottom);
903     }
904     this->close();
905 }
906 
addPoly(const SkPoint pts[],int count,bool close)907 void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
908     SkDEBUGCODE(this->validate();)
909     if (count <= 0) {
910         return;
911     }
912 
913     SkPathRef::Editor ed(&fPathRef);
914     fLastMoveToIndex = ed.pathRef()->countPoints();
915     uint8_t* vb;
916     SkPoint* p;
917     // +close makes room for the extra kClose_Verb
918     ed.grow(count + close, count, &vb, &p);
919 
920     memcpy(p, pts, count * sizeof(SkPoint));
921     vb[~0] = kMove_Verb;
922     if (count > 1) {
923         // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
924         // be 0, the compiler will remove the test/branch entirely.
925         if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
926             memset(vb - count, kLine_Verb, count - 1);
927         } else {
928             for (int i = 1; i < count; ++i) {
929                 vb[~i] = kLine_Verb;
930             }
931         }
932         fSegmentMask |= kLine_SegmentMask;
933     }
934     if (close) {
935         vb[~count] = kClose_Verb;
936     }
937 
938     GEN_ID_INC;
939     DIRTY_AFTER_EDIT;
940     SkDEBUGCODE(this->validate();)
941 }
942 
add_corner_arc(SkPath * path,const SkRect & rect,SkScalar rx,SkScalar ry,int startAngle,SkPath::Direction dir,bool forceMoveTo)943 static void add_corner_arc(SkPath* path, const SkRect& rect,
944                            SkScalar rx, SkScalar ry, int startAngle,
945                            SkPath::Direction dir, bool forceMoveTo) {
946     // These two asserts are not sufficient, since really we want to know
947     // that the pair of radii (e.g. left and right, or top and bottom) sum
948     // to <= dimension, but we don't have that data here, so we just have
949     // these conservative asserts.
950     SkASSERT(0 <= rx && rx <= rect.width());
951     SkASSERT(0 <= ry && ry <= rect.height());
952 
953     SkRect   r;
954     r.set(-rx, -ry, rx, ry);
955 
956     switch (startAngle) {
957         case   0:
958             r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom);
959             break;
960         case  90:
961             r.offset(rect.fLeft - r.fLeft,   rect.fBottom - r.fBottom);
962             break;
963         case 180: r.offset(rect.fLeft - r.fLeft,   rect.fTop - r.fTop); break;
964         case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break;
965         default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc");
966     }
967 
968     SkScalar start = SkIntToScalar(startAngle);
969     SkScalar sweep = SkIntToScalar(90);
970     if (SkPath::kCCW_Direction == dir) {
971         start += sweep;
972         sweep = -sweep;
973     }
974 
975     path->arcTo(r, start, sweep, forceMoveTo);
976 }
977 
addRoundRect(const SkRect & rect,const SkScalar radii[],Direction dir)978 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
979                           Direction dir) {
980     SkRRect rrect;
981     rrect.setRectRadii(rect, (const SkVector*) radii);
982     this->addRRect(rrect, dir);
983 }
984 
addRRect(const SkRRect & rrect,Direction dir)985 void SkPath::addRRect(const SkRRect& rrect, Direction dir) {
986     assert_known_direction(dir);
987 
988     if (rrect.isEmpty()) {
989         return;
990     }
991 
992     const SkRect& bounds = rrect.getBounds();
993 
994     if (rrect.isRect()) {
995         this->addRect(bounds, dir);
996     } else if (rrect.isOval()) {
997         this->addOval(bounds, dir);
998     } else if (rrect.isSimple()) {
999         const SkVector& rad = rrect.getSimpleRadii();
1000         this->addRoundRect(bounds, rad.x(), rad.y(), dir);
1001     } else {
1002         SkAutoPathBoundsUpdate apbu(this, bounds);
1003 
1004         if (kCW_Direction == dir) {
1005             add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true);
1006             add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false);
1007             add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY,   0, dir, false);
1008             add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY,  90, dir, false);
1009         } else {
1010             add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true);
1011             add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY,  90, dir, false);
1012             add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY,   0, dir, false);
1013             add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false);
1014         }
1015         this->close();
1016     }
1017 }
1018 
hasOnlyMoveTos() const1019 bool SkPath::hasOnlyMoveTos() const {
1020     int count = fPathRef->countVerbs();
1021     const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin();
1022     for (int i = 0; i < count; ++i) {
1023         if (*verbs == kLine_Verb ||
1024             *verbs == kQuad_Verb ||
1025             *verbs == kCubic_Verb) {
1026             return false;
1027         }
1028         ++verbs;
1029     }
1030     return true;
1031 }
1032 
1033 #define CUBIC_ARC_FACTOR    ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
1034 
addRoundRect(const SkRect & rect,SkScalar rx,SkScalar ry,Direction dir)1035 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
1036                           Direction dir) {
1037     assert_known_direction(dir);
1038 
1039     SkScalar    w = rect.width();
1040     SkScalar    halfW = SkScalarHalf(w);
1041     SkScalar    h = rect.height();
1042     SkScalar    halfH = SkScalarHalf(h);
1043 
1044     if (halfW <= 0 || halfH <= 0) {
1045         return;
1046     }
1047 
1048     bool skip_hori = rx >= halfW;
1049     bool skip_vert = ry >= halfH;
1050 
1051     if (skip_hori && skip_vert) {
1052         this->addOval(rect, dir);
1053         return;
1054     }
1055 
1056     fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
1057 
1058     SkAutoPathBoundsUpdate apbu(this, rect);
1059     SkAutoDisableDirectionCheck(this);
1060 
1061     if (skip_hori) {
1062         rx = halfW;
1063     } else if (skip_vert) {
1064         ry = halfH;
1065     }
1066 
1067     SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
1068     SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
1069 
1070     this->incReserve(17);
1071     this->moveTo(rect.fRight - rx, rect.fTop);
1072     if (dir == kCCW_Direction) {
1073         if (!skip_hori) {
1074             this->lineTo(rect.fLeft + rx, rect.fTop);       // top
1075         }
1076         this->cubicTo(rect.fLeft + rx - sx, rect.fTop,
1077                       rect.fLeft, rect.fTop + ry - sy,
1078                       rect.fLeft, rect.fTop + ry);          // top-left
1079         if (!skip_vert) {
1080             this->lineTo(rect.fLeft, rect.fBottom - ry);        // left
1081         }
1082         this->cubicTo(rect.fLeft, rect.fBottom - ry + sy,
1083                       rect.fLeft + rx - sx, rect.fBottom,
1084                       rect.fLeft + rx, rect.fBottom);       // bot-left
1085         if (!skip_hori) {
1086             this->lineTo(rect.fRight - rx, rect.fBottom);   // bottom
1087         }
1088         this->cubicTo(rect.fRight - rx + sx, rect.fBottom,
1089                       rect.fRight, rect.fBottom - ry + sy,
1090                       rect.fRight, rect.fBottom - ry);      // bot-right
1091         if (!skip_vert) {
1092             this->lineTo(rect.fRight, rect.fTop + ry);
1093         }
1094         this->cubicTo(rect.fRight, rect.fTop + ry - sy,
1095                       rect.fRight - rx + sx, rect.fTop,
1096                       rect.fRight - rx, rect.fTop);         // top-right
1097     } else {
1098         this->cubicTo(rect.fRight - rx + sx, rect.fTop,
1099                       rect.fRight, rect.fTop + ry - sy,
1100                       rect.fRight, rect.fTop + ry);         // top-right
1101         if (!skip_vert) {
1102             this->lineTo(rect.fRight, rect.fBottom - ry);
1103         }
1104         this->cubicTo(rect.fRight, rect.fBottom - ry + sy,
1105                       rect.fRight - rx + sx, rect.fBottom,
1106                       rect.fRight - rx, rect.fBottom);      // bot-right
1107         if (!skip_hori) {
1108             this->lineTo(rect.fLeft + rx, rect.fBottom);    // bottom
1109         }
1110         this->cubicTo(rect.fLeft + rx - sx, rect.fBottom,
1111                       rect.fLeft, rect.fBottom - ry + sy,
1112                       rect.fLeft, rect.fBottom - ry);       // bot-left
1113         if (!skip_vert) {
1114             this->lineTo(rect.fLeft, rect.fTop + ry);       // left
1115         }
1116         this->cubicTo(rect.fLeft, rect.fTop + ry - sy,
1117                       rect.fLeft + rx - sx, rect.fTop,
1118                       rect.fLeft + rx, rect.fTop);          // top-left
1119         if (!skip_hori) {
1120             this->lineTo(rect.fRight - rx, rect.fTop);      // top
1121         }
1122     }
1123     this->close();
1124 }
1125 
addOval(const SkRect & oval,Direction dir)1126 void SkPath::addOval(const SkRect& oval, Direction dir) {
1127     assert_known_direction(dir);
1128 
1129     /* If addOval() is called after previous moveTo(),
1130        this path is still marked as an oval. This is used to
1131        fit into WebKit's calling sequences.
1132        We can't simply check isEmpty() in this case, as additional
1133        moveTo() would mark the path non empty.
1134      */
1135     fIsOval = hasOnlyMoveTos();
1136     if (fIsOval) {
1137         fDirection = dir;
1138     } else {
1139         fDirection = kUnknown_Direction;
1140     }
1141 
1142     SkAutoDisableOvalCheck adoc(this);
1143     SkAutoDisableDirectionCheck addc(this);
1144 
1145     SkAutoPathBoundsUpdate apbu(this, oval);
1146 
1147     SkScalar    cx = oval.centerX();
1148     SkScalar    cy = oval.centerY();
1149     SkScalar    rx = SkScalarHalf(oval.width());
1150     SkScalar    ry = SkScalarHalf(oval.height());
1151 
1152     SkScalar    sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
1153     SkScalar    sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
1154     SkScalar    mx = SkScalarMul(rx, SK_ScalarRoot2Over2);
1155     SkScalar    my = SkScalarMul(ry, SK_ScalarRoot2Over2);
1156 
1157     /*
1158         To handle imprecision in computing the center and radii, we revert to
1159         the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx)
1160         to ensure that we don't exceed the oval's bounds *ever*, since we want
1161         to use oval for our fast-bounds, rather than have to recompute it.
1162     */
1163     const SkScalar L = oval.fLeft;      // cx - rx
1164     const SkScalar T = oval.fTop;       // cy - ry
1165     const SkScalar R = oval.fRight;     // cx + rx
1166     const SkScalar B = oval.fBottom;    // cy + ry
1167 
1168     this->incReserve(17);   // 8 quads + close
1169     this->moveTo(R, cy);
1170     if (dir == kCCW_Direction) {
1171         this->quadTo(      R, cy - sy, cx + mx, cy - my);
1172         this->quadTo(cx + sx,       T, cx     ,       T);
1173         this->quadTo(cx - sx,       T, cx - mx, cy - my);
1174         this->quadTo(      L, cy - sy,       L, cy     );
1175         this->quadTo(      L, cy + sy, cx - mx, cy + my);
1176         this->quadTo(cx - sx,       B, cx     ,       B);
1177         this->quadTo(cx + sx,       B, cx + mx, cy + my);
1178         this->quadTo(      R, cy + sy,       R, cy     );
1179     } else {
1180         this->quadTo(      R, cy + sy, cx + mx, cy + my);
1181         this->quadTo(cx + sx,       B, cx     ,       B);
1182         this->quadTo(cx - sx,       B, cx - mx, cy + my);
1183         this->quadTo(      L, cy + sy,       L, cy     );
1184         this->quadTo(      L, cy - sy, cx - mx, cy - my);
1185         this->quadTo(cx - sx,       T, cx     ,       T);
1186         this->quadTo(cx + sx,       T, cx + mx, cy - my);
1187         this->quadTo(      R, cy - sy,       R, cy     );
1188     }
1189     this->close();
1190 }
1191 
isOval(SkRect * rect) const1192 bool SkPath::isOval(SkRect* rect) const {
1193     if (fIsOval && rect) {
1194         *rect = getBounds();
1195     }
1196 
1197     return fIsOval;
1198 }
1199 
addCircle(SkScalar x,SkScalar y,SkScalar r,Direction dir)1200 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
1201     if (r > 0) {
1202         SkRect  rect;
1203         rect.set(x - r, y - r, x + r, y + r);
1204         this->addOval(rect, dir);
1205     }
1206 }
1207 
1208 #include "SkGeometry.h"
1209 
build_arc_points(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,SkPoint pts[kSkBuildQuadArcStorage])1210 static int build_arc_points(const SkRect& oval, SkScalar startAngle,
1211                             SkScalar sweepAngle,
1212                             SkPoint pts[kSkBuildQuadArcStorage]) {
1213 
1214     if (0 == sweepAngle &&
1215         (0 == startAngle || SkIntToScalar(360) == startAngle)) {
1216         // Chrome uses this path to move into and out of ovals. If not
1217         // treated as a special case the moves can distort the oval's
1218         // bounding box (and break the circle special case).
1219         pts[0].set(oval.fRight, oval.centerY());
1220         return 1;
1221     } else if (0 == oval.width() && 0 == oval.height()) {
1222         // Chrome will sometimes create 0 radius round rects. Having degenerate
1223         // quad segments in the path prevents the path from being recognized as
1224         // a rect.
1225         // TODO: optimizing the case where only one of width or height is zero
1226         // should also be considered. This case, however, doesn't seem to be
1227         // as common as the single point case.
1228         pts[0].set(oval.fRight, oval.fTop);
1229         return 1;
1230     }
1231 
1232     SkVector start, stop;
1233 
1234     start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX);
1235     stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle),
1236                              &stop.fX);
1237 
1238     /*  If the sweep angle is nearly (but less than) 360, then due to precision
1239         loss in radians-conversion and/or sin/cos, we may end up with coincident
1240         vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead
1241         of drawing a nearly complete circle (good).
1242              e.g. canvas.drawArc(0, 359.99, ...)
1243              -vs- canvas.drawArc(0, 359.9, ...)
1244         We try to detect this edge case, and tweak the stop vector
1245      */
1246     if (start == stop) {
1247         SkScalar sw = SkScalarAbs(sweepAngle);
1248         if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
1249             SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
1250             // make a guess at a tiny angle (in radians) to tweak by
1251             SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
1252             // not sure how much will be enough, so we use a loop
1253             do {
1254                 stopRad -= deltaRad;
1255                 stop.fY = SkScalarSinCos(stopRad, &stop.fX);
1256             } while (start == stop);
1257         }
1258     }
1259 
1260     SkMatrix    matrix;
1261 
1262     matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
1263     matrix.postTranslate(oval.centerX(), oval.centerY());
1264 
1265     return SkBuildQuadArc(start, stop,
1266           sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection,
1267                           &matrix, pts);
1268 }
1269 
arcTo(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool forceMoveTo)1270 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
1271                    bool forceMoveTo) {
1272     if (oval.width() < 0 || oval.height() < 0) {
1273         return;
1274     }
1275 
1276     SkPoint pts[kSkBuildQuadArcStorage];
1277     int count = build_arc_points(oval, startAngle, sweepAngle, pts);
1278     SkASSERT((count & 1) == 1);
1279 
1280     if (fPathRef->countVerbs() == 0) {
1281         forceMoveTo = true;
1282     }
1283     this->incReserve(count);
1284     forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]);
1285     for (int i = 1; i < count; i += 2) {
1286         this->quadTo(pts[i], pts[i+1]);
1287     }
1288 }
1289 
addArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle)1290 void SkPath::addArc(const SkRect& oval, SkScalar startAngle,
1291                     SkScalar sweepAngle) {
1292     if (oval.isEmpty() || 0 == sweepAngle) {
1293         return;
1294     }
1295 
1296     const SkScalar kFullCircleAngle = SkIntToScalar(360);
1297 
1298     if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
1299         this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction);
1300         return;
1301     }
1302 
1303     SkPoint pts[kSkBuildQuadArcStorage];
1304     int count = build_arc_points(oval, startAngle, sweepAngle, pts);
1305 
1306     this->incReserve(count);
1307     this->moveTo(pts[0]);
1308     for (int i = 1; i < count; i += 2) {
1309         this->quadTo(pts[i], pts[i+1]);
1310     }
1311 }
1312 
1313 /*
1314     Need to handle the case when the angle is sharp, and our computed end-points
1315     for the arc go behind pt1 and/or p2...
1316 */
arcTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar radius)1317 void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
1318                    SkScalar radius) {
1319     SkVector    before, after;
1320 
1321     // need to know our prev pt so we can construct tangent vectors
1322     {
1323         SkPoint start;
1324         this->getLastPt(&start);
1325         // Handle degenerate cases by adding a line to the first point and
1326         // bailing out.
1327         if ((x1 == start.fX && y1 == start.fY) ||
1328             (x1 == x2 && y1 == y2) ||
1329             radius == 0) {
1330             this->lineTo(x1, y1);
1331             return;
1332         }
1333         before.setNormalize(x1 - start.fX, y1 - start.fY);
1334         after.setNormalize(x2 - x1, y2 - y1);
1335     }
1336 
1337     SkScalar cosh = SkPoint::DotProduct(before, after);
1338     SkScalar sinh = SkPoint::CrossProduct(before, after);
1339 
1340     if (SkScalarNearlyZero(sinh)) {   // angle is too tight
1341         this->lineTo(x1, y1);
1342         return;
1343     }
1344 
1345     SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh);
1346     if (dist < 0) {
1347         dist = -dist;
1348     }
1349 
1350     SkScalar xx = x1 - SkScalarMul(dist, before.fX);
1351     SkScalar yy = y1 - SkScalarMul(dist, before.fY);
1352     SkRotationDirection arcDir;
1353 
1354     // now turn before/after into normals
1355     if (sinh > 0) {
1356         before.rotateCCW();
1357         after.rotateCCW();
1358         arcDir = kCW_SkRotationDirection;
1359     } else {
1360         before.rotateCW();
1361         after.rotateCW();
1362         arcDir = kCCW_SkRotationDirection;
1363     }
1364 
1365     SkMatrix    matrix;
1366     SkPoint     pts[kSkBuildQuadArcStorage];
1367 
1368     matrix.setScale(radius, radius);
1369     matrix.postTranslate(xx - SkScalarMul(radius, before.fX),
1370                          yy - SkScalarMul(radius, before.fY));
1371 
1372     int count = SkBuildQuadArc(before, after, arcDir, &matrix, pts);
1373 
1374     this->incReserve(count);
1375     // [xx,yy] == pts[0]
1376     this->lineTo(xx, yy);
1377     for (int i = 1; i < count; i += 2) {
1378         this->quadTo(pts[i], pts[i+1]);
1379     }
1380 }
1381 
1382 ///////////////////////////////////////////////////////////////////////////////
1383 
addPath(const SkPath & path,SkScalar dx,SkScalar dy)1384 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
1385     SkMatrix matrix;
1386 
1387     matrix.setTranslate(dx, dy);
1388     this->addPath(path, matrix);
1389 }
1390 
addPath(const SkPath & path,const SkMatrix & matrix)1391 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
1392     SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
1393 
1394     fIsOval = false;
1395 
1396     RawIter iter(path);
1397     SkPoint pts[4];
1398     Verb    verb;
1399 
1400     SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
1401 
1402     while ((verb = iter.next(pts)) != kDone_Verb) {
1403         switch (verb) {
1404             case kMove_Verb:
1405                 proc(matrix, &pts[0], &pts[0], 1);
1406                 this->moveTo(pts[0]);
1407                 break;
1408             case kLine_Verb:
1409                 proc(matrix, &pts[1], &pts[1], 1);
1410                 this->lineTo(pts[1]);
1411                 break;
1412             case kQuad_Verb:
1413                 proc(matrix, &pts[1], &pts[1], 2);
1414                 this->quadTo(pts[1], pts[2]);
1415                 break;
1416             case kCubic_Verb:
1417                 proc(matrix, &pts[1], &pts[1], 3);
1418                 this->cubicTo(pts[1], pts[2], pts[3]);
1419                 break;
1420             case kClose_Verb:
1421                 this->close();
1422                 break;
1423             default:
1424                 SkDEBUGFAIL("unknown verb");
1425         }
1426     }
1427 }
1428 
1429 ///////////////////////////////////////////////////////////////////////////////
1430 
1431 static const uint8_t gPtsInVerb[] = {
1432     1,  // kMove
1433     1,  // kLine
1434     2,  // kQuad
1435     3,  // kCubic
1436     0,  // kClose
1437     0   // kDone
1438 };
1439 
1440 // ignore the initial moveto, and stop when the 1st contour ends
pathTo(const SkPath & path)1441 void SkPath::pathTo(const SkPath& path) {
1442     int i, vcount = path.fPathRef->countVerbs();
1443     // exit early if the path is empty, or just has a moveTo.
1444     if (vcount < 2) {
1445         return;
1446     }
1447 
1448     SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1449 
1450     fIsOval = false;
1451 
1452     const uint8_t* verbs = path.fPathRef->verbs();
1453     // skip the initial moveTo
1454     const SkPoint*  pts = path.fPathRef->points() + 1;
1455 
1456     SkASSERT(verbs[~0] == kMove_Verb);
1457     for (i = 1; i < vcount; i++) {
1458         switch (verbs[~i]) {
1459             case kLine_Verb:
1460                 this->lineTo(pts[0].fX, pts[0].fY);
1461                 break;
1462             case kQuad_Verb:
1463                 this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
1464                 break;
1465             case kCubic_Verb:
1466                 this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
1467                 break;
1468             case kClose_Verb:
1469                 return;
1470         }
1471         pts += gPtsInVerb[verbs[~i]];
1472     }
1473 }
1474 
1475 // ignore the last point of the 1st contour
reversePathTo(const SkPath & path)1476 void SkPath::reversePathTo(const SkPath& path) {
1477     int i, vcount = path.fPathRef->countVerbs();
1478     // exit early if the path is empty, or just has a moveTo.
1479     if (vcount < 2) {
1480         return;
1481     }
1482 
1483     SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1484 
1485     fIsOval = false;
1486 
1487     const uint8_t*  verbs = path.fPathRef->verbs();
1488     const SkPoint*  pts = path.fPathRef->points();
1489 
1490     SkASSERT(verbs[~0] == kMove_Verb);
1491     for (i = 1; i < vcount; ++i) {
1492         int n = gPtsInVerb[verbs[~i]];
1493         if (n == 0) {
1494             break;
1495         }
1496         pts += n;
1497     }
1498 
1499     while (--i > 0) {
1500         switch (verbs[~i]) {
1501             case kLine_Verb:
1502                 this->lineTo(pts[-1].fX, pts[-1].fY);
1503                 break;
1504             case kQuad_Verb:
1505                 this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
1506                 break;
1507             case kCubic_Verb:
1508                 this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY,
1509                               pts[-3].fX, pts[-3].fY);
1510                 break;
1511             default:
1512                 SkDEBUGFAIL("bad verb");
1513                 break;
1514         }
1515         pts -= gPtsInVerb[verbs[~i]];
1516     }
1517 }
1518 
reverseAddPath(const SkPath & src)1519 void SkPath::reverseAddPath(const SkPath& src) {
1520     SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs());
1521 
1522     const SkPoint* pts = src.fPathRef->pointsEnd();
1523     // we will iterator through src's verbs backwards
1524     const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
1525     const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb
1526 
1527     fIsOval = false;
1528 
1529     bool needMove = true;
1530     bool needClose = false;
1531     while (verbs < verbsEnd) {
1532         uint8_t v = *(verbs++);
1533         int n = gPtsInVerb[v];
1534 
1535         if (needMove) {
1536             --pts;
1537             this->moveTo(pts->fX, pts->fY);
1538             needMove = false;
1539         }
1540         pts -= n;
1541         switch (v) {
1542             case kMove_Verb:
1543                 if (needClose) {
1544                     this->close();
1545                     needClose = false;
1546                 }
1547                 needMove = true;
1548                 pts += 1;   // so we see the point in "if (needMove)" above
1549                 break;
1550             case kLine_Verb:
1551                 this->lineTo(pts[0]);
1552                 break;
1553             case kQuad_Verb:
1554                 this->quadTo(pts[1], pts[0]);
1555                 break;
1556             case kCubic_Verb:
1557                 this->cubicTo(pts[2], pts[1], pts[0]);
1558                 break;
1559             case kClose_Verb:
1560                 needClose = true;
1561                 break;
1562             default:
1563                 SkASSERT(!"unexpected verb");
1564         }
1565     }
1566 }
1567 
1568 ///////////////////////////////////////////////////////////////////////////////
1569 
offset(SkScalar dx,SkScalar dy,SkPath * dst) const1570 void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
1571     SkMatrix    matrix;
1572 
1573     matrix.setTranslate(dx, dy);
1574     this->transform(matrix, dst);
1575 }
1576 
1577 #include "SkGeometry.h"
1578 
subdivide_quad_to(SkPath * path,const SkPoint pts[3],int level=2)1579 static void subdivide_quad_to(SkPath* path, const SkPoint pts[3],
1580                               int level = 2) {
1581     if (--level >= 0) {
1582         SkPoint tmp[5];
1583 
1584         SkChopQuadAtHalf(pts, tmp);
1585         subdivide_quad_to(path, &tmp[0], level);
1586         subdivide_quad_to(path, &tmp[2], level);
1587     } else {
1588         path->quadTo(pts[1], pts[2]);
1589     }
1590 }
1591 
subdivide_cubic_to(SkPath * path,const SkPoint pts[4],int level=2)1592 static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
1593                                int level = 2) {
1594     if (--level >= 0) {
1595         SkPoint tmp[7];
1596 
1597         SkChopCubicAtHalf(pts, tmp);
1598         subdivide_cubic_to(path, &tmp[0], level);
1599         subdivide_cubic_to(path, &tmp[3], level);
1600     } else {
1601         path->cubicTo(pts[1], pts[2], pts[3]);
1602     }
1603 }
1604 
transform(const SkMatrix & matrix,SkPath * dst) const1605 void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
1606     SkDEBUGCODE(this->validate();)
1607     if (dst == NULL) {
1608         dst = (SkPath*)this;
1609     }
1610 
1611     if (matrix.hasPerspective()) {
1612         SkPath  tmp;
1613         tmp.fFillType = fFillType;
1614 
1615         SkPath::Iter    iter(*this, false);
1616         SkPoint         pts[4];
1617         SkPath::Verb    verb;
1618 
1619         while ((verb = iter.next(pts, false)) != kDone_Verb) {
1620             switch (verb) {
1621                 case kMove_Verb:
1622                     tmp.moveTo(pts[0]);
1623                     break;
1624                 case kLine_Verb:
1625                     tmp.lineTo(pts[1]);
1626                     break;
1627                 case kQuad_Verb:
1628                     subdivide_quad_to(&tmp, pts);
1629                     break;
1630                 case kCubic_Verb:
1631                     subdivide_cubic_to(&tmp, pts);
1632                     break;
1633                 case kClose_Verb:
1634                     tmp.close();
1635                     break;
1636                 default:
1637                     SkDEBUGFAIL("unknown verb");
1638                     break;
1639             }
1640         }
1641 
1642         // swap() will increment the gen id if needed
1643         dst->swap(tmp);
1644         SkPathRef::Editor ed(&dst->fPathRef);
1645         matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
1646         dst->fDirection = kUnknown_Direction;
1647     } else {
1648         /*
1649          *  If we're not in perspective, we can transform all of the points at
1650          *  once.
1651          *
1652          *  Here we also want to optimize bounds, by noting if the bounds are
1653          *  already known, and if so, we just transform those as well and mark
1654          *  them as "known", rather than force the transformed path to have to
1655          *  recompute them.
1656          *
1657          *  Special gotchas if the path is effectively empty (<= 1 point) or
1658          *  if it is non-finite. In those cases bounds need to stay empty,
1659          *  regardless of the matrix.
1660          */
1661         if (!fBoundsIsDirty && matrix.rectStaysRect() && fPathRef->countPoints() > 1) {
1662             dst->fBoundsIsDirty = false;
1663             if (fIsFinite) {
1664                 matrix.mapRect(&dst->fBounds, fBounds);
1665                 if (!(dst->fIsFinite = dst->fBounds.isFinite())) {
1666                     dst->fBounds.setEmpty();
1667                 }
1668             } else {
1669                 dst->fIsFinite = false;
1670                 dst->fBounds.setEmpty();
1671             }
1672         } else {
1673             GEN_ID_PTR_INC(dst);
1674             dst->fBoundsIsDirty = true;
1675         }
1676 
1677         SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix);
1678 
1679         if (this != dst) {
1680             dst->fFillType = fFillType;
1681             dst->fSegmentMask = fSegmentMask;
1682             dst->fConvexity = fConvexity;
1683         }
1684 
1685         if (!matrix.isIdentity()) {
1686             GEN_ID_PTR_INC(dst);
1687         }
1688 
1689         if (kUnknown_Direction == fDirection) {
1690             dst->fDirection = kUnknown_Direction;
1691         } else {
1692             SkScalar det2x2 =
1693                 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix::kMScaleY)) -
1694                 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::kMSkewY));
1695             if (det2x2 < 0) {
1696                 dst->fDirection = SkPath::OppositeDirection(static_cast<Direction>(fDirection));
1697             } else if (det2x2 > 0) {
1698                 dst->fDirection = fDirection;
1699             } else {
1700                 dst->fDirection = kUnknown_Direction;
1701             }
1702         }
1703 
1704         // It's an oval only if it stays a rect.
1705         dst->fIsOval = fIsOval && matrix.rectStaysRect();
1706 
1707         SkDEBUGCODE(dst->validate();)
1708     }
1709 }
1710 
1711 ///////////////////////////////////////////////////////////////////////////////
1712 ///////////////////////////////////////////////////////////////////////////////
1713 
1714 enum SegmentState {
1715     kEmptyContour_SegmentState,   // The current contour is empty. We may be
1716                                   // starting processing or we may have just
1717                                   // closed a contour.
1718     kAfterMove_SegmentState,      // We have seen a move, but nothing else.
1719     kAfterPrimitive_SegmentState  // We have seen a primitive but not yet
1720                                   // closed the path. Also the initial state.
1721 };
1722 
Iter()1723 SkPath::Iter::Iter() {
1724 #ifdef SK_DEBUG
1725     fPts = NULL;
1726     fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1727     fForceClose = fCloseLine = false;
1728     fSegmentState = kEmptyContour_SegmentState;
1729 #endif
1730     // need to init enough to make next() harmlessly return kDone_Verb
1731     fVerbs = NULL;
1732     fVerbStop = NULL;
1733     fNeedClose = false;
1734 }
1735 
Iter(const SkPath & path,bool forceClose)1736 SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
1737     this->setPath(path, forceClose);
1738 }
1739 
setPath(const SkPath & path,bool forceClose)1740 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
1741     fPts = path.fPathRef->points();
1742     fVerbs = path.fPathRef->verbs();
1743     fVerbStop = path.fPathRef->verbsMemBegin();
1744     fLastPt.fX = fLastPt.fY = 0;
1745     fMoveTo.fX = fMoveTo.fY = 0;
1746     fForceClose = SkToU8(forceClose);
1747     fNeedClose = false;
1748     fSegmentState = kEmptyContour_SegmentState;
1749 }
1750 
isClosedContour() const1751 bool SkPath::Iter::isClosedContour() const {
1752     if (fVerbs == NULL || fVerbs == fVerbStop) {
1753         return false;
1754     }
1755     if (fForceClose) {
1756         return true;
1757     }
1758 
1759     const uint8_t* verbs = fVerbs;
1760     const uint8_t* stop = fVerbStop;
1761 
1762     if (kMove_Verb == *(verbs - 1)) {
1763         verbs -= 1; // skip the initial moveto
1764     }
1765 
1766     while (verbs > stop) {
1767         // verbs points one beyond the current verb, decrement first.
1768         unsigned v = *(--verbs);
1769         if (kMove_Verb == v) {
1770             break;
1771         }
1772         if (kClose_Verb == v) {
1773             return true;
1774         }
1775     }
1776     return false;
1777 }
1778 
autoClose(SkPoint pts[2])1779 SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
1780     SkASSERT(pts);
1781     if (fLastPt != fMoveTo) {
1782         // A special case: if both points are NaN, SkPoint::operation== returns
1783         // false, but the iterator expects that they are treated as the same.
1784         // (consider SkPoint is a 2-dimension float point).
1785         if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
1786             SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
1787             return kClose_Verb;
1788         }
1789 
1790         pts[0] = fLastPt;
1791         pts[1] = fMoveTo;
1792         fLastPt = fMoveTo;
1793         fCloseLine = true;
1794         return kLine_Verb;
1795     } else {
1796         pts[0] = fMoveTo;
1797         return kClose_Verb;
1798     }
1799 }
1800 
cons_moveTo()1801 const SkPoint& SkPath::Iter::cons_moveTo() {
1802     if (fSegmentState == kAfterMove_SegmentState) {
1803         // Set the first return pt to the move pt
1804         fSegmentState = kAfterPrimitive_SegmentState;
1805         return fMoveTo;
1806     } else {
1807         SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
1808          // Set the first return pt to the last pt of the previous primitive.
1809         return fPts[-1];
1810     }
1811 }
1812 
consumeDegenerateSegments()1813 void SkPath::Iter::consumeDegenerateSegments() {
1814     // We need to step over anything that will not move the current draw point
1815     // forward before the next move is seen
1816     const uint8_t* lastMoveVerb = 0;
1817     const SkPoint* lastMovePt = 0;
1818     SkPoint lastPt = fLastPt;
1819     while (fVerbs != fVerbStop) {
1820         unsigned verb = *(fVerbs - 1); // fVerbs is one beyond the current verb
1821         switch (verb) {
1822             case kMove_Verb:
1823                 // Keep a record of this most recent move
1824                 lastMoveVerb = fVerbs;
1825                 lastMovePt = fPts;
1826                 lastPt = fPts[0];
1827                 fVerbs--;
1828                 fPts++;
1829                 break;
1830 
1831             case kClose_Verb:
1832                 // A close when we are in a segment is always valid except when it
1833                 // follows a move which follows a segment.
1834                 if (fSegmentState == kAfterPrimitive_SegmentState && !lastMoveVerb) {
1835                     return;
1836                 }
1837                 // A close at any other time must be ignored
1838                 fVerbs--;
1839                 break;
1840 
1841             case kLine_Verb:
1842                 if (!IsLineDegenerate(lastPt, fPts[0])) {
1843                     if (lastMoveVerb) {
1844                         fVerbs = lastMoveVerb;
1845                         fPts = lastMovePt;
1846                         return;
1847                     }
1848                     return;
1849                 }
1850                 // Ignore this line and continue
1851                 fVerbs--;
1852                 fPts++;
1853                 break;
1854 
1855             case kQuad_Verb:
1856                 if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
1857                     if (lastMoveVerb) {
1858                         fVerbs = lastMoveVerb;
1859                         fPts = lastMovePt;
1860                         return;
1861                     }
1862                     return;
1863                 }
1864                 // Ignore this line and continue
1865                 fVerbs--;
1866                 fPts += 2;
1867                 break;
1868 
1869             case kCubic_Verb:
1870                 if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) {
1871                     if (lastMoveVerb) {
1872                         fVerbs = lastMoveVerb;
1873                         fPts = lastMovePt;
1874                         return;
1875                     }
1876                     return;
1877                 }
1878                 // Ignore this line and continue
1879                 fVerbs--;
1880                 fPts += 3;
1881                 break;
1882 
1883             default:
1884                 SkDEBUGFAIL("Should never see kDone_Verb");
1885         }
1886     }
1887 }
1888 
doNext(SkPoint ptsParam[4])1889 SkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) {
1890     SkASSERT(ptsParam);
1891 
1892     if (fVerbs == fVerbStop) {
1893         // Close the curve if requested and if there is some curve to close
1894         if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
1895             if (kLine_Verb == this->autoClose(ptsParam)) {
1896                 return kLine_Verb;
1897             }
1898             fNeedClose = false;
1899             return kClose_Verb;
1900         }
1901         return kDone_Verb;
1902     }
1903 
1904     // fVerbs is one beyond the current verb, decrement first
1905     unsigned verb = *(--fVerbs);
1906     const SkPoint* SK_RESTRICT srcPts = fPts;
1907     SkPoint* SK_RESTRICT       pts = ptsParam;
1908 
1909     switch (verb) {
1910         case kMove_Verb:
1911             if (fNeedClose) {
1912                 fVerbs++; // move back one verb
1913                 verb = this->autoClose(pts);
1914                 if (verb == kClose_Verb) {
1915                     fNeedClose = false;
1916                 }
1917                 return (Verb)verb;
1918             }
1919             if (fVerbs == fVerbStop) {    // might be a trailing moveto
1920                 return kDone_Verb;
1921             }
1922             fMoveTo = *srcPts;
1923             pts[0] = *srcPts;
1924             srcPts += 1;
1925             fSegmentState = kAfterMove_SegmentState;
1926             fLastPt = fMoveTo;
1927             fNeedClose = fForceClose;
1928             break;
1929         case kLine_Verb:
1930             pts[0] = this->cons_moveTo();
1931             pts[1] = srcPts[0];
1932             fLastPt = srcPts[0];
1933             fCloseLine = false;
1934             srcPts += 1;
1935             break;
1936         case kQuad_Verb:
1937             pts[0] = this->cons_moveTo();
1938             memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
1939             fLastPt = srcPts[1];
1940             srcPts += 2;
1941             break;
1942         case kCubic_Verb:
1943             pts[0] = this->cons_moveTo();
1944             memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
1945             fLastPt = srcPts[2];
1946             srcPts += 3;
1947             break;
1948         case kClose_Verb:
1949             verb = this->autoClose(pts);
1950             if (verb == kLine_Verb) {
1951                 fVerbs++; // move back one verb
1952             } else {
1953                 fNeedClose = false;
1954                 fSegmentState = kEmptyContour_SegmentState;
1955             }
1956             fLastPt = fMoveTo;
1957             break;
1958     }
1959     fPts = srcPts;
1960     return (Verb)verb;
1961 }
1962 
1963 ///////////////////////////////////////////////////////////////////////////////
1964 
RawIter()1965 SkPath::RawIter::RawIter() {
1966 #ifdef SK_DEBUG
1967     fPts = NULL;
1968     fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1969 #endif
1970     // need to init enough to make next() harmlessly return kDone_Verb
1971     fVerbs = NULL;
1972     fVerbStop = NULL;
1973 }
1974 
RawIter(const SkPath & path)1975 SkPath::RawIter::RawIter(const SkPath& path) {
1976     this->setPath(path);
1977 }
1978 
setPath(const SkPath & path)1979 void SkPath::RawIter::setPath(const SkPath& path) {
1980     fPts = path.fPathRef->points();
1981     fVerbs = path.fPathRef->verbs();
1982     fVerbStop = path.fPathRef->verbsMemBegin();
1983     fMoveTo.fX = fMoveTo.fY = 0;
1984     fLastPt.fX = fLastPt.fY = 0;
1985 }
1986 
next(SkPoint pts[4])1987 SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
1988     SkASSERT(NULL != pts);
1989     if (fVerbs == fVerbStop) {
1990         return kDone_Verb;
1991     }
1992 
1993     // fVerbs points one beyond next verb so decrement first.
1994     unsigned verb = *(--fVerbs);
1995     const SkPoint* srcPts = fPts;
1996 
1997     switch (verb) {
1998         case kMove_Verb:
1999             pts[0] = *srcPts;
2000             fMoveTo = srcPts[0];
2001             fLastPt = fMoveTo;
2002             srcPts += 1;
2003             break;
2004         case kLine_Verb:
2005             pts[0] = fLastPt;
2006             pts[1] = srcPts[0];
2007             fLastPt = srcPts[0];
2008             srcPts += 1;
2009             break;
2010         case kQuad_Verb:
2011             pts[0] = fLastPt;
2012             memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
2013             fLastPt = srcPts[1];
2014             srcPts += 2;
2015             break;
2016         case kCubic_Verb:
2017             pts[0] = fLastPt;
2018             memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
2019             fLastPt = srcPts[2];
2020             srcPts += 3;
2021             break;
2022         case kClose_Verb:
2023             fLastPt = fMoveTo;
2024             pts[0] = fMoveTo;
2025             break;
2026     }
2027     fPts = srcPts;
2028     return (Verb)verb;
2029 }
2030 
2031 ///////////////////////////////////////////////////////////////////////////////
2032 
2033 /*
2034     Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]]
2035 */
2036 
writeToMemory(void * storage) const2037 uint32_t SkPath::writeToMemory(void* storage) const {
2038     SkDEBUGCODE(this->validate();)
2039 
2040     if (NULL == storage) {
2041         const int byteCount = sizeof(int32_t)
2042 #if NEW_PICTURE_FORMAT
2043                       + fPathRef->writeSize()
2044 #else
2045                       + 2 * sizeof(int32_t)
2046                       + sizeof(SkPoint) * fPathRef->countPoints()
2047                       + sizeof(uint8_t) * fPathRef->countVerbs()
2048 #endif
2049                       + sizeof(SkRect);
2050         return SkAlign4(byteCount);
2051     }
2052 
2053     SkWBuffer   buffer(storage);
2054 #if !NEW_PICTURE_FORMAT
2055     buffer.write32(fPathRef->countPoints());
2056     buffer.write32(fPathRef->countVerbs());
2057 #endif
2058 
2059     // Call getBounds() to ensure (as a side-effect) that fBounds
2060     // and fIsFinite are computed.
2061     const SkRect& bounds = this->getBounds();
2062     SkASSERT(!fBoundsIsDirty);
2063 
2064     int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
2065                      ((fIsOval & 1) << kIsOval_SerializationShift) |
2066                      (fConvexity << kConvexity_SerializationShift) |
2067                      (fFillType << kFillType_SerializationShift) |
2068                      (fSegmentMask << kSegmentMask_SerializationShift) |
2069                      (fDirection << kDirection_SerializationShift);
2070 
2071     buffer.write32(packed);
2072 
2073     fPathRef->writeToBuffer(&buffer);
2074 
2075     buffer.write(&bounds, sizeof(bounds));
2076 
2077     buffer.padToAlign4();
2078     return buffer.pos();
2079 }
2080 
readFromMemory(const void * storage)2081 uint32_t SkPath::readFromMemory(const void* storage) {
2082     SkRBuffer   buffer(storage);
2083 #if !NEW_PICTURE_FORMAT
2084     int32_t pcount = buffer.readS32();
2085     int32_t vcount = buffer.readS32();
2086 #endif
2087 
2088     uint32_t packed = buffer.readS32();
2089     fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
2090     fIsOval = (packed >> kIsOval_SerializationShift) & 1;
2091     fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
2092     fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
2093     fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0x7;
2094     fDirection = (packed >> kDirection_SerializationShift) & 0x3;
2095 
2096 #if NEW_PICTURE_FORMAT
2097     fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer));
2098 #else
2099     fPathRef.reset(SkPathRef::CreateFromBuffer(vcount, pcount, &buffer));
2100 #endif
2101 
2102     buffer.read(&fBounds, sizeof(fBounds));
2103     fBoundsIsDirty = false;
2104 
2105     buffer.skipToAlign4();
2106 
2107     GEN_ID_INC;
2108 
2109     SkDEBUGCODE(this->validate();)
2110     return buffer.pos();
2111 }
2112 
2113 ///////////////////////////////////////////////////////////////////////////////
2114 
2115 #include "SkString.h"
2116 
append_scalar(SkString * str,SkScalar value)2117 static void append_scalar(SkString* str, SkScalar value) {
2118     SkString tmp;
2119     tmp.printf("%g", value);
2120     if (tmp.contains('.')) {
2121         tmp.appendUnichar('f');
2122     }
2123     str->append(tmp);
2124 }
2125 
append_params(SkString * str,const char label[],const SkPoint pts[],int count)2126 static void append_params(SkString* str, const char label[], const SkPoint pts[],
2127                           int count) {
2128     str->append(label);
2129     str->append("(");
2130 
2131     const SkScalar* values = &pts[0].fX;
2132     count *= 2;
2133 
2134     for (int i = 0; i < count; ++i) {
2135         append_scalar(str, values[i]);
2136         if (i < count - 1) {
2137             str->append(", ");
2138         }
2139     }
2140     str->append(");\n");
2141 }
2142 
dump(bool forceClose,const char title[]) const2143 void SkPath::dump(bool forceClose, const char title[]) const {
2144     Iter    iter(*this, forceClose);
2145     SkPoint pts[4];
2146     Verb    verb;
2147 
2148     SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false",
2149              title ? title : "");
2150 
2151     SkString builder;
2152 
2153     while ((verb = iter.next(pts, false)) != kDone_Verb) {
2154         switch (verb) {
2155             case kMove_Verb:
2156                 append_params(&builder, "path.moveTo", &pts[0], 1);
2157                 break;
2158             case kLine_Verb:
2159                 append_params(&builder, "path.lineTo", &pts[1], 1);
2160                 append_params(&builder, "path.lineTo", &pts[1], 1);
2161                 break;
2162             case kQuad_Verb:
2163                 append_params(&builder, "path.quadTo", &pts[1], 2);
2164                 break;
2165             case kCubic_Verb:
2166                 append_params(&builder, "path.cubicTo", &pts[1], 3);
2167                 break;
2168             case kClose_Verb:
2169                 builder.append("path.close();\n");
2170                 break;
2171             default:
2172                 SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
2173                 verb = kDone_Verb;  // stop the loop
2174                 break;
2175         }
2176     }
2177     SkDebugf("%s\n", builder.c_str());
2178 }
2179 
dump() const2180 void SkPath::dump() const {
2181     this->dump(false);
2182 }
2183 
2184 #ifdef SK_DEBUG
validate() const2185 void SkPath::validate() const {
2186     SkASSERT(this != NULL);
2187     SkASSERT((fFillType & ~3) == 0);
2188 
2189 #ifdef SK_DEBUG_PATH
2190     if (!fBoundsIsDirty) {
2191         SkRect bounds;
2192 
2193         bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
2194         SkASSERT(SkToBool(fIsFinite) == isFinite);
2195 
2196         if (fPathRef->countPoints() <= 1) {
2197             // if we're empty, fBounds may be empty but translated, so we can't
2198             // necessarily compare to bounds directly
2199             // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
2200             // be [2, 2, 2, 2]
2201             SkASSERT(bounds.isEmpty());
2202             SkASSERT(fBounds.isEmpty());
2203         } else {
2204             if (bounds.isEmpty()) {
2205                 SkASSERT(fBounds.isEmpty());
2206             } else {
2207                 if (!fBounds.isEmpty()) {
2208                     SkASSERT(fBounds.contains(bounds));
2209                 }
2210             }
2211         }
2212     }
2213 
2214     uint32_t mask = 0;
2215     const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbs();
2216     for (int i = 0; i < fPathRef->countVerbs(); i++) {
2217         switch (verbs[~i]) {
2218             case kLine_Verb:
2219                 mask |= kLine_SegmentMask;
2220                 break;
2221             case kQuad_Verb:
2222                 mask |= kQuad_SegmentMask;
2223                 break;
2224             case kCubic_Verb:
2225                 mask |= kCubic_SegmentMask;
2226             case kMove_Verb:  // these verbs aren't included in the segment mask.
2227             case kClose_Verb:
2228                 break;
2229             case kDone_Verb:
2230                 SkDEBUGFAIL("Done verb shouldn't be recorded.");
2231                 break;
2232             default:
2233                 SkDEBUGFAIL("Unknown Verb");
2234                 break;
2235         }
2236     }
2237     SkASSERT(mask == fSegmentMask);
2238 #endif // SK_DEBUG_PATH
2239 }
2240 #endif // SK_DEBUG
2241 
2242 ///////////////////////////////////////////////////////////////////////////////
2243 
sign(SkScalar x)2244 static int sign(SkScalar x) { return x < 0; }
2245 #define kValueNeverReturnedBySign   2
2246 
CrossProductSign(const SkVector & a,const SkVector & b)2247 static int CrossProductSign(const SkVector& a, const SkVector& b) {
2248     return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
2249 }
2250 
2251 // only valid for a single contour
2252 struct Convexicator {
ConvexicatorConvexicator2253     Convexicator()
2254     : fPtCount(0)
2255     , fConvexity(SkPath::kConvex_Convexity)
2256     , fDirection(SkPath::kUnknown_Direction) {
2257         fSign = 0;
2258         // warnings
2259         fCurrPt.set(0, 0);
2260         fVec0.set(0, 0);
2261         fVec1.set(0, 0);
2262         fFirstVec.set(0, 0);
2263 
2264         fDx = fDy = 0;
2265         fSx = fSy = kValueNeverReturnedBySign;
2266     }
2267 
getConvexityConvexicator2268     SkPath::Convexity getConvexity() const { return fConvexity; }
2269 
2270     /** The direction returned is only valid if the path is determined convex */
getDirectionConvexicator2271     SkPath::Direction getDirection() const { return fDirection; }
2272 
addPtConvexicator2273     void addPt(const SkPoint& pt) {
2274         if (SkPath::kConcave_Convexity == fConvexity) {
2275             return;
2276         }
2277 
2278         if (0 == fPtCount) {
2279             fCurrPt = pt;
2280             ++fPtCount;
2281         } else {
2282             SkVector vec = pt - fCurrPt;
2283             if (vec.fX || vec.fY) {
2284                 fCurrPt = pt;
2285                 if (++fPtCount == 2) {
2286                     fFirstVec = fVec1 = vec;
2287                 } else {
2288                     SkASSERT(fPtCount > 2);
2289                     this->addVec(vec);
2290                 }
2291 
2292                 int sx = sign(vec.fX);
2293                 int sy = sign(vec.fY);
2294                 fDx += (sx != fSx);
2295                 fDy += (sy != fSy);
2296                 fSx = sx;
2297                 fSy = sy;
2298 
2299                 if (fDx > 3 || fDy > 3) {
2300                     fConvexity = SkPath::kConcave_Convexity;
2301                 }
2302             }
2303         }
2304     }
2305 
closeConvexicator2306     void close() {
2307         if (fPtCount > 2) {
2308             this->addVec(fFirstVec);
2309         }
2310     }
2311 
2312 private:
addVecConvexicator2313     void addVec(const SkVector& vec) {
2314         SkASSERT(vec.fX || vec.fY);
2315         fVec0 = fVec1;
2316         fVec1 = vec;
2317         int sign = CrossProductSign(fVec0, fVec1);
2318         if (0 == fSign) {
2319             fSign = sign;
2320             if (1 == sign) {
2321                 fDirection = SkPath::kCW_Direction;
2322             } else if (-1 == sign) {
2323                 fDirection = SkPath::kCCW_Direction;
2324             }
2325         } else if (sign) {
2326             if (fSign != sign) {
2327                 fConvexity = SkPath::kConcave_Convexity;
2328                 fDirection = SkPath::kUnknown_Direction;
2329             }
2330         }
2331     }
2332 
2333     SkPoint             fCurrPt;
2334     SkVector            fVec0, fVec1, fFirstVec;
2335     int                 fPtCount;   // non-degenerate points
2336     int                 fSign;
2337     SkPath::Convexity   fConvexity;
2338     SkPath::Direction   fDirection;
2339     int                 fDx, fDy, fSx, fSy;
2340 };
2341 
internalGetConvexity() const2342 SkPath::Convexity SkPath::internalGetConvexity() const {
2343     SkASSERT(kUnknown_Convexity == fConvexity);
2344     SkPoint         pts[4];
2345     SkPath::Verb    verb;
2346     SkPath::Iter    iter(*this, true);
2347 
2348     int             contourCount = 0;
2349     int             count;
2350     Convexicator    state;
2351 
2352     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
2353         switch (verb) {
2354             case kMove_Verb:
2355                 if (++contourCount > 1) {
2356                     fConvexity = kConcave_Convexity;
2357                     return kConcave_Convexity;
2358                 }
2359                 pts[1] = pts[0];
2360                 count = 1;
2361                 break;
2362             case kLine_Verb: count = 1; break;
2363             case kQuad_Verb: count = 2; break;
2364             case kCubic_Verb: count = 3; break;
2365             case kClose_Verb:
2366                 state.close();
2367                 count = 0;
2368                 break;
2369             default:
2370                 SkDEBUGFAIL("bad verb");
2371                 fConvexity = kConcave_Convexity;
2372                 return kConcave_Convexity;
2373         }
2374 
2375         for (int i = 1; i <= count; i++) {
2376             state.addPt(pts[i]);
2377         }
2378         // early exit
2379         if (kConcave_Convexity == state.getConvexity()) {
2380             fConvexity = kConcave_Convexity;
2381             return kConcave_Convexity;
2382         }
2383     }
2384     fConvexity = state.getConvexity();
2385     if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) {
2386         fDirection = state.getDirection();
2387     }
2388     return static_cast<Convexity>(fConvexity);
2389 }
2390 
2391 ///////////////////////////////////////////////////////////////////////////////
2392 
2393 class ContourIter {
2394 public:
2395     ContourIter(const SkPathRef& pathRef);
2396 
done() const2397     bool done() const { return fDone; }
2398     // if !done() then these may be called
count() const2399     int count() const { return fCurrPtCount; }
pts() const2400     const SkPoint* pts() const { return fCurrPt; }
2401     void next();
2402 
2403 private:
2404     int fCurrPtCount;
2405     const SkPoint* fCurrPt;
2406     const uint8_t* fCurrVerb;
2407     const uint8_t* fStopVerbs;
2408     bool fDone;
2409     SkDEBUGCODE(int fContourCounter;)
2410 };
2411 
ContourIter(const SkPathRef & pathRef)2412 ContourIter::ContourIter(const SkPathRef& pathRef) {
2413     fStopVerbs = pathRef.verbsMemBegin();
2414     fDone = false;
2415     fCurrPt = pathRef.points();
2416     fCurrVerb = pathRef.verbs();
2417     fCurrPtCount = 0;
2418     SkDEBUGCODE(fContourCounter = 0;)
2419     this->next();
2420 }
2421 
next()2422 void ContourIter::next() {
2423     if (fCurrVerb <= fStopVerbs) {
2424         fDone = true;
2425     }
2426     if (fDone) {
2427         return;
2428     }
2429 
2430     // skip pts of prev contour
2431     fCurrPt += fCurrPtCount;
2432 
2433     SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
2434     int ptCount = 1;    // moveTo
2435     const uint8_t* verbs = fCurrVerb;
2436 
2437     for (--verbs; verbs > fStopVerbs; --verbs) {
2438         switch (verbs[~0]) {
2439             case SkPath::kMove_Verb:
2440                 goto CONTOUR_END;
2441             case SkPath::kLine_Verb:
2442                 ptCount += 1;
2443                 break;
2444             case SkPath::kQuad_Verb:
2445                 ptCount += 2;
2446                 break;
2447             case SkPath::kCubic_Verb:
2448                 ptCount += 3;
2449                 break;
2450             default:    // kClose_Verb, just keep going
2451                 break;
2452         }
2453     }
2454 CONTOUR_END:
2455     fCurrPtCount = ptCount;
2456     fCurrVerb = verbs;
2457     SkDEBUGCODE(++fContourCounter;)
2458 }
2459 
2460 // returns cross product of (p1 - p0) and (p2 - p0)
cross_prod(const SkPoint & p0,const SkPoint & p1,const SkPoint & p2)2461 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
2462     SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
2463     // We may get 0 when the above subtracts underflow. We expect this to be
2464     // very rare and lazily promote to double.
2465     if (0 == cross) {
2466         double p0x = SkScalarToDouble(p0.fX);
2467         double p0y = SkScalarToDouble(p0.fY);
2468 
2469         double p1x = SkScalarToDouble(p1.fX);
2470         double p1y = SkScalarToDouble(p1.fY);
2471 
2472         double p2x = SkScalarToDouble(p2.fX);
2473         double p2y = SkScalarToDouble(p2.fY);
2474 
2475         cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
2476                                  (p1y - p0y) * (p2x - p0x));
2477 
2478     }
2479     return cross;
2480 }
2481 
2482 // Returns the first pt with the maximum Y coordinate
find_max_y(const SkPoint pts[],int count)2483 static int find_max_y(const SkPoint pts[], int count) {
2484     SkASSERT(count > 0);
2485     SkScalar max = pts[0].fY;
2486     int firstIndex = 0;
2487     for (int i = 1; i < count; ++i) {
2488         SkScalar y = pts[i].fY;
2489         if (y > max) {
2490             max = y;
2491             firstIndex = i;
2492         }
2493     }
2494     return firstIndex;
2495 }
2496 
find_diff_pt(const SkPoint pts[],int index,int n,int inc)2497 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
2498     int i = index;
2499     for (;;) {
2500         i = (i + inc) % n;
2501         if (i == index) {   // we wrapped around, so abort
2502             break;
2503         }
2504         if (pts[index] != pts[i]) { // found a different point, success!
2505             break;
2506         }
2507     }
2508     return i;
2509 }
2510 
2511 /**
2512  *  Starting at index, and moving forward (incrementing), find the xmin and
2513  *  xmax of the contiguous points that have the same Y.
2514  */
find_min_max_x_at_y(const SkPoint pts[],int index,int n,int * maxIndexPtr)2515 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
2516                                int* maxIndexPtr) {
2517     const SkScalar y = pts[index].fY;
2518     SkScalar min = pts[index].fX;
2519     SkScalar max = min;
2520     int minIndex = index;
2521     int maxIndex = index;
2522     for (int i = index + 1; i < n; ++i) {
2523         if (pts[i].fY != y) {
2524             break;
2525         }
2526         SkScalar x = pts[i].fX;
2527         if (x < min) {
2528             min = x;
2529             minIndex = i;
2530         } else if (x > max) {
2531             max = x;
2532             maxIndex = i;
2533         }
2534     }
2535     *maxIndexPtr = maxIndex;
2536     return minIndex;
2537 }
2538 
crossToDir(SkScalar cross,SkPath::Direction * dir)2539 static void crossToDir(SkScalar cross, SkPath::Direction* dir) {
2540     if (dir) {
2541         *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2542     }
2543 }
2544 
2545 #if 0
2546 #include "SkString.h"
2547 #include "../utils/SkParsePath.h"
2548 static void dumpPath(const SkPath& path) {
2549     SkString str;
2550     SkParsePath::ToSVGString(path, &str);
2551     SkDebugf("%s\n", str.c_str());
2552 }
2553 #endif
2554 
2555 namespace {
2556 // for use with convex_dir_test
mul(double a,double b)2557 double mul(double a, double b) { return a * b; }
mul(SkScalar a,SkScalar b)2558 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); }
toDouble(SkScalar a)2559 double toDouble(SkScalar a) { return SkScalarToDouble(a); }
toScalar(SkScalar a)2560 SkScalar toScalar(SkScalar a) { return a; }
2561 
2562 // determines the winding direction of a convex polygon with the precision
2563 // of T. CAST_SCALAR casts an SkScalar to T.
2564 template <typename T, T (CAST_SCALAR)(SkScalar)>
convex_dir_test(int n,const SkPoint pts[],SkPath::Direction * dir)2565 bool convex_dir_test(int n, const SkPoint pts[], SkPath::Direction* dir) {
2566     // we find the first three points that form a non-degenerate
2567     // triangle. If there are no such points then the path is
2568     // degenerate. The first is always point 0. Now we find the second
2569     // point.
2570     int i = 0;
2571     enum { kX = 0, kY = 1 };
2572     T v0[2];
2573     while (1) {
2574         v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2575         v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2576         if (v0[kX] || v0[kY]) {
2577             break;
2578         }
2579         if (++i == n - 1) {
2580             return false;
2581         }
2582     }
2583     // now find a third point that is not colinear with the first two
2584     // points and check the orientation of the triangle (which will be
2585     // the same as the orientation of the path).
2586     for (++i; i < n; ++i) {
2587         T v1[2];
2588         v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2589         v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2590         T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]);
2591         if (0 != cross) {
2592             *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2593             return true;
2594         }
2595     }
2596     return false;
2597 }
2598 }
2599 
2600 /*
2601  *  We loop through all contours, and keep the computed cross-product of the
2602  *  contour that contained the global y-max. If we just look at the first
2603  *  contour, we may find one that is wound the opposite way (correctly) since
2604  *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2605  *  that is outer most (or at least has the global y-max) before we can consider
2606  *  its cross product.
2607  */
cheapComputeDirection(Direction * dir) const2608 bool SkPath::cheapComputeDirection(Direction* dir) const {
2609 //    dumpPath(*this);
2610     // don't want to pay the cost for computing this if it
2611     // is unknown, so we don't call isConvex()
2612 
2613     if (kUnknown_Direction != fDirection) {
2614         *dir = static_cast<Direction>(fDirection);
2615         return true;
2616     }
2617     const Convexity conv = this->getConvexityOrUnknown();
2618 
2619     ContourIter iter(*fPathRef.get());
2620 
2621     // initialize with our logical y-min
2622     SkScalar ymax = this->getBounds().fTop;
2623     SkScalar ymaxCross = 0;
2624 
2625     for (; !iter.done(); iter.next()) {
2626         int n = iter.count();
2627         if (n < 3) {
2628             continue;
2629         }
2630 
2631         const SkPoint* pts = iter.pts();
2632         SkScalar cross = 0;
2633         if (kConvex_Convexity == conv) {
2634             // We try first at scalar precision, and then again at double
2635             // precision. This is because the vectors computed between distant
2636             // points may lose too much precision.
2637             if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) {
2638                 fDirection = *dir;
2639                 return true;
2640             }
2641             if (convex_dir_test<double, toDouble>(n, pts, dir)) {
2642                 fDirection = *dir;
2643                 return true;
2644             } else {
2645                 return false;
2646             }
2647         } else {
2648             int index = find_max_y(pts, n);
2649             if (pts[index].fY < ymax) {
2650                 continue;
2651             }
2652 
2653             // If there is more than 1 distinct point at the y-max, we take the
2654             // x-min and x-max of them and just subtract to compute the dir.
2655             if (pts[(index + 1) % n].fY == pts[index].fY) {
2656                 int maxIndex;
2657                 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2658                 if (minIndex == maxIndex) {
2659                     goto TRY_CROSSPROD;
2660                 }
2661                 SkASSERT(pts[minIndex].fY == pts[index].fY);
2662                 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2663                 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2664                 // we just subtract the indices, and let that auto-convert to
2665                 // SkScalar, since we just want - or + to signal the direction.
2666                 cross = minIndex - maxIndex;
2667             } else {
2668                 TRY_CROSSPROD:
2669                 // Find a next and prev index to use for the cross-product test,
2670                 // but we try to find pts that form non-zero vectors from pts[index]
2671                 //
2672                 // Its possible that we can't find two non-degenerate vectors, so
2673                 // we have to guard our search (e.g. all the pts could be in the
2674                 // same place).
2675 
2676                 // we pass n - 1 instead of -1 so we don't foul up % operator by
2677                 // passing it a negative LH argument.
2678                 int prev = find_diff_pt(pts, index, n, n - 1);
2679                 if (prev == index) {
2680                     // completely degenerate, skip to next contour
2681                     continue;
2682                 }
2683                 int next = find_diff_pt(pts, index, n, 1);
2684                 SkASSERT(next != index);
2685                 cross = cross_prod(pts[prev], pts[index], pts[next]);
2686                 // if we get a zero and the points are horizontal, then we look at the spread in
2687                 // x-direction. We really should continue to walk away from the degeneracy until
2688                 // there is a divergence.
2689                 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
2690                     // construct the subtract so we get the correct Direction below
2691                     cross = pts[index].fX - pts[next].fX;
2692                 }
2693             }
2694 
2695             if (cross) {
2696                 // record our best guess so far
2697                 ymax = pts[index].fY;
2698                 ymaxCross = cross;
2699             }
2700         }
2701     }
2702     if (ymaxCross) {
2703         crossToDir(ymaxCross, dir);
2704         fDirection = *dir;
2705         return true;
2706     } else {
2707         return false;
2708     }
2709 }
2710 
2711 ///////////////////////////////////////////////////////////////////////////////
2712 
eval_cubic_coeff(SkScalar A,SkScalar B,SkScalar C,SkScalar D,SkScalar t)2713 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
2714                                  SkScalar D, SkScalar t) {
2715     return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
2716 }
2717 
eval_cubic_pts(SkScalar c0,SkScalar c1,SkScalar c2,SkScalar c3,SkScalar t)2718 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
2719                                SkScalar t) {
2720     SkScalar A = c3 + 3*(c1 - c2) - c0;
2721     SkScalar B = 3*(c2 - c1 - c1 + c0);
2722     SkScalar C = 3*(c1 - c0);
2723     SkScalar D = c0;
2724     return eval_cubic_coeff(A, B, C, D, t);
2725 }
2726 
2727 /*  Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
2728  t value such that cubic(t) = target
2729  */
chopMonoCubicAt(SkScalar c0,SkScalar c1,SkScalar c2,SkScalar c3,SkScalar target,SkScalar * t)2730 static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
2731                             SkScalar target, SkScalar* t) {
2732     //   SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
2733     SkASSERT(c0 < target && target < c3);
2734 
2735     SkScalar D = c0 - target;
2736     SkScalar A = c3 + 3*(c1 - c2) - c0;
2737     SkScalar B = 3*(c2 - c1 - c1 + c0);
2738     SkScalar C = 3*(c1 - c0);
2739 
2740     const SkScalar TOLERANCE = SK_Scalar1 / 4096;
2741     SkScalar minT = 0;
2742     SkScalar maxT = SK_Scalar1;
2743     SkScalar mid;
2744     int i;
2745     for (i = 0; i < 16; i++) {
2746         mid = SkScalarAve(minT, maxT);
2747         SkScalar delta = eval_cubic_coeff(A, B, C, D, mid);
2748         if (delta < 0) {
2749             minT = mid;
2750             delta = -delta;
2751         } else {
2752             maxT = mid;
2753         }
2754         if (delta < TOLERANCE) {
2755             break;
2756         }
2757     }
2758     *t = mid;
2759     return true;
2760 }
2761 
find_minmax(const SkPoint pts[],SkScalar * minPtr,SkScalar * maxPtr)2762 template <size_t N> static void find_minmax(const SkPoint pts[],
2763                                             SkScalar* minPtr, SkScalar* maxPtr) {
2764     SkScalar min, max;
2765     min = max = pts[0].fX;
2766     for (size_t i = 1; i < N; ++i) {
2767         min = SkMinScalar(min, pts[i].fX);
2768         max = SkMaxScalar(max, pts[i].fX);
2769     }
2770     *minPtr = min;
2771     *maxPtr = max;
2772 }
2773 
winding_mono_cubic(const SkPoint pts[],SkScalar x,SkScalar y)2774 static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y) {
2775     SkPoint storage[4];
2776 
2777     int dir = 1;
2778     if (pts[0].fY > pts[3].fY) {
2779         storage[0] = pts[3];
2780         storage[1] = pts[2];
2781         storage[2] = pts[1];
2782         storage[3] = pts[0];
2783         pts = storage;
2784         dir = -1;
2785     }
2786     if (y < pts[0].fY || y >= pts[3].fY) {
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, xt;
2802     if (chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, &t)) {
2803         xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
2804     } else {
2805         SkScalar mid = SkScalarAve(pts[0].fY, pts[3].fY);
2806         xt = y < mid ? pts[0].fX : pts[3].fX;
2807     }
2808     return xt < x ? dir : 0;
2809 }
2810 
winding_cubic(const SkPoint pts[],SkScalar x,SkScalar y)2811 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) {
2812     SkPoint dst[10];
2813     int n = SkChopCubicAtYExtrema(pts, dst);
2814     int w = 0;
2815     for (int i = 0; i <= n; ++i) {
2816         w += winding_mono_cubic(&dst[i * 3], x, y);
2817     }
2818     return w;
2819 }
2820 
winding_mono_quad(const SkPoint pts[],SkScalar x,SkScalar y)2821 static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y) {
2822     SkScalar y0 = pts[0].fY;
2823     SkScalar y2 = pts[2].fY;
2824 
2825     int dir = 1;
2826     if (y0 > y2) {
2827         SkTSwap(y0, y2);
2828         dir = -1;
2829     }
2830     if (y < y0 || y >= y2) {
2831         return 0;
2832     }
2833 
2834     // bounds check on X (not required. is it faster?)
2835 #if 0
2836     if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) {
2837         return 0;
2838     }
2839 #endif
2840 
2841     SkScalar roots[2];
2842     int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
2843                                 2 * (pts[1].fY - pts[0].fY),
2844                                 pts[0].fY - y,
2845                                 roots);
2846     SkASSERT(n <= 1);
2847     SkScalar xt;
2848     if (0 == n) {
2849         SkScalar mid = SkScalarAve(y0, y2);
2850         // Need [0] and [2] if dir == 1
2851         // and  [2] and [0] if dir == -1
2852         xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX;
2853     } else {
2854         SkScalar t = roots[0];
2855         SkScalar C = pts[0].fX;
2856         SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
2857         SkScalar B = 2 * (pts[1].fX - C);
2858         xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
2859     }
2860     return xt < x ? dir : 0;
2861 }
2862 
is_mono_quad(SkScalar y0,SkScalar y1,SkScalar y2)2863 static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) {
2864     //    return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0;
2865     if (y0 == y1) {
2866         return true;
2867     }
2868     if (y0 < y1) {
2869         return y1 <= y2;
2870     } else {
2871         return y1 >= y2;
2872     }
2873 }
2874 
winding_quad(const SkPoint pts[],SkScalar x,SkScalar y)2875 static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y) {
2876     SkPoint dst[5];
2877     int     n = 0;
2878 
2879     if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) {
2880         n = SkChopQuadAtYExtrema(pts, dst);
2881         pts = dst;
2882     }
2883     int w = winding_mono_quad(pts, x, y);
2884     if (n > 0) {
2885         w += winding_mono_quad(&pts[2], x, y);
2886     }
2887     return w;
2888 }
2889 
winding_line(const SkPoint pts[],SkScalar x,SkScalar y)2890 static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y) {
2891     SkScalar x0 = pts[0].fX;
2892     SkScalar y0 = pts[0].fY;
2893     SkScalar x1 = pts[1].fX;
2894     SkScalar y1 = pts[1].fY;
2895 
2896     SkScalar dy = y1 - y0;
2897 
2898     int dir = 1;
2899     if (y0 > y1) {
2900         SkTSwap(y0, y1);
2901         dir = -1;
2902     }
2903     if (y < y0 || y >= y1) {
2904         return 0;
2905     }
2906 
2907     SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) -
2908     SkScalarMul(dy, x - pts[0].fX);
2909 
2910     if (SkScalarSignAsInt(cross) == dir) {
2911         dir = 0;
2912     }
2913     return dir;
2914 }
2915 
contains(SkScalar x,SkScalar y) const2916 bool SkPath::contains(SkScalar x, SkScalar y) const {
2917     bool isInverse = this->isInverseFillType();
2918     if (this->isEmpty()) {
2919         return isInverse;
2920     }
2921 
2922     const SkRect& bounds = this->getBounds();
2923     if (!bounds.contains(x, y)) {
2924         return isInverse;
2925     }
2926 
2927     SkPath::Iter iter(*this, true);
2928     bool done = false;
2929     int w = 0;
2930     do {
2931         SkPoint pts[4];
2932         switch (iter.next(pts, false)) {
2933             case SkPath::kMove_Verb:
2934             case SkPath::kClose_Verb:
2935                 break;
2936             case SkPath::kLine_Verb:
2937                 w += winding_line(pts, x, y);
2938                 break;
2939             case SkPath::kQuad_Verb:
2940                 w += winding_quad(pts, x, y);
2941                 break;
2942             case SkPath::kCubic_Verb:
2943                 w += winding_cubic(pts, x, y);
2944                 break;
2945             case SkPath::kDone_Verb:
2946                 done = true;
2947                 break;
2948         }
2949     } while (!done);
2950 
2951     switch (this->getFillType()) {
2952         case SkPath::kEvenOdd_FillType:
2953         case SkPath::kInverseEvenOdd_FillType:
2954             w &= 1;
2955             break;
2956         default:
2957             break;
2958     }
2959     return SkToBool(w);
2960 }
2961