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

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
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);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 - we insert a Move(0,0) if Line | Quad | Cubic is our first command 98 - we insert a Move(0,0) if Line | Quad | Cubic is our first command
134 99
135 The iterator does more cleanup, especially if forceClose == true 100 The iterator does more cleanup, especially if forceClose == true
136 1. If we encounter degenerate segments, remove them 101 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) 102 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 103 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 104 4. if we encounter Line | Quad | Cubic after Close, cons up a Move
140 */ 105 */
141 106
142 //////////////////////////////////////////////////////////////////////////// 107 ////////////////////////////////////////////////////////////////////////////
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() 108 SkPath::SkPath()
148 : fPathRef(SkPathRef::CreateEmpty()) 109 : fPathRef(SkPathRef::CreateEmpty())
149 #ifdef SK_BUILD_FOR_ANDROID 110 #ifdef SK_BUILD_FOR_ANDROID
150 , fGenerationID(0) 111 , fGenerationID(0)
151 #endif 112 #endif
152 { 113 {
153 this->resetFields(); 114 this->resetFields();
154 } 115 }
155 116
156 void SkPath::resetFields() { 117 void SkPath::resetFields() {
157 //fPathRef is assumed to have been emptied by the caller. 118 //fPathRef is assumed to have been emptied by the caller.
158 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE;
159 fFillType = kWinding_FillType; 119 fFillType = kWinding_FillType;
160 fSegmentMask = 0;
161 fConvexity = kUnknown_Convexity;
162 fDirection = kUnknown_Direction;
163 fIsOval = false;
164 #ifdef SK_BUILD_FOR_ANDROID 120 #ifdef SK_BUILD_FOR_ANDROID
165 GEN_ID_INC; 121 GEN_ID_INC;
166 // We don't touch fSourcePath. It's used to track texture garbage collectio n, so we don't 122 // 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. 123 // want to muck with it if it's been set to something non-NULL.
168 #endif 124 #endif
169 } 125 }
170 126
171 SkPath::SkPath(const SkPath& that) 127 SkPath::SkPath(const SkPath& that)
172 : fPathRef(SkRef(that.fPathRef.get())) { 128 : fPathRef(SkRef(that.fPathRef.get())) {
173 this->copyFields(that); 129 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. 148 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go back in time.
193 fSourcePath = that.fSourcePath; 149 fSourcePath = that.fSourcePath;
194 #endif 150 #endif
195 } 151 }
196 SkDEBUGCODE(this->validate();) 152 SkDEBUGCODE(this->validate();)
197 return *this; 153 return *this;
198 } 154 }
199 155
200 void SkPath::copyFields(const SkPath& that) { 156 void SkPath::copyFields(const SkPath& that) {
201 //fPathRef is assumed to have been set by the caller. 157 //fPathRef is assumed to have been set by the caller.
202 fLastMoveToIndex = that.fLastMoveToIndex;
203 fFillType = that.fFillType; 158 fFillType = that.fFillType;
204 fSegmentMask = that.fSegmentMask;
205 fConvexity = that.fConvexity;
206 fDirection = that.fDirection;
207 fIsOval = that.fIsOval;
208 } 159 }
209 160
210 bool operator==(const SkPath& a, const SkPath& b) { 161 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 || 162 return &a == &b ||
219 (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && 163 (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get());
220 *a.fPathRef.get() == *b.fPathRef.get());
221 } 164 }
222 165
223 void SkPath::swap(SkPath& that) { 166 void SkPath::swap(SkPath& that) {
224 SkASSERT(&that != NULL); 167 SkASSERT(&that != NULL);
225 168
226 if (this != &that) { 169 if (this != &that) {
227 fPathRef.swap(&that.fPathRef); 170 fPathRef.swap(&that.fPathRef);
228 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex);
229 SkTSwap<uint8_t>(fFillType, that.fFillType); 171 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 172 #ifdef SK_BUILD_FOR_ANDROID
235 // It doesn't really make sense to swap the generation IDs here, because they might go 173 // 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 . 174 // backwards. To be safe we increment both to mark them both as changed .
237 GEN_ID_INC; 175 GEN_ID_INC;
238 GEN_ID_PTR_INC(&that); 176 GEN_ID_PTR_INC(&that);
239 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); 177 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath);
240 #endif 178 #endif
241 } 179 }
242 } 180 }
243 181
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 Single points on the rectangle side. 341 Single points on the rectangle side.
404 342
405 The direction takes advantage of the corners found since opposite sides 343 The direction takes advantage of the corners found since opposite sides
406 must travel in opposite directions. 344 must travel in opposite directions.
407 345
408 FIXME: Allow colinear quads and cubics to be treated like lines. 346 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 347 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. 348 is a rectangle, though the caller failed to close the path.
411 */ 349 */
412 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts Ptr, 350 bool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts Ptr,
413 bool* isClosed, Direction* direction) const { 351 bool* isClosed, Direction* direction) const {
414 int corners = 0; 352 int corners = 0;
415 SkPoint first, last; 353 SkPoint first, last;
416 const SkPoint* pts = *ptsPtr; 354 const SkPoint* pts = *ptsPtr;
417 const SkPoint* savePts = NULL; 355 const SkPoint* savePts = NULL;
418 first.set(0, 0); 356 first.set(0, 0);
419 last.set(0, 0); 357 last.set(0, 0);
420 int firstDirection = 0; 358 int firstDirection = 0;
421 int lastDirection = 0; 359 int lastDirection = 0;
422 int nextDirection = 0; 360 int nextDirection = 0;
423 bool closedOrMoved = false; 361 bool closedOrMoved = false;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 return false; 561 return false;
624 } 562 }
625 563
626 void SkPath::setLastPt(SkScalar x, SkScalar y) { 564 void SkPath::setLastPt(SkScalar x, SkScalar y) {
627 SkDEBUGCODE(this->validate();) 565 SkDEBUGCODE(this->validate();)
628 566
629 int count = fPathRef->countPoints(); 567 int count = fPathRef->countPoints();
630 if (count == 0) { 568 if (count == 0) {
631 this->moveTo(x, y); 569 this->moveTo(x, y);
632 } else { 570 } else {
633 fIsOval = false; 571 fPathRef->setIsOval(false);
634 SkPathRef::Editor ed(&fPathRef); 572 SkPathRef::Editor ed(&fPathRef);
635 ed.atPoint(count-1)->set(x, y); 573 ed.atPoint(count-1)->set(x, y);
636 GEN_ID_INC; 574 GEN_ID_INC;
637 } 575 }
638 } 576 }
639 577
640 void SkPath::setConvexity(Convexity c) { 578 void SkPath::setConvexity(Convexity c) {
641 if (fConvexity != c) { 579 if (fPathRef->getConvexity() != static_cast<SkPathRef::Convexity>(c)) {
642 fConvexity = c; 580 fPathRef->setConvexity(static_cast<SkPathRef::Convexity>(c));
643 GEN_ID_INC; 581 GEN_ID_INC;
644 } 582 }
645 } 583 }
646 584
647 ////////////////////////////////////////////////////////////////////////////// 585 //////////////////////////////////////////////////////////////////////////////
648 // Construction methods 586 // Construction methods
649 587
650 #define DIRTY_AFTER_EDIT \ 588 #define DIRTY_AFTER_EDIT \
651 do { \ 589 do { \
652 fConvexity = kUnknown_Convexity; \ 590 fConvexity = kUnknown_Convexity; \
653 fDirection = kUnknown_Direction; \ 591 fDirection = kUnknown_Direction; \
654 fIsOval = false; \ 592 fIsOval = false; \
655 } while (0) 593 } while (0)
656 594
657 void SkPath::incReserve(U16CPU inc) { 595 void SkPath::incReserve(U16CPU inc) {
658 SkDEBUGCODE(this->validate();) 596 SkDEBUGCODE(this->validate();)
659 SkPathRef::Editor(&fPathRef, inc, inc); 597 SkPathRef::Editor(&fPathRef, inc, inc);
660 SkDEBUGCODE(this->validate();) 598 SkDEBUGCODE(this->validate();)
661 } 599 }
662 600
663 void SkPath::moveTo(SkScalar x, SkScalar y) { 601 void SkPath::moveTo(SkScalar x, SkScalar y) {
664 SkDEBUGCODE(this->validate();) 602 SkDEBUGCODE(this->validate();)
665 603
666 SkPathRef::Editor ed(&fPathRef); 604 SkPathRef::Editor ed(&fPathRef);
667 605
668 // remember our index 606 ed.growForVerb(SkPathRef::kMove_Verb)->set(x, y);
669 fLastMoveToIndex = ed.pathRef()->countPoints();
670
671 ed.growForVerb(kMove_Verb)->set(x, y);
672 607
673 GEN_ID_INC; 608 GEN_ID_INC;
674 } 609 }
675 610
676 void SkPath::rMoveTo(SkScalar x, SkScalar y) { 611 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
677 SkPoint pt; 612 SkPoint pt;
678 this->getLastPt(&pt); 613 this->getLastPt(&pt);
679 this->moveTo(pt.fX + x, pt.fY + y); 614 this->moveTo(pt.fX + x, pt.fY + y);
680 } 615 }
681 616
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) { 617 void SkPath::lineTo(SkScalar x, SkScalar y) {
697 SkDEBUGCODE(this->validate();) 618 SkDEBUGCODE(this->validate();)
698 619
699 this->injectMoveToIfNeeded();
700
701 SkPathRef::Editor ed(&fPathRef); 620 SkPathRef::Editor ed(&fPathRef);
702 ed.growForVerb(kLine_Verb)->set(x, y); 621 ed.growForVerb(SkPathRef::kLine_Verb)->set(x, y);
703 fSegmentMask |= kLine_SegmentMask;
704 622
705 GEN_ID_INC; 623 GEN_ID_INC;
706 DIRTY_AFTER_EDIT;
707 } 624 }
708 625
709 void SkPath::rLineTo(SkScalar x, SkScalar y) { 626 void SkPath::rLineTo(SkScalar x, SkScalar y) {
710 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 627 SkDEBUGCODE(this->validate();)
711 SkPoint pt; 628
712 this->getLastPt(&pt); 629 SkPathRef::Editor ed(&fPathRef);
713 this->lineTo(pt.fX + x, pt.fY + y); 630 SkPoint* dst = ed.growForVerb(SkPathRef::kLine_Verb);
631
632 // growForVerb can change the result of this->getPoint().
633 SkASSERT(this->countPoints() >= 2);
634 SkPoint pt = this->getPoint(this->countPoints() - 2);
635
636 dst->set(pt.fX + x, pt.fY + y);
637 GEN_ID_INC;
714 } 638 }
715 639
716 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 640 void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
717 SkDEBUGCODE(this->validate();) 641 SkDEBUGCODE(this->validate();)
718 642
719 this->injectMoveToIfNeeded();
720
721 SkPathRef::Editor ed(&fPathRef); 643 SkPathRef::Editor ed(&fPathRef);
722 SkPoint* pts = ed.growForVerb(kQuad_Verb); 644 SkPoint* pts = ed.growForVerb(SkPathRef::kQuad_Verb);
723 pts[0].set(x1, y1); 645 pts[0].set(x1, y1);
724 pts[1].set(x2, y2); 646 pts[1].set(x2, y2);
725 fSegmentMask |= kQuad_SegmentMask;
726 647
727 GEN_ID_INC; 648 GEN_ID_INC;
728 DIRTY_AFTER_EDIT;
729 } 649 }
730 650
731 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 651 void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
732 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 652 SkDEBUGCODE(this->validate();)
733 SkPoint pt; 653
734 this->getLastPt(&pt); 654 SkPathRef::Editor ed(&fPathRef);
735 this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); 655 SkPoint* pts = ed.growForVerb(SkPathRef::kQuad_Verb);
656
657 // growForVerb can change the result of this->getPoint().
658 SkASSERT(this->countPoints() >= 3);
659 SkPoint pt = this->getPoint(this->countPoints() - 3);
660
661 pts[0].set(pt.fX + x1, pt.fY + y1);
662 pts[1].set(pt.fX + x2, pt.fY + y2);
663
664 GEN_ID_INC;
736 } 665 }
737 666
738 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 667 void SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
739 SkScalar w) { 668 SkScalar w) {
740 // check for <= 0 or NaN with this test 669 // check for <= 0 or NaN with this test
741 if (!(w > 0)) { 670 if (!(w > 0)) {
742 this->lineTo(x2, y2); 671 this->lineTo(x2, y2);
743 } else if (!SkScalarIsFinite(w)) { 672 } else if (!SkScalarIsFinite(w)) {
744 this->lineTo(x1, y1); 673 this->lineTo(x1, y1);
745 this->lineTo(x2, y2); 674 this->lineTo(x2, y2);
746 } else if (SK_Scalar1 == w) { 675 } else if (SK_Scalar1 == w) {
747 this->quadTo(x1, y1, x2, y2); 676 this->quadTo(x1, y1, x2, y2);
748 } else { 677 } else {
749 SkDEBUGCODE(this->validate();) 678 SkDEBUGCODE(this->validate();)
750 679
751 this->injectMoveToIfNeeded();
752
753 SkPathRef::Editor ed(&fPathRef); 680 SkPathRef::Editor ed(&fPathRef);
754 SkPoint* pts = ed.growForConic(w); 681 SkPoint* pts = ed.growForConic(w);
755 pts[0].set(x1, y1); 682 pts[0].set(x1, y1);
756 pts[1].set(x2, y2); 683 pts[1].set(x2, y2);
757 fSegmentMask |= kConic_SegmentMask;
758 684
759 GEN_ID_INC; 685 GEN_ID_INC;
760 DIRTY_AFTER_EDIT;
761 } 686 }
762 } 687 }
763 688
764 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 689 void SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
765 SkScalar w) { 690 SkScalar w) {
766 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 691 // check for <= 0 or NaN with this test
767 SkPoint pt; 692 if (!(w > 0)) {
768 this->getLastPt(&pt); 693 this->rLineTo(dx2, dy2);
769 this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); 694 } else if (!SkScalarIsFinite(w)) {
695 this->rLineTo(dx1, dy1);
696 this->rLineTo(dx2, dy2);
697 } else if (SK_Scalar1 == w) {
698 this->rQuadTo(dx1, dy1, dx2, dy2);
699 } else {
700 SkDEBUGCODE(this->validate();)
701
702 SkPathRef::Editor ed(&fPathRef);
703 SkPoint* pts = ed.growForConic(w);
704
705 // growForConic can change the result of this->getPoint().
706 SkASSERT(this->countPoints() >= 3);
707 SkPoint pt = this->getPoint(this->countPoints() - 3);
708
709 pts[0].set(pt.fX + dx1, pt.fY + dy1);
710 pts[1].set(pt.fX + dx2, pt.fY + dy2);
711
712 GEN_ID_INC;
713 }
770 } 714 }
771 715
772 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 716 void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
773 SkScalar x3, SkScalar y3) { 717 SkScalar x3, SkScalar y3) {
774 SkDEBUGCODE(this->validate();) 718 SkDEBUGCODE(this->validate();)
775 719
776 this->injectMoveToIfNeeded();
777
778 SkPathRef::Editor ed(&fPathRef); 720 SkPathRef::Editor ed(&fPathRef);
779 SkPoint* pts = ed.growForVerb(kCubic_Verb); 721 SkPoint* pts = ed.growForVerb(SkPathRef::kCubic_Verb);
780 pts[0].set(x1, y1); 722 pts[0].set(x1, y1);
781 pts[1].set(x2, y2); 723 pts[1].set(x2, y2);
782 pts[2].set(x3, y3); 724 pts[2].set(x3, y3);
783 fSegmentMask |= kCubic_SegmentMask;
784 725
785 GEN_ID_INC; 726 GEN_ID_INC;
786 DIRTY_AFTER_EDIT;
787 } 727 }
788 728
789 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 729 void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
790 SkScalar x3, SkScalar y3) { 730 SkScalar x3, SkScalar y3) {
791 this->injectMoveToIfNeeded(); // This can change the result of this->getLas tPt(). 731 SkDEBUGCODE(this->validate();)
792 SkPoint pt; 732
793 this->getLastPt(&pt); 733 SkPathRef::Editor ed(&fPathRef);
794 this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, 734 SkPoint* pts = ed.growForVerb(SkPathRef::kCubic_Verb);
795 pt.fX + x3, pt.fY + y3); 735
736 // growForVerb can change the result of this->getPoint().
737 SkASSERT(this->countPoints() >= 4);
738 SkPoint pt = this->getPoint(this->countPoints() - 4);
739
740 pts[0].set(pt.fX + x1, pt.fY + y1);
741 pts[1].set(pt.fX + x2, pt.fY + y2);
742 pts[2].set(pt.fX + x3, pt.fY + y3);
743
744 GEN_ID_INC;
796 } 745 }
797 746
798 void SkPath::close() { 747 void SkPath::close() {
799 SkDEBUGCODE(this->validate();) 748 SkDEBUGCODE(this->validate();)
800 749
801 int count = fPathRef->countVerbs(); 750 int count = fPathRef->countVerbs();
802 if (count > 0) { 751 if (count > 0) {
803 switch (fPathRef->atVerb(count - 1)) { 752 switch (fPathRef->atVerb(count - 1)) {
804 case kLine_Verb: 753 case kLine_Verb:
805 case kQuad_Verb: 754 case kQuad_Verb:
806 case kConic_Verb: 755 case kConic_Verb:
807 case kCubic_Verb: 756 case kCubic_Verb:
808 case kMove_Verb: { 757 case kMove_Verb: {
809 SkPathRef::Editor ed(&fPathRef); 758 SkPathRef::Editor ed(&fPathRef);
810 ed.growForVerb(kClose_Verb); 759 ed.growForVerb(SkPathRef::kClose_Verb);
811 GEN_ID_INC; 760 GEN_ID_INC;
812 break; 761 break;
813 } 762 }
814 case kClose_Verb: 763 case kClose_Verb:
815 // don't add a close if it's the first verb or a repeat 764 // don't add a close if it's the first verb or a repeat
816 break; 765 break;
817 default: 766 default:
818 SkDEBUGFAIL("unexpected verb"); 767 SkDEBUGFAIL("unexpected verb");
819 break; 768 break;
820 } 769 }
821 } 770 }
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 } 771 }
832 772
833 /////////////////////////////////////////////////////////////////////////////// 773 ///////////////////////////////////////////////////////////////////////////////
834 774
835 static void assert_known_direction(int dir) { 775 static void assert_known_direction(int dir) {
836 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); 776 SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir);
837 } 777 }
838 778
839 void SkPath::addRect(const SkRect& rect, Direction dir) { 779 void SkPath::addRect(const SkRect& rect, Direction dir) {
840 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir); 780 this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
841 } 781 }
842 782
843 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, 783 void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right,
844 SkScalar bottom, Direction dir) { 784 SkScalar bottom, Direction dir) {
845 assert_known_direction(dir); 785 assert_known_direction(dir);
846 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 786 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
847 SkAutoDisableDirectionCheck addc(this);
848 787
849 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom); 788 SkAutoPathBoundsUpdate apbu(this, left, top, right, bottom);
850 789
851 this->incReserve(5); 790 this->incReserve(5);
852 791
853 this->moveTo(left, top); 792 this->moveTo(left, top);
854 if (dir == kCCW_Direction) { 793 if (dir == kCCW_Direction) {
855 this->lineTo(left, bottom); 794 this->lineTo(left, bottom);
856 this->lineTo(right, bottom); 795 this->lineTo(right, bottom);
857 this->lineTo(right, top); 796 this->lineTo(right, top);
858 } else { 797 } else {
859 this->lineTo(right, top); 798 this->lineTo(right, top);
860 this->lineTo(right, bottom); 799 this->lineTo(right, bottom);
861 this->lineTo(left, bottom); 800 this->lineTo(left, bottom);
862 } 801 }
863 this->close(); 802 this->close();
803
804 fPathRef->setDirection(static_cast<SkPathRef::Direction>(newDir));
864 } 805 }
865 806
866 void SkPath::addPoly(const SkPoint pts[], int count, bool close) { 807 void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
867 SkDEBUGCODE(this->validate();) 808 SkDEBUGCODE(this->validate();)
868 if (count <= 0) { 809 if (count <= 0) {
869 return; 810 return;
870 } 811 }
871 812
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 813 // +close makes room for the extra kClose_Verb
877 ed.grow(count + close, count, &vb, &p); 814 SkPathRef::Editor ed(&fPathRef, count+close, count);
878 815
879 memcpy(p, pts, count * sizeof(SkPoint)); 816 ed.growForVerb(SkPathRef::kMove_Verb)->set(pts[0].fX, pts[0].fY);
880 vb[~0] = kMove_Verb; 817
881 if (count > 1) { 818 if (count > 1) {
882 // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to 819 SkPoint* p = ed.growForLines(count - 1);
883 // be 0, the compiler will remove the test/branch entirely. 820
884 if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) { 821 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 } 822 }
823
893 if (close) { 824 if (close) {
894 vb[~count] = kClose_Verb; 825 ed.growForVerb(SkPathRef::kClose_Verb);
895 } 826 }
896 827
897 GEN_ID_INC; 828 GEN_ID_INC;
898 DIRTY_AFTER_EDIT;
899 SkDEBUGCODE(this->validate();) 829 SkDEBUGCODE(this->validate();)
900 } 830 }
901 831
902 static void add_corner_arc(SkPath* path, const SkRect& rect, 832 static void add_corner_arc(SkPath* path, const SkRect& rect,
903 SkScalar rx, SkScalar ry, int startAngle, 833 SkScalar rx, SkScalar ry, int startAngle,
904 SkPath::Direction dir, bool forceMoveTo) { 834 SkPath::Direction dir, bool forceMoveTo) {
905 // These two asserts are not sufficient, since really we want to know 835 // These two asserts are not sufficient, since really we want to know
906 // that the pair of radii (e.g. left and right, or top and bottom) sum 836 // that the pair of radii (e.g. left and right, or top and bottom) sum
907 // to <= dimension, but we don't have that data here, so we just have 837 // to <= dimension, but we don't have that data here, so we just have
908 // these conservative asserts. 838 // these conservative asserts.
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
984 *verbs == kCubic_Verb) { 914 *verbs == kCubic_Verb) {
985 return false; 915 return false;
986 } 916 }
987 ++verbs; 917 ++verbs;
988 } 918 }
989 return true; 919 return true;
990 } 920 }
991 921
992 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) 922 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
993 923
994 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 924 void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Directio n dir) {
995 Direction dir) {
996 assert_known_direction(dir); 925 assert_known_direction(dir);
997 926
998 if (rx < 0 || ry < 0) { 927 if (rx < 0 || ry < 0) {
999 SkErrorInternals::SetError( kInvalidArgument_SkError, 928 SkErrorInternals::SetError( kInvalidArgument_SkError,
1000 "I got %f and %f as radii to SkPath::AddRoun dRect, " 929 "I got %f and %f as radii to SkPath::AddRoun dRect, "
1001 "but negative radii are not allowed.", 930 "but negative radii are not allowed.",
1002 SkScalarToDouble(rx), SkScalarToDouble(ry) ) ; 931 SkScalarToDouble(rx), SkScalarToDouble(ry) ) ;
1003 return; 932 return;
1004 } 933 }
1005 934
1006 SkScalar w = rect.width(); 935 SkScalar w = rect.width();
1007 SkScalar halfW = SkScalarHalf(w); 936 SkScalar halfW = SkScalarHalf(w);
1008 SkScalar h = rect.height(); 937 SkScalar h = rect.height();
1009 SkScalar halfH = SkScalarHalf(h); 938 SkScalar halfH = SkScalarHalf(h);
1010 939
1011 if (halfW <= 0 || halfH <= 0) { 940 if (halfW <= 0 || halfH <= 0) {
1012 return; 941 return;
1013 } 942 }
1014 943
1015 bool skip_hori = rx >= halfW; 944 bool skip_hori = rx >= halfW;
1016 bool skip_vert = ry >= halfH; 945 bool skip_vert = ry >= halfH;
1017 946
1018 if (skip_hori && skip_vert) { 947 if (skip_hori && skip_vert) {
1019 this->addOval(rect, dir); 948 this->addOval(rect, dir);
1020 return; 949 return;
1021 } 950 }
1022 951
1023 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 952 Direction newDir = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
1024 953
1025 SkAutoPathBoundsUpdate apbu(this, rect); 954 SkAutoPathBoundsUpdate apbu(this, rect);
1026 SkAutoDisableDirectionCheck(this);
1027 955
1028 if (skip_hori) { 956 if (skip_hori) {
1029 rx = halfW; 957 rx = halfW;
1030 } else if (skip_vert) { 958 } else if (skip_vert) {
1031 ry = halfH; 959 ry = halfH;
1032 } 960 }
1033 961
1034 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); 962 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
1035 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); 963 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
1036 964
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1081 this->lineTo(rect.fLeft, rect.fTop + ry); // left 1009 this->lineTo(rect.fLeft, rect.fTop + ry); // left
1082 } 1010 }
1083 this->cubicTo(rect.fLeft, rect.fTop + ry - sy, 1011 this->cubicTo(rect.fLeft, rect.fTop + ry - sy,
1084 rect.fLeft + rx - sx, rect.fTop, 1012 rect.fLeft + rx - sx, rect.fTop,
1085 rect.fLeft + rx, rect.fTop); // top-left 1013 rect.fLeft + rx, rect.fTop); // top-left
1086 if (!skip_hori) { 1014 if (!skip_hori) {
1087 this->lineTo(rect.fRight - rx, rect.fTop); // top 1015 this->lineTo(rect.fRight - rx, rect.fTop); // top
1088 } 1016 }
1089 } 1017 }
1090 this->close(); 1018 this->close();
1019
1020 fPathRef->setDirection(static_cast<SkPathRef::Direction>(newDir));
1091 } 1021 }
1092 1022
1093 void SkPath::addOval(const SkRect& oval, Direction dir) { 1023 void SkPath::addOval(const SkRect& oval, Direction dir) {
1094 assert_known_direction(dir); 1024 assert_known_direction(dir);
1095 1025
1096 /* If addOval() is called after previous moveTo(), 1026 /* If addOval() is called after previous moveTo(),
1097 this path is still marked as an oval. This is used to 1027 this path is still marked as an oval. This is used to
1098 fit into WebKit's calling sequences. 1028 fit into WebKit's calling sequences.
1099 We can't simply check isEmpty() in this case, as additional 1029 We can't simply check isEmpty() in this case, as additional
1100 moveTo() would mark the path non empty. 1030 moveTo() would mark the path non empty.
1101 */ 1031 */
1102 fIsOval = hasOnlyMoveTos(); 1032 bool isOval = this->hasOnlyMoveTos();
1103 if (fIsOval) { 1033 Direction newDir = isOval ? dir : kUnknown_Direction;
1104 fDirection = dir;
1105 } else {
1106 fDirection = kUnknown_Direction;
1107 }
1108
1109 SkAutoDisableOvalCheck adoc(this);
1110 SkAutoDisableDirectionCheck addc(this);
1111 1034
1112 SkAutoPathBoundsUpdate apbu(this, oval); 1035 SkAutoPathBoundsUpdate apbu(this, oval);
1113 1036
1114 SkScalar cx = oval.centerX(); 1037 SkScalar cx = oval.centerX();
1115 SkScalar cy = oval.centerY(); 1038 SkScalar cy = oval.centerY();
1116 SkScalar rx = SkScalarHalf(oval.width()); 1039 SkScalar rx = SkScalarHalf(oval.width());
1117 SkScalar ry = SkScalarHalf(oval.height()); 1040 SkScalar ry = SkScalarHalf(oval.height());
1118 1041
1119 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); 1042 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
1120 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); 1043 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
(...skipping 26 matching lines...) Expand all
1147 this->quadTo( R, cy + sy, cx + mx, cy + my); 1070 this->quadTo( R, cy + sy, cx + mx, cy + my);
1148 this->quadTo(cx + sx, B, cx , B); 1071 this->quadTo(cx + sx, B, cx , B);
1149 this->quadTo(cx - sx, B, cx - mx, cy + my); 1072 this->quadTo(cx - sx, B, cx - mx, cy + my);
1150 this->quadTo( L, cy + sy, L, cy ); 1073 this->quadTo( L, cy + sy, L, cy );
1151 this->quadTo( L, cy - sy, cx - mx, cy - my); 1074 this->quadTo( L, cy - sy, cx - mx, cy - my);
1152 this->quadTo(cx - sx, T, cx , T); 1075 this->quadTo(cx - sx, T, cx , T);
1153 this->quadTo(cx + sx, T, cx + mx, cy - my); 1076 this->quadTo(cx + sx, T, cx + mx, cy - my);
1154 this->quadTo( R, cy - sy, R, cy ); 1077 this->quadTo( R, cy - sy, R, cy );
1155 } 1078 }
1156 this->close(); 1079 this->close();
1157 }
1158 1080
1159 bool SkPath::isOval(SkRect* rect) const { 1081 fPathRef->setIsOval(isOval);
1160 if (fIsOval && rect) { 1082 fPathRef->setDirection(static_cast<SkPathRef::Direction>(newDir));
1161 *rect = getBounds();
1162 }
1163
1164 return fIsOval;
1165 } 1083 }
1166 1084
1167 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { 1085 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
1168 if (r > 0) { 1086 if (r > 0) {
1169 SkRect rect; 1087 SkRect rect;
1170 rect.set(x - r, y - r, x + r, y + r); 1088 rect.set(x - r, y - r, x + r, y + r);
1171 this->addOval(rect, dir); 1089 this->addOval(rect, dir);
1172 } 1090 }
1173 } 1091 }
1174 1092
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) { 1270 void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
1353 SkMatrix matrix; 1271 SkMatrix matrix;
1354 1272
1355 matrix.setTranslate(dx, dy); 1273 matrix.setTranslate(dx, dy);
1356 this->addPath(path, matrix); 1274 this->addPath(path, matrix);
1357 } 1275 }
1358 1276
1359 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) { 1277 void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
1360 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); 1278 SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints());
1361 1279
1362 fIsOval = false; 1280 fPathRef->setIsOval(false);
1363 1281
1364 RawIter iter(path); 1282 RawIter iter(path);
1365 SkPoint pts[4]; 1283 SkPoint pts[4];
1366 Verb verb; 1284 Verb verb;
1367 1285
1368 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); 1286 SkMatrix::MapPtsProc proc = matrix.getMapPtsProc();
1369 1287
1370 while ((verb = iter.next(pts)) != kDone_Verb) { 1288 while ((verb = iter.next(pts)) != kDone_Verb) {
1371 switch (verb) { 1289 switch (verb) {
1372 case kMove_Verb: 1290 case kMove_Verb:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1418 // ignore the initial moveto, and stop when the 1st contour ends 1336 // ignore the initial moveto, and stop when the 1st contour ends
1419 void SkPath::pathTo(const SkPath& path) { 1337 void SkPath::pathTo(const SkPath& path) {
1420 int i, vcount = path.fPathRef->countVerbs(); 1338 int i, vcount = path.fPathRef->countVerbs();
1421 // exit early if the path is empty, or just has a moveTo. 1339 // exit early if the path is empty, or just has a moveTo.
1422 if (vcount < 2) { 1340 if (vcount < 2) {
1423 return; 1341 return;
1424 } 1342 }
1425 1343
1426 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1344 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1427 1345
1428 fIsOval = false; 1346 fPathRef->setIsOval(false);
1429 1347
1430 const uint8_t* verbs = path.fPathRef->verbs(); 1348 const uint8_t* verbs = path.fPathRef->verbs();
1431 // skip the initial moveTo 1349 // skip the initial moveTo
1432 const SkPoint* pts = path.fPathRef->points() + 1; 1350 const SkPoint* pts = path.fPathRef->points() + 1;
1433 const SkScalar* conicWeight = path.fPathRef->conicWeights(); 1351 const SkScalar* conicWeight = path.fPathRef->conicWeights();
1434 1352
1435 SkASSERT(verbs[~0] == kMove_Verb); 1353 SkASSERT(verbs[~0] == kMove_Verb);
1436 for (i = 1; i < vcount; i++) { 1354 for (i = 1; i < vcount; i++) {
1437 switch (verbs[~i]) { 1355 switch (verbs[~i]) {
1438 case kLine_Verb: 1356 case kLine_Verb:
(...skipping 18 matching lines...) Expand all
1457 // ignore the last point of the 1st contour 1375 // ignore the last point of the 1st contour
1458 void SkPath::reversePathTo(const SkPath& path) { 1376 void SkPath::reversePathTo(const SkPath& path) {
1459 int i, vcount = path.fPathRef->countVerbs(); 1377 int i, vcount = path.fPathRef->countVerbs();
1460 // exit early if the path is empty, or just has a moveTo. 1378 // exit early if the path is empty, or just has a moveTo.
1461 if (vcount < 2) { 1379 if (vcount < 2) {
1462 return; 1380 return;
1463 } 1381 }
1464 1382
1465 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1383 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1466 1384
1467 fIsOval = false; 1385 fPathRef->setIsOval(false);
1468 1386
1469 const uint8_t* verbs = path.fPathRef->verbs(); 1387 const uint8_t* verbs = path.fPathRef->verbs();
1470 const SkPoint* pts = path.fPathRef->points(); 1388 const SkPoint* pts = path.fPathRef->points();
1471 const SkScalar* conicWeights = path.fPathRef->conicWeights(); 1389 const SkScalar* conicWeights = path.fPathRef->conicWeights();
1472 1390
1473 SkASSERT(verbs[~0] == kMove_Verb); 1391 SkASSERT(verbs[~0] == kMove_Verb);
1474 for (i = 1; i < vcount; ++i) { 1392 for (i = 1; i < vcount; ++i) {
1475 unsigned v = verbs[~i]; 1393 unsigned v = verbs[~i];
1476 int n = pts_in_verb(v); 1394 int n = pts_in_verb(v);
1477 if (n == 0) { 1395 if (n == 0) {
(...skipping 20 matching lines...) Expand all
1498 break; 1416 break;
1499 default: 1417 default:
1500 SkDEBUGFAIL("bad verb"); 1418 SkDEBUGFAIL("bad verb");
1501 break; 1419 break;
1502 } 1420 }
1503 pts -= pts_in_verb(verbs[~i]); 1421 pts -= pts_in_verb(verbs[~i]);
1504 } 1422 }
1505 } 1423 }
1506 1424
1507 void SkPath::reverseAddPath(const SkPath& src) { 1425 void SkPath::reverseAddPath(const SkPath& src) {
1508 SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->c ountVerbs()); 1426 SkPathRef::Editor(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->coun tVerbs());
1509 1427
1510 const SkPoint* pts = src.fPathRef->pointsEnd(); 1428 const SkPoint* pts = src.fPathRef->pointsEnd();
1511 // we will iterator through src's verbs backwards 1429 // we will iterator through src's verbs backwards
1512 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb 1430 const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb
1513 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir st verb 1431 const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the fir st verb
1514 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); 1432 const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd();
1515 1433
1516 fIsOval = false; 1434 fPathRef->setIsOval(false);
1517 1435
1518 bool needMove = true; 1436 bool needMove = true;
1519 bool needClose = false; 1437 bool needClose = false;
1520 while (verbs < verbsEnd) { 1438 while (verbs < verbsEnd) {
1521 uint8_t v = *(verbs++); 1439 uint8_t v = *(verbs++);
1522 int n = pts_in_verb(v); 1440 int n = pts_in_verb(v);
1523 1441
1524 if (needMove) { 1442 if (needMove) {
1525 --pts; 1443 --pts;
1526 this->moveTo(pts->fX, pts->fY); 1444 this->moveTo(pts->fX, pts->fY);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1631 break; 1549 break;
1632 default: 1550 default:
1633 SkDEBUGFAIL("unknown verb"); 1551 SkDEBUGFAIL("unknown verb");
1634 break; 1552 break;
1635 } 1553 }
1636 } 1554 }
1637 1555
1638 dst->swap(tmp); 1556 dst->swap(tmp);
1639 SkPathRef::Editor ed(&dst->fPathRef); 1557 SkPathRef::Editor ed(&dst->fPathRef);
1640 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); 1558 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
1641 dst->fDirection = kUnknown_Direction; 1559 dst->setDirection(kUnknown_Direction);
1642 } else { 1560 } else {
1643 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix ); 1561 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix );
1644 1562
1645 if (this != dst) { 1563 if (this != dst) {
1646 dst->fFillType = fFillType; 1564 dst->fFillType = fFillType;
1647 dst->fSegmentMask = fSegmentMask;
1648 dst->fConvexity = fConvexity;
1649 } 1565 }
1650 1566
1651 #ifdef SK_BUILD_FOR_ANDROID 1567 #ifdef SK_BUILD_FOR_ANDROID
1652 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { 1568 if (!matrix.isIdentity() && !dst->hasComputedBounds()) {
1653 GEN_ID_PTR_INC(dst); 1569 GEN_ID_PTR_INC(dst);
1654 } 1570 }
1655 #endif 1571 #endif
1656 1572
1657 if (kUnknown_Direction == fDirection) {
1658 dst->fDirection = kUnknown_Direction;
1659 } else {
1660 SkScalar det2x2 =
1661 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) -
1662 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY));
1663 if (det2x2 < 0) {
1664 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection));
1665 } else if (det2x2 > 0) {
1666 dst->fDirection = fDirection;
1667 } else {
1668 dst->fDirection = kUnknown_Direction;
1669 }
1670 }
1671
1672 // It's an oval only if it stays a rect.
1673 dst->fIsOval = fIsOval && matrix.rectStaysRect();
1674
1675 SkDEBUGCODE(dst->validate();) 1573 SkDEBUGCODE(dst->validate();)
1676 } 1574 }
1677 } 1575 }
1678 1576
1679 /////////////////////////////////////////////////////////////////////////////// 1577 ///////////////////////////////////////////////////////////////////////////////
1680 /////////////////////////////////////////////////////////////////////////////// 1578 ///////////////////////////////////////////////////////////////////////////////
1681 1579
1682 enum SegmentState { 1580 enum SegmentState {
1683 kEmptyContour_SegmentState, // The current contour is empty. We may be 1581 kEmptyContour_SegmentState, // The current contour is empty. We may be
1684 // starting processing or we may have just 1582 // starting processing or we may have just
(...skipping 11 matching lines...) Expand all
1696 fForceClose = fCloseLine = false; 1594 fForceClose = fCloseLine = false;
1697 fSegmentState = kEmptyContour_SegmentState; 1595 fSegmentState = kEmptyContour_SegmentState;
1698 #endif 1596 #endif
1699 // need to init enough to make next() harmlessly return kDone_Verb 1597 // need to init enough to make next() harmlessly return kDone_Verb
1700 fVerbs = NULL; 1598 fVerbs = NULL;
1701 fVerbStop = NULL; 1599 fVerbStop = NULL;
1702 fNeedClose = false; 1600 fNeedClose = false;
1703 } 1601 }
1704 1602
1705 SkPath::Iter::Iter(const SkPath& path, bool forceClose) { 1603 SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
1706 this->setPath(path, forceClose); 1604 this->setPathRef(path.fPathRef.get(), forceClose);
1605 }
1606
1607 SkPath::Iter::Iter(const SkPathRef* pathRef, bool forceClose) {
1608 this->setPathRef(pathRef, forceClose);
1707 } 1609 }
1708 1610
1709 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) { 1611 void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
1710 fPts = path.fPathRef->points(); 1612 this->setPathRef(path.fPathRef.get(), forceClose);
1711 fVerbs = path.fPathRef->verbs(); 1613 }
1712 fVerbStop = path.fPathRef->verbsMemBegin(); 1614
1713 fConicWeights = path.fPathRef->conicWeights() - 1; // begin one behind 1615 void SkPath::Iter::setPathRef(const SkPathRef* pathRef, bool forceClose) {
1616 fPts = pathRef->points();
1617 fVerbs = pathRef->verbs();
1618 fVerbStop = pathRef->verbsMemBegin();
1619 fConicWeights = pathRef->conicWeights() - 1; // begin one behind
1714 fLastPt.fX = fLastPt.fY = 0; 1620 fLastPt.fX = fLastPt.fY = 0;
1715 fMoveTo.fX = fMoveTo.fY = 0; 1621 fMoveTo.fX = fMoveTo.fY = 0;
1716 fForceClose = SkToU8(forceClose); 1622 fForceClose = SkToU8(forceClose);
1717 fNeedClose = false; 1623 fNeedClose = false;
1718 fSegmentState = kEmptyContour_SegmentState; 1624 fSegmentState = kEmptyContour_SegmentState;
1719 } 1625 }
1720 1626
1721 bool SkPath::Iter::isClosedContour() const { 1627 bool SkPath::Iter::isClosedContour() const {
1722 if (fVerbs == NULL || fVerbs == fVerbStop) { 1628 if (fVerbs == NULL || fVerbs == fVerbStop) {
1723 return false; 1629 return false;
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after
2017 uint32_t SkPath::writeToMemory(void* storage) const { 1923 uint32_t SkPath::writeToMemory(void* storage) const {
2018 SkDEBUGCODE(this->validate();) 1924 SkDEBUGCODE(this->validate();)
2019 1925
2020 if (NULL == storage) { 1926 if (NULL == storage) {
2021 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); 1927 const int byteCount = sizeof(int32_t) + fPathRef->writeSize();
2022 return SkAlign4(byteCount); 1928 return SkAlign4(byteCount);
2023 } 1929 }
2024 1930
2025 SkWBuffer buffer(storage); 1931 SkWBuffer buffer(storage);
2026 1932
2027 int32_t packed = ((fIsOval & 1) << kIsOval_SerializationShift) | 1933 int32_t packed = (fFillType << kFillType_SerializationShift)
2028 (fConvexity << kConvexity_SerializationShift) |
2029 (fFillType << kFillType_SerializationShift) |
2030 (fSegmentMask << kSegmentMask_SerializationShift) |
2031 (fDirection << kDirection_SerializationShift)
2032 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 1934 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
2033 | (0x1 << kNewFormat_SerializationShift); 1935 | (0x1 << kNewFormat_SerializationShift);
2034 #endif 1936 #endif
2035 1937
2036 buffer.write32(packed); 1938 buffer.write32(packed);
2037 1939
2038 fPathRef->writeToBuffer(&buffer); 1940 fPathRef->writeToBuffer(&buffer);
2039 1941
2040 buffer.padToAlign4(); 1942 buffer.padToAlign4();
2041 return SkToU32(buffer.pos()); 1943 return SkToU32(buffer.pos());
2042 } 1944 }
2043 1945
2044 uint32_t SkPath::readFromMemory(const void* storage) { 1946 uint32_t SkPath::readFromMemory(const void* storage) {
2045 SkRBuffer buffer(storage); 1947 SkRBuffer buffer(storage);
2046 1948
2047 uint32_t packed = buffer.readS32(); 1949 uint32_t packed = buffer.readS32();
2048 fIsOval = (packed >> kIsOval_SerializationShift) & 1;
2049 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
2050 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; 1950 fFillType = (packed >> kFillType_SerializationShift) & 0xFF;
2051 fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
2052 fDirection = (packed >> kDirection_SerializationShift) & 0x3;
2053 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 1951 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
2054 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; 1952 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1;
2055 #endif 1953 #endif
2056 1954
2057 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer 1955 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer
2058 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 1956 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
2059 , newFormat, packed) 1957 , newFormat, packed)
2060 #endif 1958 #endif
2061 ); 1959 );
2062 1960
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
2142 } 2040 }
2143 2041
2144 void SkPath::dump() const { 2042 void SkPath::dump() const {
2145 this->dump(false); 2043 this->dump(false);
2146 } 2044 }
2147 2045
2148 #ifdef SK_DEBUG 2046 #ifdef SK_DEBUG
2149 void SkPath::validate() const { 2047 void SkPath::validate() const {
2150 SkASSERT(this != NULL); 2048 SkASSERT(this != NULL);
2151 SkASSERT((fFillType & ~3) == 0); 2049 SkASSERT((fFillType & ~3) == 0);
2152
2153 #ifdef SK_DEBUG_PATH
2154 if (!fBoundsIsDirty) {
2155 SkRect bounds;
2156
2157 bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get());
2158 SkASSERT(SkToBool(fIsFinite) == isFinite);
2159
2160 if (fPathRef->countPoints() <= 1) {
2161 // if we're empty, fBounds may be empty but translated, so we can't
2162 // necessarily compare to bounds directly
2163 // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
2164 // be [2, 2, 2, 2]
2165 SkASSERT(bounds.isEmpty());
2166 SkASSERT(fBounds.isEmpty());
2167 } else {
2168 if (bounds.isEmpty()) {
2169 SkASSERT(fBounds.isEmpty());
2170 } else {
2171 if (!fBounds.isEmpty()) {
2172 SkASSERT(fBounds.contains(bounds));
2173 }
2174 }
2175 }
2176 }
2177
2178 uint32_t mask = 0;
2179 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbs() ;
2180 for (int i = 0; i < fPathRef->countVerbs(); i++) {
2181 switch (verbs[~i]) {
2182 case kLine_Verb:
2183 mask |= kLine_SegmentMask;
2184 break;
2185 case kQuad_Verb:
2186 mask |= kQuad_SegmentMask;
2187 break;
2188 case kConic_Verb:
2189 mask |= kConic_SegmentMask;
2190 break;
2191 case kCubic_Verb:
2192 mask |= kCubic_SegmentMask;
2193 case kMove_Verb: // these verbs aren't included in the segment mask .
2194 case kClose_Verb:
2195 break;
2196 case kDone_Verb:
2197 SkDEBUGFAIL("Done verb shouldn't be recorded.");
2198 break;
2199 default:
2200 SkDEBUGFAIL("Unknown Verb");
2201 break;
2202 }
2203 }
2204 SkASSERT(mask == fSegmentMask);
2205 #endif // SK_DEBUG_PATH
2206 } 2050 }
2207 #endif // SK_DEBUG 2051 #endif // SK_DEBUG
2208 2052
2209 /////////////////////////////////////////////////////////////////////////////// 2053 ///////////////////////////////////////////////////////////////////////////////
2210 2054
2211 static int sign(SkScalar x) { return x < 0; }
2212 #define kValueNeverReturnedBySign 2
2213
2214 static int CrossProductSign(const SkVector& a, const SkVector& b) {
2215 return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
2216 }
2217
2218 // only valid for a single contour
2219 struct Convexicator {
2220 Convexicator()
2221 : fPtCount(0)
2222 , fConvexity(SkPath::kConvex_Convexity)
2223 , fDirection(SkPath::kUnknown_Direction) {
2224 fSign = 0;
2225 // warnings
2226 fCurrPt.set(0, 0);
2227 fVec0.set(0, 0);
2228 fVec1.set(0, 0);
2229 fFirstVec.set(0, 0);
2230
2231 fDx = fDy = 0;
2232 fSx = fSy = kValueNeverReturnedBySign;
2233 }
2234
2235 SkPath::Convexity getConvexity() const { return fConvexity; }
2236
2237 /** The direction returned is only valid if the path is determined convex */
2238 SkPath::Direction getDirection() const { return fDirection; }
2239
2240 void addPt(const SkPoint& pt) {
2241 if (SkPath::kConcave_Convexity == fConvexity) {
2242 return;
2243 }
2244
2245 if (0 == fPtCount) {
2246 fCurrPt = pt;
2247 ++fPtCount;
2248 } else {
2249 SkVector vec = pt - fCurrPt;
2250 if (vec.fX || vec.fY) {
2251 fCurrPt = pt;
2252 if (++fPtCount == 2) {
2253 fFirstVec = fVec1 = vec;
2254 } else {
2255 SkASSERT(fPtCount > 2);
2256 this->addVec(vec);
2257 }
2258
2259 int sx = sign(vec.fX);
2260 int sy = sign(vec.fY);
2261 fDx += (sx != fSx);
2262 fDy += (sy != fSy);
2263 fSx = sx;
2264 fSy = sy;
2265
2266 if (fDx > 3 || fDy > 3) {
2267 fConvexity = SkPath::kConcave_Convexity;
2268 }
2269 }
2270 }
2271 }
2272
2273 void close() {
2274 if (fPtCount > 2) {
2275 this->addVec(fFirstVec);
2276 }
2277 }
2278
2279 private:
2280 void addVec(const SkVector& vec) {
2281 SkASSERT(vec.fX || vec.fY);
2282 fVec0 = fVec1;
2283 fVec1 = vec;
2284 int sign = CrossProductSign(fVec0, fVec1);
2285 if (0 == fSign) {
2286 fSign = sign;
2287 if (1 == sign) {
2288 fDirection = SkPath::kCW_Direction;
2289 } else if (-1 == sign) {
2290 fDirection = SkPath::kCCW_Direction;
2291 }
2292 } else if (sign) {
2293 if (fSign != sign) {
2294 fConvexity = SkPath::kConcave_Convexity;
2295 fDirection = SkPath::kUnknown_Direction;
2296 }
2297 }
2298 }
2299
2300 SkPoint fCurrPt;
2301 SkVector fVec0, fVec1, fFirstVec;
2302 int fPtCount; // non-degenerate points
2303 int fSign;
2304 SkPath::Convexity fConvexity;
2305 SkPath::Direction fDirection;
2306 int fDx, fDy, fSx, fSy;
2307 };
2308
2309 SkPath::Convexity SkPath::internalGetConvexity() const {
2310 SkASSERT(kUnknown_Convexity == fConvexity);
2311 SkPoint pts[4];
2312 SkPath::Verb verb;
2313 SkPath::Iter iter(*this, true);
2314
2315 int contourCount = 0;
2316 int count;
2317 Convexicator state;
2318
2319 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
2320 switch (verb) {
2321 case kMove_Verb:
2322 if (++contourCount > 1) {
2323 fConvexity = kConcave_Convexity;
2324 return kConcave_Convexity;
2325 }
2326 pts[1] = pts[0];
2327 count = 1;
2328 break;
2329 case kLine_Verb: count = 1; break;
2330 case kQuad_Verb: count = 2; break;
2331 case kConic_Verb: count = 2; break;
2332 case kCubic_Verb: count = 3; break;
2333 case kClose_Verb:
2334 state.close();
2335 count = 0;
2336 break;
2337 default:
2338 SkDEBUGFAIL("bad verb");
2339 fConvexity = kConcave_Convexity;
2340 return kConcave_Convexity;
2341 }
2342
2343 for (int i = 1; i <= count; i++) {
2344 state.addPt(pts[i]);
2345 }
2346 // early exit
2347 if (kConcave_Convexity == state.getConvexity()) {
2348 fConvexity = kConcave_Convexity;
2349 return kConcave_Convexity;
2350 }
2351 }
2352 fConvexity = state.getConvexity();
2353 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) {
2354 fDirection = state.getDirection();
2355 }
2356 return static_cast<Convexity>(fConvexity);
2357 }
2358
2359 ///////////////////////////////////////////////////////////////////////////////
2360
2361 class ContourIter {
2362 public:
2363 ContourIter(const SkPathRef& pathRef);
2364
2365 bool done() const { return fDone; }
2366 // if !done() then these may be called
2367 int count() const { return fCurrPtCount; }
2368 const SkPoint* pts() const { return fCurrPt; }
2369 void next();
2370
2371 private:
2372 int fCurrPtCount;
2373 const SkPoint* fCurrPt;
2374 const uint8_t* fCurrVerb;
2375 const uint8_t* fStopVerbs;
2376 const SkScalar* fCurrConicWeight;
2377 bool fDone;
2378 SkDEBUGCODE(int fContourCounter;)
2379 };
2380
2381 ContourIter::ContourIter(const SkPathRef& pathRef) {
2382 fStopVerbs = pathRef.verbsMemBegin();
2383 fDone = false;
2384 fCurrPt = pathRef.points();
2385 fCurrVerb = pathRef.verbs();
2386 fCurrConicWeight = pathRef.conicWeights();
2387 fCurrPtCount = 0;
2388 SkDEBUGCODE(fContourCounter = 0;)
2389 this->next();
2390 }
2391
2392 void ContourIter::next() {
2393 if (fCurrVerb <= fStopVerbs) {
2394 fDone = true;
2395 }
2396 if (fDone) {
2397 return;
2398 }
2399
2400 // skip pts of prev contour
2401 fCurrPt += fCurrPtCount;
2402
2403 SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
2404 int ptCount = 1; // moveTo
2405 const uint8_t* verbs = fCurrVerb;
2406
2407 for (--verbs; verbs > fStopVerbs; --verbs) {
2408 switch (verbs[~0]) {
2409 case SkPath::kMove_Verb:
2410 goto CONTOUR_END;
2411 case SkPath::kLine_Verb:
2412 ptCount += 1;
2413 break;
2414 case SkPath::kConic_Verb:
2415 fCurrConicWeight += 1;
2416 // fall-through
2417 case SkPath::kQuad_Verb:
2418 ptCount += 2;
2419 break;
2420 case SkPath::kCubic_Verb:
2421 ptCount += 3;
2422 break;
2423 case SkPath::kClose_Verb:
2424 break;
2425 default:
2426 SkDEBUGFAIL("unexpected verb");
2427 break;
2428 }
2429 }
2430 CONTOUR_END:
2431 fCurrPtCount = ptCount;
2432 fCurrVerb = verbs;
2433 SkDEBUGCODE(++fContourCounter;)
2434 }
2435
2436 // returns cross product of (p1 - p0) and (p2 - p0)
2437 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
2438 SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
2439 // We may get 0 when the above subtracts underflow. We expect this to be
2440 // very rare and lazily promote to double.
2441 if (0 == cross) {
2442 double p0x = SkScalarToDouble(p0.fX);
2443 double p0y = SkScalarToDouble(p0.fY);
2444
2445 double p1x = SkScalarToDouble(p1.fX);
2446 double p1y = SkScalarToDouble(p1.fY);
2447
2448 double p2x = SkScalarToDouble(p2.fX);
2449 double p2y = SkScalarToDouble(p2.fY);
2450
2451 cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
2452 (p1y - p0y) * (p2x - p0x));
2453
2454 }
2455 return cross;
2456 }
2457
2458 // Returns the first pt with the maximum Y coordinate
2459 static int find_max_y(const SkPoint pts[], int count) {
2460 SkASSERT(count > 0);
2461 SkScalar max = pts[0].fY;
2462 int firstIndex = 0;
2463 for (int i = 1; i < count; ++i) {
2464 SkScalar y = pts[i].fY;
2465 if (y > max) {
2466 max = y;
2467 firstIndex = i;
2468 }
2469 }
2470 return firstIndex;
2471 }
2472
2473 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
2474 int i = index;
2475 for (;;) {
2476 i = (i + inc) % n;
2477 if (i == index) { // we wrapped around, so abort
2478 break;
2479 }
2480 if (pts[index] != pts[i]) { // found a different point, success!
2481 break;
2482 }
2483 }
2484 return i;
2485 }
2486
2487 /**
2488 * Starting at index, and moving forward (incrementing), find the xmin and
2489 * xmax of the contiguous points that have the same Y.
2490 */
2491 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
2492 int* maxIndexPtr) {
2493 const SkScalar y = pts[index].fY;
2494 SkScalar min = pts[index].fX;
2495 SkScalar max = min;
2496 int minIndex = index;
2497 int maxIndex = index;
2498 for (int i = index + 1; i < n; ++i) {
2499 if (pts[i].fY != y) {
2500 break;
2501 }
2502 SkScalar x = pts[i].fX;
2503 if (x < min) {
2504 min = x;
2505 minIndex = i;
2506 } else if (x > max) {
2507 max = x;
2508 maxIndex = i;
2509 }
2510 }
2511 *maxIndexPtr = maxIndex;
2512 return minIndex;
2513 }
2514
2515 static void crossToDir(SkScalar cross, SkPath::Direction* dir) {
2516 if (dir) {
2517 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2518 }
2519 }
2520
2521 #if 0
2522 #include "SkString.h"
2523 #include "../utils/SkParsePath.h"
2524 static void dumpPath(const SkPath& path) {
2525 SkString str;
2526 SkParsePath::ToSVGString(path, &str);
2527 SkDebugf("%s\n", str.c_str());
2528 }
2529 #endif
2530
2531 namespace {
2532 // for use with convex_dir_test
2533 double mul(double a, double b) { return a * b; }
2534 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); }
2535 double toDouble(SkScalar a) { return SkScalarToDouble(a); }
2536 SkScalar toScalar(SkScalar a) { return a; }
2537
2538 // determines the winding direction of a convex polygon with the precision
2539 // of T. CAST_SCALAR casts an SkScalar to T.
2540 template <typename T, T (CAST_SCALAR)(SkScalar)>
2541 bool convex_dir_test(int n, const SkPoint pts[], SkPath::Direction* dir) {
2542 // we find the first three points that form a non-degenerate
2543 // triangle. If there are no such points then the path is
2544 // degenerate. The first is always point 0. Now we find the second
2545 // point.
2546 int i = 0;
2547 enum { kX = 0, kY = 1 };
2548 T v0[2];
2549 while (1) {
2550 v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2551 v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2552 if (v0[kX] || v0[kY]) {
2553 break;
2554 }
2555 if (++i == n - 1) {
2556 return false;
2557 }
2558 }
2559 // now find a third point that is not colinear with the first two
2560 // points and check the orientation of the triangle (which will be
2561 // the same as the orientation of the path).
2562 for (++i; i < n; ++i) {
2563 T v1[2];
2564 v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2565 v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2566 T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]);
2567 if (0 != cross) {
2568 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2569 return true;
2570 }
2571 }
2572 return false;
2573 }
2574 }
2575
2576 /*
2577 * We loop through all contours, and keep the computed cross-product of the
2578 * contour that contained the global y-max. If we just look at the first
2579 * contour, we may find one that is wound the opposite way (correctly) since
2580 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2581 * that is outer most (or at least has the global y-max) before we can consider
2582 * its cross product.
2583 */
2584 bool SkPath::cheapComputeDirection(Direction* dir) const {
2585 // dumpPath(*this);
2586 // don't want to pay the cost for computing this if it
2587 // is unknown, so we don't call isConvex()
2588
2589 if (kUnknown_Direction != fDirection) {
2590 *dir = static_cast<Direction>(fDirection);
2591 return true;
2592 }
2593 const Convexity conv = this->getConvexityOrUnknown();
2594
2595 ContourIter iter(*fPathRef.get());
2596
2597 // initialize with our logical y-min
2598 SkScalar ymax = this->getBounds().fTop;
2599 SkScalar ymaxCross = 0;
2600
2601 for (; !iter.done(); iter.next()) {
2602 int n = iter.count();
2603 if (n < 3) {
2604 continue;
2605 }
2606
2607 const SkPoint* pts = iter.pts();
2608 SkScalar cross = 0;
2609 if (kConvex_Convexity == conv) {
2610 // We try first at scalar precision, and then again at double
2611 // precision. This is because the vectors computed between distant
2612 // points may lose too much precision.
2613 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) {
2614 fDirection = *dir;
2615 return true;
2616 }
2617 if (convex_dir_test<double, toDouble>(n, pts, dir)) {
2618 fDirection = *dir;
2619 return true;
2620 } else {
2621 return false;
2622 }
2623 } else {
2624 int index = find_max_y(pts, n);
2625 if (pts[index].fY < ymax) {
2626 continue;
2627 }
2628
2629 // If there is more than 1 distinct point at the y-max, we take the
2630 // x-min and x-max of them and just subtract to compute the dir.
2631 if (pts[(index + 1) % n].fY == pts[index].fY) {
2632 int maxIndex;
2633 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2634 if (minIndex == maxIndex) {
2635 goto TRY_CROSSPROD;
2636 }
2637 SkASSERT(pts[minIndex].fY == pts[index].fY);
2638 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2639 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2640 // we just subtract the indices, and let that auto-convert to
2641 // SkScalar, since we just want - or + to signal the direction.
2642 cross = minIndex - maxIndex;
2643 } else {
2644 TRY_CROSSPROD:
2645 // Find a next and prev index to use for the cross-product test,
2646 // but we try to find pts that form non-zero vectors from pts[in dex]
2647 //
2648 // Its possible that we can't find two non-degenerate vectors, s o
2649 // we have to guard our search (e.g. all the pts could be in the
2650 // same place).
2651
2652 // we pass n - 1 instead of -1 so we don't foul up % operator by
2653 // passing it a negative LH argument.
2654 int prev = find_diff_pt(pts, index, n, n - 1);
2655 if (prev == index) {
2656 // completely degenerate, skip to next contour
2657 continue;
2658 }
2659 int next = find_diff_pt(pts, index, n, 1);
2660 SkASSERT(next != index);
2661 cross = cross_prod(pts[prev], pts[index], pts[next]);
2662 // if we get a zero and the points are horizontal, then we look at the spread in
2663 // x-direction. We really should continue to walk away from the degeneracy until
2664 // there is a divergence.
2665 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
2666 // construct the subtract so we get the correct Direction be low
2667 cross = pts[index].fX - pts[next].fX;
2668 }
2669 }
2670
2671 if (cross) {
2672 // record our best guess so far
2673 ymax = pts[index].fY;
2674 ymaxCross = cross;
2675 }
2676 }
2677 }
2678 if (ymaxCross) {
2679 crossToDir(ymaxCross, dir);
2680 fDirection = *dir;
2681 return true;
2682 } else {
2683 return false;
2684 }
2685 }
2686 2055
2687 /////////////////////////////////////////////////////////////////////////////// 2056 ///////////////////////////////////////////////////////////////////////////////
2688 2057
2689 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C, 2058 static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
2690 SkScalar D, SkScalar t) { 2059 SkScalar D, SkScalar t) {
2691 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D); 2060 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
2692 } 2061 }
2693 2062
2694 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c 3, 2063 static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c 3,
2695 SkScalar t) { 2064 SkScalar t) {
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
2930 switch (this->getFillType()) { 2299 switch (this->getFillType()) {
2931 case SkPath::kEvenOdd_FillType: 2300 case SkPath::kEvenOdd_FillType:
2932 case SkPath::kInverseEvenOdd_FillType: 2301 case SkPath::kInverseEvenOdd_FillType:
2933 w &= 1; 2302 w &= 1;
2934 break; 2303 break;
2935 default: 2304 default:
2936 break; 2305 break;
2937 } 2306 }
2938 return SkToBool(w); 2307 return SkToBool(w);
2939 } 2308 }
OLDNEW
« include/core/SkPath.h ('K') | « include/core/SkPathRef.h ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698