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

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

Powered by Google App Engine
This is Rietveld 408576698