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