blob: f811b245ec425d1f14594f28773e745c894c8c48 [file] [log] [blame]
robertphillips@google.comca0c8382013-09-26 12:18:23 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkBuffer.h"
commit-bot@chromium.org1f81fd62013-10-23 14:44:08 +00009#include "SkOnce.h"
robertphillips@google.comca0c8382013-09-26 12:18:23 +000010#include "SkPath.h"
11#include "SkPathRef.h"
12
13SK_DEFINE_INST_COUNT(SkPathRef);
14
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000015//////////////////////////////////////////////////////////////////////////////
16SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef,
17 int incReserveVerbs,
18 int incReservePoints)
19{
20 if ((*pathRef)->unique()) {
21 (*pathRef)->incReserve(incReserveVerbs, incReservePoints);
22 } else {
23 SkPathRef* copy = SkNEW(SkPathRef);
24 copy->copy(**pathRef, incReserveVerbs, incReservePoints);
25 pathRef->reset(copy);
26 }
27 fPathRef = *pathRef;
28 fPathRef->fGenerationID = 0;
29 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
robertphillips@google.comca0c8382013-09-26 12:18:23 +000030}
31
32SkPoint* SkPathRef::Editor::growForConic(SkScalar w) {
robertphillips@google.com03087072013-10-02 16:42:21 +000033 SkDEBUGCODE(fPathRef->validate();)
robertphillips@google.comca0c8382013-09-26 12:18:23 +000034 SkPoint* pts = fPathRef->growForVerb(SkPath::kConic_Verb);
35 *fPathRef->fConicWeights.append() = w;
36 return pts;
37}
38
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000039//////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org1f81fd62013-10-23 14:44:08 +000040void SkPathRef::CreateEmptyImpl(SkPathRef** empty) {
41 *empty = SkNEW(SkPathRef);
42 (*empty)->computeBounds(); // Preemptively avoid a race to clear fBoundsIsDirty.
43}
44
45SkPathRef* SkPathRef::CreateEmpty() {
46 static SkPathRef* gEmptyPathRef;
47 SK_DECLARE_STATIC_ONCE(once);
48 SkOnce(&once, SkPathRef::CreateEmptyImpl, &gEmptyPathRef);
49 return SkRef(gEmptyPathRef);
50}
51
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000052void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
53 const SkPathRef& src,
54 const SkMatrix& matrix) {
robertphillips@google.com03087072013-10-02 16:42:21 +000055 SkDEBUGCODE(src.validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000056 if (matrix.isIdentity()) {
57 if (*dst != &src) {
58 src.ref();
59 dst->reset(const_cast<SkPathRef*>(&src));
robertphillips@google.com03087072013-10-02 16:42:21 +000060 SkDEBUGCODE((*dst)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000061 }
62 return;
63 }
64
65 bool dstUnique = (*dst)->unique();
66 if (!dstUnique) {
67 dst->reset(SkNEW(SkPathRef));
68 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
69 memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t));
70 (*dst)->fConicWeights = src.fConicWeights;
71 }
72
73 // Need to check this here in case (&src == dst)
74 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 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
robertphillips@google.com03087072013-10-02 16:42:21 +0000103 SkDEBUGCODE((*dst)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000104}
105
106SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer
107#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
108 , bool newFormat, int32_t oldPacked
109#endif
110 ) {
111 SkPathRef* ref = SkNEW(SkPathRef);
112#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
113 if (newFormat) {
114#endif
115 int32_t packed = buffer->readU32();
116
117 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
118#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V14_AND_ALL_OTHER_INSTANCES_TOO
119 } else {
120 ref->fIsFinite = (oldPacked >> SkPath::kOldIsFinite_SerializationShift) & 1;
121 }
122#endif
123
124 ref->fGenerationID = buffer->readU32();
125 int32_t verbCount = buffer->readS32();
126 int32_t pointCount = buffer->readS32();
127 int32_t conicCount = buffer->readS32();
128 ref->resetToSize(verbCount, pointCount, conicCount);
129
130 SkASSERT(verbCount == ref->countVerbs());
131 SkASSERT(pointCount == ref->countPoints());
132 SkASSERT(conicCount == ref->fConicWeights.count());
133 buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t));
134 buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
135 buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar));
136 buffer->read(&ref->fBounds, sizeof(SkRect));
137 ref->fBoundsIsDirty = false;
138 return ref;
139}
140
141void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
142 if ((*pathRef)->unique()) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000143 SkDEBUGCODE((*pathRef)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000144 (*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();
robertphillips@google.com03087072013-10-02 16:42:21 +0000150 SkDEBUGCODE((*pathRef)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000151 } 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
159bool SkPathRef::operator== (const SkPathRef& ref) const {
robertphillips@google.com03087072013-10-02 16:42:21 +0000160 SkDEBUGCODE(this->validate();)
161 SkDEBUGCODE(ref.validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000162 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 zero 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
199void SkPathRef::writeToBuffer(SkWBuffer* buffer) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000200 SkDEBUGCODE(this->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000201 SkDEBUGCODE(size_t beforePos = buffer->pos();)
202
203 // Call getBounds() to ensure (as a side-effect) that fBounds
204 // and fIsFinite are computed.
205 const SkRect& bounds = this->getBounds();
206
207 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift);
208 buffer->write32(packed);
209
210 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
211 // SkWBuffer. Until this is fixed we write 0.
212 buffer->write32(0);
213 buffer->write32(fVerbCnt);
214 buffer->write32(fPointCnt);
215 buffer->write32(fConicWeights.count());
216 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
217 buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
218 buffer->write(fConicWeights.begin(), fConicWeights.bytes());
219 buffer->write(&bounds, sizeof(bounds));
220
221 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
222}
223
224uint32_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
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000232void SkPathRef::copy(const SkPathRef& ref,
233 int additionalReserveVerbs,
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000234 int additionalReservePoints) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000235 SkDEBUGCODE(this->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000236 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 afterwards.
243 fGenerationID = ref.fGenerationID;
244 fBoundsIsDirty = ref.fBoundsIsDirty;
245 if (!fBoundsIsDirty) {
246 fBounds = ref.fBounds;
247 fIsFinite = ref.fIsFinite;
248 }
robertphillips@google.com03087072013-10-02 16:42:21 +0000249 SkDEBUGCODE(this->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000250}
251
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000252SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000253 SkDEBUGCODE(this->validate();)
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000254 int pCnt;
255 switch (verb) {
256 case SkPath::kMove_Verb:
257 pCnt = 1;
258 break;
259 case SkPath::kLine_Verb:
260 pCnt = 1;
261 break;
262 case SkPath::kQuad_Verb:
263 // fall through
264 case SkPath::kConic_Verb:
265 pCnt = 2;
266 break;
267 case SkPath::kCubic_Verb:
268 pCnt = 3;
269 break;
270 case SkPath::kClose_Verb:
271 pCnt = 0;
272 break;
273 case SkPath::kDone_Verb:
274 SkDEBUGFAIL("growForVerb called for kDone");
275 // fall through
276 default:
277 SkDEBUGFAIL("default is not reached");
278 pCnt = 0;
279 }
280 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
281 this->makeSpace(space);
282 this->fVerbs[~fVerbCnt] = verb;
283 SkPoint* ret = fPoints + fPointCnt;
284 fVerbCnt += 1;
285 fPointCnt += pCnt;
286 fFreeSpace -= space;
287 fBoundsIsDirty = true; // this also invalidates fIsFinite
robertphillips@google.com03087072013-10-02 16:42:21 +0000288 SkDEBUGCODE(this->validate();)
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000289 return ret;
290}
291
commit-bot@chromium.org1ab9f732013-10-30 18:57:55 +0000292uint32_t SkPathRef::genID() const {
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000293 SkASSERT(!fEditorsAttached);
commit-bot@chromium.org1ab9f732013-10-30 18:57:55 +0000294 static const uint32_t kMask = (static_cast<int64_t>(1) << SkPath::kPathRefGenIDBitCnt) - 1;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000295 if (!fGenerationID) {
296 if (0 == fPointCnt && 0 == fVerbCnt) {
297 fGenerationID = kEmptyGenID;
298 } else {
299 static int32_t gPathRefGenerationID;
300 // do a loop in case our global wraps around, as we never want to return a 0 or the
301 // empty ID
302 do {
commit-bot@chromium.org1ab9f732013-10-30 18:57:55 +0000303 fGenerationID = (sk_atomic_inc(&gPathRefGenerationID) + 1) & kMask;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000304 } while (fGenerationID <= kEmptyGenID);
305 }
306 }
307 return fGenerationID;
308}
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000309
robertphillips@google.com03087072013-10-02 16:42:21 +0000310#ifdef SK_DEBUG
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000311void SkPathRef::validate() const {
robertphillips@google.com03087072013-10-02 16:42:21 +0000312 this->INHERITED::validate();
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000313 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
314 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) >= 0);
315 SkASSERT((NULL == fPoints) == (NULL == fVerbs));
316 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
317 SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
318 SkASSERT(!(NULL == fPoints && fPointCnt));
319 SkASSERT(!(NULL == fVerbs && fVerbCnt));
320 SkASSERT(this->currSize() ==
321 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt);
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000322
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000323#ifdef SK_DEBUG
324 if (!fBoundsIsDirty && !fBounds.isEmpty()) {
325 bool isFinite = true;
326 for (int i = 0; i < fPointCnt; ++i) {
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000327 SkASSERT(fBounds.fLeft - fPoints[i].fX < SK_ScalarNearlyZero &&
robertphillips@google.com1cc385b2013-10-17 12:17:27 +0000328 fPoints[i].fX - fBounds.fRight < SK_ScalarNearlyZero &&
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000329 fBounds.fTop - fPoints[i].fY < SK_ScalarNearlyZero &&
robertphillips@google.com1cc385b2013-10-17 12:17:27 +0000330 fPoints[i].fY - fBounds.fBottom < SK_ScalarNearlyZero);
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000331 if (!fPoints[i].isFinite()) {
332 isFinite = false;
333 }
334 }
335 SkASSERT(SkToBool(fIsFinite) == isFinite);
336 }
337#endif
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000338}
robertphillips@google.com03087072013-10-02 16:42:21 +0000339#endif