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

Side by Side Diff: src/core/SkPathRef.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
« include/core/SkPath.h ('K') | « src/core/SkPath.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBuffer.h" 8 #include "SkBuffer.h"
9 #include "SkPath.h" 9 #include "SkPath.h"
10 #include "SkPathRef.h" 10 #include "SkPathRef.h"
(...skipping 10 matching lines...) Expand all
21 } else { 21 } else {
22 SkPathRef* copy = SkNEW(SkPathRef); 22 SkPathRef* copy = SkNEW(SkPathRef);
23 copy->copy(**pathRef, incReserveVerbs, incReservePoints); 23 copy->copy(**pathRef, incReserveVerbs, incReservePoints);
24 pathRef->reset(copy); 24 pathRef->reset(copy);
25 } 25 }
26 fPathRef = *pathRef; 26 fPathRef = *pathRef;
27 fPathRef->fGenerationID = 0; 27 fPathRef->fGenerationID = 0;
28 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) 28 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
29 } 29 }
30 30
31 SkPoint* SkPathRef::Editor::growForConic(SkScalar w) {
32 SkDEBUGCODE(fPathRef->validate();)
33 SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb);
34 *fPathRef->fConicWeights.append() = w;
35 return pts;
36 }
37
38 ////////////////////////////////////////////////////////////////////////////// 31 //////////////////////////////////////////////////////////////////////////////
39 void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, 32 void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
40 const SkPathRef& src, 33 const SkPathRef& src,
41 const SkMatrix& matrix) { 34 const SkMatrix& matrix) {
42 SkDEBUGCODE(src.validate();) 35 SkDEBUGCODE(src.validate();)
43 if (matrix.isIdentity()) { 36 if (matrix.isIdentity()) {
44 if (*dst != &src) { 37 if (*dst != &src) {
45 src.ref(); 38 src.ref();
46 dst->reset(const_cast<SkPathRef*>(&src)); 39 dst->reset(const_cast<SkPathRef*>(&src));
47 SkDEBUGCODE((*dst)->validate();) 40 SkDEBUGCODE((*dst)->validate();)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 (*dst)->fBounds.setEmpty(); 73 (*dst)->fBounds.setEmpty();
81 } 74 }
82 } else { 75 } else {
83 (*dst)->fIsFinite = false; 76 (*dst)->fIsFinite = false;
84 (*dst)->fBounds.setEmpty(); 77 (*dst)->fBounds.setEmpty();
85 } 78 }
86 } else { 79 } else {
87 (*dst)->fBoundsIsDirty = true; 80 (*dst)->fBoundsIsDirty = true;
88 } 81 }
89 82
83 (*dst)->fLastMoveToIndex = src.fLastMoveToIndex;
84 (*dst)->fSegmentMask = src.fSegmentMask;
85 (*dst)->fConvexity = src.fConvexity;
86
87 if (SkPathRef::kUnknown_Direction == src.fDirection) {
88 (*dst)->fDirection = SkPathRef::kUnknown_Direction;
89 } else {
90 SkScalar det2x2 =
91 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix::kMS caleY)) -
92 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix::kMSk ewY));
93 if (det2x2 < 0) {
94 (*dst)->fDirection = SkPathRef::OppositeDirection(src.getDirection() );
95 } else if (det2x2 > 0) {
96 (*dst)->fDirection = src.fDirection;
97 } else {
98 (*dst)->fDirection = SkPathRef::kUnknown_Direction;
99 }
100 }
101
102 // It's an oval only if it stays a rect.
103 (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect();
104
90 SkDEBUGCODE((*dst)->validate();) 105 SkDEBUGCODE((*dst)->validate();)
91 } 106 }
92 107
93 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer 108 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer
94 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 109 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
95 , bool newFormat, int32_t oldPacked 110 , bool newFormat, int32_t oldPacked
96 #endif 111 #endif
97 ) { 112 ) {
98 SkPathRef* ref = SkNEW(SkPathRef); 113 SkPathRef* ref = SkNEW(SkPathRef);
114 int32_t packed;
99 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 115 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
100 if (newFormat) { 116 if (newFormat) {
101 #endif 117 #endif
102 int32_t packed = buffer->readU32(); 118 packed = buffer->readU32();
103
104 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
105 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 119 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
106 } else {
107 ref->fIsFinite = (oldPacked >> SkPath::kOldIsFinite_SerializationShift) & 1;
108 } 120 }
109 #endif 121 #endif
110 122
111 ref->fGenerationID = buffer->readU32(); 123 ref->fGenerationID = buffer->readU32();
112 int32_t verbCount = buffer->readS32(); 124 int32_t verbCount = buffer->readS32();
113 int32_t pointCount = buffer->readS32(); 125 int32_t pointCount = buffer->readS32();
114 int32_t conicCount = buffer->readS32(); 126 int32_t conicCount = buffer->readS32();
115 ref->resetToSize(verbCount, pointCount, conicCount); 127 ref->resetToSize(verbCount, pointCount, conicCount);
116 128
129 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
130 if (newFormat) {
131 #endif
132 ref->fSegmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
133 ref->fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF;
134 ref->fIsOval = (packed >> kIsOval_SerializationShift) & 1;
135 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
136 ref->fDirection = (packed >> kDirection_SerializationShift) & 0x3;
137 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
138 } else {
139 ref->fSegmentMask = (oldPacked >> SkPath::kOldSegmentMask_SerializationS hift) & 0xF;
140 ref->fConvexity = (oldPacked >> SkPath::kOldConvexity_SerializationShift ) & 0xFF;
141 ref->fIsOval = (oldPacked >> SkPath::kOldIsOval_SerializationShift) & 1;
142 ref->fIsFinite = (oldPacked >> SkPath::kOldIsFinite_SerializationShift) & 1;
143 ref->fDirection = (oldPacked >> SkPath::kOldDirection_SerializationShift ) & 0x3;
144 }
145 #endif
146
117 SkASSERT(verbCount == ref->countVerbs()); 147 SkASSERT(verbCount == ref->countVerbs());
118 SkASSERT(pointCount == ref->countPoints()); 148 SkASSERT(pointCount == ref->countPoints());
119 SkASSERT(conicCount == ref->fConicWeights.count()); 149 SkASSERT(conicCount == ref->fConicWeights.count());
120 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)); 150 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t));
121 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); 151 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
122 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); 152 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar));
123 buffer->read(&ref->fBounds, sizeof(SkRect)); 153 buffer->read(&ref->fBounds, sizeof(SkRect));
124 ref->fBoundsIsDirty = false; 154 ref->fBoundsIsDirty = false;
155
156 #ifdef SK_DEBUG_PATH
157 int lastMoveToIndex = kINITIAL_LASTMOVETOINDEX_VALUE;
158 int pointCnt = 0;
159
160 for (int i = 0; i < ref->fVerbCnt; ++i) {
161 switch (ref->fVerbs[~i]) {
162 case kMove_Verb:
163 lastMoveToIndex = pointCnt;
164 ++pointCnt;
165 break;
166 case kLine_Verb:
167 ++pointCnt;
168 break;
169 case kQuad_Verb:
170 pointCnt += 2;
171 break;
172 case kConic_Verb:
173 pointCnt += 2;
174 break;
175 case kCubic_Verb:
176 pointCnt += 3;
177 break;
178 case kClose_Verb:
179 if (lastMoveToIndex >= 0) {
180 lastMoveToIndex = ~lastMoveToIndex;
181 }
182 break;
183 case kDone_Verb:
184 // fall through
185 default:
186 SkDEBUGFAIL("default is not reached");
187 }
188 }
189 ref->fLastMoveToIndex = lastMoveToIndex;
190 #endif
191
125 return ref; 192 return ref;
126 } 193 }
127 194
128 void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) { 195 void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
129 if ((*pathRef)->unique()) { 196 if ((*pathRef)->unique()) {
130 SkDEBUGCODE((*pathRef)->validate();) 197 SkDEBUGCODE((*pathRef)->validate();)
131 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite 198 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
132 (*pathRef)->fVerbCnt = 0; 199 (*pathRef)->fVerbCnt = 0;
133 (*pathRef)->fPointCnt = 0; 200 (*pathRef)->fPointCnt = 0;
134 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); 201 (*pathRef)->fFreeSpace = (*pathRef)->currSize();
135 (*pathRef)->fGenerationID = 0; 202 (*pathRef)->fGenerationID = 0;
136 (*pathRef)->fConicWeights.rewind(); 203 (*pathRef)->fConicWeights.rewind();
204 (*pathRef)->fLastMoveToIndex = kINITIAL_LASTMOVETOINDEX_VALUE;
205 (*pathRef)->fSegmentMask = 0;
206 (*pathRef)->fConvexity = kUnknown_Convexity;
207 (*pathRef)->fDirection = kUnknown_Direction;
208 (*pathRef)->fIsOval = false;
137 SkDEBUGCODE((*pathRef)->validate();) 209 SkDEBUGCODE((*pathRef)->validate();)
138 } else { 210 } else {
139 int oldVCnt = (*pathRef)->countVerbs(); 211 int oldVCnt = (*pathRef)->countVerbs();
140 int oldPCnt = (*pathRef)->countPoints(); 212 int oldPCnt = (*pathRef)->countPoints();
141 pathRef->reset(SkNEW(SkPathRef)); 213 pathRef->reset(SkNEW(SkPathRef));
142 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); 214 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
143 } 215 }
144 } 216 }
145 217
146 bool SkPathRef::operator== (const SkPathRef& ref) const { 218 bool SkPathRef::operator== (const SkPathRef& ref) const {
147 SkDEBUGCODE(this->validate();) 219 SkDEBUGCODE(this->validate();)
148 SkDEBUGCODE(ref.validate();) 220 SkDEBUGCODE(ref.validate();)
221 // note: don't need to look at isConvex or bounds, since just comparing the
222 // raw data is sufficient.
223
224 // We explicitly check fSegmentMask as a quick-reject. We could skip it,
225 // since it is only a cache of info in the fVerbs, but its a fast way to
226 // notice a difference
227 if (fSegmentMask != ref.fSegmentMask) {
228 return false;
229 }
149 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID; 230 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
150 #ifdef SK_RELEASE 231 #ifdef SK_RELEASE
151 if (genIDMatch) { 232 if (genIDMatch) {
152 return true; 233 return true;
153 } 234 }
154 #endif 235 #endif
155 if (fPointCnt != ref.fPointCnt || 236 if (fPointCnt != ref.fPointCnt ||
156 fVerbCnt != ref.fVerbCnt) { 237 fVerbCnt != ref.fVerbCnt) {
157 SkASSERT(!genIDMatch); 238 SkASSERT(!genIDMatch);
158 return false; 239 return false;
(...skipping 25 matching lines...) Expand all
184 } 265 }
185 266
186 void SkPathRef::writeToBuffer(SkWBuffer* buffer) { 267 void SkPathRef::writeToBuffer(SkWBuffer* buffer) {
187 SkDEBUGCODE(this->validate();) 268 SkDEBUGCODE(this->validate();)
188 SkDEBUGCODE(size_t beforePos = buffer->pos();) 269 SkDEBUGCODE(size_t beforePos = buffer->pos();)
189 270
190 // Call getBounds() to ensure (as a side-effect) that fBounds 271 // Call getBounds() to ensure (as a side-effect) that fBounds
191 // and fIsFinite are computed. 272 // and fIsFinite are computed.
192 const SkRect& bounds = this->getBounds(); 273 const SkRect& bounds = this->getBounds();
193 274
194 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift); 275 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
276 ((fIsOval & 1) << kIsOval_SerializationShift) |»
277 (fConvexity << kConvexity_SerializationShift) |»
278 (fSegmentMask << kSegmentMask_SerializationShift) |»
279 (fDirection << kDirection_SerializationShift);
195 buffer->write32(packed); 280 buffer->write32(packed);
196 281
197 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from 282 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
198 // SkWBuffer. Until this is fixed we write 0. 283 // SkWBuffer. Until this is fixed we write 0.
199 buffer->write32(0); 284 buffer->write32(0);
200 buffer->write32(fVerbCnt); 285 buffer->write32(fVerbCnt);
201 buffer->write32(fPointCnt); 286 buffer->write32(fPointCnt);
202 buffer->write32(fConicWeights.count()); 287 buffer->write32(fConicWeights.count());
203 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); 288 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
204 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); 289 buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
(...skipping 21 matching lines...) Expand all
226 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); 311 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
227 fConicWeights = ref.fConicWeights; 312 fConicWeights = ref.fConicWeights;
228 // We could call genID() here to force a real ID (instead of 0). However, if we're making 313 // We could call genID() here to force a real ID (instead of 0). However, if we're making
229 // a copy then presumably we intend to make a modification immediately after wards. 314 // a copy then presumably we intend to make a modification immediately after wards.
230 fGenerationID = ref.fGenerationID; 315 fGenerationID = ref.fGenerationID;
231 fBoundsIsDirty = ref.fBoundsIsDirty; 316 fBoundsIsDirty = ref.fBoundsIsDirty;
232 if (!fBoundsIsDirty) { 317 if (!fBoundsIsDirty) {
233 fBounds = ref.fBounds; 318 fBounds = ref.fBounds;
234 fIsFinite = ref.fIsFinite; 319 fIsFinite = ref.fIsFinite;
235 } 320 }
321 fLastMoveToIndex = ref.fLastMoveToIndex;
322 fSegmentMask = ref.fSegmentMask;
323 fConvexity = ref.fConvexity;
324 fDirection = ref.fDirection;
325 fIsOval = ref.fIsOval;
236 SkDEBUGCODE(this->validate();) 326 SkDEBUGCODE(this->validate();)
237 } 327 }
238 328
239 SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) { 329 // In some cases we need to inject a leading moveTo before we add points
330 // for lineTo, quadTo, conicTo, cubicTo
331 //
332 // SkPath path; path.lineTo(...); <--- need a leading moveTo(0, 0)
333 // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous mo veTo)
334 SkPoint* SkPathRef::growForVerb(Verb verb) {
240 SkDEBUGCODE(this->validate();) 335 SkDEBUGCODE(this->validate();)
241 int pCnt; 336 int pCnt;
337 bool dirtyAfterEdit = true;
338 bool moveInjectionNeeded = false;
339 uint8_t newMask = 0;
340 int newLastMoveToIndex = fLastMoveToIndex;
341
242 switch (verb) { 342 switch (verb) {
243 case SkPath::kMove_Verb: 343 case kMove_Verb:
344 // remember the index
345 newLastMoveToIndex = this->countPoints();
346 pCnt = 1;
347 dirtyAfterEdit = false;
348 break;
349 case kLine_Verb:
350 moveInjectionNeeded = fLastMoveToIndex < 0;
351 newMask = kLine_SegmentMask;
244 pCnt = 1; 352 pCnt = 1;
245 break; 353 break;
246 case SkPath::kLine_Verb: 354 case kQuad_Verb:
247 pCnt = 1; 355 moveInjectionNeeded = fLastMoveToIndex < 0;
248 break; 356 newMask = kQuad_SegmentMask;
249 case SkPath::kQuad_Verb:
250 // fall through
251 case SkPath::kConic_Verb:
252 pCnt = 2; 357 pCnt = 2;
253 break; 358 break;
254 case SkPath::kCubic_Verb: 359 case kConic_Verb:
360 moveInjectionNeeded = fLastMoveToIndex < 0;
361 newMask = kConic_SegmentMask;
362 pCnt = 2;
363 break;
364 case kCubic_Verb:
365 moveInjectionNeeded = fLastMoveToIndex < 0;
366 newMask = kCubic_SegmentMask;
255 pCnt = 3; 367 pCnt = 3;
256 break; 368 break;
257 case SkPath::kClose_Verb: 369 case kClose_Verb:
370 // signal that we need a moveTo to follow us (unless we're done)
371 newLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIn dex) - 1);
258 pCnt = 0; 372 pCnt = 0;
373 dirtyAfterEdit = false;
259 break; 374 break;
260 case SkPath::kDone_Verb: 375 case kDone_Verb:
261 SkDEBUGFAIL("growForVerb called for kDone"); 376 SkDEBUGFAIL("growForVerb called for kDone");
262 // fall through 377 // fall through
263 default: 378 default:
264 SkDEBUGFAIL("default is not reached"); 379 SkDEBUGFAIL("default is not reached");
380 dirtyAfterEdit = false;
265 pCnt = 0; 381 pCnt = 0;
266 } 382 }
267 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); 383 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
384 if (moveInjectionNeeded) {
385 space += sizeof(uint8_t) + sizeof(SkPoint);
386 }
268 this->makeSpace(space); 387 this->makeSpace(space);
269 this->fVerbs[~fVerbCnt] = verb; 388 fLastMoveToIndex = newLastMoveToIndex;
389 if (moveInjectionNeeded) {
390 SkASSERT(dirtyAfterEdit);
391 this->injectMove();
392 } else {
393 fLastMoveToIndex = newLastMoveToIndex;
394 }
395 fVerbs[~fVerbCnt] = verb;
396 fSegmentMask |= newMask;
270 SkPoint* ret = fPoints + fPointCnt; 397 SkPoint* ret = fPoints + fPointCnt;
271 fVerbCnt += 1; 398 fVerbCnt += 1;
272 fPointCnt += pCnt; 399 fPointCnt += pCnt;
273 fFreeSpace -= space; 400 fFreeSpace -= space;
274 fBoundsIsDirty = true; // this also invalidates fIsFinite 401 fBoundsIsDirty = true; // this also invalidates fIsFinite
402 if (dirtyAfterEdit) {
403 fConvexity = kUnknown_Convexity;
404 fDirection = kUnknown_Direction;
405 fIsOval = false;
406 }
407
275 SkDEBUGCODE(this->validate();) 408 SkDEBUGCODE(this->validate();)
276 return ret; 409 return ret;
277 } 410 }
278 411
279 int32_t SkPathRef::genID() const { 412 int32_t SkPathRef::genID() const {
280 SkASSERT(!fEditorsAttached); 413 SkASSERT(!fEditorsAttached);
281 if (!fGenerationID) { 414 if (!fGenerationID) {
282 if (0 == fPointCnt && 0 == fVerbCnt) { 415 if (0 == fPointCnt && 0 == fVerbCnt) {
283 fGenerationID = kEmptyGenID; 416 fGenerationID = kEmptyGenID;
284 } else { 417 } else {
(...skipping 14 matching lines...) Expand all
299 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0); 432 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
300 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPo ints) >= 0); 433 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPo ints) >= 0);
301 SkASSERT((NULL == fPoints) == (NULL == fVerbs)); 434 SkASSERT((NULL == fPoints) == (NULL == fVerbs));
302 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); 435 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
303 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace)); 436 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
304 SkASSERT(!(NULL == fPoints && fPointCnt)); 437 SkASSERT(!(NULL == fPoints && fPointCnt));
305 SkASSERT(!(NULL == fVerbs && fVerbCnt)); 438 SkASSERT(!(NULL == fVerbs && fVerbCnt));
306 SkASSERT(this->currSize() == 439 SkASSERT(this->currSize() ==
307 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVe rbCnt); 440 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVe rbCnt);
308 441
309 #ifdef SK_DEBUG
310 if (!fBoundsIsDirty && !fBounds.isEmpty()) { 442 if (!fBoundsIsDirty && !fBounds.isEmpty()) {
311 bool isFinite = true; 443 bool isFinite = true;
312 for (int i = 0; i < fPointCnt; ++i) { 444 for (int i = 0; i < fPointCnt; ++i) {
313 SkASSERT(fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBounds. fRight && 445 SkASSERT(fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBounds. fRight &&
314 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBound s.fBottom); 446 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBound s.fBottom);
315 if (!fPoints[i].isFinite()) { 447 if (!fPoints[i].isFinite()) {
316 isFinite = false; 448 isFinite = false;
317 } 449 }
318 } 450 }
319 SkASSERT(SkToBool(fIsFinite) == isFinite); 451 SkASSERT(SkToBool(fIsFinite) == isFinite);
320 } 452 }
453
454 #ifdef SK_DEBUG_PATH
455 if (!fBoundsIsDirty) {
456 SkRect bounds;
457
458 bool isFinite = ComputePtBounds(&bounds, fPoints, fPointCnt);
459 SkASSERT(SkToBool(fIsFinite) == isFinite);
460
461 if (fPointCnt <= 1) {
462 // if we're empty, fBounds may be empty but translated, so we can't
463 // necessarily compare to bounds directly
464 // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will
465 // be [2, 2, 2, 2]
466 SkASSERT(bounds.isEmpty());
467 SkASSERT(fBounds.isEmpty());
468 } else {
469 if (bounds.isEmpty()) {
470 SkASSERT(fBounds.isEmpty());
471 } else {
472 if (!fBounds.isEmpty()) {
473 SkASSERT(fBounds.contains(bounds));
474 }
475 }
476 }
477 }
478
479 uint32_t mask = 0;
480 int pointCnt = 0;
481 int lastMoveToIndex = ~0;
482 for (int i = 0; i < fVerbCnt; i++) {
483 switch (fVerbs[~i]) {
484 case kMove_Verb:
485 lastMoveToIndex = pointCnt;
486 ++pointCnt;
487 break;
488 case kLine_Verb:
489 mask |= kLine_SegmentMask;
490 ++pointCnt;
491 break;
492 case kQuad_Verb:
493 mask |= kQuad_SegmentMask;
494 pointCnt += 2;
495 break;
496 case kConic_Verb:
497 mask |= kConic_SegmentMask;
498 pointCnt += 2;
499 break;
500 case kCubic_Verb:
501 mask |= kCubic_SegmentMask;
502 pointCnt += 3;
503 break;
504 case kClose_Verb:
505 if (lastMoveToIndex >= 0) {
506 lastMoveToIndex = ~lastMoveToIndex;
507 }
508 break;
509 case kDone_Verb:
510 SkDEBUGFAIL("Done verb shouldn't be recorded.");
511 break;
512 default:
513 SkDEBUGFAIL("Unknown Verb");
514 break;
515 }
516 }
517 SkASSERT(mask == fSegmentMask);
518 SkASSERT(lastMoveToIndex == fLastMoveToIndex);
519 #endif // SK_DEBUG_PATH
520 }
321 #endif 521 #endif
522
523 ///////////////////////////////////////////////////////////////////////////////
524
525 static int sign(SkScalar x) { return x < 0; }
526 #define kValueNeverReturnedBySign 2
527
528 static int CrossProductSign(const SkVector& a, const SkVector& b) {
529 return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
530 }
531
532 // only valid for a single contour
533 struct Convexicator {
534 Convexicator()
535 : fPtCount(0)
536 , fConvexity(SkPathRef::kConvex_Convexity)
537 , fDirection(SkPathRef::kUnknown_Direction) {
538 fSign = 0;
539 // warnings
540 fCurrPt.set(0, 0);
541 fVec0.set(0, 0);
542 fVec1.set(0, 0);
543 fFirstVec.set(0, 0);
544
545 fDx = fDy = 0;
546 fSx = fSy = kValueNeverReturnedBySign;
547 }
548
549 SkPathRef::Convexity getConvexity() const { return fConvexity; }
550
551 /** The direction returned is only valid if the path is determined convex */
552 SkPathRef::Direction getDirection() const { return fDirection; }
553
554 void addPt(const SkPoint& pt) {
555 if (SkPathRef::kConcave_Convexity == fConvexity) {
556 return;
557 }
558
559 if (0 == fPtCount) {
560 fCurrPt = pt;
561 ++fPtCount;
562 } else {
563 SkVector vec = pt - fCurrPt;
564 if (vec.fX || vec.fY) {
565 fCurrPt = pt;
566 if (++fPtCount == 2) {
567 fFirstVec = fVec1 = vec;
568 } else {
569 SkASSERT(fPtCount > 2);
570 this->addVec(vec);
571 }
572
573 int sx = sign(vec.fX);
574 int sy = sign(vec.fY);
575 fDx += (sx != fSx);
576 fDy += (sy != fSy);
577 fSx = sx;
578 fSy = sy;
579
580 if (fDx > 3 || fDy > 3) {
581 fConvexity = SkPathRef::kConcave_Convexity;
582 }
583 }
584 }
585 }
586
587 void close() {
588 if (fPtCount > 2) {
589 this->addVec(fFirstVec);
590 }
591 }
592
593 private:
594 void addVec(const SkVector& vec) {
595 SkASSERT(vec.fX || vec.fY);
596 fVec0 = fVec1;
597 fVec1 = vec;
598 int sign = CrossProductSign(fVec0, fVec1);
599 if (0 == fSign) {
600 fSign = sign;
601 if (1 == sign) {
602 fDirection = SkPathRef::kCW_Direction;
603 } else if (-1 == sign) {
604 fDirection = SkPathRef::kCCW_Direction;
605 }
606 } else if (sign) {
607 if (fSign != sign) {
608 fConvexity = SkPathRef::kConcave_Convexity;
609 fDirection = SkPathRef::kUnknown_Direction;
610 }
611 }
612 }
613
614 SkPoint fCurrPt;
615 SkVector fVec0, fVec1, fFirstVec;
616 int fPtCount; // non-degenerate points
617 int fSign;
618 SkPathRef::Convexity fConvexity;
619 SkPathRef::Direction fDirection;
620 int fDx, fDy, fSx, fSy;
621 };
622
623 SkPathRef::Convexity SkPathRef::internalGetConvexity() const {
624 SkASSERT(kUnknown_Convexity == fConvexity);
625 SkPoint pts[4];
626 SkPath::Verb verb;
627 SkPath::Iter iter(this, true);
628
629 int contourCount = 0;
630 int count;
631 Convexicator state;
632
633 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
634 switch (verb) {
635 case SkPath::kMove_Verb:
636 if (++contourCount > 1) {
637 fConvexity = kConcave_Convexity;
638 return kConcave_Convexity;
639 }
640 pts[1] = pts[0];
641 count = 1;
642 break;
643 case SkPath::kLine_Verb: count = 1; break;
644 case SkPath::kQuad_Verb: count = 2; break;
645 case SkPath::kConic_Verb: count = 2; break;
646 case SkPath::kCubic_Verb: count = 3; break;
647 case SkPath::kClose_Verb:
648 state.close();
649 count = 0;
650 break;
651 default:
652 SkDEBUGFAIL("bad verb");
653 fConvexity = kConcave_Convexity;
654 return kConcave_Convexity;
655 }
656
657 for (int i = 1; i <= count; i++) {
658 state.addPt(pts[i]);
659 }
660 // early exit
661 if (kConcave_Convexity == state.getConvexity()) {
662 fConvexity = kConcave_Convexity;
663 return kConcave_Convexity;
664 }
665 }
666 fConvexity = state.getConvexity();
667 if (kConvex_Convexity == fConvexity && kUnknown_Direction == fDirection) {
668 fDirection = state.getDirection();
669 }
670 return static_cast<Convexity>(fConvexity);
671 }
672
673 class ContourIter {
674 public:
675 ContourIter(const SkPathRef& pathRef);
676
677 bool done() const { return fDone; }
678 // if !done() then these may be called
679 int count() const { return fCurrPtCount; }
680 const SkPoint* pts() const { return fCurrPt; }
681 void next();
682
683 private:
684 int fCurrPtCount;
685 const SkPoint* fCurrPt;
686 const uint8_t* fCurrVerb;
687 const uint8_t* fStopVerbs;
688 const SkScalar* fCurrConicWeight;
689 bool fDone;
690 SkDEBUGCODE(int fContourCounter;)
691 };
692
693 ContourIter::ContourIter(const SkPathRef& pathRef) {
694 fStopVerbs = pathRef.verbsMemBegin();
695 fDone = false;
696 fCurrPt = pathRef.points();
697 fCurrVerb = pathRef.verbs();
698 fCurrConicWeight = pathRef.conicWeights();
699 fCurrPtCount = 0;
700 SkDEBUGCODE(fContourCounter = 0;)
701 this->next();
702 }
703
704 void ContourIter::next() {
705 if (fCurrVerb <= fStopVerbs) {
706 fDone = true;
707 }
708 if (fDone) {
709 return;
710 }
711
712 // skip pts of prev contour
713 fCurrPt += fCurrPtCount;
714
715 SkASSERT(SkPathRef::kMove_Verb == fCurrVerb[~0]);
716 int ptCount = 1; // moveTo
717 const uint8_t* verbs = fCurrVerb;
718
719 for (--verbs; verbs > fStopVerbs; --verbs) {
720 switch (verbs[~0]) {
721 case SkPathRef::kMove_Verb:
722 goto CONTOUR_END;
723 case SkPathRef::kLine_Verb:
724 ptCount += 1;
725 break;
726 case SkPathRef::kConic_Verb:
727 fCurrConicWeight += 1;
728 // fall-through
729 case SkPathRef::kQuad_Verb:
730 ptCount += 2;
731 break;
732 case SkPathRef::kCubic_Verb:
733 ptCount += 3;
734 break;
735 case SkPathRef::kClose_Verb:
736 break;
737 default:
738 SkDEBUGFAIL("unexpected verb");
739 break;
740 }
741 }
742 CONTOUR_END:
743 fCurrPtCount = ptCount;
744 fCurrVerb = verbs;
745 SkDEBUGCODE(++fContourCounter;)
746 }
747
748 // returns cross product of (p1 - p0) and (p2 - p0)
749 static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
750 SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0);
751 // We may get 0 when the above subtracts underflow. We expect this to be
752 // very rare and lazily promote to double.
753 if (0 == cross) {
754 double p0x = SkScalarToDouble(p0.fX);
755 double p0y = SkScalarToDouble(p0.fY);
756
757 double p1x = SkScalarToDouble(p1.fX);
758 double p1y = SkScalarToDouble(p1.fY);
759
760 double p2x = SkScalarToDouble(p2.fX);
761 double p2y = SkScalarToDouble(p2.fY);
762
763 cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) -
764 (p1y - p0y) * (p2x - p0x));
765
766 }
767 return cross;
768 }
769
770 // Returns the first pt with the maximum Y coordinate
771 static int find_max_y(const SkPoint pts[], int count) {
772 SkASSERT(count > 0);
773 SkScalar max = pts[0].fY;
774 int firstIndex = 0;
775 for (int i = 1; i < count; ++i) {
776 SkScalar y = pts[i].fY;
777 if (y > max) {
778 max = y;
779 firstIndex = i;
780 }
781 }
782 return firstIndex;
783 }
784
785 static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
786 int i = index;
787 for (;;) {
788 i = (i + inc) % n;
789 if (i == index) { // we wrapped around, so abort
790 break;
791 }
792 if (pts[index] != pts[i]) { // found a different point, success!
793 break;
794 }
795 }
796 return i;
797 }
798
799 /**
800 * Starting at index, and moving forward (incrementing), find the xmin and
801 * xmax of the contiguous points that have the same Y.
802 */
803 static int find_min_max_x_at_y(const SkPoint pts[], int index, int n,
804 int* maxIndexPtr) {
805 const SkScalar y = pts[index].fY;
806 SkScalar min = pts[index].fX;
807 SkScalar max = min;
808 int minIndex = index;
809 int maxIndex = index;
810 for (int i = index + 1; i < n; ++i) {
811 if (pts[i].fY != y) {
812 break;
813 }
814 SkScalar x = pts[i].fX;
815 if (x < min) {
816 min = x;
817 minIndex = i;
818 } else if (x > max) {
819 max = x;
820 maxIndex = i;
821 }
822 }
823 *maxIndexPtr = maxIndex;
824 return minIndex;
825 }
826
827 static void crossToDir(SkScalar cross, SkPathRef::Direction* dir) {
828 if (dir) {
829 *dir = cross > 0 ? SkPathRef::kCW_Direction : SkPathRef::kCCW_Direction;
830 }
831 }
832
833 #if 0
834 #include "SkString.h"
835 #include "../utils/SkParsePath.h"
836 static void dumpPath(const SkPath& path) {
837 SkString str;
838 SkParsePath::ToSVGString(path, &str);
839 SkDebugf("%s\n", str.c_str());
322 } 840 }
323 #endif 841 #endif
842
843 namespace {
844 // for use with convex_dir_test
845 double mul(double a, double b) { return a * b; }
846 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); }
847 double toDouble(SkScalar a) { return SkScalarToDouble(a); }
848 SkScalar toScalar(SkScalar a) { return a; }
849
850 // determines the winding direction of a convex polygon with the precision
851 // of T. CAST_SCALAR casts an SkScalar to T.
852 template <typename T, T (CAST_SCALAR)(SkScalar)>
853 bool convex_dir_test(int n, const SkPoint pts[], SkPathRef::Direction* dir) {
854 // we find the first three points that form a non-degenerate
855 // triangle. If there are no such points then the path is
856 // degenerate. The first is always point 0. Now we find the second
857 // point.
858 int i = 0;
859 enum { kX = 0, kY = 1 };
860 T v0[2];
861 while (1) {
862 v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
863 v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
864 if (v0[kX] || v0[kY]) {
865 break;
866 }
867 if (++i == n - 1) {
868 return false;
869 }
870 }
871 // now find a third point that is not colinear with the first two
872 // points and check the orientation of the triangle (which will be
873 // the same as the orientation of the path).
874 for (++i; i < n; ++i) {
875 T v1[2];
876 v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
877 v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
878 T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]);
879 if (0 != cross) {
880 *dir = cross > 0 ? SkPathRef::kCW_Direction : SkPathRef::kCCW_Direct ion;
881 return true;
882 }
883 }
884 return false;
885 }
886 }
887
888 /*
889 * We loop through all contours, and keep the computed cross-product of the
890 * contour that contained the global y-max. If we just look at the first
891 * contour, we may find one that is wound the opposite way (correctly) since
892 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour
893 * that is outer most (or at least has the global y-max) before we can consider
894 * its cross product.
895 */
896 bool SkPathRef::cheapComputeDirection(Direction* dir) const {
897 // dumpPath(*this);
898 // don't want to pay the cost for computing this if it
899 // is unknown, so we don't call isConvex()
900
901 if (kUnknown_Direction != fDirection) {
902 *dir = static_cast<Direction>(fDirection);
903 return true;
904 }
905 const SkPathRef::Convexity conv = this->getConvexityOrUnknown();
906
907 ContourIter iter(*this);
908
909 // initialize with our logical y-min
910 SkScalar ymax = this->getBounds().fTop;
911 SkScalar ymaxCross = 0;
912
913 for (; !iter.done(); iter.next()) {
914 int n = iter.count();
915 if (n < 3) {
916 continue;
917 }
918
919 const SkPoint* pts = iter.pts();
920 SkScalar cross = 0;
921 if (SkPathRef::kConvex_Convexity == conv) {
922 // We try first at scalar precision, and then again at double
923 // precision. This is because the vectors computed between distant
924 // points may lose too much precision.
925 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) {
926 fDirection = *dir;
927 return true;
928 }
929 if (convex_dir_test<double, toDouble>(n, pts, dir)) {
930 fDirection = *dir;
931 return true;
932 } else {
933 return false;
934 }
935 } else {
936 int index = find_max_y(pts, n);
937 if (pts[index].fY < ymax) {
938 continue;
939 }
940
941 // If there is more than 1 distinct point at the y-max, we take the
942 // x-min and x-max of them and just subtract to compute the dir.
943 if (pts[(index + 1) % n].fY == pts[index].fY) {
944 int maxIndex;
945 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
946 if (minIndex == maxIndex) {
947 goto TRY_CROSSPROD;
948 }
949 SkASSERT(pts[minIndex].fY == pts[index].fY);
950 SkASSERT(pts[maxIndex].fY == pts[index].fY);
951 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
952 // we just subtract the indices, and let that auto-convert to
953 // SkScalar, since we just want - or + to signal the direction.
954 cross = minIndex - maxIndex;
955 } else {
956 TRY_CROSSPROD:
957 // Find a next and prev index to use for the cross-product test,
958 // but we try to find pts that form non-zero vectors from pts[in dex]
959 //
960 // Its possible that we can't find two non-degenerate vectors, s o
961 // we have to guard our search (e.g. all the pts could be in the
962 // same place).
963
964 // we pass n - 1 instead of -1 so we don't foul up % operator by
965 // passing it a negative LH argument.
966 int prev = find_diff_pt(pts, index, n, n - 1);
967 if (prev == index) {
968 // completely degenerate, skip to next contour
969 continue;
970 }
971 int next = find_diff_pt(pts, index, n, 1);
972 SkASSERT(next != index);
973 cross = cross_prod(pts[prev], pts[index], pts[next]);
974 // if we get a zero and the points are horizontal, then we look at the spread in
975 // x-direction. We really should continue to walk away from the degeneracy until
976 // there is a divergence.
977 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
978 // construct the subtract so we get the correct Direction be low
979 cross = pts[index].fX - pts[next].fX;
980 }
981 }
982
983 if (cross) {
984 // record our best guess so far
985 ymax = pts[index].fY;
986 ymaxCross = cross;
987 }
988 }
989 }
990 if (ymaxCross) {
991 crossToDir(ymaxCross, dir);
992 fDirection = *dir;
993 return true;
994 } else {
995 return false;
996 }
997 }
998
OLDNEW
« include/core/SkPath.h ('K') | « src/core/SkPath.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698