• 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 "SkReader32.h"
12 #include "SkWriter32.h"
13 #include "SkMath.h"
14 
15 ////////////////////////////////////////////////////////////////////////////
16 
17 /**
18  *  Path.bounds is defined to be the bounds of all the control points.
19  *  If we called bounds.join(r) we would skip r if r was empty, which breaks
20  *  our promise. Hence we have a custom joiner that doesn't look at emptiness
21  */
joinNoEmptyChecks(SkRect * dst,const SkRect & src)22 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
23     dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
24     dst->fTop = SkMinScalar(dst->fTop, src.fTop);
25     dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
26     dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
27 }
28 
is_degenerate(const SkPath & path)29 static bool is_degenerate(const SkPath& path) {
30     SkPath::Iter iter(path, false);
31     SkPoint pts[4];
32     return SkPath::kDone_Verb == iter.next(pts);
33 }
34 
35 /*  This guy's constructor/destructor bracket a path editing operation. It is
36     used when we know the bounds of the amount we are going to add to the path
37     (usually a new contour, but not required).
38 
39     It captures some state about the path up front (i.e. if it already has a
40     cached bounds), and the if it can, it updates the cache bounds explicitly,
41     avoiding the need to revisit all of the points in getBounds().
42 
43     It also notes if the path was originally degenerate, and if so, sets
44     isConvex to true. Thus it can only be used if the contour being added is
45     convex.
46  */
47 class SkAutoPathBoundsUpdate {
48 public:
SkAutoPathBoundsUpdate(SkPath * path,const SkRect & r)49     SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
50         this->init(path);
51     }
52 
SkAutoPathBoundsUpdate(SkPath * path,SkScalar left,SkScalar top,SkScalar right,SkScalar bottom)53     SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
54                            SkScalar right, SkScalar bottom) {
55         fRect.set(left, top, right, bottom);
56         this->init(path);
57     }
58 
~SkAutoPathBoundsUpdate()59     ~SkAutoPathBoundsUpdate() {
60         fPath->setIsConvex(fDegenerate);
61         if (fEmpty) {
62             fPath->fBounds = fRect;
63             fPath->fBoundsIsDirty = false;
64         } else if (!fDirty) {
65             joinNoEmptyChecks(&fPath->fBounds, fRect);
66             fPath->fBoundsIsDirty = false;
67         }
68     }
69 
70 private:
71     SkPath* fPath;
72     SkRect  fRect;
73     bool    fDirty;
74     bool    fDegenerate;
75     bool    fEmpty;
76 
77     // returns true if we should proceed
init(SkPath * path)78     void init(SkPath* path) {
79         fPath = path;
80         fDirty = SkToBool(path->fBoundsIsDirty);
81         fDegenerate = is_degenerate(*path);
82         fEmpty = path->isEmpty();
83         // Cannot use fRect for our bounds unless we know it is sorted
84         fRect.sort();
85     }
86 };
87 
compute_pt_bounds(SkRect * bounds,const SkTDArray<SkPoint> & pts)88 static void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
89     if (pts.count() <= 1) {  // we ignore just 1 point (moveto)
90         bounds->set(0, 0, 0, 0);
91     } else {
92         bounds->set(pts.begin(), pts.count());
93 //        SkDebugf("------- compute bounds %p %d", &pts, pts.count());
94     }
95 }
96 
97 ////////////////////////////////////////////////////////////////////////////
98 
99 /*
100     Stores the verbs and points as they are given to us, with exceptions:
101     - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic
102     - we insert a Move(0,0) if Line | Quad | Cubic is our first command
103 
104     The iterator does more cleanup, especially if forceClose == true
105     1. If we encounter degenerate segments, remove them
106     2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
107     3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
108     4. if we encounter Line | Quad | Cubic after Close, cons up a Move
109 */
110 
111 ////////////////////////////////////////////////////////////////////////////
112 
113 // flag to require a moveTo if we begin with something else, like lineTo etc.
114 #define INITIAL_LASTMOVETOINDEX_VALUE   ~0
115 
SkPath()116 SkPath::SkPath()
117     : fFillType(kWinding_FillType)
118     , fBoundsIsDirty(true) {
119     fConvexity = kUnknown_Convexity;
120     fSegmentMask = 0;
121     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
122 #ifdef SK_BUILD_FOR_ANDROID
123     fGenerationID = 0;
124     fSourcePath = NULL;
125 #endif
126 }
127 
SkPath(const SkPath & src)128 SkPath::SkPath(const SkPath& src) {
129     SkDEBUGCODE(src.validate();)
130     *this = src;
131 #ifdef SK_BUILD_FOR_ANDROID
132     // the assignment operator above increments the ID so correct for that here
133     fGenerationID = src.fGenerationID;
134     fSourcePath = NULL;
135 #endif
136 }
137 
~SkPath()138 SkPath::~SkPath() {
139     SkDEBUGCODE(this->validate();)
140 }
141 
operator =(const SkPath & src)142 SkPath& SkPath::operator=(const SkPath& src) {
143     SkDEBUGCODE(src.validate();)
144 
145     if (this != &src) {
146         fBounds         = src.fBounds;
147         fPts            = src.fPts;
148         fVerbs          = src.fVerbs;
149         fFillType       = src.fFillType;
150         fBoundsIsDirty  = src.fBoundsIsDirty;
151         fConvexity      = src.fConvexity;
152         fSegmentMask    = src.fSegmentMask;
153         fLastMoveToIndex = src.fLastMoveToIndex;
154         GEN_ID_INC;
155     }
156     SkDEBUGCODE(this->validate();)
157     return *this;
158 }
159 
operator ==(const SkPath & a,const SkPath & b)160 bool operator==(const SkPath& a, const SkPath& b) {
161     // note: don't need to look at isConvex or bounds, since just comparing the
162     // raw data is sufficient.
163 
164     // We explicitly check fSegmentMask as a quick-reject. We could skip it,
165     // since it is only a cache of info in the fVerbs, but its a fast way to
166     // notice a difference
167 
168     return &a == &b ||
169         (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
170          a.fVerbs == b.fVerbs && a.fPts == b.fPts);
171 }
172 
swap(SkPath & other)173 void SkPath::swap(SkPath& other) {
174     SkASSERT(&other != NULL);
175 
176     if (this != &other) {
177         SkTSwap<SkRect>(fBounds, other.fBounds);
178         fPts.swap(other.fPts);
179         fVerbs.swap(other.fVerbs);
180         SkTSwap<uint8_t>(fFillType, other.fFillType);
181         SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
182         SkTSwap<uint8_t>(fConvexity, other.fConvexity);
183         SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
184         SkTSwap<int>(fLastMoveToIndex, other.fLastMoveToIndex);
185         GEN_ID_INC;
186     }
187 }
188 
189 #ifdef SK_BUILD_FOR_ANDROID
getGenerationID() const190 uint32_t SkPath::getGenerationID() const {
191     return fGenerationID;
192 }
193 
getSourcePath() const194 const SkPath* SkPath::getSourcePath() const {
195     return fSourcePath;
196 }
197 
setSourcePath(const SkPath * path)198 void SkPath::setSourcePath(const SkPath* path) {
199     fSourcePath = path;
200 }
201 #endif
202 
reset()203 void SkPath::reset() {
204     SkDEBUGCODE(this->validate();)
205 
206     fPts.reset();
207     fVerbs.reset();
208     GEN_ID_INC;
209     fBoundsIsDirty = true;
210     fConvexity = kUnknown_Convexity;
211     fSegmentMask = 0;
212     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
213 }
214 
rewind()215 void SkPath::rewind() {
216     SkDEBUGCODE(this->validate();)
217 
218     fPts.rewind();
219     fVerbs.rewind();
220     GEN_ID_INC;
221     fConvexity = kUnknown_Convexity;
222     fBoundsIsDirty = true;
223     fSegmentMask = 0;
224     fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
225 }
226 
isEmpty() const227 bool SkPath::isEmpty() const {
228     SkDEBUGCODE(this->validate();)
229     return 0 == fVerbs.count();
230 }
231 
232 /*
233  Determines if path is a rect by keeping track of changes in direction
234  and looking for a loop either clockwise or counterclockwise.
235 
236  The direction is computed such that:
237   0: vertical up
238   1: horizontal right
239   2: vertical down
240   3: horizontal left
241 
242 A rectangle cycles up/right/down/left or up/left/down/right.
243 
244 The test fails if:
245   The path is closed, and followed by a line.
246   A second move creates a new endpoint.
247   A diagonal line is parsed.
248   There's more than four changes of direction.
249   There's a discontinuity on the line (e.g., a move in the middle)
250   The line reverses direction.
251   The rectangle doesn't complete a cycle.
252   The path contains a quadratic or cubic.
253   The path contains fewer than four points.
254   The final point isn't equal to the first point.
255 
256 It's OK if the path has:
257   Several colinear line segments composing a rectangle side.
258   Single points on the rectangle side.
259 
260 The direction takes advantage of the corners found since opposite sides
261 must travel in opposite directions.
262 
263 FIXME: Allow colinear quads and cubics to be treated like lines.
264 FIXME: If the API passes fill-only, return true if the filled stroke
265        is a rectangle, though the caller failed to close the path.
266  */
isRect(SkRect * rect) const267 bool SkPath::isRect(SkRect* rect) const {
268     SkDEBUGCODE(this->validate();)
269 
270     int corners = 0;
271     SkPoint first, last;
272     first.set(0, 0);
273     last.set(0, 0);
274     int firstDirection = 0;
275     int lastDirection = 0;
276     int nextDirection = 0;
277     bool closedOrMoved = false;
278     bool autoClose = false;
279     const uint8_t* verbs = fVerbs.begin();
280     const uint8_t* verbStop = fVerbs.end();
281     const SkPoint* pts = fPts.begin();
282     while (verbs != verbStop) {
283         switch (*verbs++) {
284             case kClose_Verb:
285                 pts = fPts.begin();
286                 autoClose = true;
287             case kLine_Verb: {
288                 SkScalar left = last.fX;
289                 SkScalar top = last.fY;
290                 SkScalar right = pts->fX;
291                 SkScalar bottom = pts->fY;
292                 ++pts;
293                 if (left != right && top != bottom) {
294                     return false; // diagonal
295                 }
296                 if (left == right && top == bottom) {
297                     break; // single point on side OK
298                 }
299                 nextDirection = (left != right) << 0 |
300                     (left < right || top < bottom) << 1;
301                 if (0 == corners) {
302                     firstDirection = nextDirection;
303                     first = last;
304                     last = pts[-1];
305                     corners = 1;
306                     closedOrMoved = false;
307                     break;
308                 }
309                 if (closedOrMoved) {
310                     return false; // closed followed by a line
311                 }
312                 closedOrMoved = autoClose;
313                 if (lastDirection != nextDirection) {
314                     if (++corners > 4) {
315                         return false; // too many direction changes
316                     }
317                 }
318                 last = pts[-1];
319                 if (lastDirection == nextDirection) {
320                     break; // colinear segment
321                 }
322                 // Possible values for corners are 2, 3, and 4.
323                 // When corners == 3, nextDirection opposes firstDirection.
324                 // Otherwise, nextDirection at corner 2 opposes corner 4.
325                 int turn = firstDirection ^ (corners - 1);
326                 int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
327                 if ((directionCycle ^ turn) != nextDirection) {
328                     return false; // direction didn't follow cycle
329                 }
330                 break;
331             }
332             case kQuad_Verb:
333             case kCubic_Verb:
334                 return false; // quadratic, cubic not allowed
335             case kMove_Verb:
336                 last = *pts++;
337                 closedOrMoved = true;
338                 break;
339         }
340         lastDirection = nextDirection;
341     }
342     // Success if 4 corners and first point equals last
343     bool result = 4 == corners && first == last;
344     if (result && rect) {
345         *rect = getBounds();
346     }
347     return result;
348 }
349 
getPoints(SkPoint copy[],int max) const350 int SkPath::getPoints(SkPoint copy[], int max) const {
351     SkDEBUGCODE(this->validate();)
352 
353     SkASSERT(max >= 0);
354     int count = fPts.count();
355     if (copy && max > 0 && count > 0) {
356         memcpy(copy, fPts.begin(), sizeof(SkPoint) * SkMin32(max, count));
357     }
358     return count;
359 }
360 
getPoint(int index) const361 SkPoint SkPath::getPoint(int index) const {
362     if ((unsigned)index < (unsigned)fPts.count()) {
363         return fPts[index];
364     }
365     return SkPoint::Make(0, 0);
366 }
367 
getLastPt(SkPoint * lastPt) const368 bool SkPath::getLastPt(SkPoint* lastPt) const {
369     SkDEBUGCODE(this->validate();)
370 
371     int count = fPts.count();
372     if (count > 0) {
373         if (lastPt) {
374             *lastPt = fPts[count - 1];
375         }
376         return true;
377     }
378     if (lastPt) {
379         lastPt->set(0, 0);
380     }
381     return false;
382 }
383 
setLastPt(SkScalar x,SkScalar y)384 void SkPath::setLastPt(SkScalar x, SkScalar y) {
385     SkDEBUGCODE(this->validate();)
386 
387     int count = fPts.count();
388     if (count == 0) {
389         this->moveTo(x, y);
390     } else {
391         fPts[count - 1].set(x, y);
392         GEN_ID_INC;
393     }
394 }
395 
computeBounds() const396 void SkPath::computeBounds() const {
397     SkDEBUGCODE(this->validate();)
398     SkASSERT(fBoundsIsDirty);
399 
400     fBoundsIsDirty = false;
401     compute_pt_bounds(&fBounds, fPts);
402 }
403 
setConvexity(Convexity c)404 void SkPath::setConvexity(Convexity c) {
405     if (fConvexity != c) {
406         fConvexity = c;
407         GEN_ID_INC;
408     }
409 }
410 
411 //////////////////////////////////////////////////////////////////////////////
412 //  Construction methods
413 
414 #define DIRTY_AFTER_EDIT                 \
415     do {                                 \
416         fBoundsIsDirty = true;           \
417         fConvexity = kUnknown_Convexity; \
418     } while (0)
419 
420 #define DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE    \
421     do {                                        \
422         fBoundsIsDirty = true;                  \
423     } while (0)
424 
incReserve(U16CPU inc)425 void SkPath::incReserve(U16CPU inc) {
426     SkDEBUGCODE(this->validate();)
427 
428     fVerbs.setReserve(fVerbs.count() + inc);
429     fPts.setReserve(fPts.count() + inc);
430 
431     SkDEBUGCODE(this->validate();)
432 }
433 
moveTo(SkScalar x,SkScalar y)434 void SkPath::moveTo(SkScalar x, SkScalar y) {
435     SkDEBUGCODE(this->validate();)
436 
437     int      vc = fVerbs.count();
438     SkPoint* pt;
439 
440     // remember our index
441     fLastMoveToIndex = fPts.count();
442 
443     pt = fPts.append();
444     *fVerbs.append() = kMove_Verb;
445     pt->set(x, y);
446 
447     GEN_ID_INC;
448     DIRTY_AFTER_EDIT_NO_CONVEXITY_CHANGE;
449 }
450 
rMoveTo(SkScalar x,SkScalar y)451 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
452     SkPoint pt;
453     this->getLastPt(&pt);
454     this->moveTo(pt.fX + x, pt.fY + y);
455 }
456 
injectMoveToIfNeeded()457 void SkPath::injectMoveToIfNeeded() {
458     if (fLastMoveToIndex < 0) {
459         SkScalar x, y;
460         if (fVerbs.count() == 0) {
461             x = y = 0;
462         } else {
463             const SkPoint& pt = fPts[~fLastMoveToIndex];
464             x = pt.fX;
465             y = pt.fY;
466         }
467         this->moveTo(x, y);
468     }
469 }
470 
lineTo(SkScalar x,SkScalar y)471 void SkPath::lineTo(SkScalar x, SkScalar y) {
472     SkDEBUGCODE(this->validate();)
473 
474     this->injectMoveToIfNeeded();
475 
476     fPts.append()->set(x, y);
477     *fVerbs.append() = kLine_Verb;
478     fSegmentMask |= kLine_SegmentMask;
479 
480     GEN_ID_INC;
481     DIRTY_AFTER_EDIT;
482 }
483 
rLineTo(SkScalar x,SkScalar y)484 void SkPath::rLineTo(SkScalar x, SkScalar y) {
485     SkPoint pt;
486     this->getLastPt(&pt);
487     this->lineTo(pt.fX + x, pt.fY + y);
488 }
489 
quadTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)490 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
491     SkDEBUGCODE(this->validate();)
492 
493     this->injectMoveToIfNeeded();
494 
495     SkPoint* pts = fPts.append(2);
496     pts[0].set(x1, y1);
497     pts[1].set(x2, y2);
498     *fVerbs.append() = kQuad_Verb;
499     fSegmentMask |= kQuad_SegmentMask;
500 
501     GEN_ID_INC;
502     DIRTY_AFTER_EDIT;
503 }
504 
rQuadTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2)505 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
506     SkPoint pt;
507     this->getLastPt(&pt);
508     this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
509 }
510 
cubicTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar x3,SkScalar y3)511 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
512                      SkScalar x3, SkScalar y3) {
513     SkDEBUGCODE(this->validate();)
514 
515     this->injectMoveToIfNeeded();
516 
517     SkPoint* pts = fPts.append(3);
518     pts[0].set(x1, y1);
519     pts[1].set(x2, y2);
520     pts[2].set(x3, y3);
521     *fVerbs.append() = kCubic_Verb;
522     fSegmentMask |= kCubic_SegmentMask;
523 
524     GEN_ID_INC;
525     DIRTY_AFTER_EDIT;
526 }
527 
rCubicTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar x3,SkScalar y3)528 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
529                       SkScalar x3, SkScalar y3) {
530     SkPoint pt;
531     this->getLastPt(&pt);
532     this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2,
533                   pt.fX + x3, pt.fY + y3);
534 }
535 
close()536 void SkPath::close() {
537     SkDEBUGCODE(this->validate();)
538 
539     int count = fVerbs.count();
540     if (count > 0) {
541         switch (fVerbs[count - 1]) {
542             case kLine_Verb:
543             case kQuad_Verb:
544             case kCubic_Verb:
545             case kMove_Verb:
546                 *fVerbs.append() = kClose_Verb;
547                 GEN_ID_INC;
548                 break;
549             default:
550                 // don't add a close if it's the first verb or a repeat
551                 break;
552         }
553     }
554 
555     // signal that we need a moveTo to follow us (unless we're done)
556 #if 0
557     if (fLastMoveToIndex >= 0) {
558         fLastMoveToIndex = ~fLastMoveToIndex;
559     }
560 #else
561     fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
562 #endif
563 }
564 
565 ///////////////////////////////////////////////////////////////////////////////
566 
addRect(const SkRect & rect,Direction dir)567 void SkPath::addRect(const SkRect& rect, Direction dir) {
568     this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
569 }
570 
addRect(SkScalar left,SkScalar top,SkScalar right,SkScalar bottom,Direction dir)571 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
572                      SkScalar bottom, Direction dir) {
573     SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom);
574 
575     this->incReserve(5);
576 
577     this->moveTo(left, top);
578     if (dir == kCCW_Direction) {
579         this->lineTo(left, bottom);
580         this->lineTo(right, bottom);
581         this->lineTo(right, top);
582     } else {
583         this->lineTo(right, top);
584         this->lineTo(right, bottom);
585         this->lineTo(left, bottom);
586     }
587     this->close();
588 }
589 
590 #define CUBIC_ARC_FACTOR    ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
591 
addRoundRect(const SkRect & rect,SkScalar rx,SkScalar ry,Direction dir)592 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
593                           Direction dir) {
594     SkScalar    w = rect.width();
595     SkScalar    halfW = SkScalarHalf(w);
596     SkScalar    h = rect.height();
597     SkScalar    halfH = SkScalarHalf(h);
598 
599     if (halfW <= 0 || halfH <= 0) {
600         return;
601     }
602 
603     bool skip_hori = rx >= halfW;
604     bool skip_vert = ry >= halfH;
605 
606     if (skip_hori && skip_vert) {
607         this->addOval(rect, dir);
608         return;
609     }
610 
611     SkAutoPathBoundsUpdate apbu(this, rect);
612 
613     if (skip_hori) {
614         rx = halfW;
615     } else if (skip_vert) {
616         ry = halfH;
617     }
618 
619     SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
620     SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
621 
622     this->incReserve(17);
623     this->moveTo(rect.fRight - rx, rect.fTop);
624     if (dir == kCCW_Direction) {
625         if (!skip_hori) {
626             this->lineTo(rect.fLeft + rx, rect.fTop);       // top
627         }
628         this->cubicTo(rect.fLeft + rx - sx, rect.fTop,
629                       rect.fLeft, rect.fTop + ry - sy,
630                       rect.fLeft, rect.fTop + ry);          // top-left
631         if (!skip_vert) {
632             this->lineTo(rect.fLeft, rect.fBottom - ry);        // left
633         }
634         this->cubicTo(rect.fLeft, rect.fBottom - ry + sy,
635                       rect.fLeft + rx - sx, rect.fBottom,
636                       rect.fLeft + rx, rect.fBottom);       // bot-left
637         if (!skip_hori) {
638             this->lineTo(rect.fRight - rx, rect.fBottom);   // bottom
639         }
640         this->cubicTo(rect.fRight - rx + sx, rect.fBottom,
641                       rect.fRight, rect.fBottom - ry + sy,
642                       rect.fRight, rect.fBottom - ry);      // bot-right
643         if (!skip_vert) {
644             this->lineTo(rect.fRight, rect.fTop + ry);
645         }
646         this->cubicTo(rect.fRight, rect.fTop + ry - sy,
647                       rect.fRight - rx + sx, rect.fTop,
648                       rect.fRight - rx, rect.fTop);         // top-right
649     } else {
650         this->cubicTo(rect.fRight - rx + sx, rect.fTop,
651                       rect.fRight, rect.fTop + ry - sy,
652                       rect.fRight, rect.fTop + ry);         // top-right
653         if (!skip_vert) {
654             this->lineTo(rect.fRight, rect.fBottom - ry);
655         }
656         this->cubicTo(rect.fRight, rect.fBottom - ry + sy,
657                       rect.fRight - rx + sx, rect.fBottom,
658                       rect.fRight - rx, rect.fBottom);      // bot-right
659         if (!skip_hori) {
660             this->lineTo(rect.fLeft + rx, rect.fBottom);    // bottom
661         }
662         this->cubicTo(rect.fLeft + rx - sx, rect.fBottom,
663                       rect.fLeft, rect.fBottom - ry + sy,
664                       rect.fLeft, rect.fBottom - ry);       // bot-left
665         if (!skip_vert) {
666             this->lineTo(rect.fLeft, rect.fTop + ry);       // left
667         }
668         this->cubicTo(rect.fLeft, rect.fTop + ry - sy,
669                       rect.fLeft + rx - sx, rect.fTop,
670                       rect.fLeft + rx, rect.fTop);          // top-left
671         if (!skip_hori) {
672             this->lineTo(rect.fRight - rx, rect.fTop);      // top
673         }
674     }
675     this->close();
676 }
677 
add_corner_arc(SkPath * path,const SkRect & rect,SkScalar rx,SkScalar ry,int startAngle,SkPath::Direction dir,bool forceMoveTo)678 static void add_corner_arc(SkPath* path, const SkRect& rect,
679                            SkScalar rx, SkScalar ry, int startAngle,
680                            SkPath::Direction dir, bool forceMoveTo) {
681     rx = SkMinScalar(SkScalarHalf(rect.width()), rx);
682     ry = SkMinScalar(SkScalarHalf(rect.height()), ry);
683 
684     SkRect   r;
685     r.set(-rx, -ry, rx, ry);
686 
687     switch (startAngle) {
688         case   0:
689             r.offset(rect.fRight - r.fRight, rect.fBottom - r.fBottom);
690             break;
691         case  90:
692             r.offset(rect.fLeft - r.fLeft,   rect.fBottom - r.fBottom);
693             break;
694         case 180: r.offset(rect.fLeft - r.fLeft,   rect.fTop - r.fTop); break;
695         case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break;
696         default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc");
697     }
698 
699     SkScalar start = SkIntToScalar(startAngle);
700     SkScalar sweep = SkIntToScalar(90);
701     if (SkPath::kCCW_Direction == dir) {
702         start += sweep;
703         sweep = -sweep;
704     }
705 
706     path->arcTo(r, start, sweep, forceMoveTo);
707 }
708 
addRoundRect(const SkRect & rect,const SkScalar rad[],Direction dir)709 void SkPath::addRoundRect(const SkRect& rect, const SkScalar rad[],
710                           Direction dir) {
711     // abort before we invoke SkAutoPathBoundsUpdate()
712     if (rect.isEmpty()) {
713         return;
714     }
715 
716     SkAutoPathBoundsUpdate apbu(this, rect);
717 
718     if (kCW_Direction == dir) {
719         add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
720         add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
721         add_corner_arc(this, rect, rad[4], rad[5],   0, dir, false);
722         add_corner_arc(this, rect, rad[6], rad[7],  90, dir, false);
723     } else {
724         add_corner_arc(this, rect, rad[0], rad[1], 180, dir, true);
725         add_corner_arc(this, rect, rad[6], rad[7],  90, dir, false);
726         add_corner_arc(this, rect, rad[4], rad[5],   0, dir, false);
727         add_corner_arc(this, rect, rad[2], rad[3], 270, dir, false);
728     }
729     this->close();
730 }
731 
addOval(const SkRect & oval,Direction dir)732 void SkPath::addOval(const SkRect& oval, Direction dir) {
733     SkAutoPathBoundsUpdate apbu(this, oval);
734 
735     SkScalar    cx = oval.centerX();
736     SkScalar    cy = oval.centerY();
737     SkScalar    rx = SkScalarHalf(oval.width());
738     SkScalar    ry = SkScalarHalf(oval.height());
739 #if 0   // these seem faster than using quads (1/2 the number of edges)
740     SkScalar    sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
741     SkScalar    sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
742 
743     this->incReserve(13);
744     this->moveTo(cx + rx, cy);
745     if (dir == kCCW_Direction) {
746         this->cubicTo(cx + rx, cy - sy, cx + sx, cy - ry, cx, cy - ry);
747         this->cubicTo(cx - sx, cy - ry, cx - rx, cy - sy, cx - rx, cy);
748         this->cubicTo(cx - rx, cy + sy, cx - sx, cy + ry, cx, cy + ry);
749         this->cubicTo(cx + sx, cy + ry, cx + rx, cy + sy, cx + rx, cy);
750     } else {
751         this->cubicTo(cx + rx, cy + sy, cx + sx, cy + ry, cx, cy + ry);
752         this->cubicTo(cx - sx, cy + ry, cx - rx, cy + sy, cx - rx, cy);
753         this->cubicTo(cx - rx, cy - sy, cx - sx, cy - ry, cx, cy - ry);
754         this->cubicTo(cx + sx, cy - ry, cx + rx, cy - sy, cx + rx, cy);
755     }
756 #else
757     SkScalar    sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
758     SkScalar    sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
759     SkScalar    mx = SkScalarMul(rx, SK_ScalarRoot2Over2);
760     SkScalar    my = SkScalarMul(ry, SK_ScalarRoot2Over2);
761 
762     /*
763         To handle imprecision in computing the center and radii, we revert to
764         the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx)
765         to ensure that we don't exceed the oval's bounds *ever*, since we want
766         to use oval for our fast-bounds, rather than have to recompute it.
767     */
768     const SkScalar L = oval.fLeft;      // cx - rx
769     const SkScalar T = oval.fTop;       // cy - ry
770     const SkScalar R = oval.fRight;     // cx + rx
771     const SkScalar B = oval.fBottom;    // cy + ry
772 
773     this->incReserve(17);   // 8 quads + close
774     this->moveTo(R, cy);
775     if (dir == kCCW_Direction) {
776         this->quadTo(      R, cy - sy, cx + mx, cy - my);
777         this->quadTo(cx + sx,       T, cx     ,       T);
778         this->quadTo(cx - sx,       T, cx - mx, cy - my);
779         this->quadTo(      L, cy - sy,       L, cy     );
780         this->quadTo(      L, cy + sy, cx - mx, cy + my);
781         this->quadTo(cx - sx,       B, cx     ,       B);
782         this->quadTo(cx + sx,       B, cx + mx, cy + my);
783         this->quadTo(      R, cy + sy,       R, cy     );
784     } else {
785         this->quadTo(      R, cy + sy, cx + mx, cy + my);
786         this->quadTo(cx + sx,       B, cx     ,       B);
787         this->quadTo(cx - sx,       B, cx - mx, cy + my);
788         this->quadTo(      L, cy + sy,       L, cy     );
789         this->quadTo(      L, cy - sy, cx - mx, cy - my);
790         this->quadTo(cx - sx,       T, cx     ,       T);
791         this->quadTo(cx + sx,       T, cx + mx, cy - my);
792         this->quadTo(      R, cy - sy,       R, cy     );
793     }
794 #endif
795     this->close();
796 }
797 
addCircle(SkScalar x,SkScalar y,SkScalar r,Direction dir)798 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
799     if (r > 0) {
800         SkRect  rect;
801         rect.set(x - r, y - r, x + r, y + r);
802         this->addOval(rect, dir);
803     }
804 }
805 
806 #include "SkGeometry.h"
807 
build_arc_points(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,SkPoint pts[kSkBuildQuadArcStorage])808 static int build_arc_points(const SkRect& oval, SkScalar startAngle,
809                             SkScalar sweepAngle,
810                             SkPoint pts[kSkBuildQuadArcStorage]) {
811     SkVector start, stop;
812 
813     start.fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &start.fX);
814     stop.fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle),
815                              &stop.fX);
816 
817     /*  If the sweep angle is nearly (but less than) 360, then due to precision
818         loss in radians-conversion and/or sin/cos, we may end up with coincident
819         vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead
820         of drawing a nearly complete circle (good).
821              e.g. canvas.drawArc(0, 359.99, ...)
822              -vs- canvas.drawArc(0, 359.9, ...)
823         We try to detect this edge case, and tweak the stop vector
824      */
825     if (start == stop) {
826         SkScalar sw = SkScalarAbs(sweepAngle);
827         if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) {
828             SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle);
829             // make a guess at a tiny angle (in radians) to tweak by
830             SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle);
831             // not sure how much will be enough, so we use a loop
832             do {
833                 stopRad -= deltaRad;
834                 stop.fY = SkScalarSinCos(stopRad, &stop.fX);
835             } while (start == stop);
836         }
837     }
838 
839     SkMatrix    matrix;
840 
841     matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height()));
842     matrix.postTranslate(oval.centerX(), oval.centerY());
843 
844     return SkBuildQuadArc(start, stop,
845           sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection,
846                           &matrix, pts);
847 }
848 
arcTo(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool forceMoveTo)849 void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
850                    bool forceMoveTo) {
851     if (oval.width() < 0 || oval.height() < 0) {
852         return;
853     }
854 
855     SkPoint pts[kSkBuildQuadArcStorage];
856     int count = build_arc_points(oval, startAngle, sweepAngle, pts);
857     SkASSERT((count & 1) == 1);
858 
859     if (fVerbs.count() == 0) {
860         forceMoveTo = true;
861     }
862     this->incReserve(count);
863     forceMoveTo ? this->moveTo(pts[0]) : this->lineTo(pts[0]);
864     for (int i = 1; i < count; i += 2) {
865         this->quadTo(pts[i], pts[i+1]);
866     }
867 }
868 
addArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle)869 void SkPath::addArc(const SkRect& oval, SkScalar startAngle,
870                     SkScalar sweepAngle) {
871     if (oval.isEmpty() || 0 == sweepAngle) {
872         return;
873     }
874 
875     const SkScalar kFullCircleAngle = SkIntToScalar(360);
876 
877     if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
878         this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction);
879         return;
880     }
881 
882     SkPoint pts[kSkBuildQuadArcStorage];
883     int count = build_arc_points(oval, startAngle, sweepAngle, pts);
884 
885     this->incReserve(count);
886     this->moveTo(pts[0]);
887     for (int i = 1; i < count; i += 2) {
888         this->quadTo(pts[i], pts[i+1]);
889     }
890 }
891 
892 /*
893     Need to handle the case when the angle is sharp, and our computed end-points
894     for the arc go behind pt1 and/or p2...
895 */
arcTo(SkScalar x1,SkScalar y1,SkScalar x2,SkScalar y2,SkScalar radius)896 void SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
897                    SkScalar radius) {
898     SkVector    before, after;
899 
900     // need to know our prev pt so we can construct tangent vectors
901     {
902         SkPoint start;
903         this->getLastPt(&start);
904         // Handle degenerate cases by adding a line to the first point and
905         // bailing out.
906         if ((x1 == start.fX && y1 == start.fY) ||
907             (x1 == x2 && y1 == y2) ||
908             radius == 0) {
909             this->lineTo(x1, y1);
910             return;
911         }
912         before.setNormalize(x1 - start.fX, y1 - start.fY);
913         after.setNormalize(x2 - x1, y2 - y1);
914     }
915 
916     SkScalar cosh = SkPoint::DotProduct(before, after);
917     SkScalar sinh = SkPoint::CrossProduct(before, after);
918 
919     if (SkScalarNearlyZero(sinh)) {   // angle is too tight
920         this->lineTo(x1, y1);
921         return;
922     }
923 
924     SkScalar dist = SkScalarMulDiv(radius, SK_Scalar1 - cosh, sinh);
925     if (dist < 0) {
926         dist = -dist;
927     }
928 
929     SkScalar xx = x1 - SkScalarMul(dist, before.fX);
930     SkScalar yy = y1 - SkScalarMul(dist, before.fY);
931     SkRotationDirection arcDir;
932 
933     // now turn before/after into normals
934     if (sinh > 0) {
935         before.rotateCCW();
936         after.rotateCCW();
937         arcDir = kCW_SkRotationDirection;
938     } else {
939         before.rotateCW();
940         after.rotateCW();
941         arcDir = kCCW_SkRotationDirection;
942     }
943 
944     SkMatrix    matrix;
945     SkPoint     pts[kSkBuildQuadArcStorage];
946 
947     matrix.setScale(radius, radius);
948     matrix.postTranslate(xx - SkScalarMul(radius, before.fX),
949                          yy - SkScalarMul(radius, before.fY));
950 
951     int count = SkBuildQuadArc(before, after, arcDir, &matrix, pts);
952 
953     this->incReserve(count);
954     // [xx,yy] == pts[0]
955     this->lineTo(xx, yy);
956     for (int i = 1; i < count; i += 2) {
957         this->quadTo(pts[i], pts[i+1]);
958     }
959 }
960 
961 ///////////////////////////////////////////////////////////////////////////////
962 
addPath(const SkPath & path,SkScalar dx,SkScalar dy)963 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
964     SkMatrix matrix;
965 
966     matrix.setTranslate(dx, dy);
967     this->addPath(path, matrix);
968 }
969 
addPath(const SkPath & path,const SkMatrix & matrix)970 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
971     this->incReserve(path.fPts.count());
972 
973     RawIter iter(path);
974     SkPoint pts[4];
975     Verb    verb;
976 
977     SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
978 
979     while ((verb = iter.next(pts)) != kDone_Verb) {
980         switch (verb) {
981             case kMove_Verb:
982                 proc(matrix, &pts[0], &pts[0], 1);
983                 this->moveTo(pts[0]);
984                 break;
985             case kLine_Verb:
986                 proc(matrix, &pts[1], &pts[1], 1);
987                 this->lineTo(pts[1]);
988                 break;
989             case kQuad_Verb:
990                 proc(matrix, &pts[1], &pts[1], 2);
991                 this->quadTo(pts[1], pts[2]);
992                 break;
993             case kCubic_Verb:
994                 proc(matrix, &pts[1], &pts[1], 3);
995                 this->cubicTo(pts[1], pts[2], pts[3]);
996                 break;
997             case kClose_Verb:
998                 this->close();
999                 break;
1000             default:
1001                 SkDEBUGFAIL("unknown verb");
1002         }
1003     }
1004 }
1005 
1006 ///////////////////////////////////////////////////////////////////////////////
1007 
1008 static const uint8_t gPtsInVerb[] = {
1009     1,  // kMove
1010     1,  // kLine
1011     2,  // kQuad
1012     3,  // kCubic
1013     0,  // kClose
1014     0   // kDone
1015 };
1016 
1017 // ignore the initial moveto, and stop when the 1st contour ends
pathTo(const SkPath & path)1018 void SkPath::pathTo(const SkPath& path) {
1019     int i, vcount = path.fVerbs.count();
1020     if (vcount == 0) {
1021         return;
1022     }
1023 
1024     this->incReserve(vcount);
1025 
1026     const uint8_t*  verbs = path.fVerbs.begin();
1027     const SkPoint*  pts = path.fPts.begin() + 1;    // 1 for the initial moveTo
1028 
1029     SkASSERT(verbs[0] == kMove_Verb);
1030     for (i = 1; i < vcount; i++) {
1031         switch (verbs[i]) {
1032             case kLine_Verb:
1033                 this->lineTo(pts[0].fX, pts[0].fY);
1034                 break;
1035             case kQuad_Verb:
1036                 this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
1037                 break;
1038             case kCubic_Verb:
1039                 this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY,
1040                               pts[2].fX, pts[2].fY);
1041                 break;
1042             case kClose_Verb:
1043                 return;
1044         }
1045         pts += gPtsInVerb[verbs[i]];
1046     }
1047 }
1048 
1049 // ignore the last point of the 1st contour
reversePathTo(const SkPath & path)1050 void SkPath::reversePathTo(const SkPath& path) {
1051     int i, vcount = path.fVerbs.count();
1052     if (vcount == 0) {
1053         return;
1054     }
1055 
1056     this->incReserve(vcount);
1057 
1058     const uint8_t*  verbs = path.fVerbs.begin();
1059     const SkPoint*  pts = path.fPts.begin();
1060 
1061     SkASSERT(verbs[0] == kMove_Verb);
1062     for (i = 1; i < vcount; i++) {
1063         int n = gPtsInVerb[verbs[i]];
1064         if (n == 0) {
1065             break;
1066         }
1067         pts += n;
1068     }
1069 
1070     while (--i > 0) {
1071         switch (verbs[i]) {
1072             case kLine_Verb:
1073                 this->lineTo(pts[-1].fX, pts[-1].fY);
1074                 break;
1075             case kQuad_Verb:
1076                 this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
1077                 break;
1078             case kCubic_Verb:
1079                 this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY,
1080                               pts[-3].fX, pts[-3].fY);
1081                 break;
1082             default:
1083                 SkDEBUGFAIL("bad verb");
1084                 break;
1085         }
1086         pts -= gPtsInVerb[verbs[i]];
1087     }
1088 }
1089 
reverseAddPath(const SkPath & src)1090 void SkPath::reverseAddPath(const SkPath& src) {
1091     this->incReserve(src.fPts.count());
1092 
1093     const SkPoint* startPts = src.fPts.begin();
1094     const SkPoint* pts = src.fPts.end();
1095     const uint8_t* startVerbs = src.fVerbs.begin();
1096     const uint8_t* verbs = src.fVerbs.end();
1097 
1098     bool needMove = true;
1099     bool needClose = false;
1100     while (verbs > startVerbs) {
1101         uint8_t v = *--verbs;
1102         int n = gPtsInVerb[v];
1103 
1104         if (needMove) {
1105             --pts;
1106             this->moveTo(pts->fX, pts->fY);
1107             needMove = false;
1108         }
1109         pts -= n;
1110         switch (v) {
1111             case kMove_Verb:
1112                 if (needClose) {
1113                     this->close();
1114                     needClose = false;
1115                 }
1116                 needMove = true;
1117                 pts += 1;   // so we see the point in "if (needMove)" above
1118                 break;
1119             case kLine_Verb:
1120                 this->lineTo(pts[0]);
1121                 break;
1122             case kQuad_Verb:
1123                 this->quadTo(pts[1], pts[0]);
1124                 break;
1125             case kCubic_Verb:
1126                 this->cubicTo(pts[2], pts[1], pts[0]);
1127                 break;
1128             case kClose_Verb:
1129                 needClose = true;
1130                 break;
1131             default:
1132                 SkASSERT(!"unexpected verb");
1133         }
1134     }
1135 }
1136 
1137 ///////////////////////////////////////////////////////////////////////////////
1138 
offset(SkScalar dx,SkScalar dy,SkPath * dst) const1139 void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
1140     SkMatrix    matrix;
1141 
1142     matrix.setTranslate(dx, dy);
1143     this->transform(matrix, dst);
1144 }
1145 
1146 #include "SkGeometry.h"
1147 
subdivide_quad_to(SkPath * path,const SkPoint pts[3],int level=2)1148 static void subdivide_quad_to(SkPath* path, const SkPoint pts[3],
1149                               int level = 2) {
1150     if (--level >= 0) {
1151         SkPoint tmp[5];
1152 
1153         SkChopQuadAtHalf(pts, tmp);
1154         subdivide_quad_to(path, &tmp[0], level);
1155         subdivide_quad_to(path, &tmp[2], level);
1156     } else {
1157         path->quadTo(pts[1], pts[2]);
1158     }
1159 }
1160 
subdivide_cubic_to(SkPath * path,const SkPoint pts[4],int level=2)1161 static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
1162                                int level = 2) {
1163     if (--level >= 0) {
1164         SkPoint tmp[7];
1165 
1166         SkChopCubicAtHalf(pts, tmp);
1167         subdivide_cubic_to(path, &tmp[0], level);
1168         subdivide_cubic_to(path, &tmp[3], level);
1169     } else {
1170         path->cubicTo(pts[1], pts[2], pts[3]);
1171     }
1172 }
1173 
transform(const SkMatrix & matrix,SkPath * dst) const1174 void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
1175     SkDEBUGCODE(this->validate();)
1176     if (dst == NULL) {
1177         dst = (SkPath*)this;
1178     }
1179 
1180     if (matrix.hasPerspective()) {
1181         SkPath  tmp;
1182         tmp.fFillType = fFillType;
1183 
1184         SkPath::Iter    iter(*this, false);
1185         SkPoint         pts[4];
1186         SkPath::Verb    verb;
1187 
1188         while ((verb = iter.next(pts)) != kDone_Verb) {
1189             switch (verb) {
1190                 case kMove_Verb:
1191                     tmp.moveTo(pts[0]);
1192                     break;
1193                 case kLine_Verb:
1194                     tmp.lineTo(pts[1]);
1195                     break;
1196                 case kQuad_Verb:
1197                     subdivide_quad_to(&tmp, pts);
1198                     break;
1199                 case kCubic_Verb:
1200                     subdivide_cubic_to(&tmp, pts);
1201                     break;
1202                 case kClose_Verb:
1203                     tmp.close();
1204                     break;
1205                 default:
1206                     SkDEBUGFAIL("unknown verb");
1207                     break;
1208             }
1209         }
1210 
1211         dst->swap(tmp);
1212         matrix.mapPoints(dst->fPts.begin(), dst->fPts.count());
1213     } else {
1214         // remember that dst might == this, so be sure to check
1215         // fBoundsIsDirty before we set it
1216         if (!fBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) {
1217             // if we're empty, fastbounds should not be mapped
1218             matrix.mapRect(&dst->fBounds, fBounds);
1219             dst->fBoundsIsDirty = false;
1220         } else {
1221             GEN_ID_PTR_INC(dst);
1222             dst->fBoundsIsDirty = true;
1223         }
1224 
1225         if (this != dst) {
1226             dst->fVerbs = fVerbs;
1227             dst->fPts.setCount(fPts.count());
1228             dst->fFillType = fFillType;
1229             dst->fSegmentMask = fSegmentMask;
1230             dst->fConvexity = fConvexity;
1231         }
1232         matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
1233         SkDEBUGCODE(dst->validate();)
1234     }
1235 }
1236 
1237 ///////////////////////////////////////////////////////////////////////////////
1238 ///////////////////////////////////////////////////////////////////////////////
1239 
1240 enum SegmentState {
1241     kEmptyContour_SegmentState,   // The current contour is empty. We may be
1242                                   // starting processing or we may have just
1243                                   // closed a contour.
1244     kAfterMove_SegmentState,      // We have seen a move, but nothing else.
1245     kAfterPrimitive_SegmentState  // We have seen a primitive but not yet
1246                                   // closed the path. Also the initial state.
1247 };
1248 
Iter()1249 SkPath::Iter::Iter() {
1250 #ifdef SK_DEBUG
1251     fPts = NULL;
1252     fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1253     fForceClose = fCloseLine = false;
1254     fSegmentState = kEmptyContour_SegmentState;
1255 #endif
1256     // need to init enough to make next() harmlessly return kDone_Verb
1257     fVerbs = NULL;
1258     fVerbStop = NULL;
1259     fNeedClose = false;
1260 }
1261 
Iter(const SkPath & path,bool forceClose)1262 SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
1263     this->setPath(path, forceClose);
1264 }
1265 
setPath(const SkPath & path,bool forceClose)1266 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
1267     fPts = path.fPts.begin();
1268     fVerbs = path.fVerbs.begin();
1269     fVerbStop = path.fVerbs.end();
1270     fLastPt.fX = fLastPt.fY = 0;
1271     fMoveTo.fX = fMoveTo.fY = 0;
1272     fForceClose = SkToU8(forceClose);
1273     fNeedClose = false;
1274     fSegmentState = kEmptyContour_SegmentState;
1275 }
1276 
isClosedContour() const1277 bool SkPath::Iter::isClosedContour() const {
1278     if (fVerbs == NULL || fVerbs == fVerbStop) {
1279         return false;
1280     }
1281     if (fForceClose) {
1282         return true;
1283     }
1284 
1285     const uint8_t* verbs = fVerbs;
1286     const uint8_t* stop = fVerbStop;
1287 
1288     if (kMove_Verb == *verbs) {
1289         verbs += 1; // skip the initial moveto
1290     }
1291 
1292     while (verbs < stop) {
1293         unsigned v = *verbs++;
1294         if (kMove_Verb == v) {
1295             break;
1296         }
1297         if (kClose_Verb == v) {
1298             return true;
1299         }
1300     }
1301     return false;
1302 }
1303 
autoClose(SkPoint pts[2])1304 SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
1305     if (fLastPt != fMoveTo) {
1306         // A special case: if both points are NaN, SkPoint::operation== returns
1307         // false, but the iterator expects that they are treated as the same.
1308         // (consider SkPoint is a 2-dimension float point).
1309         if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
1310             SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
1311             return kClose_Verb;
1312         }
1313 
1314         if (pts) {
1315             pts[0] = fLastPt;
1316             pts[1] = fMoveTo;
1317         }
1318         fLastPt = fMoveTo;
1319         fCloseLine = true;
1320         return kLine_Verb;
1321     } else {
1322         pts[0] = fMoveTo;
1323         return kClose_Verb;
1324     }
1325 }
1326 
cons_moveTo(SkPoint pts[1])1327 bool SkPath::Iter::cons_moveTo(SkPoint pts[1]) {
1328     if (fSegmentState == kAfterMove_SegmentState) {
1329         // Set the first return pt to the move pt
1330         if (pts) {
1331             *pts = fMoveTo;
1332         }
1333         fSegmentState = kAfterPrimitive_SegmentState;
1334     } else {
1335         SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
1336          // Set the first return pt to the last pt of the previous primitive.
1337         if (pts) {
1338             *pts = fPts[-1];
1339         }
1340     }
1341     return false;
1342 }
1343 
consumeDegenerateSegments()1344 void SkPath::Iter::consumeDegenerateSegments() {
1345     // We need to step over anything that will not move the current draw point
1346     // forward before the next move is seen
1347     const uint8_t* lastMoveVerb = 0;
1348     const SkPoint* lastMovePt = 0;
1349     SkPoint lastPt = fLastPt;
1350     while (fVerbs != fVerbStop) {
1351         unsigned verb = *fVerbs;
1352         switch (verb) {
1353             case kMove_Verb:
1354                 // Keep a record of this most recent move
1355                 lastMoveVerb = fVerbs;
1356                 lastMovePt = fPts;
1357                 lastPt = fPts[0];
1358                 fVerbs++;
1359                 fPts++;
1360                 break;
1361 
1362             case kClose_Verb:
1363                 // A close when we are in a segment is always valid
1364                 if (fSegmentState == kAfterPrimitive_SegmentState) {
1365                     return;
1366                 }
1367                 // A close at any other time must be ignored
1368                 fVerbs++;
1369                 break;
1370 
1371             case kLine_Verb:
1372                 if (!IsLineDegenerate(lastPt, fPts[0])) {
1373                     if (lastMoveVerb) {
1374                         fVerbs = lastMoveVerb;
1375                         fPts = lastMovePt;
1376                         return;
1377                     }
1378                     return;
1379                 }
1380                 // Ignore this line and continue
1381                 fVerbs++;
1382                 fPts++;
1383                 break;
1384 
1385             case kQuad_Verb:
1386                 if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
1387                     if (lastMoveVerb) {
1388                         fVerbs = lastMoveVerb;
1389                         fPts = lastMovePt;
1390                         return;
1391                     }
1392                     return;
1393                 }
1394                 // Ignore this line and continue
1395                 fVerbs++;
1396                 fPts += 2;
1397                 break;
1398 
1399             case kCubic_Verb:
1400                 if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) {
1401                     if (lastMoveVerb) {
1402                         fVerbs = lastMoveVerb;
1403                         fPts = lastMovePt;
1404                         return;
1405                     }
1406                     return;
1407                 }
1408                 // Ignore this line and continue
1409                 fVerbs++;
1410                 fPts += 3;
1411                 break;
1412 
1413             default:
1414                 SkDEBUGFAIL("Should never see kDone_Verb");
1415         }
1416     }
1417 }
1418 
next(SkPoint pts[4])1419 SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
1420     this->consumeDegenerateSegments();
1421 
1422     if (fVerbs == fVerbStop) {
1423         // Close the curve if requested and if there is some curve to close
1424         if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
1425             if (kLine_Verb == this->autoClose(pts)) {
1426                 return kLine_Verb;
1427             }
1428             fNeedClose = false;
1429             return kClose_Verb;
1430         }
1431         return kDone_Verb;
1432     }
1433 
1434     unsigned        verb = *fVerbs++;
1435     const SkPoint*  srcPts = fPts;
1436 
1437     switch (verb) {
1438         case kMove_Verb:
1439             if (fNeedClose) {
1440                 fVerbs -= 1;
1441                 verb = this->autoClose(pts);
1442                 if (verb == kClose_Verb) {
1443                     fNeedClose = false;
1444                 }
1445                 return (Verb)verb;
1446             }
1447             if (fVerbs == fVerbStop) {    // might be a trailing moveto
1448                 return kDone_Verb;
1449             }
1450             fMoveTo = *srcPts;
1451             if (pts) {
1452                 pts[0] = *srcPts;
1453             }
1454             srcPts += 1;
1455             fSegmentState = kAfterMove_SegmentState;
1456             fLastPt = fMoveTo;
1457             fNeedClose = fForceClose;
1458             break;
1459         case kLine_Verb:
1460             if (this->cons_moveTo(pts)) {
1461                 return kMove_Verb;
1462             }
1463             if (pts) {
1464                 pts[1] = srcPts[0];
1465             }
1466             fLastPt = srcPts[0];
1467             fCloseLine = false;
1468             srcPts += 1;
1469             break;
1470         case kQuad_Verb:
1471             if (this->cons_moveTo(pts)) {
1472                 return kMove_Verb;
1473             }
1474             if (pts) {
1475                 memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
1476             }
1477             fLastPt = srcPts[1];
1478             srcPts += 2;
1479             break;
1480         case kCubic_Verb:
1481             if (this->cons_moveTo(pts)) {
1482                 return kMove_Verb;
1483             }
1484             if (pts) {
1485                 memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
1486             }
1487             fLastPt = srcPts[2];
1488             srcPts += 3;
1489             break;
1490         case kClose_Verb:
1491             verb = this->autoClose(pts);
1492             if (verb == kLine_Verb) {
1493                 fVerbs -= 1;
1494             } else {
1495                 fNeedClose = false;
1496                 fSegmentState = kEmptyContour_SegmentState;
1497             }
1498             fLastPt = fMoveTo;
1499             break;
1500     }
1501     fPts = srcPts;
1502     return (Verb)verb;
1503 }
1504 
1505 ///////////////////////////////////////////////////////////////////////////////
1506 
RawIter()1507 SkPath::RawIter::RawIter() {
1508 #ifdef SK_DEBUG
1509     fPts = NULL;
1510     fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
1511 #endif
1512     // need to init enough to make next() harmlessly return kDone_Verb
1513     fVerbs = NULL;
1514     fVerbStop = NULL;
1515 }
1516 
RawIter(const SkPath & path)1517 SkPath::RawIter::RawIter(const SkPath& path) {
1518     this->setPath(path);
1519 }
1520 
setPath(const SkPath & path)1521 void SkPath::RawIter::setPath(const SkPath& path) {
1522     fPts = path.fPts.begin();
1523     fVerbs = path.fVerbs.begin();
1524     fVerbStop = path.fVerbs.end();
1525     fMoveTo.fX = fMoveTo.fY = 0;
1526     fLastPt.fX = fLastPt.fY = 0;
1527 }
1528 
next(SkPoint pts[4])1529 SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
1530     if (fVerbs == fVerbStop) {
1531         return kDone_Verb;
1532     }
1533 
1534     unsigned        verb = *fVerbs++;
1535     const SkPoint*  srcPts = fPts;
1536 
1537     switch (verb) {
1538         case kMove_Verb:
1539             if (pts) {
1540                 pts[0] = *srcPts;
1541             }
1542             fMoveTo = srcPts[0];
1543             fLastPt = fMoveTo;
1544             srcPts += 1;
1545             break;
1546         case kLine_Verb:
1547             if (pts) {
1548                 pts[0] = fLastPt;
1549                 pts[1] = srcPts[0];
1550             }
1551             fLastPt = srcPts[0];
1552             srcPts += 1;
1553             break;
1554         case kQuad_Verb:
1555             if (pts) {
1556                 pts[0] = fLastPt;
1557                 memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
1558             }
1559             fLastPt = srcPts[1];
1560             srcPts += 2;
1561             break;
1562         case kCubic_Verb:
1563             if (pts) {
1564                 pts[0] = fLastPt;
1565                 memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
1566             }
1567             fLastPt = srcPts[2];
1568             srcPts += 3;
1569             break;
1570         case kClose_Verb:
1571             fLastPt = fMoveTo;
1572             if (pts) {
1573                 pts[0] = fMoveTo;
1574             }
1575             break;
1576     }
1577     fPts = srcPts;
1578     return (Verb)verb;
1579 }
1580 
1581 ///////////////////////////////////////////////////////////////////////////////
1582 
1583 /*
1584     Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]]
1585 */
1586 
flatten(SkWriter32 & buffer) const1587 void SkPath::flatten(SkWriter32& buffer) const {
1588     SkDEBUGCODE(this->validate();)
1589 
1590     buffer.write32(fPts.count());
1591     buffer.write32(fVerbs.count());
1592     buffer.write32((fFillType << 8) | fSegmentMask);
1593     buffer.writeMul4(fPts.begin(), sizeof(SkPoint) * fPts.count());
1594     buffer.writePad(fVerbs.begin(), fVerbs.count());
1595 }
1596 
unflatten(SkReader32 & buffer)1597 void SkPath::unflatten(SkReader32& buffer) {
1598     fPts.setCount(buffer.readS32());
1599     fVerbs.setCount(buffer.readS32());
1600     uint32_t packed = buffer.readS32();
1601     fFillType = packed >> 8;
1602     fSegmentMask = packed & 0xFF;
1603     buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
1604     buffer.read(fVerbs.begin(), fVerbs.count());
1605 
1606     GEN_ID_INC;
1607     DIRTY_AFTER_EDIT;
1608 
1609     SkDEBUGCODE(this->validate();)
1610 }
1611 
1612 ///////////////////////////////////////////////////////////////////////////////
1613 
dump(bool forceClose,const char title[]) const1614 void SkPath::dump(bool forceClose, const char title[]) const {
1615     Iter    iter(*this, forceClose);
1616     SkPoint pts[4];
1617     Verb    verb;
1618 
1619     SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false",
1620              title ? title : "");
1621 
1622     while ((verb = iter.next(pts)) != kDone_Verb) {
1623         switch (verb) {
1624             case kMove_Verb:
1625 #ifdef SK_CAN_USE_FLOAT
1626                 SkDebugf("  path: moveTo [%g %g]\n",
1627                         SkScalarToFloat(pts[0].fX), SkScalarToFloat(pts[0].fY));
1628 #else
1629                 SkDebugf("  path: moveTo [%x %x]\n", pts[0].fX, pts[0].fY);
1630 #endif
1631                 break;
1632             case kLine_Verb:
1633 #ifdef SK_CAN_USE_FLOAT
1634                 SkDebugf("  path: lineTo [%g %g]\n",
1635                         SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY));
1636 #else
1637                 SkDebugf("  path: lineTo [%x %x]\n", pts[1].fX, pts[1].fY);
1638 #endif
1639                 break;
1640             case kQuad_Verb:
1641 #ifdef SK_CAN_USE_FLOAT
1642                 SkDebugf("  path: quadTo [%g %g] [%g %g]\n",
1643                         SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
1644                         SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY));
1645 #else
1646                 SkDebugf("  path: quadTo [%x %x] [%x %x]\n",
1647                          pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
1648 #endif
1649                 break;
1650             case kCubic_Verb:
1651 #ifdef SK_CAN_USE_FLOAT
1652                 SkDebugf("  path: cubeTo [%g %g] [%g %g] [%g %g]\n",
1653                         SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
1654                         SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY),
1655                         SkScalarToFloat(pts[3].fX), SkScalarToFloat(pts[3].fY));
1656 #else
1657                 SkDebugf("  path: cubeTo [%x %x] [%x %x] [%x %x]\n",
1658                          pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
1659                          pts[3].fX, pts[3].fY);
1660 #endif
1661                 break;
1662             case kClose_Verb:
1663                 SkDebugf("  path: close\n");
1664                 break;
1665             default:
1666                 SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
1667                 verb = kDone_Verb;  // stop the loop
1668                 break;
1669         }
1670     }
1671     SkDebugf("path: done %s\n", title ? title : "");
1672 }
1673 
dump() const1674 void SkPath::dump() const {
1675     this->dump(false);
1676 }
1677 
1678 #ifdef SK_DEBUG
validate() const1679 void SkPath::validate() const {
1680     SkASSERT(this != NULL);
1681     SkASSERT((fFillType & ~3) == 0);
1682     fPts.validate();
1683     fVerbs.validate();
1684 
1685     if (!fBoundsIsDirty) {
1686         SkRect bounds;
1687         compute_pt_bounds(&bounds, fPts);
1688         if (fPts.count() <= 1) {
1689             // if we're empty, fBounds may be empty but translated, so we can't
1690             // necessarily compare to bounds directly
1691             // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
1692             // be [2, 2, 2, 2]
1693             SkASSERT(bounds.isEmpty());
1694             SkASSERT(fBounds.isEmpty());
1695         } else {
1696             if (bounds.isEmpty()) {
1697                 SkASSERT(fBounds.isEmpty());
1698             } else {
1699                 if (!fBounds.isEmpty()) {
1700                     SkASSERT(fBounds.contains(bounds));
1701                 }
1702             }
1703         }
1704     }
1705 
1706     uint32_t mask = 0;
1707     for (int i = 0; i < fVerbs.count(); i++) {
1708         switch (fVerbs[i]) {
1709             case kLine_Verb:
1710                 mask |= kLine_SegmentMask;
1711                 break;
1712             case kQuad_Verb:
1713                 mask |= kQuad_SegmentMask;
1714                 break;
1715             case kCubic_Verb:
1716                 mask |= kCubic_SegmentMask;
1717         }
1718     }
1719     SkASSERT(mask == fSegmentMask);
1720 }
1721 #endif
1722 
1723 ///////////////////////////////////////////////////////////////////////////////
1724 
sign(SkScalar x)1725 static int sign(SkScalar x) { return x < 0; }
1726 #define kValueNeverReturnedBySign   2
1727 
CrossProductSign(const SkVector & a,const SkVector & b)1728 static int CrossProductSign(const SkVector& a, const SkVector& b) {
1729     return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
1730 }
1731 
1732 // only valid for a single contour
1733 struct Convexicator {
ConvexicatorConvexicator1734     Convexicator() : fPtCount(0), fConvexity(SkPath::kConvex_Convexity) {
1735         fSign = 0;
1736         // warnings
1737         fCurrPt.set(0, 0);
1738         fVec0.set(0, 0);
1739         fVec1.set(0, 0);
1740         fFirstVec.set(0, 0);
1741 
1742         fDx = fDy = 0;
1743         fSx = fSy = kValueNeverReturnedBySign;
1744     }
1745 
getConvexityConvexicator1746     SkPath::Convexity getConvexity() const { return fConvexity; }
1747 
addPtConvexicator1748     void addPt(const SkPoint& pt) {
1749         if (SkPath::kConcave_Convexity == fConvexity) {
1750             return;
1751         }
1752 
1753         if (0 == fPtCount) {
1754             fCurrPt = pt;
1755             ++fPtCount;
1756         } else {
1757             SkVector vec = pt - fCurrPt;
1758             if (vec.fX || vec.fY) {
1759                 fCurrPt = pt;
1760                 if (++fPtCount == 2) {
1761                     fFirstVec = fVec1 = vec;
1762                 } else {
1763                     SkASSERT(fPtCount > 2);
1764                     this->addVec(vec);
1765                 }
1766 
1767                 int sx = sign(vec.fX);
1768                 int sy = sign(vec.fY);
1769                 fDx += (sx != fSx);
1770                 fDy += (sy != fSy);
1771                 fSx = sx;
1772                 fSy = sy;
1773 
1774                 if (fDx > 3 || fDy > 3) {
1775                     fConvexity = SkPath::kConcave_Convexity;
1776                 }
1777             }
1778         }
1779     }
1780 
closeConvexicator1781     void close() {
1782         if (fPtCount > 2) {
1783             this->addVec(fFirstVec);
1784         }
1785     }
1786 
1787 private:
addVecConvexicator1788     void addVec(const SkVector& vec) {
1789         SkASSERT(vec.fX || vec.fY);
1790         fVec0 = fVec1;
1791         fVec1 = vec;
1792         int sign = CrossProductSign(fVec0, fVec1);
1793         if (0 == fSign) {
1794             fSign = sign;
1795         } else if (sign) {
1796             if (fSign != sign) {
1797                 fConvexity = SkPath::kConcave_Convexity;
1798             }
1799         }
1800     }
1801 
1802     SkPoint             fCurrPt;
1803     SkVector            fVec0, fVec1, fFirstVec;
1804     int                 fPtCount;   // non-degenerate points
1805     int                 fSign;
1806     SkPath::Convexity   fConvexity;
1807     int                 fDx, fDy, fSx, fSy;
1808 };
1809 
ComputeConvexity(const SkPath & path)1810 SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) {
1811     SkPoint         pts[4];
1812     SkPath::Verb    verb;
1813     SkPath::Iter    iter(path, true);
1814 
1815     int             contourCount = 0;
1816     int             count;
1817     Convexicator    state;
1818 
1819     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
1820         switch (verb) {
1821             case kMove_Verb:
1822                 if (++contourCount > 1) {
1823                     return kConcave_Convexity;
1824                 }
1825                 pts[1] = pts[0];
1826                 count = 1;
1827                 break;
1828             case kLine_Verb: count = 1; break;
1829             case kQuad_Verb: count = 2; break;
1830             case kCubic_Verb: count = 3; break;
1831             case kClose_Verb:
1832                 state.close();
1833                 count = 0;
1834                 break;
1835             default:
1836                 SkDEBUGFAIL("bad verb");
1837                 return kConcave_Convexity;
1838         }
1839 
1840         for (int i = 1; i <= count; i++) {
1841             state.addPt(pts[i]);
1842         }
1843         // early exit
1844         if (kConcave_Convexity == state.getConvexity()) {
1845             return kConcave_Convexity;
1846         }
1847     }
1848     return state.getConvexity();
1849 }
1850 
1851 ///////////////////////////////////////////////////////////////////////////////
1852 
1853 class ContourIter {
1854 public:
1855     ContourIter(const SkTDArray<uint8_t>& verbs, const SkTDArray<SkPoint>& pts);
1856 
done() const1857     bool done() const { return fDone; }
1858     // if !done() then these may be called
count() const1859     int count() const { return fCurrPtCount; }
pts() const1860     const SkPoint* pts() const { return fCurrPt; }
1861     void next();
1862 
1863 private:
1864     int fCurrPtCount;
1865     const SkPoint* fCurrPt;
1866     const uint8_t* fCurrVerb;
1867     const uint8_t* fStopVerbs;
1868     bool fDone;
1869     SkDEBUGCODE(int fContourCounter;)
1870 };
1871 
ContourIter(const SkTDArray<uint8_t> & verbs,const SkTDArray<SkPoint> & pts)1872 ContourIter::ContourIter(const SkTDArray<uint8_t>& verbs,
1873                          const SkTDArray<SkPoint>& pts) {
1874     fStopVerbs = verbs.begin() + verbs.count();
1875 
1876     fDone = false;
1877     fCurrPt = pts.begin();
1878     fCurrVerb = verbs.begin();
1879     fCurrPtCount = 0;
1880     SkDEBUGCODE(fContourCounter = 0;)
1881     this->next();
1882 }
1883 
next()1884 void ContourIter::next() {
1885     if (fCurrVerb >= fStopVerbs) {
1886         fDone = true;
1887     }
1888     if (fDone) {
1889         return;
1890     }
1891 
1892     // skip pts of prev contour
1893     fCurrPt += fCurrPtCount;
1894 
1895     SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
1896     int ptCount = 1;    // moveTo
1897     const uint8_t* verbs = fCurrVerb;
1898 
1899     for (++verbs; verbs < fStopVerbs; ++verbs) {
1900         switch (*verbs) {
1901             case SkPath::kMove_Verb:
1902                 goto CONTOUR_END;
1903             case SkPath::kLine_Verb:
1904                 ptCount += 1;
1905                 break;
1906             case SkPath::kQuad_Verb:
1907                 ptCount += 2;
1908                 break;
1909             case SkPath::kCubic_Verb:
1910                 ptCount += 3;
1911                 break;
1912             default:    // kClose_Verb, just keep going
1913                 break;
1914         }
1915     }
1916 CONTOUR_END:
1917     fCurrPtCount = ptCount;
1918     fCurrVerb = verbs;
1919     SkDEBUGCODE(++fContourCounter;)
1920 }
1921 
1922 // returns cross product of (p1 - p0) and (p2 - p0)
cross_prod(const SkPoint & p0,const SkPoint & p1,const SkPoint & p2)1923 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
1924     SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
1925     // We may get 0 when the above subtracts underflow. We expect this to be
1926     // very rare and lazily promote to double.
1927     if (0 == cross) {
1928         double p0x = SkScalarToDouble(p0.fX);
1929         double p0y = SkScalarToDouble(p0.fY);
1930 
1931         double p1x = SkScalarToDouble(p1.fX);
1932         double p1y = SkScalarToDouble(p1.fY);
1933 
1934         double p2x = SkScalarToDouble(p2.fX);
1935         double p2y = SkScalarToDouble(p2.fY);
1936 
1937         cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
1938                                  (p1y - p0y) * (p2x - p0x));
1939 
1940     }
1941     return cross;
1942 }
1943 
1944 // Returns the first pt with the maximum Y coordinate
find_max_y(const SkPoint pts[],int count)1945 static int find_max_y(const SkPoint pts[], int count) {
1946     SkASSERT(count > 0);
1947     SkScalar max = pts[0].fY;
1948     int firstIndex = 0;
1949     for (int i = 1; i < count; ++i) {
1950         SkScalar y = pts[i].fY;
1951         if (y > max) {
1952             max = y;
1953             firstIndex = i;
1954         }
1955     }
1956     return firstIndex;
1957 }
1958 
find_diff_pt(const SkPoint pts[],int index,int n,int inc)1959 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
1960     int i = index;
1961     for (;;) {
1962         i = (i + inc) % n;
1963         if (i == index) {   // we wrapped around, so abort
1964             break;
1965         }
1966         if (pts[index] != pts[i]) { // found a different point, success!
1967             break;
1968         }
1969     }
1970     return i;
1971 }
1972 
1973 /**
1974  *  Starting at index, and moving forward (incrementing), find the xmin and
1975  *  xmax of the contiguous points that have the same Y.
1976  */
find_min_max_x_at_y(const SkPoint pts[],int index,int n,int * maxIndexPtr)1977 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
1978                                int* maxIndexPtr) {
1979     const SkScalar y = pts[index].fY;
1980     SkScalar min = pts[index].fX;
1981     SkScalar max = min;
1982     int minIndex = index;
1983     int maxIndex = index;
1984     for (int i = index + 1; i < n; ++i) {
1985         if (pts[i].fY != y) {
1986             break;
1987         }
1988         SkScalar x = pts[i].fX;
1989         if (x < min) {
1990             min = x;
1991             minIndex = i;
1992         } else if (x > max) {
1993             max = x;
1994             maxIndex = i;
1995         }
1996     }
1997     *maxIndexPtr = maxIndex;
1998     return minIndex;
1999 }
2000 
crossToDir(SkScalar cross,SkPath::Direction * dir)2001 static bool crossToDir(SkScalar cross, SkPath::Direction* dir) {
2002     if (dir) {
2003         *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2004     }
2005     return true;
2006 }
2007 
2008 #if 0
2009 #include "SkString.h"
2010 #include "../utils/SkParsePath.h"
2011 static void dumpPath(const SkPath& path) {
2012     SkString str;
2013     SkParsePath::ToSVGString(path, &str);
2014     SkDebugf("%s\n", str.c_str());
2015 }
2016 #endif
2017 
2018 /*
2019  *  We loop through all contours, and keep the computed cross-product of the
2020  *  contour that contained the global y-max. If we just look at the first
2021  *  contour, we may find one that is wound the opposite way (correctly) since
2022  *  it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2023  *  that is outer most (or at least has the global y-max) before we can consider
2024  *  its cross product.
2025  */
cheapComputeDirection(Direction * dir) const2026 bool SkPath::cheapComputeDirection(Direction* dir) const {
2027 //    dumpPath(*this);
2028     // don't want to pay the cost for computing this if it
2029     // is unknown, so we don't call isConvex()
2030     const Convexity conv = this->getConvexityOrUnknown();
2031 
2032     ContourIter iter(fVerbs, fPts);
2033 
2034     // initialize with our logical y-min
2035     SkScalar ymax = this->getBounds().fTop;
2036     SkScalar ymaxCross = 0;
2037 
2038     for (; !iter.done(); iter.next()) {
2039         int n = iter.count();
2040         if (n < 3) {
2041             continue;
2042         }
2043 
2044         const SkPoint* pts = iter.pts();
2045         SkScalar cross = 0;
2046         if (kConvex_Convexity == conv) {
2047             // we loop, skipping over degenerate or flat segments that will
2048             // return 0 for the cross-product
2049             for (int i = 0; i < n - 2; ++i) {
2050                 cross = cross_prod(pts[i], pts[i + 1], pts[i + 2]);
2051                 if (cross) {
2052                     // early-exit, as kConvex is assumed to have only 1
2053                     // non-degenerate contour
2054                     return crossToDir(cross, dir);
2055                 }
2056             }
2057         } else {
2058             int index = find_max_y(pts, n);
2059             if (pts[index].fY < ymax) {
2060                 continue;
2061             }
2062 
2063             // If there is more than 1 distinct point at the y-max, we take the
2064             // x-min and x-max of them and just subtract to compute the dir.
2065             if (pts[(index + 1) % n].fY == pts[index].fY) {
2066                 int maxIndex;
2067                 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2068                 if (minIndex == maxIndex) {
2069                     goto TRY_CROSSPROD;
2070                 }
2071                 SkASSERT(pts[minIndex].fY == pts[index].fY);
2072                 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2073                 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2074                 // we just subtract the indices, and let that auto-convert to
2075                 // SkScalar, since we just want - or + to signal the direction.
2076                 cross = minIndex - maxIndex;
2077             } else {
2078                 TRY_CROSSPROD:
2079                 // Find a next and prev index to use for the cross-product test,
2080                 // but we try to find pts that form non-zero vectors from pts[index]
2081                 //
2082                 // Its possible that we can't find two non-degenerate vectors, so
2083                 // we have to guard our search (e.g. all the pts could be in the
2084                 // same place).
2085 
2086                 // we pass n - 1 instead of -1 so we don't foul up % operator by
2087                 // passing it a negative LH argument.
2088                 int prev = find_diff_pt(pts, index, n, n - 1);
2089                 if (prev == index) {
2090                     // completely degenerate, skip to next contour
2091                     continue;
2092                 }
2093                 int next = find_diff_pt(pts, index, n, 1);
2094                 SkASSERT(next != index);
2095                 cross = cross_prod(pts[prev], pts[index], pts[next]);
2096                 // if we get a zero, but the pts aren't on top of each other, then
2097                 // we can just look at the direction
2098                 if (0 == cross) {
2099                     // construct the subtract so we get the correct Direction below
2100                     cross = pts[index].fX - pts[next].fX;
2101                 }
2102             }
2103 
2104             if (cross) {
2105                 // record our best guess so far
2106                 ymax = pts[index].fY;
2107                 ymaxCross = cross;
2108             }
2109         }
2110     }
2111 
2112     return ymaxCross ? crossToDir(ymaxCross, dir) : false;
2113 }
2114