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

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

Issue 24998004: Move unlikely-to-be-inlined code from SkPathRef.h to SkPathRef.cpp (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: 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/SkPathRef.h ('K') | « include/core/SkPathRef.h ('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 SkPoint* SkPathRef::Editor::growForVerb(int /*SkPath::Verb*/ verb) { 14 //////////////////////////////////////////////////////////////////////////////
15 fPathRef->validate(); 15 SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef,
16 return fPathRef->growForVerb(verb); 16 int incReserveVerbs,
17 int incReservePoints)
18 {
19 if ((*pathRef)->unique()) {
20 (*pathRef)->incReserve(incReserveVerbs, incReservePoints);
21 } else {
22 SkPathRef* copy = SkNEW(SkPathRef);
23 copy->copy(**pathRef, incReserveVerbs, incReservePoints);
24 pathRef->reset(copy);
25 }
26 fPathRef = *pathRef;
27 fPathRef->fGenerationID = 0;
28 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
17 } 29 }
18 30
19 SkPoint* SkPathRef::Editor::growForConic(SkScalar w) { 31 SkPoint* SkPathRef::Editor::growForConic(SkScalar w) {
20 fPathRef->validate(); 32 fPathRef->validate();
21 SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb); 33 SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb);
22 *fPathRef->fConicWeights.append() = w; 34 *fPathRef->fConicWeights.append() = w;
23 return pts; 35 return pts;
24 } 36 }
25 37
26 SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) { 38 void SkPathRef::Editor::grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint* * pts) {
27 this->validate(); 39 SkASSERT(NULL != verbs);
28 int pCnt; 40 SkASSERT(NULL != pts);
29 switch (verb) { 41 fPathRef->validate();
30 case SkPath::kMove_Verb: 42 int oldVerbCnt = fPathRef->fVerbCnt;
31 pCnt = 1; 43 int oldPointCnt = fPathRef->fPointCnt;
32 break; 44 SkASSERT(verbs && pts);
33 case SkPath::kLine_Verb: 45 fPathRef->grow(newVerbs, newPts);
34 pCnt = 1; 46 *verbs = fPathRef->fVerbs - oldVerbCnt;
35 break; 47 *pts = fPathRef->fPoints + oldPointCnt;
36 case SkPath::kQuad_Verb: 48 fPathRef->validate();
37 // fall through 49 }
38 case SkPath::kConic_Verb: 50
39 pCnt = 2; 51 //////////////////////////////////////////////////////////////////////////////
40 break; 52 void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
41 case SkPath::kCubic_Verb: 53 const SkPathRef& src,
42 pCnt = 3; 54 const SkMatrix& matrix) {
43 break; 55 src.validate();
44 case SkPath::kClose_Verb: 56 if (matrix.isIdentity()) {
45 pCnt = 0; 57 if (*dst != &src) {
46 break; 58 src.ref();
47 case SkPath::kDone_Verb: 59 dst->reset(const_cast<SkPathRef*>(&src));
48 SkDEBUGFAIL("growForVerb called for kDone"); 60 (*dst)->validate();
49 // fall through 61 }
50 default: 62 return;
51 SkDEBUGFAIL("default is not reached");
52 pCnt = 0;
53 } 63 }
54 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); 64
55 this->makeSpace(space); 65 bool dstUnique = (*dst)->unique();
56 this->fVerbs[~fVerbCnt] = verb; 66 if (!dstUnique) {
57 SkPoint* ret = fPoints + fPointCnt; 67 dst->reset(SkNEW(SkPathRef));
58 fVerbCnt += 1; 68 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count ());
59 fPointCnt += pCnt; 69 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * s izeof(uint8_t));
60 fFreeSpace -= space; 70 (*dst)->fConicWeights = src.fConicWeights;
61 fBoundsIsDirty = true; // this also invalidates fIsFinite 71 }
62 this->validate(); 72
63 return ret; 73 // Need to check this here in case (&src == dst)
74 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.c ountPoints() > 1;
75
76 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
77
78 /*
79 * Here we optimize the bounds computation, by noting if the bounds are
80 * already known, and if so, we just transform those as well and mark
81 * them as "known", rather than force the transformed path to have to
82 * recompute them.
83 *
84 * Special gotchas if the path is effectively empty (<= 1 point) or
85 * if it is non-finite. In those cases bounds need to stay empty,
86 * regardless of the matrix.
87 */
88 if (canXformBounds) {
89 (*dst)->fBoundsIsDirty = false;
90 if (src.fIsFinite) {
91 matrix.mapRect(&(*dst)->fBounds, src.fBounds);
92 if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) {
93 (*dst)->fBounds.setEmpty();
94 }
95 } else {
96 (*dst)->fIsFinite = false;
97 (*dst)->fBounds.setEmpty();
98 }
99 } else {
100 (*dst)->fBoundsIsDirty = true;
101 }
102
103 (*dst)->validate();
64 } 104 }
65 105
66 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer 106 SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer
67 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 107 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
68 , bool newFormat, int32_t oldPacked 108 , bool newFormat, int32_t oldPacked
69 #endif 109 #endif
70 ) { 110 ) {
71 SkPathRef* ref = SkNEW(SkPathRef); 111 SkPathRef* ref = SkNEW(SkPathRef);
72 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O 112 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TO O
73 if (newFormat) { 113 if (newFormat) {
(...skipping 17 matching lines...) Expand all
91 SkASSERT(pointCount == ref->countPoints()); 131 SkASSERT(pointCount == ref->countPoints());
92 SkASSERT(conicCount == ref->fConicWeights.count()); 132 SkASSERT(conicCount == ref->fConicWeights.count());
93 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)); 133 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t));
94 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)); 134 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
95 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)); 135 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar));
96 buffer->read(&ref->fBounds, sizeof(SkRect)); 136 buffer->read(&ref->fBounds, sizeof(SkRect));
97 ref->fBoundsIsDirty = false; 137 ref->fBoundsIsDirty = false;
98 return ref; 138 return ref;
99 } 139 }
100 140
101 /** 141 void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
102 * Writes the path points and verbs to a buffer. 142 if ((*pathRef)->unique()) {
103 */ 143 (*pathRef)->validate();
144 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
145 (*pathRef)->fVerbCnt = 0;
146 (*pathRef)->fPointCnt = 0;
147 (*pathRef)->fFreeSpace = (*pathRef)->currSize();
148 (*pathRef)->fGenerationID = 0;
149 (*pathRef)->fConicWeights.rewind();
150 (*pathRef)->validate();
151 } else {
152 int oldVCnt = (*pathRef)->countVerbs();
153 int oldPCnt = (*pathRef)->countPoints();
154 pathRef->reset(SkNEW(SkPathRef));
155 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
156 }
157 }
158
159 bool SkPathRef::operator== (const SkPathRef& ref) const {
160 this->validate();
161 ref.validate();
162 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
163 #ifdef SK_RELEASE
164 if (genIDMatch) {
165 return true;
166 }
167 #endif
168 if (fPointCnt != ref.fPointCnt ||
169 fVerbCnt != ref.fVerbCnt) {
170 SkASSERT(!genIDMatch);
171 return false;
172 }
173 if (0 != memcmp(this->verbsMemBegin(),
174 ref.verbsMemBegin(),
175 ref.fVerbCnt * sizeof(uint8_t))) {
176 SkASSERT(!genIDMatch);
177 return false;
178 }
179 if (0 != memcmp(this->points(),
180 ref.points(),
181 ref.fPointCnt * sizeof(SkPoint))) {
182 SkASSERT(!genIDMatch);
183 return false;
184 }
185 if (fConicWeights != ref.fConicWeights) {
186 SkASSERT(!genIDMatch);
187 return false;
188 }
189 // We've done the work to determine that these are equal. If either has a ze ro genID, copy
190 // the other's. If both are 0 then genID() will compute the next ID.
191 if (0 == fGenerationID) {
192 fGenerationID = ref.genID();
193 } else if (0 == ref.fGenerationID) {
194 ref.fGenerationID = this->genID();
195 }
196 return true;
197 }
198
104 void SkPathRef::writeToBuffer(SkWBuffer* buffer) { 199 void SkPathRef::writeToBuffer(SkWBuffer* buffer) {
105 this->validate(); 200 this->validate();
106 SkDEBUGCODE(size_t beforePos = buffer->pos();) 201 SkDEBUGCODE(size_t beforePos = buffer->pos();)
107 202
108 // Call getBounds() to ensure (as a side-effect) that fBounds 203 // Call getBounds() to ensure (as a side-effect) that fBounds
109 // and fIsFinite are computed. 204 // and fIsFinite are computed.
110 const SkRect& bounds = this->getBounds(); 205 const SkRect& bounds = this->getBounds();
111 206
112 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift); 207 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift);
113 buffer->write32(packed); 208 buffer->write32(packed);
114 209
115 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from 210 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
116 // SkWBuffer. Until this is fixed we write 0. 211 // SkWBuffer. Until this is fixed we write 0.
117 buffer->write32(0); 212 buffer->write32(0);
118 buffer->write32(fVerbCnt); 213 buffer->write32(fVerbCnt);
119 buffer->write32(fPointCnt); 214 buffer->write32(fPointCnt);
120 buffer->write32(fConicWeights.count()); 215 buffer->write32(fConicWeights.count());
121 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); 216 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
122 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); 217 buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
123 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); 218 buffer->write(fConicWeights.begin(), fConicWeights.bytes());
124 buffer->write(&bounds, sizeof(bounds)); 219 buffer->write(&bounds, sizeof(bounds));
125 220
126 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); 221 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
127 } 222 }
223
224 uint32_t SkPathRef::writeSize() {
225 return uint32_t(5 * sizeof(uint32_t) +
226 fVerbCnt * sizeof(uint8_t) +
227 fPointCnt * sizeof(SkPoint) +
228 fConicWeights.bytes() +
229 sizeof(SkRect));
230 }
231
232 void SkPathRef::copy(const SkPathRef& ref,
233 int additionalReserveVerbs,
234 int additionalReservePoints) {
235 this->validate();
236 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
237 additionalReserveVerbs, additionalReservePoints);
238 memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof( uint8_t));
239 memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
240 fConicWeights = ref.fConicWeights;
241 // We could call genID() here to force a real ID (instead of 0). However, if we're making
242 // a copy then presumably we intend to make a modification immediately after wards.
243 fGenerationID = ref.fGenerationID;
244 fBoundsIsDirty = ref.fBoundsIsDirty;
245 if (!fBoundsIsDirty) {
246 fBounds = ref.fBounds;
247 fIsFinite = ref.fIsFinite;
248 }
249 this->validate();
250 }
251
252 void SkPathRef::resetToSize(int verbCount, int pointCount, int conicCount,
253 int reserveVerbs, int reservePoints) {
254 this->validate();
255 fBoundsIsDirty = true; // this also invalidates fIsFinite
256 fGenerationID = 0;
257
258 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount;
259 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reser vePoints;
260 size_t minSize = newSize + newReserve;
261
262 ptrdiff_t sizeDelta = this->currSize() - minSize;
263
264 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) {
265 sk_free(fPoints);
266 fPoints = NULL;
267 fVerbs = NULL;
268 fFreeSpace = 0;
269 fVerbCnt = 0;
270 fPointCnt = 0;
271 this->makeSpace(minSize);
272 fVerbCnt = verbCount;
273 fPointCnt = pointCount;
274 fFreeSpace -= newSize;
275 } else {
276 fPointCnt = pointCount;
277 fVerbCnt = verbCount;
278 fFreeSpace = this->currSize() - minSize;
279 }
280 fConicWeights.setCount(conicCount);
281 this->validate();
282 }
283
284 void SkPathRef::grow(int newVerbs, int newPoints) {
285 this->validate();
286 size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint);
287 this->makeSpace(space);
288 fVerbCnt += newVerbs;
289 fPointCnt += newPoints;
290 fFreeSpace -= space;
291 fBoundsIsDirty = true; // this also invalidates fIsFinite
292 this->validate();
293 }
294
295 SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) {
296 this->validate();
297 int pCnt;
298 switch (verb) {
299 case SkPath::kMove_Verb:
300 pCnt = 1;
301 break;
302 case SkPath::kLine_Verb:
303 pCnt = 1;
304 break;
305 case SkPath::kQuad_Verb:
306 // fall through
307 case SkPath::kConic_Verb:
308 pCnt = 2;
309 break;
310 case SkPath::kCubic_Verb:
311 pCnt = 3;
312 break;
313 case SkPath::kClose_Verb:
314 pCnt = 0;
315 break;
316 case SkPath::kDone_Verb:
317 SkDEBUGFAIL("growForVerb called for kDone");
318 // fall through
319 default:
320 SkDEBUGFAIL("default is not reached");
321 pCnt = 0;
322 }
323 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
324 this->makeSpace(space);
325 this->fVerbs[~fVerbCnt] = verb;
326 SkPoint* ret = fPoints + fPointCnt;
327 fVerbCnt += 1;
328 fPointCnt += pCnt;
329 fFreeSpace -= space;
330 fBoundsIsDirty = true; // this also invalidates fIsFinite
331 this->validate();
332 return ret;
333 }
334
335 void SkPathRef::makeSpace(size_t size) {
336 this->validate();
337 ptrdiff_t growSize = size - fFreeSpace;
338 if (growSize <= 0) {
339 return;
340 }
341 size_t oldSize = this->currSize();
342 // round to next multiple of 8 bytes
343 growSize = (growSize + 7) & ~static_cast<size_t>(7);
344 // we always at least double the allocation
345 if (static_cast<size_t>(growSize) < oldSize) {
346 growSize = oldSize;
347 }
348 if (growSize < kMinSize) {
349 growSize = kMinSize;
350 }
351 size_t newSize = oldSize + growSize;
352 // Note that realloc could memcpy more than we need. It seems to be a win an yway. TODO:
353 // encapsulate this.
354 fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize));
355 size_t oldVerbSize = fVerbCnt * sizeof(uint8_t);
356 void* newVerbsDst = reinterpret_cast<void*>(
357 reinterpret_cast<intptr_t>(fPoints) + newSize - oldV erbSize);
358 void* oldVerbsSrc = reinterpret_cast<void*>(
359 reinterpret_cast<intptr_t>(fPoints) + oldSize - oldV erbSize);
360 memmove(newVerbsDst, oldVerbsSrc, oldVerbSize);
361 fVerbs = reinterpret_cast<uint8_t*>(reinterpret_cast<intptr_t>(fPoints) + ne wSize);
362 fFreeSpace += growSize;
363 this->validate();
364 }
365
366 int32_t SkPathRef::genID() const {
367 SkASSERT(!fEditorsAttached);
368 if (!fGenerationID) {
369 if (0 == fPointCnt && 0 == fVerbCnt) {
370 fGenerationID = kEmptyGenID;
371 } else {
372 static int32_t gPathRefGenerationID;
373 // do a loop in case our global wraps around, as we never want to re turn a 0 or the
374 // empty ID
375 do {
376 fGenerationID = sk_atomic_inc(&gPathRefGenerationID) + 1;
377 } while (fGenerationID <= kEmptyGenID);
378 }
379 }
380 return fGenerationID;
381 }
382
383 void SkPathRef::validate() const {
384 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
385 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPo ints) >= 0);
386 SkASSERT((NULL == fPoints) == (NULL == fVerbs));
387 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
388 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
389 SkASSERT(!(NULL == fPoints && fPointCnt));
390 SkASSERT(!(NULL == fVerbs && fVerbCnt));
391 SkASSERT(this->currSize() ==
392 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVe rbCnt);
393
394 #ifdef SK_DEBUG
395 if (!fBoundsIsDirty && !fBounds.isEmpty()) {
396 bool isFinite = true;
397 for (int i = 0; i < fPointCnt; ++i) {
398 SkASSERT(fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBounds. fRight &&
399 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBound s.fBottom);
400 if (!fPoints[i].isFinite()) {
401 isFinite = false;
402 }
403 }
404 SkASSERT(SkToBool(fIsFinite) == isFinite);
405 }
406 #endif
407 }
OLDNEW
« include/core/SkPathRef.h ('K') | « include/core/SkPathRef.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698