OLD | NEW |
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" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 private: | 70 private: |
71 SkPath* fPath; | 71 SkPath* fPath; |
72 SkPath::Direction fSaved; | 72 SkPath::Direction fSaved; |
73 }; | 73 }; |
74 | 74 |
75 /* This guy's constructor/destructor bracket a path editing operation. It is | 75 /* 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 | 76 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). | 77 (usually a new contour, but not required). |
78 | 78 |
79 It captures some state about the path up front (i.e. if it already has a | 79 It captures some state about the path up front (i.e. if it already has a |
80 cached bounds), and the if it can, it updates the cache bounds explicitly, | 80 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(). | 81 avoiding the need to revisit all of the points in getBounds(). |
82 | 82 |
83 It also notes if the path was originally degenerate, and if so, sets | 83 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 | 84 isConvex to true. Thus it can only be used if the contour being added is |
85 convex. | 85 convex (which is always true since we only allow the addition of rects). |
86 */ | 86 */ |
87 class SkAutoPathBoundsUpdate { | 87 class SkAutoPathBoundsUpdate { |
88 public: | 88 public: |
89 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { | 89 SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { |
90 this->init(path); | 90 this->init(path); |
91 } | 91 } |
92 | 92 |
93 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, | 93 SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, |
94 SkScalar right, SkScalar bottom) { | 94 SkScalar right, SkScalar bottom) { |
95 fRect.set(left, top, right, bottom); | 95 fRect.set(left, top, right, bottom); |
96 this->init(path); | 96 this->init(path); |
97 } | 97 } |
98 | 98 |
99 ~SkAutoPathBoundsUpdate() { | 99 ~SkAutoPathBoundsUpdate() { |
100 fPath->setIsConvex(fDegenerate); | 100 fPath->setIsConvex(fDegenerate); |
101 if (fEmpty) { | 101 if (fEmpty || fHasValidBounds) { |
102 fPath->fBounds = fRect; | 102 fPath->setBounds(fRect); |
103 fPath->fBoundsIsDirty = false; | |
104 fPath->fIsFinite = fPath->fBounds.isFinite(); | |
105 } else if (!fDirty) { | |
106 joinNoEmptyChecks(&fPath->fBounds, fRect); | |
107 fPath->fBoundsIsDirty = false; | |
108 fPath->fIsFinite = fPath->fBounds.isFinite(); | |
109 } | 103 } |
110 } | 104 } |
111 | 105 |
112 private: | 106 private: |
113 SkPath* fPath; | 107 SkPath* fPath; |
114 SkRect fRect; | 108 SkRect fRect; |
115 bool fDirty; | 109 bool fHasValidBounds; |
116 bool fDegenerate; | 110 bool fDegenerate; |
117 bool fEmpty; | 111 bool fEmpty; |
118 | 112 |
119 // returns true if we should proceed | |
120 void init(SkPath* path) { | 113 void init(SkPath* path) { |
| 114 // Cannot use fRect for our bounds unless we know it is sorted |
| 115 fRect.sort(); |
121 fPath = path; | 116 fPath = path; |
122 // Mark the path's bounds as dirty if (1) they are, or (2) the path | 117 // Mark the path's bounds as dirty if (1) they are, or (2) the path |
123 // is non-finite, and therefore its bounds are not meaningful | 118 // is non-finite, and therefore its bounds are not meaningful |
124 fDirty = SkToBool(path->fBoundsIsDirty) || !path->fIsFinite; | 119 fHasValidBounds = path->hasComputedBounds() && path->isFinite(); |
| 120 fEmpty = path->isEmpty(); |
| 121 if (fHasValidBounds && !fEmpty) { |
| 122 joinNoEmptyChecks(&fRect, fPath->getBounds()); |
| 123 } |
125 fDegenerate = is_degenerate(*path); | 124 fDegenerate = is_degenerate(*path); |
126 fEmpty = path->isEmpty(); | |
127 // Cannot use fRect for our bounds unless we know it is sorted | |
128 fRect.sort(); | |
129 } | 125 } |
130 }; | 126 }; |
131 | 127 |
132 // Return true if the computed bounds are finite. | |
133 static bool compute_pt_bounds(SkRect* bounds, const SkPathRef& ref) { | |
134 int count = ref.countPoints(); | |
135 if (count <= 1) { // we ignore just 1 point (moveto) | |
136 bounds->setEmpty(); | |
137 return count ? ref.points()->isFinite() : true; | |
138 } else { | |
139 return bounds->setBoundsCheck(ref.points(), count); | |
140 } | |
141 } | |
142 | |
143 //////////////////////////////////////////////////////////////////////////// | 128 //////////////////////////////////////////////////////////////////////////// |
144 | 129 |
145 /* | 130 /* |
146 Stores the verbs and points as they are given to us, with exceptions: | 131 Stores the verbs and points as they are given to us, with exceptions: |
147 - we only record "Close" if it was immediately preceeded by Move | Line | Qu
ad | Cubic | 132 - we only record "Close" if it was immediately preceeded by Move | Line | Qu
ad | Cubic |
148 - we insert a Move(0,0) if Line | Quad | Cubic is our first command | 133 - we insert a Move(0,0) if Line | Quad | Cubic is our first command |
149 | 134 |
150 The iterator does more cleanup, especially if forceClose == true | 135 The iterator does more cleanup, especially if forceClose == true |
151 1. If we encounter degenerate segments, remove them | 136 1. If we encounter degenerate segments, remove them |
152 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt !=
start-pt) | 137 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt !=
start-pt) |
(...skipping 13 matching lines...) Expand all Loading... |
166 #endif | 151 #endif |
167 { | 152 { |
168 this->resetFields(); | 153 this->resetFields(); |
169 } | 154 } |
170 | 155 |
171 void SkPath::resetFields() { | 156 void SkPath::resetFields() { |
172 //fPathRef is assumed to have been emptied by the caller. | 157 //fPathRef is assumed to have been emptied by the caller. |
173 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; | 158 fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; |
174 fFillType = kWinding_FillType; | 159 fFillType = kWinding_FillType; |
175 fSegmentMask = 0; | 160 fSegmentMask = 0; |
176 fBoundsIsDirty = true; | |
177 fConvexity = kUnknown_Convexity; | 161 fConvexity = kUnknown_Convexity; |
178 fDirection = kUnknown_Direction; | 162 fDirection = kUnknown_Direction; |
179 fIsFinite = false; | |
180 fIsOval = false; | 163 fIsOval = false; |
181 #ifdef SK_BUILD_FOR_ANDROID | 164 #ifdef SK_BUILD_FOR_ANDROID |
182 GEN_ID_INC; | 165 GEN_ID_INC; |
183 // We don't touch fSourcePath. It's used to track texture garbage collectio
n, so we don't | 166 // We don't touch fSourcePath. It's used to track texture garbage collectio
n, so we don't |
184 // want to muck with it if it's been set to something non-NULL. | 167 // want to muck with it if it's been set to something non-NULL. |
185 #endif | 168 #endif |
186 } | 169 } |
187 | 170 |
188 SkPath::SkPath(const SkPath& that) | 171 SkPath::SkPath(const SkPath& that) |
189 : fPathRef(SkRef(that.fPathRef.get())) { | 172 : fPathRef(SkRef(that.fPathRef.get())) { |
(...skipping 19 matching lines...) Expand all Loading... |
209 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go
back in time. | 192 GEN_ID_INC; // Similar to swap, we can't just copy this or it could go
back in time. |
210 fSourcePath = that.fSourcePath; | 193 fSourcePath = that.fSourcePath; |
211 #endif | 194 #endif |
212 } | 195 } |
213 SkDEBUGCODE(this->validate();) | 196 SkDEBUGCODE(this->validate();) |
214 return *this; | 197 return *this; |
215 } | 198 } |
216 | 199 |
217 void SkPath::copyFields(const SkPath& that) { | 200 void SkPath::copyFields(const SkPath& that) { |
218 //fPathRef is assumed to have been set by the caller. | 201 //fPathRef is assumed to have been set by the caller. |
219 fBounds = that.fBounds; | |
220 fLastMoveToIndex = that.fLastMoveToIndex; | 202 fLastMoveToIndex = that.fLastMoveToIndex; |
221 fFillType = that.fFillType; | 203 fFillType = that.fFillType; |
222 fSegmentMask = that.fSegmentMask; | 204 fSegmentMask = that.fSegmentMask; |
223 fBoundsIsDirty = that.fBoundsIsDirty; | |
224 fConvexity = that.fConvexity; | 205 fConvexity = that.fConvexity; |
225 fDirection = that.fDirection; | 206 fDirection = that.fDirection; |
226 fIsFinite = that.fIsFinite; | |
227 fIsOval = that.fIsOval; | 207 fIsOval = that.fIsOval; |
228 } | 208 } |
229 | 209 |
230 bool operator==(const SkPath& a, const SkPath& b) { | 210 bool operator==(const SkPath& a, const SkPath& b) { |
231 // note: don't need to look at isConvex or bounds, since just comparing the | 211 // note: don't need to look at isConvex or bounds, since just comparing the |
232 // raw data is sufficient. | 212 // raw data is sufficient. |
233 | 213 |
234 // We explicitly check fSegmentMask as a quick-reject. We could skip it, | 214 // We explicitly check fSegmentMask as a quick-reject. We could skip it, |
235 // since it is only a cache of info in the fVerbs, but its a fast way to | 215 // since it is only a cache of info in the fVerbs, but its a fast way to |
236 // notice a difference | 216 // notice a difference |
237 | 217 |
238 return &a == &b || | 218 return &a == &b || |
239 (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && | 219 (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask && |
240 *a.fPathRef.get() == *b.fPathRef.get()); | 220 *a.fPathRef.get() == *b.fPathRef.get()); |
241 } | 221 } |
242 | 222 |
243 void SkPath::swap(SkPath& that) { | 223 void SkPath::swap(SkPath& that) { |
244 SkASSERT(&that != NULL); | 224 SkASSERT(&that != NULL); |
245 | 225 |
246 if (this != &that) { | 226 if (this != &that) { |
247 fPathRef.swap(&that.fPathRef); | 227 fPathRef.swap(&that.fPathRef); |
248 SkTSwap<SkRect>(fBounds, that.fBounds); | |
249 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); | 228 SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); |
250 SkTSwap<uint8_t>(fFillType, that.fFillType); | 229 SkTSwap<uint8_t>(fFillType, that.fFillType); |
251 SkTSwap<uint8_t>(fSegmentMask, that.fSegmentMask); | 230 SkTSwap<uint8_t>(fSegmentMask, that.fSegmentMask); |
252 SkTSwap<uint8_t>(fBoundsIsDirty, that.fBoundsIsDirty); | |
253 SkTSwap<uint8_t>(fConvexity, that.fConvexity); | 231 SkTSwap<uint8_t>(fConvexity, that.fConvexity); |
254 SkTSwap<uint8_t>(fDirection, that.fDirection); | 232 SkTSwap<uint8_t>(fDirection, that.fDirection); |
255 SkTSwap<SkBool8>(fIsFinite, that.fIsFinite); | |
256 SkTSwap<SkBool8>(fIsOval, that.fIsOval); | 233 SkTSwap<SkBool8>(fIsOval, that.fIsOval); |
257 #ifdef SK_BUILD_FOR_ANDROID | 234 #ifdef SK_BUILD_FOR_ANDROID |
258 // It doesn't really make sense to swap the generation IDs here, because
they might go | 235 // It doesn't really make sense to swap the generation IDs here, because
they might go |
259 // backwards. To be safe we increment both to mark them both as changed
. | 236 // backwards. To be safe we increment both to mark them both as changed
. |
260 GEN_ID_INC; | 237 GEN_ID_INC; |
261 GEN_ID_PTR_INC(&that); | 238 GEN_ID_PTR_INC(&that); |
262 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); | 239 SkTSwap<const SkPath*>(fSourcePath, that.fSourcePath); |
263 #endif | 240 #endif |
264 } | 241 } |
265 } | 242 } |
266 | 243 |
| 244 const SkRect& SkPath::getBounds() const { |
| 245 return fPathRef->getBounds(); |
| 246 } |
| 247 |
| 248 void SkPath::setBounds(const SkRect& rect) { |
| 249 fPathRef->setBounds(rect); |
| 250 } |
| 251 |
267 static inline bool check_edge_against_rect(const SkPoint& p0, | 252 static inline bool check_edge_against_rect(const SkPoint& p0, |
268 const SkPoint& p1, | 253 const SkPoint& p1, |
269 const SkRect& rect, | 254 const SkRect& rect, |
270 SkPath::Direction dir) { | 255 SkPath::Direction dir) { |
271 const SkPoint* edgeBegin; | 256 const SkPoint* edgeBegin; |
272 SkVector v; | 257 SkVector v; |
273 if (SkPath::kCW_Direction == dir) { | 258 if (SkPath::kCW_Direction == dir) { |
274 v = p1 - p0; | 259 v = p1 - p0; |
275 edgeBegin = &p0; | 260 edgeBegin = &p0; |
276 } else { | 261 } else { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 | 362 |
378 SkPathRef::Rewind(&fPathRef); | 363 SkPathRef::Rewind(&fPathRef); |
379 this->resetFields(); | 364 this->resetFields(); |
380 } | 365 } |
381 | 366 |
382 bool SkPath::isEmpty() const { | 367 bool SkPath::isEmpty() const { |
383 SkDEBUGCODE(this->validate();) | 368 SkDEBUGCODE(this->validate();) |
384 return 0 == fPathRef->countVerbs(); | 369 return 0 == fPathRef->countVerbs(); |
385 } | 370 } |
386 | 371 |
| 372 bool SkPath::isFinite() const { |
| 373 SkDEBUGCODE(this->validate();) |
| 374 return fPathRef->isFinite(); |
| 375 } |
| 376 |
| 377 bool SkPath::hasComputedBounds() const { |
| 378 SkDEBUGCODE(this->validate();) |
| 379 return fPathRef->hasComputedBounds(); |
| 380 } |
| 381 |
387 bool SkPath::isLine(SkPoint line[2]) const { | 382 bool SkPath::isLine(SkPoint line[2]) const { |
388 int verbCount = fPathRef->countVerbs(); | 383 int verbCount = fPathRef->countVerbs(); |
389 | 384 |
390 if (2 == verbCount) { | 385 if (2 == verbCount) { |
391 SkASSERT(kMove_Verb == fPathRef->atVerb(0)); | 386 SkASSERT(kMove_Verb == fPathRef->atVerb(0)); |
392 if (kLine_Verb == fPathRef->atVerb(1)) { | 387 if (kLine_Verb == fPathRef->atVerb(1)) { |
393 SkASSERT(2 == fPathRef->countPoints()); | 388 SkASSERT(2 == fPathRef->countPoints()); |
394 if (line) { | 389 if (line) { |
395 const SkPoint* pts = fPathRef->points(); | 390 const SkPoint* pts = fPathRef->points(); |
396 line[0] = pts[0]; | 391 line[0] = pts[0]; |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 if (count == 0) { | 653 if (count == 0) { |
659 this->moveTo(x, y); | 654 this->moveTo(x, y); |
660 } else { | 655 } else { |
661 fIsOval = false; | 656 fIsOval = false; |
662 SkPathRef::Editor ed(&fPathRef); | 657 SkPathRef::Editor ed(&fPathRef); |
663 ed.atPoint(count-1)->set(x, y); | 658 ed.atPoint(count-1)->set(x, y); |
664 GEN_ID_INC; | 659 GEN_ID_INC; |
665 } | 660 } |
666 } | 661 } |
667 | 662 |
668 void SkPath::computeBounds() const { | |
669 SkDEBUGCODE(this->validate();) | |
670 SkASSERT(fBoundsIsDirty); | |
671 | |
672 fIsFinite = compute_pt_bounds(&fBounds, *fPathRef.get()); | |
673 fBoundsIsDirty = false; | |
674 } | |
675 | |
676 void SkPath::setConvexity(Convexity c) { | 663 void SkPath::setConvexity(Convexity c) { |
677 if (fConvexity != c) { | 664 if (fConvexity != c) { |
678 fConvexity = c; | 665 fConvexity = c; |
679 GEN_ID_INC; | 666 GEN_ID_INC; |
680 } | 667 } |
681 } | 668 } |
682 | 669 |
683 ////////////////////////////////////////////////////////////////////////////// | 670 ////////////////////////////////////////////////////////////////////////////// |
684 // Construction methods | 671 // Construction methods |
685 | 672 |
686 #define DIRTY_AFTER_EDIT \ | 673 #define DIRTY_AFTER_EDIT \ |
687 do { \ | 674 do { \ |
688 fBoundsIsDirty = true; \ | |
689 fConvexity = kUnknown_Convexity; \ | 675 fConvexity = kUnknown_Convexity; \ |
690 fDirection = kUnknown_Direction; \ | 676 fDirection = kUnknown_Direction; \ |
691 fIsOval = false; \ | 677 fIsOval = false; \ |
692 } while (0) | 678 } while (0) |
693 | 679 |
694 #define DIRTY_AFTER_EDIT_NO_CONVEXITY_OR_DIRECTION_CHANGE \ | |
695 do { \ | |
696 fBoundsIsDirty = true; \ | |
697 } while (0) | |
698 | |
699 void SkPath::incReserve(U16CPU inc) { | 680 void SkPath::incReserve(U16CPU inc) { |
700 SkDEBUGCODE(this->validate();) | 681 SkDEBUGCODE(this->validate();) |
701 SkPathRef::Editor(&fPathRef, inc, inc); | 682 SkPathRef::Editor(&fPathRef, inc, inc); |
702 SkDEBUGCODE(this->validate();) | 683 SkDEBUGCODE(this->validate();) |
703 } | 684 } |
704 | 685 |
705 void SkPath::moveTo(SkScalar x, SkScalar y) { | 686 void SkPath::moveTo(SkScalar x, SkScalar y) { |
706 SkDEBUGCODE(this->validate();) | 687 SkDEBUGCODE(this->validate();) |
707 | 688 |
708 SkPathRef::Editor ed(&fPathRef); | 689 SkPathRef::Editor ed(&fPathRef); |
709 | 690 |
710 // remember our index | 691 // remember our index |
711 fLastMoveToIndex = ed.pathRef()->countPoints(); | 692 fLastMoveToIndex = ed.pathRef()->countPoints(); |
712 | 693 |
713 ed.growForVerb(kMove_Verb)->set(x, y); | 694 ed.growForVerb(kMove_Verb)->set(x, y); |
714 | 695 |
715 GEN_ID_INC; | 696 GEN_ID_INC; |
716 DIRTY_AFTER_EDIT_NO_CONVEXITY_OR_DIRECTION_CHANGE; | |
717 } | 697 } |
718 | 698 |
719 void SkPath::rMoveTo(SkScalar x, SkScalar y) { | 699 void SkPath::rMoveTo(SkScalar x, SkScalar y) { |
720 SkPoint pt; | 700 SkPoint pt; |
721 this->getLastPt(&pt); | 701 this->getLastPt(&pt); |
722 this->moveTo(pt.fX + x, pt.fY + y); | 702 this->moveTo(pt.fX + x, pt.fY + y); |
723 } | 703 } |
724 | 704 |
725 void SkPath::injectMoveToIfNeeded() { | 705 void SkPath::injectMoveToIfNeeded() { |
726 if (fLastMoveToIndex < 0) { | 706 if (fLastMoveToIndex < 0) { |
(...skipping 948 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1675 SkDEBUGFAIL("unknown verb"); | 1655 SkDEBUGFAIL("unknown verb"); |
1676 break; | 1656 break; |
1677 } | 1657 } |
1678 } | 1658 } |
1679 | 1659 |
1680 dst->swap(tmp); | 1660 dst->swap(tmp); |
1681 SkPathRef::Editor ed(&dst->fPathRef); | 1661 SkPathRef::Editor ed(&dst->fPathRef); |
1682 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); | 1662 matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); |
1683 dst->fDirection = kUnknown_Direction; | 1663 dst->fDirection = kUnknown_Direction; |
1684 } else { | 1664 } else { |
1685 /* | |
1686 * If we're not in perspective, we can transform all of the points at | |
1687 * once. | |
1688 * | |
1689 * Here we also want to optimize bounds, by noting if the bounds are | |
1690 * already known, and if so, we just transform those as well and mark | |
1691 * them as "known", rather than force the transformed path to have to | |
1692 * recompute them. | |
1693 * | |
1694 * Special gotchas if the path is effectively empty (<= 1 point) or | |
1695 * if it is non-finite. In those cases bounds need to stay empty, | |
1696 * regardless of the matrix. | |
1697 */ | |
1698 if (!fBoundsIsDirty && matrix.rectStaysRect() && fPathRef->countPoints()
> 1) { | |
1699 dst->fBoundsIsDirty = false; | |
1700 if (fIsFinite) { | |
1701 matrix.mapRect(&dst->fBounds, fBounds); | |
1702 if (!(dst->fIsFinite = dst->fBounds.isFinite())) { | |
1703 dst->fBounds.setEmpty(); | |
1704 } | |
1705 } else { | |
1706 dst->fIsFinite = false; | |
1707 dst->fBounds.setEmpty(); | |
1708 } | |
1709 } else { | |
1710 GEN_ID_PTR_INC(dst); | |
1711 dst->fBoundsIsDirty = true; | |
1712 } | |
1713 | |
1714 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix
); | 1665 SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix
); |
1715 | 1666 |
1716 if (this != dst) { | 1667 if (this != dst) { |
1717 dst->fFillType = fFillType; | 1668 dst->fFillType = fFillType; |
1718 dst->fSegmentMask = fSegmentMask; | 1669 dst->fSegmentMask = fSegmentMask; |
1719 dst->fConvexity = fConvexity; | 1670 dst->fConvexity = fConvexity; |
1720 } | 1671 } |
1721 | 1672 |
1722 #ifdef SK_BUILD_FOR_ANDROID | 1673 #ifdef SK_BUILD_FOR_ANDROID |
1723 if (!matrix.isIdentity()) { | 1674 if (!matrix.isIdentity() && !dst->hasComputedBounds()) { |
1724 GEN_ID_PTR_INC(dst); | 1675 GEN_ID_PTR_INC(dst); |
1725 } | 1676 } |
1726 #endif | 1677 #endif |
1727 | 1678 |
1728 if (kUnknown_Direction == fDirection) { | 1679 if (kUnknown_Direction == fDirection) { |
1729 dst->fDirection = kUnknown_Direction; | 1680 dst->fDirection = kUnknown_Direction; |
1730 } else { | 1681 } else { |
1731 SkScalar det2x2 = | 1682 SkScalar det2x2 = |
1732 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix:
:kMScaleY)) - | 1683 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix:
:kMScaleY)) - |
1733 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::
kMSkewY)); | 1684 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::
kMSkewY)); |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2082 /////////////////////////////////////////////////////////////////////////////// | 2033 /////////////////////////////////////////////////////////////////////////////// |
2083 | 2034 |
2084 /* | 2035 /* |
2085 Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]] | 2036 Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]] |
2086 */ | 2037 */ |
2087 | 2038 |
2088 uint32_t SkPath::writeToMemory(void* storage) const { | 2039 uint32_t SkPath::writeToMemory(void* storage) const { |
2089 SkDEBUGCODE(this->validate();) | 2040 SkDEBUGCODE(this->validate();) |
2090 | 2041 |
2091 if (NULL == storage) { | 2042 if (NULL == storage) { |
2092 const int byteCount = sizeof(int32_t) | 2043 const int byteCount = sizeof(int32_t) + fPathRef->writeSize(); |
2093 + fPathRef->writeSize() | |
2094 + sizeof(SkRect); | |
2095 return SkAlign4(byteCount); | 2044 return SkAlign4(byteCount); |
2096 } | 2045 } |
2097 | 2046 |
2098 SkWBuffer buffer(storage); | 2047 SkWBuffer buffer(storage); |
2099 | 2048 |
2100 // Call getBounds() to ensure (as a side-effect) that fBounds | 2049 int32_t packed = ((fIsOval & 1) << kIsOval_SerializationShift) | |
2101 // and fIsFinite are computed. | |
2102 const SkRect& bounds = this->getBounds(); | |
2103 SkASSERT(!fBoundsIsDirty); | |
2104 | |
2105 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | | |
2106 ((fIsOval & 1) << kIsOval_SerializationShift) | | |
2107 (fConvexity << kConvexity_SerializationShift) | | 2050 (fConvexity << kConvexity_SerializationShift) | |
2108 (fFillType << kFillType_SerializationShift) | | 2051 (fFillType << kFillType_SerializationShift) | |
2109 (fSegmentMask << kSegmentMask_SerializationShift) | | 2052 (fSegmentMask << kSegmentMask_SerializationShift) | |
2110 (fDirection << kDirection_SerializationShift); | 2053 (fDirection << kDirection_SerializationShift) |
| 2054 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 2055 | (0x1 << kNewFormat_SerializationShift); |
| 2056 #endif |
2111 | 2057 |
2112 buffer.write32(packed); | 2058 buffer.write32(packed); |
2113 | 2059 |
2114 fPathRef->writeToBuffer(&buffer); | 2060 fPathRef->writeToBuffer(&buffer); |
2115 | 2061 |
2116 buffer.write(&bounds, sizeof(bounds)); | |
2117 | |
2118 buffer.padToAlign4(); | 2062 buffer.padToAlign4(); |
2119 return SkToU32(buffer.pos()); | 2063 return SkToU32(buffer.pos()); |
2120 } | 2064 } |
2121 | 2065 |
2122 uint32_t SkPath::readFromMemory(const void* storage) { | 2066 uint32_t SkPath::readFromMemory(const void* storage) { |
2123 SkRBuffer buffer(storage); | 2067 SkRBuffer buffer(storage); |
2124 | 2068 |
2125 uint32_t packed = buffer.readS32(); | 2069 uint32_t packed = buffer.readS32(); |
2126 fIsFinite = (packed >> kIsFinite_SerializationShift) & 1; | |
2127 fIsOval = (packed >> kIsOval_SerializationShift) & 1; | 2070 fIsOval = (packed >> kIsOval_SerializationShift) & 1; |
2128 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; | 2071 fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; |
2129 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; | 2072 fFillType = (packed >> kFillType_SerializationShift) & 0xFF; |
2130 fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; | 2073 fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; |
2131 fDirection = (packed >> kDirection_SerializationShift) & 0x3; | 2074 fDirection = (packed >> kDirection_SerializationShift) & 0x3; |
| 2075 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
| 2076 bool newFormat = (packed >> kNewFormat_SerializationShift) & 1; |
| 2077 #endif |
2132 | 2078 |
2133 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer)); | 2079 fPathRef.reset(SkPathRef::CreateFromBuffer(&buffer |
2134 | 2080 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO
O |
2135 buffer.read(&fBounds, sizeof(fBounds)); | 2081 , newFormat, packed) |
2136 fBoundsIsDirty = false; | 2082 #endif |
| 2083 ); |
2137 | 2084 |
2138 buffer.skipToAlign4(); | 2085 buffer.skipToAlign4(); |
2139 | 2086 |
2140 GEN_ID_INC; | 2087 GEN_ID_INC; |
2141 | 2088 |
2142 SkDEBUGCODE(this->validate();) | 2089 SkDEBUGCODE(this->validate();) |
2143 return SkToU32(buffer.pos()); | 2090 return SkToU32(buffer.pos()); |
2144 } | 2091 } |
2145 | 2092 |
2146 /////////////////////////////////////////////////////////////////////////////// | 2093 /////////////////////////////////////////////////////////////////////////////// |
(...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3005 switch (this->getFillType()) { | 2952 switch (this->getFillType()) { |
3006 case SkPath::kEvenOdd_FillType: | 2953 case SkPath::kEvenOdd_FillType: |
3007 case SkPath::kInverseEvenOdd_FillType: | 2954 case SkPath::kInverseEvenOdd_FillType: |
3008 w &= 1; | 2955 w &= 1; |
3009 break; | 2956 break; |
3010 default: | 2957 default: |
3011 break; | 2958 break; |
3012 } | 2959 } |
3013 return SkToBool(w); | 2960 return SkToBool(w); |
3014 } | 2961 } |
OLD | NEW |