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