Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(584)

Side by Side Diff: src/core/SkPath.cpp

Issue 25787002: Move more of SkPath into SkPathRef (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: cleaned up Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « include/core/SkPathRef.h ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkBuffer.h" 10 #include "SkBuffer.h"
11 #include "SkErrorInternals.h" 11 #include "SkErrorInternals.h"
12 #include "SkMath.h" 12 #include "SkMath.h"
13 #include "SkPath.h" 13 #include "SkPath.h"
14 #include "SkPathRef.h" 14 #include "SkPathRef.h"
15 #include "SkRRect.h" 15 #include "SkRRect.h"
16 #include "SkThread.h" 16 #include "SkThread.h"
17 17
18 SK_DEFINE_INST_COUNT(SkPath); 18 SK_DEFINE_INST_COUNT(SkPath);
19 19
20 // This value is just made-up for now. When count is 4, calling memset was much
21 // slower than just writing the loop. This seems odd, and hopefully in the
22 // future this we appear to have been a fluke...
23 #define MIN_COUNT_FOR_MEMSET_TO_BE_FAST 16
24
25 //////////////////////////////////////////////////////////////////////////// 20 ////////////////////////////////////////////////////////////////////////////
26 21
27 /** 22 /**
28 * Path.bounds is defined to be the bounds of all the control points. 23 * 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 24 * 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 25 * our promise. Hence we have a custom joiner that doesn't look at emptiness
31 */ 26 */
32 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { 27 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
33 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); 28 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
34 dst->fTop = SkMinScalar(dst->fTop, src.fTop); 29 dst->fTop = SkMinScalar(dst->fTop, src.fTop);
35 dst->fRight = SkMaxScalar(dst->fRight, src.fRight); 30 dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
36 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); 31 dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
37 } 32 }
38 33
39 static bool is_degenerate(const SkPath& path) { 34 static bool is_degenerate(const SkPath& path) {
40 SkPath::Iter iter(path, false); 35 SkPath::Iter iter(path, false);
41 SkPoint pts[4]; 36 SkPoint pts[4];
42 return SkPath::kDone_Verb == iter.next(pts); 37 return SkPath::kDone_Verb == iter.next(pts);
43 } 38 }
44 39
45 class SkAutoDisableOvalCheck {
46 public:
47 SkAutoDisableOvalCheck(SkPath* path) : fPath(path) {
48 fSaved = fPath->fIsOval;
49 }
50
51 ~SkAutoDisableOvalCheck() {
52 fPath->fIsOval = fSaved;
53 }
54
55 private:
56 SkPath* fPath;
57 bool fSaved;
58 };
59
60 class SkAutoDisableDirectionCheck {
61 public:
62 SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) {
63 fSaved = static_cast<SkPath::Direction>(fPath->fDirection);
64 }
65
66 ~SkAutoDisableDirectionCheck() {
67 fPath->fDirection = fSaved;
68 }
69
70 private:
71 SkPath* fPath;
72 SkPath::Direction fSaved;
73 };
74
75 /* This guy's constructor/destructor bracket a path editing operation. It is 40 /* This guy's constructor/destructor bracket a path editing operation. It is
76 used when we know the bounds of the amount we are going to add to the path 41 used when we know the bounds of the amount we are going to add to the path
77 (usually a new contour, but not required). 42 (usually a new contour, but not required).
78 43
79 It captures some state about the path up front (i.e. if it already has a 44 It captures some state about the path up front (i.e. if it already has a
80 cached bounds), and then if it can, it updates the cache bounds explicitly, 45 cached bounds), and then if it can, it updates the cache bounds explicitly,
81 avoiding the need to revisit all of the points in getBounds(). 46 avoiding the need to revisit all of the points in getBounds().
82 47
83 It also notes if the path was originally degenerate, and if so, sets 48 It also notes if the path was originally degenerate, and if so, sets
84 isConvex to true. Thus it can only be used if the contour being added is 49 isConvex to true. Thus it can only be used if the contour being added is
85 convex (which is always true since we only allow the addition of rects). 50 convex.
86 */ 51 */
87 class SkAutoPathBoundsUpdate { 52 class SkAutoPathBoundsUpdate {
88 public: 53 public:
89 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { 54 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) {
90 this->init(path); 55 this->init(path);
91 } 56 }
92 57
93 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, 58 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top,
94 SkScalar right, SkScalar bottom) { 59 SkScalar right, SkScalar bottom) {
95 fRect.set(left, top, right, bottom); 60 fRect.set(left, top, right, bottom);
96 this->init(path); 61 this->init(path);
97 } 62 }
98 63
99 ~SkAutoPathBoundsUpdate() { 64 ~SkAutoPathBoundsUpdate() {
100 fPath->setIsConvex(fDegenerate); 65 SkPathRef::Editor ed(&fPath->fPathRef);
66
67 ed.setConvexity(fDegenerate ? SkPath::kConvex_Convexity
68 : SkPath::kConcave_Convexity);
101 if (fEmpty || fHasValidBounds) { 69 if (fEmpty || fHasValidBounds) {
102 fPath->setBounds(fRect); 70 ed.setBounds(fRect);
103 } 71 }
104 } 72 }
105 73
106 private: 74 private:
107 SkPath* fPath; 75 SkPath* fPath;
108 SkRect fRect; 76 SkRect fRect;
109 bool fHasValidBounds; 77 bool fHasValidBounds;
110 bool fDegenerate; 78 bool fDegenerate;
111 bool fEmpty; 79 bool fEmpty;
112 80
(...skipping 20 matching lines...) Expand all
133 - we insert a Move(0,0) if Line | Quad | Cubic is our first command 101 - we insert a Move(0,0) if Line | Quad | Cubic is our first command
134 102
135 The iterator does more cleanup, especially if forceClose == true 103 The iterator does more cleanup, especially if forceClose == true
136 1. If we encounter degenerate segments, remove them 104 1. If we encounter degenerate segments, remove them
137 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt) 105 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
138 3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2 106 3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
139 4. if we encounter Line | Quad | Cubic after Close, cons up a Move 107 4. if we encounter Line | Quad | Cubic after Close, cons up a Move
140 */ 108 */
141 109
142 //////////////////////////////////////////////////////////////////////////// 110 ////////////////////////////////////////////////////////////////////////////
143
144 // flag to require a moveTo if we begin with something else, like lineTo etc.
145 #define INITIAL_LASTMOVETOINDEX_VALUE ~0
146
147 SkPath::SkPath() 111 SkPath::SkPath()
148 : fPathRef(SkPathRef::CreateEmpty()) 112 : fPathRef(SkPathRef::CreateEmpty())
149 #ifdef SK_BUILD_FOR_ANDROID 113 #ifdef SK_BUILD_FOR_ANDROID
150 , fGenerationID(0) 114 , fGenerationID(0)
151 #endif 115 #endif
152 { 116 {
153 this->resetFields(); 117 this->resetFields();
154 } 118 }
155 119
156 void SkPath::resetFields() { 120 void SkPath::resetFields() {
157 //fPathRef is assumed to have been emptied by the caller. 121 //fPathRef is assumed to have been emptied by the caller.
158 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
159 fFillType = kWinding_FillType; 122 fFillType = kWinding_FillType;
160 fSegmentMask = 0;
161 fConvexity = kUnknown_Convexity;
162 fDirection = kUnknown_Direction;
163 fIsOval = false;
164 #ifdef SK_BUILD_FOR_ANDROID 123 #ifdef SK_BUILD_FOR_ANDROID
165 GEN_ID_INC; 124 GEN_ID_INC;
166 // We don't touch fSourcePath. It's used to track texture garbage collectio n, so we don't 125 // We don't touch fSourcePath. It's used to track texture garbage collectio n, so we don't
167 // want to muck with it if it's been set to something non-NULL. 126 // want to muck with it if it's been set to something non-NULL.
168 #endif 127 #endif
169 } 128 }
170 129
171 SkPath::SkPath(const SkPath& that) 130 SkPath::SkPath(const SkPath& that)
172 : fPathRef(SkRef(that.fPathRef.get())) { 131 : fPathRef(SkRef(that.fPathRef.get())) {
173 this->copyFields(that); 132 this->copyFields(that);
(...skipping 18 matching lines...) Expand all
192 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go back in time. 151 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go back in time.
193 fSourcePath = that.fSourcePath; 152 fSourcePath = that.fSourcePath;
194 #endif 153 #endif
195 } 154 }
196 SkDEBUGCODE(this->validate();) 155 SkDEBUGCODE(this->validate();)
197 return *this; 156 return *this;
198 } 157 }
199 158
200 void SkPath::copyFields(const SkPath& that) { 159 void SkPath::copyFields(const SkPath& that) {
201 //fPathRef is assumed to have been set by the caller. 160 //fPathRef is assumed to have been set by the caller.
202 fLastMoveToIndex = that.fLastMoveToIndex;
203 fFillType = that.fFillType; 161 fFillType = that.fFillType;
204 fSegmentMask = that.fSegmentMask;
205 fConvexity = that.fConvexity;
206 fDirection = that.fDirection;
207 fIsOval = that.fIsOval;
208 } 162 }
209 163
210 bool operator==(const SkPath& a, const SkPath& b) { 164 bool operator==(const SkPath& a, const SkPath& b) {
211 // note: don't need to look at isConvex or bounds, since just comparing the
212 // raw data is sufficient.
213
214 // We explicitly check fSegmentMask as a quick-reject. We could skip it,
215 // since it is only a cache of info in the fVerbs, but its a fast way to
216 // notice a difference
217
218 return &a == &b || 165 return &a == &b ||
219 (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && 166 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get());
220 *a.fPathRef.get() == *b.fPathRef.get());
221 } 167 }
222 168
223 void SkPath::swap(SkPath& that) { 169 void SkPath::swap(SkPath& that) {
224 SkASSERT(&that != NULL); 170 SkASSERT(&that != NULL);
225 171
226 if (this != &that) { 172 if (this != &that) {
227 fPathRef.swap(&that.fPathRef); 173 fPathRef.swap(&that.fPathRef);
228 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex);
229 SkTSwap<uint8_t>(fFillType, that.fFillType); 174 SkTSwap<uint8_t>(fFillType, that.fFillType);
230 SkTSwap<uint8_t>(fSegmentMask, that.fSegmentMask);
231 SkTSwap<uint8_t>(fConvexity, that.fConvexity);
232 SkTSwap<uint8_t>(fDirection, that.fDirection);
233 SkTSwap<SkBool8>(fIsOval, that.fIsOval);
234 #ifdef SK_BUILD_FOR_ANDROID 175 #ifdef SK_BUILD_FOR_ANDROID
235 // It doesn't really make sense to swap the generation IDs here, because they might go 176 // It doesn't really make sense to swap the generation IDs here, because they might go
236 // backwards. To be safe we increment both to mark them both as changed . 177 // backwards. To be safe we increment both to mark them both as changed .
237 GEN_ID_INC; 178 GEN_ID_INC;
238 GEN_ID_PTR_INC(&that); 179 GEN_ID_PTR_INC(&that);
239 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); 180 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath);
240 #endif 181 #endif
241 } 182 }
242 } 183 }
243 184
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 Single points on the rectangle side. 344 Single points on the rectangle side.
404 345
405 The direction takes advantage of the corners found since opposite sides 346 The direction takes advantage of the corners found since opposite sides
406 must travel in opposite directions. 347 must travel in opposite directions.
407 348
408 FIXME: Allow colinear quads and cubics to be treated like lines. 349 FIXME: Allow colinear quads and cubics to be treated like lines.
409 FIXME: If the API passes fill-only, return true if the filled stroke 350 FIXME: If the API passes fill-only, return true if the filled stroke
410 is a rectangle, though the caller failed to close the path. 351 is a rectangle, though the caller failed to close the path.
411 */ 352 */
412 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts Ptr, 353 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts Ptr,
413 bool* isClosed, Direction* direction) const { 354 bool* isClosed, Direction* direction) const {
414 int corners = 0; 355 int corners = 0;
415 SkPoint first, last; 356 SkPoint first, last;
416 const SkPoint* pts = *ptsPtr; 357 const SkPoint* pts = *ptsPtr;
417 const SkPoint* savePts = NULL; 358 const SkPoint* savePts = NULL;
418 first.set(0, 0); 359 first.set(0, 0);
419 last.set(0, 0); 360 last.set(0, 0);
420 int firstDirection = 0; 361 int firstDirection = 0;
421 int lastDirection = 0; 362 int lastDirection = 0;
422 int nextDirection = 0; 363 int nextDirection = 0;
423 bool closedOrMoved = false; 364 bool closedOrMoved = false;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 return false; 564 return false;
624 } 565 }
625 566
626 void SkPath::setLastPt(SkScalar x, SkScalar y) { 567 void SkPath::setLastPt(SkScalar x, SkScalar y) {
627 SkDEBUGCODE(this->validate();) 568 SkDEBUGCODE(this->validate();)
628 569
629 int count = fPathRef->countPoints(); 570 int count = fPathRef->countPoints();
630 if (count == 0) { 571 if (count == 0) {
631 this->moveTo(x, y); 572 this->moveTo(x, y);
632 } else { 573 } else {
633 fIsOval = false;
634 SkPathRef::Editor ed(&fPathRef); 574 SkPathRef::Editor ed(&fPathRef);
635 ed.atPoint(count-1)->set(x, y); 575 ed.atPoint(count-1)->set(x, y);
636 GEN_ID_INC; 576 GEN_ID_INC;
637 } 577 }
638 } 578 }
639 579
640 void SkPath::setConvexity(Convexity c) { 580 void SkPath::setConvexity(Convexity c) {
641 if (fConvexity != c) { 581 if (static_cast<SkPath::Convexity>(fPathRef->getConvexity()) != c) {
642 fConvexity = c; 582 SkPathRef::Editor ed(&fPathRef);
583 ed.setConvexity(c);
643 GEN_ID_INC; 584 GEN_ID_INC;
644 } 585 }
645 } 586 }
646 587
647 ////////////////////////////////////////////////////////////////////////////// 588 //////////////////////////////////////////////////////////////////////////////
648 // Construction methods 589 // Construction methods
649 590
650 #define DIRTY_AFTER_EDIT \ 591 #define DIRTY_AFTER_EDIT \
651 do { \ 592 do { \
652 fConvexity = kUnknown_Convexity; \ 593 fConvexity = kUnknown_Convexity; \
653 fDirection = kUnknown_Direction; \ 594 fDirection = kUnknown_Direction; \
654 fIsOval = false; \ 595 fIsOval = false; \
655 } while (0) 596 } while (0)
656 597
657 void SkPath::incReserve(U16CPU inc) { 598 void SkPath::incReserve(U16CPU inc) {
658 SkDEBUGCODE(this->validate();) 599 SkDEBUGCODE(this->validate();)
659 SkPathRef::Editor(&fPathRef, inc, inc); 600 SkPathRef::Editor(&fPathRef, inc, inc);
660 SkDEBUGCODE(this->validate();) 601 SkDEBUGCODE(this->validate();)
661 } 602 }
662 603
663 void SkPath::moveTo(SkScalar x, SkScalar y) { 604 void SkPath::moveTo(SkScalar x, SkScalar y) {
664 SkDEBUGCODE(this->validate();) 605 SkDEBUGCODE(this->validate();)
665 606
666 SkPathRef::Editor ed(&fPathRef); 607 SkPathRef::Editor ed(&fPathRef);
667 608
668 // remember our index
669 fLastMoveToIndex = ed.pathRef()->countPoints();
670
671 ed.growForVerb(kMove_Verb)->set(x, y); 609 ed.growForVerb(kMove_Verb)->set(x, y);
672 610
673 GEN_ID_INC; 611 GEN_ID_INC;
674 } 612 }
675 613
676 void SkPath::rMoveTo(SkScalar x, SkScalar y) { 614 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
677 SkPoint pt; 615 SkPoint pt;
678 this->getLastPt(&pt); 616 this->getLastPt(&pt);
679 this->moveTo(pt.fX + x, pt.fY + y); 617 this->moveTo(pt.fX + x, pt.fY + y);
680 } 618 }
681 619
682 void SkPath::injectMoveToIfNeeded() {
683 if (fLastMoveToIndex < 0) {
684 SkScalar x, y;
685 if (fPathRef->countVerbs() == 0) {
686 x = y = 0;
687 } else {
688 const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex);
689 x = pt.fX;
690 y = pt.fY;
691 }
692 this->moveTo(x, y);
693 }
694 }
695
696 void SkPath::lineTo(SkScalar x, SkScalar y) { 620 void SkPath::lineTo(SkScalar x, SkScalar y) {
697 SkDEBUGCODE(this->validate();) 621 SkDEBUGCODE(this->validate();)
698 622
699 this->injectMoveToIfNeeded();
700
701 SkPathRef::Editor ed(&fPathRef); 623 SkPathRef::Editor ed(&fPathRef);
702 ed.growForVerb(kLine_Verb)->set(x, y); 624 ed.growForVerb(kLine_Verb)->set(x, y);
703 fSegmentMask |= kLine_SegmentMask;
704 625
705 GEN_ID_INC; 626 GEN_ID_INC;
706 DIRTY_AFTER_EDIT;
707 } 627 }
708 628
709 void SkPath::rLineTo(SkScalar x, SkScalar y) { 629 void SkPath::rLineTo(SkScalar x, SkScalar y) {
710 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 630 SkDEBUGCODE(this->validate();)
711 SkPoint pt; 631
712 this->getLastPt(&pt); 632 SkPathRef::Editor ed(&fPathRef);
713 this->lineTo(pt.fX + x, pt.fY + y); 633 SkPoint* dst = ed.growForVerb(kLine_Verb);
634
635 // growForVerb can change the result of this->getPoint().
636 SkASSERT(this->countPoints() >= 2);
637 SkPoint pt = this->getPoint(this->countPoints() - 2);
638
639 dst->set(pt.fX + x, pt.fY + y);
640 GEN_ID_INC;
714 } 641 }
715 642
716 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 643 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
717 SkDEBUGCODE(this->validate();) 644 SkDEBUGCODE(this->validate();)
718 645
719 this->injectMoveToIfNeeded();
720
721 SkPathRef::Editor ed(&fPathRef); 646 SkPathRef::Editor ed(&fPathRef);
722 SkPoint* pts = ed.growForVerb(kQuad_Verb); 647 SkPoint* pts = ed.growForVerb(kQuad_Verb);
723 pts[0].set(x1, y1); 648 pts[0].set(x1, y1);
724 pts[1].set(x2, y2); 649 pts[1].set(x2, y2);
725 fSegmentMask |= kQuad_SegmentMask;
726 650
727 GEN_ID_INC; 651 GEN_ID_INC;
728 DIRTY_AFTER_EDIT;
729 } 652 }
730 653
731 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 654 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
732 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 655 SkDEBUGCODE(this->validate();)
733 SkPoint pt; 656
734 this->getLastPt(&pt); 657 SkPathRef::Editor ed(&fPathRef);
735 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); 658 SkPoint* pts = ed.growForVerb(kQuad_Verb);
659
660 // growForVerb can change the result of this->getPoint().
661 SkASSERT(this->countPoints() >= 3);
662 SkPoint pt = this->getPoint(this->countPoints() - 3);
663
664 pts[0].set(pt.fX + x1, pt.fY + y1);
665 pts[1].set(pt.fX + x2, pt.fY + y2);
666
667 GEN_ID_INC;
736 } 668 }
737 669
738 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 670 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
739 SkScalar w) { 671 SkScalar w) {
740 // check for <= 0 or NaN with this test 672 // check for <= 0 or NaN with this test
741 if (!(w > 0)) { 673 if (!(w > 0)) {
742 this->lineTo(x2, y2); 674 this->lineTo(x2, y2);
743 } else if (!SkScalarIsFinite(w)) { 675 } else if (!SkScalarIsFinite(w)) {
744 this->lineTo(x1, y1); 676 this->lineTo(x1, y1);
745 this->lineTo(x2, y2); 677 this->lineTo(x2, y2);
746 } else if (SK_Scalar1 == w) { 678 } else if (SK_Scalar1 == w) {
747 this->quadTo(x1, y1, x2, y2); 679 this->quadTo(x1, y1, x2, y2);
748 } else { 680 } else {
749 SkDEBUGCODE(this->validate();) 681 SkDEBUGCODE(this->validate();)
750 682
751 this->injectMoveToIfNeeded();
752
753 SkPathRef::Editor ed(&fPathRef); 683 SkPathRef::Editor ed(&fPathRef);
754 SkPoint* pts = ed.growForConic(w); 684 SkPoint* pts = ed.growForConic(w);
755 pts[0].set(x1, y1); 685 pts[0].set(x1, y1);
756 pts[1].set(x2, y2); 686 pts[1].set(x2, y2);
757 fSegmentMask |= kConic_SegmentMask;
758 687
759 GEN_ID_INC; 688 GEN_ID_INC;
760 DIRTY_AFTER_EDIT;
761 } 689 }
762 } 690 }
763 691
764 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 692 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
765 SkScalar w) { 693 SkScalar w) {
766 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 694 // check for <= 0 or NaN with this test
767 SkPoint pt; 695 if (!(w > 0)) {
768 this->getLastPt(&pt); 696 this->rLineTo(dx2, dy2);
769 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); 697 } else if (!SkScalarIsFinite(w)) {
698 this->rLineTo(dx1, dy1);
699 this->rLineTo(dx2, dy2);
700 } else if (SK_Scalar1 == w) {
701 this->rQuadTo(dx1, dy1, dx2, dy2);
702 } else {
703 SkDEBUGCODE(this->validate();)
704
705 SkPathRef::Editor ed(&fPathRef);
706 SkPoint* pts = ed.growForConic(w);
707
708 // growForConic can change the result of this->getPoint().
709 SkASSERT(this->countPoints() >= 3);
710 SkPoint pt = this->getPoint(this->countPoints() - 3);
711
712 pts[0].set(pt.fX + dx1, pt.fY + dy1);
713 pts[1].set(pt.fX + dx2, pt.fY + dy2);
714
715 GEN_ID_INC;
716 }
770 } 717 }
771 718
772 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 719 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
773 SkScalar x3, SkScalar y3) { 720 SkScalar x3, SkScalar y3) {
774 SkDEBUGCODE(this->validate();) 721 SkDEBUGCODE(this->validate();)
775 722
776 this->injectMoveToIfNeeded();
777
778 SkPathRef::Editor ed(&fPathRef); 723 SkPathRef::Editor ed(&fPathRef);
779 SkPoint* pts = ed.growForVerb(kCubic_Verb); 724 SkPoint* pts = ed.growForVerb(kCubic_Verb);
780 pts[0].set(x1, y1); 725 pts[0].set(x1, y1);
781 pts[1].set(x2, y2); 726 pts[1].set(x2, y2);
782 pts[2].set(x3, y3); 727 pts[2].set(x3, y3);
783 fSegmentMask |= kCubic_SegmentMask;
784 728
785 GEN_ID_INC; 729 GEN_ID_INC;
786 DIRTY_AFTER_EDIT;
787 } 730 }
788 731
789 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 732 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
790 SkScalar x3, SkScalar y3) { 733 SkScalar x3, SkScalar y3) {
791 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 734 SkDEBUGCODE(this->validate();)
792 SkPoint pt; 735
793 this->getLastPt(&pt); 736 SkPathRef::Editor ed(&fPathRef);
794 this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, 737 SkPoint* pts = ed.growForVerb(kCubic_Verb);
795 pt.fX + x3, pt.fY + y3); 738
739 // growForVerb can change the result of this->getPoint().
740 SkASSERT(this->countPoints() >= 4);
741 SkPoint pt = this->getPoint(this->countPoints() - 4);
742
743 pts[0].set(pt.fX + x1, pt.fY + y1);
744 pts[1].set(pt.fX + x2, pt.fY + y2);
745 pts[2].set(pt.fX + x3, pt.fY + y3);
746
747 GEN_ID_INC;
796 } 748 }
797 749
798 void SkPath::close() { 750 void SkPath::close() {
799 SkDEBUGCODE(this->validate();) 751 SkDEBUGCODE(this->validate();)
800 752
801 int count = fPathRef->countVerbs(); 753 int count = fPathRef->countVerbs();
802 if (count > 0) { 754 if (count > 0) {
803 switch (fPathRef->atVerb(count - 1)) { 755 switch (fPathRef->atVerb(count - 1)) {
804 case kLine_Verb: 756 case kLine_Verb:
805 case kQuad_Verb: 757 case kQuad_Verb:
806 case kConic_Verb: 758 case kConic_Verb:
807 case kCubic_Verb: 759 case kCubic_Verb:
808 case kMove_Verb: { 760 case kMove_Verb: {
809 SkPathRef::Editor ed(&fPathRef); 761 SkPathRef::Editor ed(&fPathRef);
810 ed.growForVerb(kClose_Verb); 762 ed.growForVerb(kClose_Verb);
811 GEN_ID_INC; 763 GEN_ID_INC;
812 break; 764 break;
813 } 765 }
814 case kClose_Verb: 766 case kClose_Verb:
815 // don't add a close if it's the first verb or a repeat 767 // don't add a close if it's the first verb or a repeat
816 break; 768 break;
817 default: 769 default:
818 SkDEBUGFAIL("unexpected verb"); 770 SkDEBUGFAIL("unexpected verb");
819 break; 771 break;
820 } 772 }
821 } 773 }
822
823 // signal that we need a moveTo to follow us (unless we're done)
824 #if 0
825 if (fLastMoveToIndex >= 0) {
826 fLastMoveToIndex = ~fLastMoveToIndex;
827 }
828 #else
829 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1);
830 #endif
831 } 774 }
832 775
833 /////////////////////////////////////////////////////////////////////////////// 776 ///////////////////////////////////////////////////////////////////////////////
834 777
835 static void assert_known_direction(int dir) { 778 static void assert_known_direction(int dir) {
836 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); 779 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir);
837 } 780 }
838 781
839 void SkPath::addRect(const SkRect& rect, Direction dir) { 782 void SkPath::addRect(const SkRect& rect, Direction dir) {
840 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); 783 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
841 } 784 }
842 785
843 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, 786 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
844 SkScalar bottom, Direction dir) { 787 SkScalar bottom, Direction dir) {
845 assert_known_direction(dir); 788 assert_known_direction(dir);
846 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 789 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
847 SkAutoDisableDirectionCheck addc(this);
848 790
849 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); 791 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom);
850 792
851 this->incReserve(5); 793 this->incReserve(5);
852 794
853 this->moveTo(left, top); 795 this->moveTo(left, top);
854 if (dir == kCCW_Direction) { 796 if (dir == kCCW_Direction) {
855 this->lineTo(left, bottom); 797 this->lineTo(left, bottom);
856 this->lineTo(right, bottom); 798 this->lineTo(right, bottom);
857 this->lineTo(right, top); 799 this->lineTo(right, top);
858 } else { 800 } else {
859 this->lineTo(right, top); 801 this->lineTo(right, top);
860 this->lineTo(right, bottom); 802 this->lineTo(right, bottom);
861 this->lineTo(left, bottom); 803 this->lineTo(left, bottom);
862 } 804 }
863 this->close(); 805 this->close();
806
807 SkPathRef::Editor ed(&fPathRef);
808 ed.setDirection(newDir);
864 } 809 }
865 810
866 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { 811 void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
867 SkDEBUGCODE(this->validate();) 812 SkDEBUGCODE(this->validate();)
868 if (count <= 0) { 813 if (count <= 0) {
869 return; 814 return;
870 } 815 }
871 816
872 SkPathRef::Editor ed(&fPathRef);
873 fLastMoveToIndex = ed.pathRef()->countPoints();
874 uint8_t* vb;
875 SkPoint* p;
876 // +close makes room for the extra kClose_Verb 817 // +close makes room for the extra kClose_Verb
877 ed.grow(count + close, count, &vb, &p); 818 SkPathRef::Editor ed(&fPathRef, count+close, count);
878 819
879 memcpy(p, pts, count * sizeof(SkPoint)); 820 ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY);
880 vb[~0] = kMove_Verb; 821
881 if (count > 1) { 822 if (count > 1) {
882 // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to 823 SkPoint* p = ed.growForLines(count - 1);
883 // be 0, the compiler will remove the test/branch entirely. 824
884 if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) { 825 memcpy(p, &pts[1], (count-1) * sizeof(SkPoint));
885 memset(vb - count, kLine_Verb, count - 1);
886 } else {
887 for (int i = 1; i < count; ++i) {
888 vb[~i] = kLine_Verb;
889 }
890 }
891 fSegmentMask |= kLine_SegmentMask;
892 } 826 }
827
893 if (close) { 828 if (close) {
894 vb[~count] = kClose_Verb; 829 ed.growForVerb(kClose_Verb);
895 } 830 }
896 831
897 GEN_ID_INC; 832 GEN_ID_INC;
898 DIRTY_AFTER_EDIT;
899 SkDEBUGCODE(this->validate();) 833 SkDEBUGCODE(this->validate();)
900 } 834 }
901 835
902 #include "SkGeometry.h" 836 #include "SkGeometry.h"
903 837
904 static int build_arc_points(const SkRect& oval, SkScalar startAngle, 838 static int build_arc_points(const SkRect& oval, SkScalar startAngle,
905 SkScalar sweepAngle, 839 SkScalar sweepAngle,
906 SkPoint pts[kSkBuildQuadArcStorage]) { 840 SkPoint pts[kSkBuildQuadArcStorage]) {
907 841
908 if (0 == sweepAngle && 842 if (0 == sweepAngle &&
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 } 983 }
1050 ++verbs; 984 ++verbs;
1051 } 985 }
1052 return true; 986 return true;
1053 } 987 }
1054 988
1055 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 989 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT
1056 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) 990 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
1057 #endif 991 #endif
1058 992
1059 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 993 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Directio n dir) {
1060 Direction dir) {
1061 assert_known_direction(dir); 994 assert_known_direction(dir);
1062 995
1063 if (rx < 0 || ry < 0) { 996 if (rx < 0 || ry < 0) {
1064 SkErrorInternals::SetError( kInvalidArgument_SkError, 997 SkErrorInternals::SetError( kInvalidArgument_SkError,
1065 "I got %f and %f as radii to SkPath::AddRoun dRect, " 998 "I got %f and %f as radii to SkPath::AddRoun dRect, "
1066 "but negative radii are not allowed.", 999 "but negative radii are not allowed.",
1067 SkScalarToDouble(rx), SkScalarToDouble(ry) ) ; 1000 SkScalarToDouble(rx), SkScalarToDouble(ry) ) ;
1068 return; 1001 return;
1069 } 1002 }
1070 1003
1071 SkScalar w = rect.width(); 1004 SkScalar w = rect.width();
1072 SkScalar halfW = SkScalarHalf(w); 1005 SkScalar halfW = SkScalarHalf(w);
1073 SkScalar h = rect.height(); 1006 SkScalar h = rect.height();
1074 SkScalar halfH = SkScalarHalf(h); 1007 SkScalar halfH = SkScalarHalf(h);
1075 1008
1076 if (halfW <= 0 || halfH <= 0) { 1009 if (halfW <= 0 || halfH <= 0) {
1077 return; 1010 return;
1078 } 1011 }
1079 1012
1080 bool skip_hori = rx >= halfW; 1013 bool skip_hori = rx >= halfW;
1081 bool skip_vert = ry >= halfH; 1014 bool skip_vert = ry >= halfH;
1082 1015
1083 if (skip_hori && skip_vert) { 1016 if (skip_hori && skip_vert) {
1084 this->addOval(rect, dir); 1017 this->addOval(rect, dir);
1085 return; 1018 return;
1086 } 1019 }
1087 1020
1088 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 1021 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
1089 1022
1090 SkAutoPathBoundsUpdate apbu(this, rect); 1023 SkAutoPathBoundsUpdate apbu(this, rect);
1091 SkAutoDisableDirectionCheck(this);
1092 1024
1093 if (skip_hori) { 1025 if (skip_hori) {
1094 rx = halfW; 1026 rx = halfW;
1095 } else if (skip_vert) { 1027 } else if (skip_vert) {
1096 ry = halfH; 1028 ry = halfH;
1097 } 1029 }
1098 1030
1099 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 1031 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT
1100 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); 1032 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
1101 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); 1033 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1217 this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY, 1149 this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY,
1218 rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY); 1150 rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY);
1219 this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon, 1151 this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon,
1220 rect.fLeft + rx, rect.fTop); 1152 rect.fLeft + rx, rect.fTop);
1221 #endif 1153 #endif
1222 if (!skip_hori) { 1154 if (!skip_hori) {
1223 this->lineTo(rect.fRight - rx, rect.fTop); // top 1155 this->lineTo(rect.fRight - rx, rect.fTop); // top
1224 } 1156 }
1225 } 1157 }
1226 this->close(); 1158 this->close();
1159
1160 SkPathRef::Editor ed(&fPathRef);
1161 ed.setDirection(newDir);
1227 } 1162 }
1228 1163
1229 void SkPath::addOval(const SkRect& oval, Direction dir) { 1164 void SkPath::addOval(const SkRect& oval, Direction dir) {
1230 assert_known_direction(dir); 1165 assert_known_direction(dir);
1231 1166
1232 /* If addOval() is called after previous moveTo(), 1167 /* If addOval() is called after previous moveTo(),
1233 this path is still marked as an oval. This is used to 1168 this path is still marked as an oval. This is used to
1234 fit into WebKit's calling sequences. 1169 fit into WebKit's calling sequences.
1235 We can't simply check isEmpty() in this case, as additional 1170 We can't simply check isEmpty() in this case, as additional
1236 moveTo() would mark the path non empty. 1171 moveTo() would mark the path non empty.
1237 */ 1172 */
1238 fIsOval = hasOnlyMoveTos(); 1173 bool isOval = this->hasOnlyMoveTos();
1239 if (fIsOval) { 1174 Direction newDir = isOval ? dir : kUnknown_Direction;
1240 fDirection = dir;
1241 } else {
1242 fDirection = kUnknown_Direction;
1243 }
1244
1245 SkAutoDisableOvalCheck adoc(this);
1246 SkAutoDisableDirectionCheck addc(this);
1247 1175
1248 SkAutoPathBoundsUpdate apbu(this, oval); 1176 SkAutoPathBoundsUpdate apbu(this, oval);
1249 1177
1250 SkScalar cx = oval.centerX(); 1178 SkScalar cx = oval.centerX();
1251 SkScalar cy = oval.centerY(); 1179 SkScalar cy = oval.centerY();
1252 SkScalar rx = SkScalarHalf(oval.width()); 1180 SkScalar rx = SkScalarHalf(oval.width());
1253 SkScalar ry = SkScalarHalf(oval.height()); 1181 SkScalar ry = SkScalarHalf(oval.height());
1254 1182
1255 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); 1183 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
1256 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); 1184 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
(...skipping 26 matching lines...) Expand all
1283 this->quadTo( R, cy + sy, cx + mx, cy + my); 1211 this->quadTo( R, cy + sy, cx + mx, cy + my);
1284 this->quadTo(cx + sx, B, cx , B); 1212 this->quadTo(cx + sx, B, cx , B);
1285 this->quadTo(cx - sx, B, cx - mx, cy + my); 1213 this->quadTo(cx - sx, B, cx - mx, cy + my);
1286 this->quadTo( L, cy + sy, L, cy ); 1214 this->quadTo( L, cy + sy, L, cy );
1287 this->quadTo( L, cy - sy, cx - mx, cy - my); 1215 this->quadTo( L, cy - sy, cx - mx, cy - my);
1288 this->quadTo(cx - sx, T, cx , T); 1216 this->quadTo(cx - sx, T, cx , T);
1289 this->quadTo(cx + sx, T, cx + mx, cy - my); 1217 this->quadTo(cx + sx, T, cx + mx, cy - my);
1290 this->quadTo( R, cy - sy, R, cy ); 1218 this->quadTo( R, cy - sy, R, cy );
1291 } 1219 }
1292 this->close(); 1220 this->close();
1293 }
1294 1221
1295 bool SkPath::isOval(SkRect* rect) const { 1222 SkPathRef::Editor ed(&fPathRef);
1296 if (fIsOval && rect) {
1297 *rect = getBounds();
1298 }
1299 1223
1300 return fIsOval; 1224 ed.setIsOval(isOval);
1225 ed.setDirection(newDir);
1301 } 1226 }
1302 1227
1303 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { 1228 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
1304 if (r > 0) { 1229 if (r > 0) {
1305 SkRect rect; 1230 SkRect rect;
1306 rect.set(x - r, y - r, x + r, y + r); 1231 rect.set(x - r, y - r, x + r, y + r);
1307 this->addOval(rect, dir); 1232 this->addOval(rect, dir);
1308 } 1233 }
1309 } 1234 }
1310 1235
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1424 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { 1349 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
1425 SkMatrix matrix; 1350 SkMatrix matrix;
1426 1351
1427 matrix.setTranslate(dx, dy); 1352 matrix.setTranslate(dx, dy);
1428 this->addPath(path, matrix); 1353 this->addPath(path, matrix);
1429 } 1354 }
1430 1355
1431 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { 1356 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
1432 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); 1357 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
1433 1358
1434 fIsOval = false;
1435
1436 RawIter iter(path); 1359 RawIter iter(path);
1437 SkPoint pts[4]; 1360 SkPoint pts[4];
1438 Verb verb; 1361 Verb verb;
1439 1362
1440 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); 1363 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
1441 1364
1442 while ((verb = iter.next(pts)) != kDone_Verb) { 1365 while ((verb = iter.next(pts)) != kDone_Verb) {
1443 switch (verb) { 1366 switch (verb) {
1444 case kMove_Verb: 1367 case kMove_Verb:
1445 proc(matrix, &pts[0], &pts[0], 1); 1368 proc(matrix, &pts[0], &pts[0], 1);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1490 // ignore the initial moveto, and stop when the 1st contour ends 1413 // ignore the initial moveto, and stop when the 1st contour ends
1491 void SkPath::pathTo(const SkPath& path) { 1414 void SkPath::pathTo(const SkPath& path) {
1492 int i, vcount = path.fPathRef->countVerbs(); 1415 int i, vcount = path.fPathRef->countVerbs();
1493 // exit early if the path is empty, or just has a moveTo. 1416 // exit early if the path is empty, or just has a moveTo.
1494 if (vcount < 2) { 1417 if (vcount < 2) {
1495 return; 1418 return;
1496 } 1419 }
1497 1420
1498 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1421 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1499 1422
1500 fIsOval = false;
1501
1502 const uint8_t* verbs = path.fPathRef->verbs(); 1423 const uint8_t* verbs = path.fPathRef->verbs();
1503 // skip the initial moveTo 1424 // skip the initial moveTo
1504 const SkPoint* pts = path.fPathRef->points() + 1; 1425 const SkPoint* pts = path.fPathRef->points() + 1;
1505 const SkScalar* conicWeight = path.fPathRef->conicWeights(); 1426 const SkScalar* conicWeight = path.fPathRef->conicWeights();
1506 1427
1507 SkASSERT(verbs[~0] == kMove_Verb); 1428 SkASSERT(verbs[~0] == kMove_Verb);
1508 for (i = 1; i < vcount; i++) { 1429 for (i = 1; i < vcount; i++) {
1509 switch (verbs[~i]) { 1430 switch (verbs[~i]) {
1510 case kLine_Verb: 1431 case kLine_Verb:
1511 this->lineTo(pts[0].fX, pts[0].fY); 1432 this->lineTo(pts[0].fX, pts[0].fY);
(...skipping 17 matching lines...) Expand all
1529 // ignore the last point of the 1st contour 1450 // ignore the last point of the 1st contour
1530 void SkPath::reversePathTo(const SkPath& path) { 1451 void SkPath::reversePathTo(const SkPath& path) {
1531 int i, vcount = path.fPathRef->countVerbs(); 1452 int i, vcount = path.fPathRef->countVerbs();
1532 // exit early if the path is empty, or just has a moveTo. 1453 // exit early if the path is empty, or just has a moveTo.
1533 if (vcount < 2) { 1454 if (vcount < 2) {
1534 return; 1455 return;
1535 } 1456 }
1536 1457
1537 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1458 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1538 1459
1539 fIsOval = false;
1540
1541 const uint8_t* verbs = path.fPathRef->verbs(); 1460 const uint8_t* verbs = path.fPathRef->verbs();
1542 const SkPoint* pts = path.fPathRef->points(); 1461 const SkPoint* pts = path.fPathRef->points();
1543 const SkScalar* conicWeights = path.fPathRef->conicWeights(); 1462 const SkScalar* conicWeights = path.fPathRef->conicWeights();
1544 1463
1545 SkASSERT(verbs[~0] == kMove_Verb); 1464 SkASSERT(verbs[~0] == kMove_Verb);
1546 for (i = 1; i < vcount; ++i) { 1465 for (i = 1; i < vcount; ++i) {
1547 unsigned v = verbs[~i]; 1466 unsigned v = verbs[~i];
1548 int n = pts_in_verb(v); 1467 int n = pts_in_verb(v);
1549 if (n == 0) { 1468 if (n == 0) {
1550 break; 1469 break;
(...skipping 19 matching lines...) Expand all
1570 break; 1489 break;
1571 default: 1490 default:
1572 SkDEBUGFAIL("bad verb"); 1491 SkDEBUGFAIL("bad verb");
1573 break; 1492 break;
1574 } 1493 }
1575 pts -= pts_in_verb(verbs[~i]); 1494 pts -= pts_in_verb(verbs[~i]);
1576 } 1495 }
1577 } 1496 }
1578 1497
1579 void SkPath::reverseAddPath(const SkPath& src) { 1498 void SkPath::reverseAddPath(const SkPath& src) {
1580 SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->c ountVerbs()); 1499 SkPathRef::Editor(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->coun tVerbs());
1581 1500
1582 const SkPoint* pts = src.fPathRef->pointsEnd(); 1501 const SkPoint* pts = src.fPathRef->pointsEnd();
1583 // we will iterator through src's verbs backwards 1502 // we will iterator through src's verbs backwards
1584 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb 1503 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
1585 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir st verb 1504 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir st verb
1586 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); 1505 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
1587 1506
1588 fIsOval = false;
1589
1590 bool needMove = true; 1507 bool needMove = true;
1591 bool needClose = false; 1508 bool needClose = false;
1592 while (verbs < verbsEnd) { 1509 while (verbs < verbsEnd) {
1593 uint8_t v = *(verbs++); 1510 uint8_t v = *(verbs++);
1594 int n = pts_in_verb(v); 1511 int n = pts_in_verb(v);
1595 1512
1596 if (needMove) { 1513 if (needMove) {
1597 --pts; 1514 --pts;
1598 this->moveTo(pts->fX, pts->fY); 1515 this->moveTo(pts->fX, pts->fY);
1599 needMove = false; 1516 needMove = false;
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1703 break; 1620 break;
1704 default: 1621 default:
1705 SkDEBUGFAIL("unknown verb"); 1622 SkDEBUGFAIL("unknown verb");
1706 break; 1623 break;
1707 } 1624 }
1708 } 1625 }
1709 1626
1710 dst->swap(tmp); 1627 dst->swap(tmp);
1711 SkPathRef::Editor ed(&dst->fPathRef); 1628 SkPathRef::Editor ed(&dst->fPathRef);
1712 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); 1629 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
1713 dst->fDirection = kUnknown_Direction; 1630 ed.setDirection(kUnknown_Direction);
1714 } else { 1631 } else {
1715 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix ); 1632 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix );
1716 1633
1717 if (this != dst) { 1634 if (this != dst) {
1718 dst->fFillType = fFillType; 1635 dst->fFillType = fFillType;
1719 dst->fSegmentMask = fSegmentMask;
1720 dst->fConvexity = fConvexity;
1721 } 1636 }
1722 1637
1723 #ifdef SK_BUILD_FOR_ANDROID 1638 #ifdef SK_BUILD_FOR_ANDROID
1724 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { 1639 if (!matrix.isIdentity() && !dst->hasComputedBounds()) {
1725 GEN_ID_PTR_INC(dst); 1640 GEN_ID_PTR_INC(dst);
1726 } 1641 }
1727 #endif 1642 #endif
1728 1643
1729 if (kUnknown_Direction == fDirection) {
1730 dst->fDirection = kUnknown_Direction;
1731 } else {
1732 SkScalar det2x2 =
1733 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) -
1734 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY));
1735 if (det2x2 < 0) {
1736 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection));
1737 } else if (det2x2 > 0) {
1738 dst->fDirection = fDirection;
1739 } else {
1740 dst->fDirection = kUnknown_Direction;
1741 }
1742 }
1743
1744 // It's an oval only if it stays a rect.
1745 dst->fIsOval = fIsOval && matrix.rectStaysRect();
1746
1747 SkDEBUGCODE(dst->validate();) 1644 SkDEBUGCODE(dst->validate();)
1748 } 1645 }
1749 } 1646 }
1750 1647
1751 /////////////////////////////////////////////////////////////////////////////// 1648 ///////////////////////////////////////////////////////////////////////////////
1752 /////////////////////////////////////////////////////////////////////////////// 1649 ///////////////////////////////////////////////////////////////////////////////
1753 1650
1754 enum SegmentState { 1651 enum SegmentState {
1755 kEmptyContour_SegmentState, // The current contour is empty. We may be 1652 kEmptyContour_SegmentState, // The current contour is empty. We may be
1756 // starting processing or we may have just 1653 // starting processing or we may have just
(...skipping 11 matching lines...) Expand all
1768 fForceClose = fCloseLine = false; 1665 fForceClose = fCloseLine = false;
1769 fSegmentState = kEmptyContour_SegmentState; 1666 fSegmentState = kEmptyContour_SegmentState;
1770 #endif 1667 #endif
1771 // need to init enough to make next() harmlessly return kDone_Verb 1668 // need to init enough to make next() harmlessly return kDone_Verb
1772 fVerbs = NULL; 1669 fVerbs = NULL;
1773 fVerbStop = NULL; 1670 fVerbStop = NULL;
1774 fNeedClose = false; 1671 fNeedClose = false;
1775 } 1672 }
1776 1673
1777 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { 1674 SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
1778 this->setPath(path, forceClose); 1675 this->setPathRef(path.fPathRef.get(), forceClose);
1676 }
1677
1678 SkPath::Iter::Iter(const SkPathRef* pathRef, bool forceClose) {
1679 this->setPathRef(pathRef, forceClose);
1779 } 1680 }
1780 1681
1781 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { 1682 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
1782 fPts = path.fPathRef->points(); 1683 this->setPathRef(path.fPathRef.get(), forceClose);
1783 fVerbs = path.fPathRef->verbs(); 1684 }
1784 fVerbStop = path.fPathRef->verbsMemBegin(); 1685
1785 fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind 1686 void SkPath::Iter::setPathRef(const SkPathRef* pathRef, bool forceClose) {
1687 fPts = pathRef->points();
1688 fVerbs = pathRef->verbs();
1689 fVerbStop = pathRef->verbsMemBegin();
1690 fConicWeights = pathRef->conicWeights() - 1; // begin one behind
1786 fLastPt.fX = fLastPt.fY = 0; 1691 fLastPt.fX = fLastPt.fY = 0;
1787 fMoveTo.fX = fMoveTo.fY = 0; 1692 fMoveTo.fX = fMoveTo.fY = 0;
1788 fForceClose = SkToU8(forceClose); 1693 fForceClose = SkToU8(forceClose);
1789 fNeedClose = false; 1694 fNeedClose = false;
1790 fSegmentState = kEmptyContour_SegmentState; 1695 fSegmentState = kEmptyContour_SegmentState;
1791 } 1696 }
1792 1697
1793 bool SkPath::Iter::isClosedContour() const { 1698 bool SkPath::Iter::isClosedContour() const {
1794 if (fVerbs == NULL || fVerbs == fVerbStop) { 1699 if (fVerbs == NULL || fVerbs == fVerbStop) {
1795 return false; 1700 return false;
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
2089 uint32_t SkPath::writeToMemory(void* storage) const { 1994 uint32_t SkPath::writeToMemory(void* storage) const {
2090 SkDEBUGCODE(this->validate();) 1995 SkDEBUGCODE(this->validate();)
2091 1996
2092 if (NULL == storage) { 1997 if (NULL == storage) {
2093 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); 1998 const int byteCount = sizeof(int32_t) + fPathRef->writeSize();
2094 return SkAlign4(byteCount); 1999 return SkAlign4(byteCount);
2095 } 2000 }
2096 2001
2097 SkWBuffer buffer(storage); 2002 SkWBuffer buffer(storage);
2098 2003
2099 int32_t packed = ((fIsOval & 1) << kIsOval_SerializationShift) | 2004 int32_t packed = (fFillType << kFillType_SerializationShift)
2100 (fConvexity << kConvexity_SerializationShift) |
2101 (fFillType << kFillType_SerializationShift) |
2102 (fSegmentMask << kSegmentMask_SerializationShift) |
2103 (fDirection << kDirection_SerializationShift)
2104 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 2005 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
2105 | (0x1 << kNewFormat_SerializationShift); 2006 | (0x1 << kNewFormat_SerializationShift);
2106 #endif 2007 #endif
2107 2008
2108 buffer.write32(packed); 2009 buffer.write32(packed);
2109 2010
2110 fPathRef->writeToBuffer(&buffer); 2011 fPathRef->writeToBuffer(&buffer);
2111 2012
2112 buffer.padToAlign4(); 2013 buffer.padToAlign4();
2113 return SkToU32(buffer.pos()); 2014 return SkToU32(buffer.pos());
2114 } 2015 }
2115 2016
2116 uint32_t SkPath::readFromMemory(const void* storage) { 2017 uint32_t SkPath::readFromMemory(const void* storage) {
2117 SkRBuffer buffer(storage); 2018 SkRBuffer buffer(storage);
2118 2019
2119 uint32_t packed = buffer.readS32(); 2020 uint32_t packed = buffer.readS32();
2120 fIsOval = (packed >> kIsOval_SerializationShift) & 1;
2121 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
2122 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; 2021 fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
2123 fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
2124 fDirection = (packed >> kDirection_SerializationShift) & 0x3;
2125 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 2022 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
2126 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; 2023 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1;
2127 #endif 2024 #endif
2128 2025
2129 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer 2026 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer
2130 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 2027 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
2131 , newFormat, packed) 2028 , newFormat, packed)
2132 #endif 2029 #endif
2133 ); 2030 );
2134 2031
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
2214 } 2111 }
2215 2112
2216 void SkPath::dump() const { 2113 void SkPath::dump() const {
2217 this->dump(false); 2114 this->dump(false);
2218 } 2115 }
2219 2116
2220 #ifdef SK_DEBUG 2117 #ifdef SK_DEBUG
2221 void SkPath::validate() const { 2118 void SkPath::validate() const {
2222 SkASSERT(this != NULL); 2119 SkASSERT(this != NULL);
2223 SkASSERT((fFillType & ~3) == 0); 2120 SkASSERT((fFillType & ~3) == 0);
2224
2225 #ifdef SK_DEBUG_PATH
2226 if (!fBoundsIsDirty) {
2227 SkRect bounds;
2228
2229 bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
2230 SkASSERT(SkToBool(fIsFinite) == isFinite);
2231
2232 if (fPathRef->countPoints() <= 1) {
2233 // if we're empty, fBounds may be empty but translated, so we can't
2234 // necessarily compare to bounds directly
2235 // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
2236 // be [2, 2, 2, 2]
2237 SkASSERT(bounds.isEmpty());
2238 SkASSERT(fBounds.isEmpty());
2239 } else {
2240 if (bounds.isEmpty()) {
2241 SkASSERT(fBounds.isEmpty());
2242 } else {
2243 if (!fBounds.isEmpty()) {
2244 SkASSERT(fBounds.contains(bounds));
2245 }
2246 }
2247 }
2248 }
2249
2250 uint32_t mask = 0;
2251 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbs() ;
2252 for (int i = 0; i < fPathRef->countVerbs(); i++) {
2253 switch (verbs[~i]) {
2254 case kLine_Verb:
2255 mask |= kLine_SegmentMask;
2256 break;
2257 case kQuad_Verb:
2258 mask |= kQuad_SegmentMask;
2259 break;
2260 case kConic_Verb:
2261 mask |= kConic_SegmentMask;
2262 break;
2263 case kCubic_Verb:
2264 mask |= kCubic_SegmentMask;
2265 case kMove_Verb: // these verbs aren't included in the segment mask .
2266 case kClose_Verb:
2267 break;
2268 case kDone_Verb:
2269 SkDEBUGFAIL("Done verb shouldn't be recorded.");
2270 break;
2271 default:
2272 SkDEBUGFAIL("Unknown Verb");
2273 break;
2274 }
2275 }
2276 SkASSERT(mask == fSegmentMask);
2277 #endif // SK_DEBUG_PATH
2278 } 2121 }
2279 #endif // SK_DEBUG 2122 #endif // SK_DEBUG
2280 2123
2281 /////////////////////////////////////////////////////////////////////////////// 2124 ///////////////////////////////////////////////////////////////////////////////
2282 2125
2283 static int sign(SkScalar x) { return x < 0; }
2284 #define kValueNeverReturnedBySign 2
2285
2286 static int CrossProductSign(const SkVector& a, const SkVector& b) {
2287 return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
2288 }
2289
2290 // only valid for a single contour
2291 struct Convexicator {
2292 Convexicator()
2293 : fPtCount(0)
2294 , fConvexity(SkPath::kConvex_Convexity)
2295 , fDirection(SkPath::kUnknown_Direction) {
2296 fSign = 0;
2297 // warnings
2298 fCurrPt.set(0, 0);
2299 fVec0.set(0, 0);
2300 fVec1.set(0, 0);
2301 fFirstVec.set(0, 0);
2302
2303 fDx = fDy = 0;
2304 fSx = fSy = kValueNeverReturnedBySign;
2305 }
2306
2307 SkPath::Convexity getConvexity() const { return fConvexity; }
2308
2309 /** The direction returned is only valid if the path is determined convex */
2310 SkPath::Direction getDirection() const { return fDirection; }
2311
2312 void addPt(const SkPoint& pt) {
2313 if (SkPath::kConcave_Convexity == fConvexity) {
2314 return;
2315 }
2316
2317 if (0 == fPtCount) {
2318 fCurrPt = pt;
2319 ++fPtCount;
2320 } else {
2321 SkVector vec = pt - fCurrPt;
2322 if (vec.fX || vec.fY) {
2323 fCurrPt = pt;
2324 if (++fPtCount == 2) {
2325 fFirstVec = fVec1 = vec;
2326 } else {
2327 SkASSERT(fPtCount > 2);
2328 this->addVec(vec);
2329 }
2330
2331 int sx = sign(vec.fX);
2332 int sy = sign(vec.fY);
2333 fDx += (sx != fSx);
2334 fDy += (sy != fSy);
2335 fSx = sx;
2336 fSy = sy;
2337
2338 if (fDx > 3 || fDy > 3) {
2339 fConvexity = SkPath::kConcave_Convexity;
2340 }
2341 }
2342 }
2343 }
2344
2345 void close() {
2346 if (fPtCount > 2) {
2347 this->addVec(fFirstVec);
2348 }
2349 }
2350
2351 private:
2352 void addVec(const SkVector& vec) {
2353 SkASSERT(vec.fX || vec.fY);
2354 fVec0 = fVec1;
2355 fVec1 = vec;
2356 int sign = CrossProductSign(fVec0, fVec1);
2357 if (0 == fSign) {
2358 fSign = sign;
2359 if (1 == sign) {
2360 fDirection = SkPath::kCW_Direction;
2361 } else if (-1 == sign) {
2362 fDirection = SkPath::kCCW_Direction;
2363 }
2364 } else if (sign) {
2365 if (fSign != sign) {
2366 fConvexity = SkPath::kConcave_Convexity;
2367 fDirection = SkPath::kUnknown_Direction;
2368 }
2369 }
2370 }
2371
2372 SkPoint fCurrPt;
2373 SkVector fVec0, fVec1, fFirstVec;
2374 int fPtCount; // non-degenerate points
2375 int fSign;
2376 SkPath::Convexity fConvexity;
2377 SkPath::Direction fDirection;
2378 int fDx, fDy, fSx, fSy;
2379 };
2380
2381 SkPath::Convexity SkPath::internalGetConvexity() const {
2382 SkASSERT(kUnknown_Convexity == fConvexity);
2383 SkPoint pts[4];
2384 SkPath::Verb verb;
2385 SkPath::Iter iter(*this, true);
2386
2387 int contourCount = 0;
2388 int count;
2389 Convexicator state;
2390
2391 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
2392 switch (verb) {
2393 case kMove_Verb:
2394 if (++contourCount > 1) {
2395 fConvexity = kConcave_Convexity;
2396 return kConcave_Convexity;
2397 }
2398 pts[1] = pts[0];
2399 count = 1;
2400 break;
2401 case kLine_Verb: count = 1; break;
2402 case kQuad_Verb: count = 2; break;
2403 case kConic_Verb: count = 2; break;
2404 case kCubic_Verb: count = 3; break;
2405 case kClose_Verb:
2406 state.close();
2407 count = 0;
2408 break;
2409 default:
2410 SkDEBUGFAIL("bad verb");
2411 fConvexity = kConcave_Convexity;
2412 return kConcave_Convexity;
2413 }
2414
2415 for (int i = 1; i <= count; i++) {
2416 state.addPt(pts[i]);
2417 }
2418 // early exit
2419 if (kConcave_Convexity == state.getConvexity()) {
2420 fConvexity = kConcave_Convexity;
2421 return kConcave_Convexity;
2422 }
2423 }
2424 fConvexity = state.getConvexity();
2425 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) {
2426 fDirection = state.getDirection();
2427 }
2428 return static_cast<Convexity>(fConvexity);
2429 }
2430
2431 ///////////////////////////////////////////////////////////////////////////////
2432
2433 class ContourIter {
2434 public:
2435 ContourIter(const SkPathRef& pathRef);
2436
2437 bool done() const { return fDone; }
2438 // if !done() then these may be called
2439 int count() const { return fCurrPtCount; }
2440 const SkPoint* pts() const { return fCurrPt; }
2441 void next();
2442
2443 private:
2444 int fCurrPtCount;
2445 const SkPoint* fCurrPt;
2446 const uint8_t* fCurrVerb;
2447 const uint8_t* fStopVerbs;
2448 const SkScalar* fCurrConicWeight;
2449 bool fDone;
2450 SkDEBUGCODE(int fContourCounter;)
2451 };
2452
2453 ContourIter::ContourIter(const SkPathRef& pathRef) {
2454 fStopVerbs = pathRef.verbsMemBegin();
2455 fDone = false;
2456 fCurrPt = pathRef.points();
2457 fCurrVerb = pathRef.verbs();
2458 fCurrConicWeight = pathRef.conicWeights();
2459 fCurrPtCount = 0;
2460 SkDEBUGCODE(fContourCounter = 0;)
2461 this->next();
2462 }
2463
2464 void ContourIter::next() {
2465 if (fCurrVerb <= fStopVerbs) {
2466 fDone = true;
2467 }
2468 if (fDone) {
2469 return;
2470 }
2471
2472 // skip pts of prev contour
2473 fCurrPt += fCurrPtCount;
2474
2475 SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
2476 int ptCount = 1; // moveTo
2477 const uint8_t* verbs = fCurrVerb;
2478
2479 for (--verbs; verbs > fStopVerbs; --verbs) {
2480 switch (verbs[~0]) {
2481 case SkPath::kMove_Verb:
2482 goto CONTOUR_END;
2483 case SkPath::kLine_Verb:
2484 ptCount += 1;
2485 break;
2486 case SkPath::kConic_Verb:
2487 fCurrConicWeight += 1;
2488 // fall-through
2489 case SkPath::kQuad_Verb:
2490 ptCount += 2;
2491 break;
2492 case SkPath::kCubic_Verb:
2493 ptCount += 3;
2494 break;
2495 case SkPath::kClose_Verb:
2496 break;
2497 default:
2498 SkDEBUGFAIL("unexpected verb");
2499 break;
2500 }
2501 }
2502 CONTOUR_END:
2503 fCurrPtCount = ptCount;
2504 fCurrVerb = verbs;
2505 SkDEBUGCODE(++fContourCounter;)
2506 }
2507
2508 // returns cross product of (p1 - p0) and (p2 - p0)
2509 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
2510 SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
2511 // We may get 0 when the above subtracts underflow. We expect this to be
2512 // very rare and lazily promote to double.
2513 if (0 == cross) {
2514 double p0x = SkScalarToDouble(p0.fX);
2515 double p0y = SkScalarToDouble(p0.fY);
2516
2517 double p1x = SkScalarToDouble(p1.fX);
2518 double p1y = SkScalarToDouble(p1.fY);
2519
2520 double p2x = SkScalarToDouble(p2.fX);
2521 double p2y = SkScalarToDouble(p2.fY);
2522
2523 cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
2524 (p1y - p0y) * (p2x - p0x));
2525
2526 }
2527 return cross;
2528 }
2529
2530 // Returns the first pt with the maximum Y coordinate
2531 static int find_max_y(const SkPoint pts[], int count) {
2532 SkASSERT(count > 0);
2533 SkScalar max = pts[0].fY;
2534 int firstIndex = 0;
2535 for (int i = 1; i < count; ++i) {
2536 SkScalar y = pts[i].fY;
2537 if (y > max) {
2538 max = y;
2539 firstIndex = i;
2540 }
2541 }
2542 return firstIndex;
2543 }
2544
2545 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
2546 int i = index;
2547 for (;;) {
2548 i = (i + inc) % n;
2549 if (i == index) { // we wrapped around, so abort
2550 break;
2551 }
2552 if (pts[index] != pts[i]) { // found a different point, success!
2553 break;
2554 }
2555 }
2556 return i;
2557 }
2558
2559 /**
2560 * Starting at index, and moving forward (incrementing), find the xmin and
2561 * xmax of the contiguous points that have the same Y.
2562 */
2563 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
2564 int* maxIndexPtr) {
2565 const SkScalar y = pts[index].fY;
2566 SkScalar min = pts[index].fX;
2567 SkScalar max = min;
2568 int minIndex = index;
2569 int maxIndex = index;
2570 for (int i = index + 1; i < n; ++i) {
2571 if (pts[i].fY != y) {
2572 break;
2573 }
2574 SkScalar x = pts[i].fX;
2575 if (x < min) {
2576 min = x;
2577 minIndex = i;
2578 } else if (x > max) {
2579 max = x;
2580 maxIndex = i;
2581 }
2582 }
2583 *maxIndexPtr = maxIndex;
2584 return minIndex;
2585 }
2586
2587 static void crossToDir(SkScalar cross, SkPath::Direction* dir) {
2588 if (dir) {
2589 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2590 }
2591 }
2592
2593 #if 0
2594 #include "SkString.h"
2595 #include "../utils/SkParsePath.h"
2596 static void dumpPath(const SkPath& path) {
2597 SkString str;
2598 SkParsePath::ToSVGString(path, &str);
2599 SkDebugf("%s\n", str.c_str());
2600 }
2601 #endif
2602
2603 namespace {
2604 // for use with convex_dir_test
2605 double mul(double a, double b) { return a * b; }
2606 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); }
2607 double toDouble(SkScalar a) { return SkScalarToDouble(a); }
2608 SkScalar toScalar(SkScalar a) { return a; }
2609
2610 // determines the winding direction of a convex polygon with the precision
2611 // of T. CAST_SCALAR casts an SkScalar to T.
2612 template <typename T, T (CAST_SCALAR)(SkScalar)>
2613 bool convex_dir_test(int n, const SkPoint pts[], SkPath::Direction* dir) {
2614 // we find the first three points that form a non-degenerate
2615 // triangle. If there are no such points then the path is
2616 // degenerate. The first is always point 0. Now we find the second
2617 // point.
2618 int i = 0;
2619 enum { kX = 0, kY = 1 };
2620 T v0[2];
2621 while (1) {
2622 v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2623 v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2624 if (v0[kX] || v0[kY]) {
2625 break;
2626 }
2627 if (++i == n - 1) {
2628 return false;
2629 }
2630 }
2631 // now find a third point that is not colinear with the first two
2632 // points and check the orientation of the triangle (which will be
2633 // the same as the orientation of the path).
2634 for (++i; i < n; ++i) {
2635 T v1[2];
2636 v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2637 v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2638 T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]);
2639 if (0 != cross) {
2640 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2641 return true;
2642 }
2643 }
2644 return false;
2645 }
2646 }
2647
2648 /*
2649 * We loop through all contours, and keep the computed cross-product of the
2650 * contour that contained the global y-max. If we just look at the first
2651 * contour, we may find one that is wound the opposite way (correctly) since
2652 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2653 * that is outer most (or at least has the global y-max) before we can consider
2654 * its cross product.
2655 */
2656 bool SkPath::cheapComputeDirection(Direction* dir) const {
2657 // dumpPath(*this);
2658 // don't want to pay the cost for computing this if it
2659 // is unknown, so we don't call isConvex()
2660
2661 if (kUnknown_Direction != fDirection) {
2662 *dir = static_cast<Direction>(fDirection);
2663 return true;
2664 }
2665 const Convexity conv = this->getConvexityOrUnknown();
2666
2667 ContourIter iter(*fPathRef.get());
2668
2669 // initialize with our logical y-min
2670 SkScalar ymax = this->getBounds().fTop;
2671 SkScalar ymaxCross = 0;
2672
2673 for (; !iter.done(); iter.next()) {
2674 int n = iter.count();
2675 if (n < 3) {
2676 continue;
2677 }
2678
2679 const SkPoint* pts = iter.pts();
2680 SkScalar cross = 0;
2681 if (kConvex_Convexity == conv) {
2682 // We try first at scalar precision, and then again at double
2683 // precision. This is because the vectors computed between distant
2684 // points may lose too much precision.
2685 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) {
2686 fDirection = *dir;
2687 return true;
2688 }
2689 if (convex_dir_test<double, toDouble>(n, pts, dir)) {
2690 fDirection = *dir;
2691 return true;
2692 } else {
2693 return false;
2694 }
2695 } else {
2696 int index = find_max_y(pts, n);
2697 if (pts[index].fY < ymax) {
2698 continue;
2699 }
2700
2701 // If there is more than 1 distinct point at the y-max, we take the
2702 // x-min and x-max of them and just subtract to compute the dir.
2703 if (pts[(index + 1) % n].fY == pts[index].fY) {
2704 int maxIndex;
2705 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2706 if (minIndex == maxIndex) {
2707 goto TRY_CROSSPROD;
2708 }
2709 SkASSERT(pts[minIndex].fY == pts[index].fY);
2710 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2711 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2712 // we just subtract the indices, and let that auto-convert to
2713 // SkScalar, since we just want - or + to signal the direction.
2714 cross = minIndex - maxIndex;
2715 } else {
2716 TRY_CROSSPROD:
2717 // Find a next and prev index to use for the cross-product test,
2718 // but we try to find pts that form non-zero vectors from pts[in dex]
2719 //
2720 // Its possible that we can't find two non-degenerate vectors, s o
2721 // we have to guard our search (e.g. all the pts could be in the
2722 // same place).
2723
2724 // we pass n - 1 instead of -1 so we don't foul up % operator by
2725 // passing it a negative LH argument.
2726 int prev = find_diff_pt(pts, index, n, n - 1);
2727 if (prev == index) {
2728 // completely degenerate, skip to next contour
2729 continue;
2730 }
2731 int next = find_diff_pt(pts, index, n, 1);
2732 SkASSERT(next != index);
2733 cross = cross_prod(pts[prev], pts[index], pts[next]);
2734 // if we get a zero and the points are horizontal, then we look at the spread in
2735 // x-direction. We really should continue to walk away from the degeneracy until
2736 // there is a divergence.
2737 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
2738 // construct the subtract so we get the correct Direction be low
2739 cross = pts[index].fX - pts[next].fX;
2740 }
2741 }
2742
2743 if (cross) {
2744 // record our best guess so far
2745 ymax = pts[index].fY;
2746 ymaxCross = cross;
2747 }
2748 }
2749 }
2750 if (ymaxCross) {
2751 crossToDir(ymaxCross, dir);
2752 fDirection = *dir;
2753 return true;
2754 } else {
2755 return false;
2756 }
2757 }
2758 2126
2759 /////////////////////////////////////////////////////////////////////////////// 2127 ///////////////////////////////////////////////////////////////////////////////
2760 2128
2761 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, 2129 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
2762 SkScalar D, SkScalar t) { 2130 SkScalar D, SkScalar t) {
2763 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); 2131 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
2764 } 2132 }
2765 2133
2766 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c 3, 2134 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c 3,
2767 SkScalar t) { 2135 SkScalar t) {
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
3002 switch (this->getFillType()) { 2370 switch (this->getFillType()) {
3003 case SkPath::kEvenOdd_FillType: 2371 case SkPath::kEvenOdd_FillType:
3004 case SkPath::kInverseEvenOdd_FillType: 2372 case SkPath::kInverseEvenOdd_FillType:
3005 w &= 1; 2373 w &= 1;
3006 break; 2374 break;
3007 default: 2375 default:
3008 break; 2376 break;
3009 } 2377 }
3010 return SkToBool(w); 2378 return SkToBool(w);
3011 } 2379 }
OLDNEW
« no previous file with comments | « include/core/SkPathRef.h ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698