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