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

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

Issue 105083003: Move segment mask from SkPath to SkPathRef (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: fixed comment Created 7 years 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/SkPathRef.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 "SkOnce.h" 9 #include "SkOnce.h"
10 #include "SkPath.h" 10 #include "SkPath.h"
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 (*dst)->fBounds.setEmpty(); 98 (*dst)->fBounds.setEmpty();
99 } 99 }
100 } else { 100 } else {
101 (*dst)->fIsFinite = false; 101 (*dst)->fIsFinite = false;
102 (*dst)->fBounds.setEmpty(); 102 (*dst)->fBounds.setEmpty();
103 } 103 }
104 } else { 104 } else {
105 (*dst)->fBoundsIsDirty = true; 105 (*dst)->fBoundsIsDirty = true;
106 } 106 }
107 107
108 (*dst)->fSegmentMask = src.fSegmentMask;
109
108 // It's an oval only if it stays a rect. 110 // It's an oval only if it stays a rect.
109 (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect(); 111 (*dst)->fIsOval = src.fIsOval && matrix.rectStaysRect();
110 112
111 SkDEBUGCODE((*dst)->validate();) 113 SkDEBUGCODE((*dst)->validate();)
112 } 114 }
113 115
114 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer 116 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer
115 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TO O 117 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TO O
116 , bool newFormat, int32_t oldPacked 118 , bool newFormat, int32_t oldPacked
117 #endif 119 #endif
118 ) { 120 ) {
119 SkPathRef* ref = SkNEW(SkPathRef); 121 SkPathRef* ref = SkNEW(SkPathRef);
120 bool isOval; 122 bool isOval;
123 uint8_t segmentMask;
121 124
122 int32_t packed; 125 int32_t packed;
123 if (!buffer->readS32(&packed)) { 126 if (!buffer->readS32(&packed)) {
124 SkDELETE(ref); 127 SkDELETE(ref);
125 return NULL; 128 return NULL;
126 } 129 }
127 130
128 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1; 131 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
129 132
130 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TO O 133 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TO O
131 if (newFormat) { 134 if (newFormat) {
132 #endif 135 #endif
136 segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
133 isOval = (packed >> kIsOval_SerializationShift) & 1; 137 isOval = (packed >> kIsOval_SerializationShift) & 1;
134 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TO O 138 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TO O
135 } else { 139 } else {
140 segmentMask = (oldPacked >> SkPath::kOldSegmentMask_SerializationShift) & 0xF;
136 isOval = (oldPacked >> SkPath::kOldIsOval_SerializationShift) & 1; 141 isOval = (oldPacked >> SkPath::kOldIsOval_SerializationShift) & 1;
137 } 142 }
138 #endif 143 #endif
139 144
140 int32_t verbCount, pointCount, conicCount; 145 int32_t verbCount, pointCount, conicCount;
141 if (!buffer->readU32(&(ref->fGenerationID)) || 146 if (!buffer->readU32(&(ref->fGenerationID)) ||
142 !buffer->readS32(&verbCount) || 147 !buffer->readS32(&verbCount) ||
143 !buffer->readS32(&pointCount) || 148 !buffer->readS32(&pointCount) ||
144 !buffer->readS32(&conicCount)) { 149 !buffer->readS32(&conicCount)) {
145 SkDELETE(ref); 150 SkDELETE(ref);
146 return NULL; 151 return NULL;
147 } 152 }
148 153
149 ref->resetToSize(verbCount, pointCount, conicCount); 154 ref->resetToSize(verbCount, pointCount, conicCount);
150 SkASSERT(verbCount == ref->countVerbs()); 155 SkASSERT(verbCount == ref->countVerbs());
151 SkASSERT(pointCount == ref->countPoints()); 156 SkASSERT(pointCount == ref->countPoints());
152 SkASSERT(conicCount == ref->fConicWeights.count()); 157 SkASSERT(conicCount == ref->fConicWeights.count());
153 158
154 if (!buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)) || 159 if (!buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)) ||
155 !buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)) || 160 !buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)) ||
156 !buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)) || 161 !buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)) ||
157 !buffer->read(&ref->fBounds, sizeof(SkRect))) { 162 !buffer->read(&ref->fBounds, sizeof(SkRect))) {
158 SkDELETE(ref); 163 SkDELETE(ref);
159 return NULL; 164 return NULL;
160 } 165 }
161 ref->fBoundsIsDirty = false; 166 ref->fBoundsIsDirty = false;
167
168 // resetToSize clears fSegmentMask and fIsOval
169 ref->fSegmentMask = segmentMask;
162 ref->fIsOval = isOval; 170 ref->fIsOval = isOval;
163 return ref; 171 return ref;
164 } 172 }
165 173
166 void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) { 174 void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
167 if ((*pathRef)->unique()) { 175 if ((*pathRef)->unique()) {
168 SkDEBUGCODE((*pathRef)->validate();) 176 SkDEBUGCODE((*pathRef)->validate();)
169 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite 177 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
170 (*pathRef)->fVerbCnt = 0; 178 (*pathRef)->fVerbCnt = 0;
171 (*pathRef)->fPointCnt = 0; 179 (*pathRef)->fPointCnt = 0;
172 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); 180 (*pathRef)->fFreeSpace = (*pathRef)->currSize();
173 (*pathRef)->fGenerationID = 0; 181 (*pathRef)->fGenerationID = 0;
174 (*pathRef)->fConicWeights.rewind(); 182 (*pathRef)->fConicWeights.rewind();
183 (*pathRef)->fSegmentMask = 0;
175 (*pathRef)->fIsOval = false; 184 (*pathRef)->fIsOval = false;
176 SkDEBUGCODE((*pathRef)->validate();) 185 SkDEBUGCODE((*pathRef)->validate();)
177 } else { 186 } else {
178 int oldVCnt = (*pathRef)->countVerbs(); 187 int oldVCnt = (*pathRef)->countVerbs();
179 int oldPCnt = (*pathRef)->countPoints(); 188 int oldPCnt = (*pathRef)->countPoints();
180 pathRef->reset(SkNEW(SkPathRef)); 189 pathRef->reset(SkNEW(SkPathRef));
181 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); 190 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
182 } 191 }
183 } 192 }
184 193
185 bool SkPathRef::operator== (const SkPathRef& ref) const { 194 bool SkPathRef::operator== (const SkPathRef& ref) const {
186 SkDEBUGCODE(this->validate();) 195 SkDEBUGCODE(this->validate();)
187 SkDEBUGCODE(ref.validate();) 196 SkDEBUGCODE(ref.validate();)
197
198 // We explicitly check fSegmentMask as a quick-reject. We could skip it,
199 // since it is only a cache of info in the fVerbs, but its a fast way to
200 // notice a difference
201 if (fSegmentMask != ref.fSegmentMask) {
202 return false;
203 }
204
188 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID; 205 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
189 #ifdef SK_RELEASE 206 #ifdef SK_RELEASE
190 if (genIDMatch) { 207 if (genIDMatch) {
191 return true; 208 return true;
192 } 209 }
193 #endif 210 #endif
194 if (fPointCnt != ref.fPointCnt || 211 if (fPointCnt != ref.fPointCnt ||
195 fVerbCnt != ref.fVerbCnt) { 212 fVerbCnt != ref.fVerbCnt) {
196 SkASSERT(!genIDMatch); 213 SkASSERT(!genIDMatch);
197 return false; 214 return false;
(...skipping 17 matching lines...) Expand all
215 // We've done the work to determine that these are equal. If either has a ze ro genID, copy 232 // We've done the work to determine that these are equal. If either has a ze ro genID, copy
216 // the other's. If both are 0 then genID() will compute the next ID. 233 // the other's. If both are 0 then genID() will compute the next ID.
217 if (0 == fGenerationID) { 234 if (0 == fGenerationID) {
218 fGenerationID = ref.genID(); 235 fGenerationID = ref.genID();
219 } else if (0 == ref.fGenerationID) { 236 } else if (0 == ref.fGenerationID) {
220 ref.fGenerationID = this->genID(); 237 ref.fGenerationID = this->genID();
221 } 238 }
222 return true; 239 return true;
223 } 240 }
224 241
225 void SkPathRef::writeToBuffer(SkWBuffer* buffer) { 242 void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
226 SkDEBUGCODE(this->validate();) 243 SkDEBUGCODE(this->validate();)
227 SkDEBUGCODE(size_t beforePos = buffer->pos();) 244 SkDEBUGCODE(size_t beforePos = buffer->pos();)
228 245
229 // Call getBounds() to ensure (as a side-effect) that fBounds 246 // Call getBounds() to ensure (as a side-effect) that fBounds
230 // and fIsFinite are computed. 247 // and fIsFinite are computed.
231 const SkRect& bounds = this->getBounds(); 248 const SkRect& bounds = this->getBounds();
232 249
233 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | 250 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
234 ((fIsOval & 1) << kIsOval_SerializationShift); 251 ((fIsOval & 1) << kIsOval_SerializationShift) |
252 (fSegmentMask << kSegmentMask_SerializationShift);
235 buffer->write32(packed); 253 buffer->write32(packed);
236 254
237 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from 255 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
238 // SkWBuffer. Until this is fixed we write 0. 256 // SkWBuffer. Until this is fixed we write 0.
239 buffer->write32(0); 257 buffer->write32(0);
240 buffer->write32(fVerbCnt); 258 buffer->write32(fVerbCnt);
241 buffer->write32(fPointCnt); 259 buffer->write32(fPointCnt);
242 buffer->write32(fConicWeights.count()); 260 buffer->write32(fConicWeights.count());
243 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); 261 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
244 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); 262 buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
245 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); 263 buffer->write(fConicWeights.begin(), fConicWeights.bytes());
246 buffer->write(&bounds, sizeof(bounds)); 264 buffer->write(&bounds, sizeof(bounds));
247 265
248 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); 266 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
249 } 267 }
250 268
251 uint32_t SkPathRef::writeSize() { 269 uint32_t SkPathRef::writeSize() const {
252 return uint32_t(5 * sizeof(uint32_t) + 270 return uint32_t(5 * sizeof(uint32_t) +
253 fVerbCnt * sizeof(uint8_t) + 271 fVerbCnt * sizeof(uint8_t) +
254 fPointCnt * sizeof(SkPoint) + 272 fPointCnt * sizeof(SkPoint) +
255 fConicWeights.bytes() + 273 fConicWeights.bytes() +
256 sizeof(SkRect)); 274 sizeof(SkRect));
257 } 275 }
258 276
259 void SkPathRef::copy(const SkPathRef& ref, 277 void SkPathRef::copy(const SkPathRef& ref,
260 int additionalReserveVerbs, 278 int additionalReserveVerbs,
261 int additionalReservePoints) { 279 int additionalReservePoints) {
262 SkDEBUGCODE(this->validate();) 280 SkDEBUGCODE(this->validate();)
263 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(), 281 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
264 additionalReserveVerbs, additionalReservePoints); 282 additionalReserveVerbs, additionalReservePoints);
265 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof( uint8_t)); 283 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof( uint8_t));
266 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); 284 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
267 fConicWeights = ref.fConicWeights; 285 fConicWeights = ref.fConicWeights;
268 // We could call genID() here to force a real ID (instead of 0). However, if we're making 286 // We could call genID() here to force a real ID (instead of 0). However, if we're making
269 // a copy then presumably we intend to make a modification immediately after wards. 287 // a copy then presumably we intend to make a modification immediately after wards.
270 fGenerationID = ref.fGenerationID; 288 fGenerationID = ref.fGenerationID;
271 fBoundsIsDirty = ref.fBoundsIsDirty; 289 fBoundsIsDirty = ref.fBoundsIsDirty;
272 if (!fBoundsIsDirty) { 290 if (!fBoundsIsDirty) {
273 fBounds = ref.fBounds; 291 fBounds = ref.fBounds;
274 fIsFinite = ref.fIsFinite; 292 fIsFinite = ref.fIsFinite;
275 } 293 }
294 fSegmentMask = ref.fSegmentMask;
276 fIsOval = ref.fIsOval; 295 fIsOval = ref.fIsOval;
277 SkDEBUGCODE(this->validate();) 296 SkDEBUGCODE(this->validate();)
278 } 297 }
279 298
299 SkPoint* SkPathRef::growForLines(int numLines) {
300 // This value is just made-up for now. When count is 4, calling memset was m uch
301 // slower than just writing the loop. This seems odd, and hopefully in the
302 // future this will appear to have been a fluke...
303 static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16;
304
305 // TODO: The following isn't hyper-optimized for the lines case since
306 // it should be expanded to handle quads, conics and cubics
307 SkDEBUGCODE(this->validate();)
308
309 size_t space = numLines * sizeof(uint8_t) + numLines * sizeof (SkPoint);
310 this->makeSpace(space);
311
312 SkPoint* ret = fPoints + fPointCnt;
313 uint8_t* vb = fVerbs - fVerbCnt;
314
315 // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
316 // be 0, the compiler will remove the test/branch entirely.
317 if ((unsigned)numLines >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
318 memset(vb - numLines, SkPath::kLine_Verb, numLines);
319 } else {
320 for (int i = 0; i < numLines; ++i) {
321 vb[~i] = SkPath::kLine_Verb;
322 }
323 }
324 fSegmentMask |= SkPath::kLine_SegmentMask;
325
326 fVerbCnt += numLines;
327 fPointCnt += numLines;
328 fFreeSpace -= space;
329 fBoundsIsDirty = true; // this also invalidates fIsFinite
330 fIsOval = false;
331
332 SkDEBUGCODE(this->validate();)
333 return ret;
334 }
335
280 SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) { 336 SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) {
281 SkDEBUGCODE(this->validate();) 337 SkDEBUGCODE(this->validate();)
282 int pCnt; 338 int pCnt;
283 bool dirtyAfterEdit = true; 339 bool dirtyAfterEdit = true;
284 switch (verb) { 340 switch (verb) {
285 case SkPath::kMove_Verb: 341 case SkPath::kMove_Verb:
286 pCnt = 1; 342 pCnt = 1;
287 dirtyAfterEdit = false; 343 dirtyAfterEdit = false;
288 break; 344 break;
289 case SkPath::kLine_Verb: 345 case SkPath::kLine_Verb:
346 fSegmentMask |= SkPath::kLine_SegmentMask;
290 pCnt = 1; 347 pCnt = 1;
291 break; 348 break;
292 case SkPath::kQuad_Verb: 349 case SkPath::kQuad_Verb:
293 // fall through 350 fSegmentMask |= SkPath::kQuad_SegmentMask;
351 pCnt = 2;
352 break;
294 case SkPath::kConic_Verb: 353 case SkPath::kConic_Verb:
354 fSegmentMask |= SkPath::kConic_SegmentMask;
295 pCnt = 2; 355 pCnt = 2;
296 break; 356 break;
297 case SkPath::kCubic_Verb: 357 case SkPath::kCubic_Verb:
358 fSegmentMask |= SkPath::kCubic_SegmentMask;
298 pCnt = 3; 359 pCnt = 3;
299 break; 360 break;
300 case SkPath::kClose_Verb: 361 case SkPath::kClose_Verb:
301 pCnt = 0; 362 pCnt = 0;
302 dirtyAfterEdit = false; 363 dirtyAfterEdit = false;
303 break; 364 break;
304 case SkPath::kDone_Verb: 365 case SkPath::kDone_Verb:
305 SkDEBUGFAIL("growForVerb called for kDone"); 366 SkDEBUGFAIL("growForVerb called for kDone");
306 // fall through 367 // fall through
307 default: 368 default:
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 fBounds.fLeft - fPoints[i].fX < SK_ScalarNearlyZero && 423 fBounds.fLeft - fPoints[i].fX < SK_ScalarNearlyZero &&
363 fPoints[i].fX - fBounds.fRight < SK_ScalarNearlyZero && 424 fPoints[i].fX - fBounds.fRight < SK_ScalarNearlyZero &&
364 fBounds.fTop - fPoints[i].fY < SK_ScalarNearlyZero && 425 fBounds.fTop - fPoints[i].fY < SK_ScalarNearlyZero &&
365 fPoints[i].fY - fBounds.fBottom < SK_ScalarNearlyZero)); 426 fPoints[i].fY - fBounds.fBottom < SK_ScalarNearlyZero));
366 if (!fPoints[i].isFinite()) { 427 if (!fPoints[i].isFinite()) {
367 isFinite = false; 428 isFinite = false;
368 } 429 }
369 } 430 }
370 SkASSERT(SkToBool(fIsFinite) == isFinite); 431 SkASSERT(SkToBool(fIsFinite) == isFinite);
371 } 432 }
433
434 #ifdef SK_DEBUG_PATH
435 uint32_t mask = 0;
436 for (int i = 0; i < fVerbCnt; ++i) {
437 switch (fVerbs[~i]) {
438 case SkPath::kMove_Verb:
439 break;
440 case SkPath::kLine_Verb:
441 mask |= SkPath::kLine_SegmentMask;
442 break;
443 case SkPath::kQuad_Verb:
444 mask |= SkPath::kQuad_SegmentMask;
445 break;
446 case SkPath::kConic_Verb:
447 mask |= SkPath::kConic_SegmentMask;
448 break;
449 case SkPath::kCubic_Verb:
450 mask |= SkPath::kCubic_SegmentMask;
451 break;
452 case SkPath::kClose_Verb:
453 break;
454 case SkPath::kDone_Verb:
455 SkDEBUGFAIL("Done verb shouldn't be recorded.");
456 break;
457 default:
458 SkDEBUGFAIL("Unknown Verb");
459 break;
460 }
461 }
462 SkASSERT(mask == fSegmentMask);
463 #endif // SK_DEBUG_PATH
372 } 464 }
373 #endif 465 #endif
OLDNEW
« include/core/SkPathRef.h ('K') | « src/core/SkPath.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698