blob: cf4e8ffba20477e471f53c454ebced02be523523 [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"
mtklein6c59d802015-09-09 09:09:53 -07009#include "SkOncePtr.h"
robertphillips@google.comca0c8382013-09-26 12:18:23 +000010#include "SkPath.h"
11#include "SkPathRef.h"
12
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000013//////////////////////////////////////////////////////////////////////////////
14SkPathRef::Editor::Editor(SkAutoTUnref<SkPathRef>* pathRef,
15 int incReserveVerbs,
16 int incReservePoints)
17{
18 if ((*pathRef)->unique()) {
19 (*pathRef)->incReserve(incReserveVerbs, incReservePoints);
20 } else {
halcanary385fe4d2015-08-26 13:07:48 -070021 SkPathRef* copy = new SkPathRef;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000022 copy->copy(**pathRef, incReserveVerbs, incReservePoints);
23 pathRef->reset(copy);
24 }
25 fPathRef = *pathRef;
senorblanco84cd6212015-08-04 10:01:58 -070026 fPathRef->callGenIDChangeListeners();
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000027 fPathRef->fGenerationID = 0;
28 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);)
robertphillips@google.comca0c8382013-09-26 12:18:23 +000029}
30
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000031//////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org709ca752014-01-24 22:38:39 +000032
senorblanco84cd6212015-08-04 10:01:58 -070033SkPathRef::~SkPathRef() {
34 this->callGenIDChangeListeners();
35 SkDEBUGCODE(this->validate();)
36 sk_free(fPoints);
37
halcanary96fcdcc2015-08-27 07:41:13 -070038 SkDEBUGCODE(fPoints = nullptr;)
39 SkDEBUGCODE(fVerbs = nullptr;)
senorblanco84cd6212015-08-04 10:01:58 -070040 SkDEBUGCODE(fVerbCnt = 0x9999999;)
41 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;)
42 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;)
43 SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;)
44 SkDEBUGCODE(fEditorsAttached = 0x7777777;)
45}
46
mtklein6c59d802015-09-09 09:09:53 -070047SK_DECLARE_STATIC_ONCE_PTR(SkPathRef, empty);
commit-bot@chromium.org1f81fd62013-10-23 14:44:08 +000048SkPathRef* SkPathRef::CreateEmpty() {
mtklein6c59d802015-09-09 09:09:53 -070049 return SkRef(empty.get([]{
50 SkPathRef* pr = new SkPathRef;
51 pr->computeBounds(); // Avoids races later to be the first to do this.
52 return pr;
53 }));
commit-bot@chromium.org1f81fd62013-10-23 14:44:08 +000054}
55
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000056void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
57 const SkPathRef& src,
58 const SkMatrix& matrix) {
robertphillips@google.com03087072013-10-02 16:42:21 +000059 SkDEBUGCODE(src.validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000060 if (matrix.isIdentity()) {
61 if (*dst != &src) {
62 src.ref();
63 dst->reset(const_cast<SkPathRef*>(&src));
robertphillips@google.com03087072013-10-02 16:42:21 +000064 SkDEBUGCODE((*dst)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000065 }
66 return;
67 }
68
robertphillips@google.comb06e88d2013-12-03 17:15:36 +000069 if (!(*dst)->unique()) {
halcanary385fe4d2015-08-26 13:07:48 -070070 dst->reset(new SkPathRef);
robertphillips@google.comb06e88d2013-12-03 17:15:36 +000071 }
72
73 if (*dst != &src) {
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000074 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
mtkleincc881da2015-12-08 11:55:17 -080075 sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(),
76 src.fVerbCnt * sizeof(uint8_t));
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000077 (*dst)->fConicWeights = src.fConicWeights;
78 }
79
robertphillips@google.comb06e88d2013-12-03 17:15:36 +000080 SkASSERT((*dst)->countPoints() == src.countPoints());
81 SkASSERT((*dst)->countVerbs() == src.countVerbs());
82 SkASSERT((*dst)->fConicWeights.count() == src.fConicWeights.count());
83
robertphillips@google.com3e292aa2013-09-27 17:48:49 +000084 // Need to check this here in case (&src == dst)
85 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1;
86
87 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
88
89 /*
90 * Here we optimize the bounds computation, by noting if the bounds are
91 * already known, and if so, we just transform those as well and mark
92 * them as "known", rather than force the transformed path to have to
93 * recompute them.
94 *
95 * Special gotchas if the path is effectively empty (<= 1 point) or
96 * if it is non-finite. In those cases bounds need to stay empty,
97 * regardless of the matrix.
98 */
99 if (canXformBounds) {
100 (*dst)->fBoundsIsDirty = false;
101 if (src.fIsFinite) {
mtklein5c9c9be2014-12-01 06:59:54 -0800102 matrix.mapRect(&(*dst)->fBounds, src.fBounds);
103 if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) {
104 (*dst)->fBounds.setEmpty();
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000105 }
106 } else {
107 (*dst)->fIsFinite = false;
mtklein5c9c9be2014-12-01 06:59:54 -0800108 (*dst)->fBounds.setEmpty();
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000109 }
110 } else {
111 (*dst)->fBoundsIsDirty = true;
112 }
113
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000114 (*dst)->fSegmentMask = src.fSegmentMask;
115
robertphillips@google.com466310d2013-12-03 16:43:54 +0000116 // It's an oval only if it stays a rect.
caryclarkda707bf2015-11-19 14:47:43 -0800117 bool rectStaysRect = matrix.rectStaysRect();
118 (*dst)->fIsOval = src.fIsOval && rectStaysRect;
119 (*dst)->fIsRRect = src.fIsRRect && rectStaysRect;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000120
robertphillips@google.com03087072013-10-02 16:42:21 +0000121 SkDEBUGCODE((*dst)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000122}
123
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000124SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
halcanary385fe4d2015-08-26 13:07:48 -0700125 SkPathRef* ref = new SkPathRef;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000126
127 int32_t packed;
128 if (!buffer->readS32(&packed)) {
halcanary385fe4d2015-08-26 13:07:48 -0700129 delete ref;
halcanary96fcdcc2015-08-27 07:41:13 -0700130 return nullptr;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000131 }
132
133 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
caryclarkda707bf2015-11-19 14:47:43 -0800134 uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF;
135 bool isOval = (packed >> kIsOval_SerializationShift) & 1;
136 bool isRRect = (packed >> kIsRRect_SerializationShift) & 1;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000137
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000138 int32_t verbCount, pointCount, conicCount;
139 if (!buffer->readU32(&(ref->fGenerationID)) ||
140 !buffer->readS32(&verbCount) ||
ajumaf8aec582016-01-13 13:46:31 -0800141 verbCount < 0 ||
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000142 !buffer->readS32(&pointCount) ||
ajumaf8aec582016-01-13 13:46:31 -0800143 pointCount < 0 ||
144 !buffer->readS32(&conicCount) ||
145 conicCount < 0) {
halcanary385fe4d2015-08-26 13:07:48 -0700146 delete ref;
halcanary96fcdcc2015-08-27 07:41:13 -0700147 return nullptr;
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000148 }
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000149
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000150 ref->resetToSize(verbCount, pointCount, conicCount);
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000151 SkASSERT(verbCount == ref->countVerbs());
152 SkASSERT(pointCount == ref->countPoints());
153 SkASSERT(conicCount == ref->fConicWeights.count());
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000154
155 if (!buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t)) ||
156 !buffer->read(ref->fPoints, pointCount * sizeof(SkPoint)) ||
157 !buffer->read(ref->fConicWeights.begin(), conicCount * sizeof(SkScalar)) ||
158 !buffer->read(&ref->fBounds, sizeof(SkRect))) {
halcanary385fe4d2015-08-26 13:07:48 -0700159 delete ref;
halcanary96fcdcc2015-08-27 07:41:13 -0700160 return nullptr;
commit-bot@chromium.org8f457e32013-11-08 19:22:57 +0000161 }
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000162 ref->fBoundsIsDirty = false;
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000163
164 // resetToSize clears fSegmentMask and fIsOval
165 ref->fSegmentMask = segmentMask;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000166 ref->fIsOval = isOval;
caryclarkda707bf2015-11-19 14:47:43 -0800167 ref->fIsRRect = isRRect;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000168 return ref;
169}
170
171void SkPathRef::Rewind(SkAutoTUnref<SkPathRef>* pathRef) {
172 if ((*pathRef)->unique()) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000173 SkDEBUGCODE((*pathRef)->validate();)
senorblanco84cd6212015-08-04 10:01:58 -0700174 (*pathRef)->callGenIDChangeListeners();
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000175 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
176 (*pathRef)->fVerbCnt = 0;
177 (*pathRef)->fPointCnt = 0;
178 (*pathRef)->fFreeSpace = (*pathRef)->currSize();
179 (*pathRef)->fGenerationID = 0;
180 (*pathRef)->fConicWeights.rewind();
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000181 (*pathRef)->fSegmentMask = 0;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000182 (*pathRef)->fIsOval = false;
caryclarkda707bf2015-11-19 14:47:43 -0800183 (*pathRef)->fIsRRect = false;
robertphillips@google.com03087072013-10-02 16:42:21 +0000184 SkDEBUGCODE((*pathRef)->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000185 } else {
186 int oldVCnt = (*pathRef)->countVerbs();
187 int oldPCnt = (*pathRef)->countPoints();
halcanary385fe4d2015-08-26 13:07:48 -0700188 pathRef->reset(new SkPathRef);
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000189 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt);
190 }
191}
192
193bool SkPathRef::operator== (const SkPathRef& ref) const {
robertphillips@google.com03087072013-10-02 16:42:21 +0000194 SkDEBUGCODE(this->validate();)
195 SkDEBUGCODE(ref.validate();)
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000196
197 // We explicitly check fSegmentMask as a quick-reject. We could skip it,
198 // since it is only a cache of info in the fVerbs, but its a fast way to
199 // notice a difference
200 if (fSegmentMask != ref.fSegmentMask) {
201 return false;
202 }
203
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000204 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
205#ifdef SK_RELEASE
206 if (genIDMatch) {
207 return true;
208 }
209#endif
210 if (fPointCnt != ref.fPointCnt ||
211 fVerbCnt != ref.fVerbCnt) {
212 SkASSERT(!genIDMatch);
213 return false;
214 }
mtkleind4897592014-11-14 09:22:40 -0800215 if (0 == ref.fVerbCnt) {
216 SkASSERT(0 == ref.fPointCnt);
217 return true;
218 }
219 SkASSERT(this->verbsMemBegin() && ref.verbsMemBegin());
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000220 if (0 != memcmp(this->verbsMemBegin(),
221 ref.verbsMemBegin(),
222 ref.fVerbCnt * sizeof(uint8_t))) {
223 SkASSERT(!genIDMatch);
224 return false;
225 }
mtkleind4897592014-11-14 09:22:40 -0800226 SkASSERT(this->points() && ref.points());
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000227 if (0 != memcmp(this->points(),
228 ref.points(),
229 ref.fPointCnt * sizeof(SkPoint))) {
230 SkASSERT(!genIDMatch);
231 return false;
232 }
233 if (fConicWeights != ref.fConicWeights) {
234 SkASSERT(!genIDMatch);
235 return false;
236 }
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000237 return true;
238}
239
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000240void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
robertphillips@google.com03087072013-10-02 16:42:21 +0000241 SkDEBUGCODE(this->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000242 SkDEBUGCODE(size_t beforePos = buffer->pos();)
243
244 // Call getBounds() to ensure (as a side-effect) that fBounds
245 // and fIsFinite are computed.
246 const SkRect& bounds = this->getBounds();
247
robertphillips@google.com466310d2013-12-03 16:43:54 +0000248 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) |
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000249 ((fIsOval & 1) << kIsOval_SerializationShift) |
caryclarkda707bf2015-11-19 14:47:43 -0800250 ((fIsRRect & 1) << kIsRRect_SerializationShift) |
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000251 (fSegmentMask << kSegmentMask_SerializationShift);
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000252 buffer->write32(packed);
253
254 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from
255 // SkWBuffer. Until this is fixed we write 0.
256 buffer->write32(0);
257 buffer->write32(fVerbCnt);
258 buffer->write32(fPointCnt);
259 buffer->write32(fConicWeights.count());
260 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
261 buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
262 buffer->write(fConicWeights.begin(), fConicWeights.bytes());
263 buffer->write(&bounds, sizeof(bounds));
264
265 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
266}
267
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000268uint32_t SkPathRef::writeSize() const {
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000269 return uint32_t(5 * sizeof(uint32_t) +
270 fVerbCnt * sizeof(uint8_t) +
271 fPointCnt * sizeof(SkPoint) +
272 fConicWeights.bytes() +
273 sizeof(SkRect));
274}
275
skia.committer@gmail.com50df4d02013-09-28 07:01:33 +0000276void SkPathRef::copy(const SkPathRef& ref,
277 int additionalReserveVerbs,
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000278 int additionalReservePoints) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000279 SkDEBUGCODE(this->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000280 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
281 additionalReserveVerbs, additionalReservePoints);
mtkleincc881da2015-12-08 11:55:17 -0800282 sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t));
283 sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000284 fConicWeights = ref.fConicWeights;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000285 fBoundsIsDirty = ref.fBoundsIsDirty;
286 if (!fBoundsIsDirty) {
287 fBounds = ref.fBounds;
288 fIsFinite = ref.fIsFinite;
289 }
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000290 fSegmentMask = ref.fSegmentMask;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000291 fIsOval = ref.fIsOval;
caryclarkda707bf2015-11-19 14:47:43 -0800292 fIsRRect = ref.fIsRRect;
robertphillips@google.com03087072013-10-02 16:42:21 +0000293 SkDEBUGCODE(this->validate();)
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000294}
295
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000296SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
297 int numVbs,
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000298 SkScalar** weights) {
299 // This value is just made-up for now. When count is 4, calling memset was much
300 // slower than just writing the loop. This seems odd, and hopefully in the
301 // future this will appear to have been a fluke...
302 static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16;
303
304 SkDEBUGCODE(this->validate();)
305 int pCnt;
306 bool dirtyAfterEdit = true;
307 switch (verb) {
308 case SkPath::kMove_Verb:
309 pCnt = numVbs;
310 dirtyAfterEdit = false;
311 break;
312 case SkPath::kLine_Verb:
313 fSegmentMask |= SkPath::kLine_SegmentMask;
314 pCnt = numVbs;
315 break;
316 case SkPath::kQuad_Verb:
317 fSegmentMask |= SkPath::kQuad_SegmentMask;
318 pCnt = 2 * numVbs;
319 break;
320 case SkPath::kConic_Verb:
321 fSegmentMask |= SkPath::kConic_SegmentMask;
322 pCnt = 2 * numVbs;
323 break;
324 case SkPath::kCubic_Verb:
325 fSegmentMask |= SkPath::kCubic_SegmentMask;
326 pCnt = 3 * numVbs;
327 break;
328 case SkPath::kClose_Verb:
329 SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb");
330 pCnt = 0;
331 dirtyAfterEdit = false;
332 break;
333 case SkPath::kDone_Verb:
334 SkDEBUGFAIL("growForRepeatedVerb called for kDone");
335 // fall through
336 default:
337 SkDEBUGFAIL("default should not be reached");
338 pCnt = 0;
339 dirtyAfterEdit = false;
340 }
341
342 size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint);
343 this->makeSpace(space);
344
345 SkPoint* ret = fPoints + fPointCnt;
346 uint8_t* vb = fVerbs - fVerbCnt;
347
348 // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
349 // be 0, the compiler will remove the test/branch entirely.
350 if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
351 memset(vb - numVbs, verb, numVbs);
352 } else {
353 for (int i = 0; i < numVbs; ++i) {
354 vb[~i] = verb;
355 }
356 }
357
358 fVerbCnt += numVbs;
359 fPointCnt += pCnt;
360 fFreeSpace -= space;
361 fBoundsIsDirty = true; // this also invalidates fIsFinite
362 if (dirtyAfterEdit) {
363 fIsOval = false;
caryclarkda707bf2015-11-19 14:47:43 -0800364 fIsRRect = false;
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000365 }
366
367 if (SkPath::kConic_Verb == verb) {
bsalomon49f085d2014-09-05 13:34:00 -0700368 SkASSERT(weights);
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000369 *weights = fConicWeights.append(numVbs);
370 }
371
372 SkDEBUGCODE(this->validate();)
373 return ret;
374}
375
376SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) {
robertphillips@google.com03087072013-10-02 16:42:21 +0000377 SkDEBUGCODE(this->validate();)
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000378 int pCnt;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000379 bool dirtyAfterEdit = true;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000380 switch (verb) {
381 case SkPath::kMove_Verb:
382 pCnt = 1;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000383 dirtyAfterEdit = false;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000384 break;
385 case SkPath::kLine_Verb:
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000386 fSegmentMask |= SkPath::kLine_SegmentMask;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000387 pCnt = 1;
388 break;
389 case SkPath::kQuad_Verb:
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000390 fSegmentMask |= SkPath::kQuad_SegmentMask;
391 pCnt = 2;
392 break;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000393 case SkPath::kConic_Verb:
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000394 fSegmentMask |= SkPath::kConic_SegmentMask;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000395 pCnt = 2;
396 break;
397 case SkPath::kCubic_Verb:
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000398 fSegmentMask |= SkPath::kCubic_SegmentMask;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000399 pCnt = 3;
400 break;
401 case SkPath::kClose_Verb:
402 pCnt = 0;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000403 dirtyAfterEdit = false;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000404 break;
405 case SkPath::kDone_Verb:
406 SkDEBUGFAIL("growForVerb called for kDone");
407 // fall through
408 default:
409 SkDEBUGFAIL("default is not reached");
robertphillips@google.com466310d2013-12-03 16:43:54 +0000410 dirtyAfterEdit = false;
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000411 pCnt = 0;
412 }
413 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
414 this->makeSpace(space);
415 this->fVerbs[~fVerbCnt] = verb;
416 SkPoint* ret = fPoints + fPointCnt;
417 fVerbCnt += 1;
418 fPointCnt += pCnt;
419 fFreeSpace -= space;
420 fBoundsIsDirty = true; // this also invalidates fIsFinite
robertphillips@google.com466310d2013-12-03 16:43:54 +0000421 if (dirtyAfterEdit) {
422 fIsOval = false;
caryclarkda707bf2015-11-19 14:47:43 -0800423 fIsRRect = false;
robertphillips@google.com466310d2013-12-03 16:43:54 +0000424 }
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000425
426 if (SkPath::kConic_Verb == verb) {
427 *fConicWeights.append() = weight;
428 }
429
robertphillips@google.com03087072013-10-02 16:42:21 +0000430 SkDEBUGCODE(this->validate();)
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000431 return ret;
432}
433
commit-bot@chromium.org1ab9f732013-10-30 18:57:55 +0000434uint32_t SkPathRef::genID() const {
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000435 SkASSERT(!fEditorsAttached);
commit-bot@chromium.org1ab9f732013-10-30 18:57:55 +0000436 static const uint32_t kMask = (static_cast<int64_t>(1) << SkPath::kPathRefGenIDBitCnt) - 1;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000437 if (!fGenerationID) {
438 if (0 == fPointCnt && 0 == fVerbCnt) {
439 fGenerationID = kEmptyGenID;
440 } else {
441 static int32_t gPathRefGenerationID;
442 // do a loop in case our global wraps around, as we never want to return a 0 or the
443 // empty ID
444 do {
commit-bot@chromium.org1ab9f732013-10-30 18:57:55 +0000445 fGenerationID = (sk_atomic_inc(&gPathRefGenerationID) + 1) & kMask;
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000446 } while (fGenerationID <= kEmptyGenID);
447 }
448 }
449 return fGenerationID;
450}
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000451
senorblanco84cd6212015-08-04 10:01:58 -0700452void SkPathRef::addGenIDChangeListener(GenIDChangeListener* listener) {
mtklein6c59d802015-09-09 09:09:53 -0700453 if (nullptr == listener || this == (SkPathRef*)empty) {
halcanary385fe4d2015-08-26 13:07:48 -0700454 delete listener;
senorblanco84cd6212015-08-04 10:01:58 -0700455 return;
456 }
457 *fGenIDChangeListeners.append() = listener;
458}
459
460// we need to be called *before* the genID gets changed or zerod
461void SkPathRef::callGenIDChangeListeners() {
462 for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
463 fGenIDChangeListeners[i]->onChange();
464 }
465
466 // Listeners get at most one shot, so whether these triggered or not, blow them away.
467 fGenIDChangeListeners.deleteAll();
468}
469
caryclarkda707bf2015-11-19 14:47:43 -0800470SkRRect SkPathRef::getRRect() const {
471 const SkRect& bounds = this->getBounds();
472 SkVector radii[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
473 Iter iter(*this);
474 SkPoint pts[4];
475 uint8_t verb = iter.next(pts);
476 SkASSERT(SkPath::kMove_Verb == verb);
477 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
478 if (SkPath::kConic_Verb == verb) {
479 SkVector v1_0 = pts[1] - pts[0];
480 SkVector v2_1 = pts[2] - pts[1];
481 SkVector dxdy;
482 if (v1_0.fX) {
483 SkASSERT(!v2_1.fX && !v1_0.fY);
484 dxdy.set(SkScalarAbs(v1_0.fX), SkScalarAbs(v2_1.fY));
485 } else if (!v1_0.fY) {
486 SkASSERT(!v2_1.fX || !v2_1.fY);
487 dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v2_1.fY));
488 } else {
489 SkASSERT(!v2_1.fY);
490 dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v1_0.fY));
491 }
492 SkRRect::Corner corner =
493 pts[1].fX == bounds.fLeft ?
494 pts[1].fY == bounds.fTop ?
495 SkRRect::kUpperLeft_Corner : SkRRect::kLowerLeft_Corner :
496 pts[1].fY == bounds.fTop ?
497 SkRRect::kUpperRight_Corner : SkRRect::kLowerRight_Corner;
498 SkASSERT(!radii[corner].fX && !radii[corner].fY);
499 radii[corner] = dxdy;
500 } else {
501 SkASSERT((verb == SkPath::kLine_Verb
502 && (!(pts[1].fX - pts[0].fX) || !(pts[1].fY - pts[0].fY)))
503 || verb == SkPath::kClose_Verb);
504 }
505 }
506 SkRRect rrect;
507 rrect.setRectRadii(bounds, radii);
508 return rrect;
509}
510
511///////////////////////////////////////////////////////////////////////////////
512
513SkPathRef::Iter::Iter() {
514#ifdef SK_DEBUG
515 fPts = nullptr;
516 fConicWeights = nullptr;
517#endif
518 // need to init enough to make next() harmlessly return kDone_Verb
519 fVerbs = nullptr;
520 fVerbStop = nullptr;
521}
522
523SkPathRef::Iter::Iter(const SkPathRef& path) {
524 this->setPathRef(path);
525}
526
527void SkPathRef::Iter::setPathRef(const SkPathRef& path) {
528 fPts = path.points();
529 fVerbs = path.verbs();
530 fVerbStop = path.verbsMemBegin();
531 fConicWeights = path.conicWeights() - 1; // begin one behind
532}
533
534uint8_t SkPathRef::Iter::next(SkPoint pts[4]) {
535 SkASSERT(pts);
536 if (fVerbs == fVerbStop) {
537 return (uint8_t) SkPath::kDone_Verb;
538 }
539
540 // fVerbs points one beyond next verb so decrement first.
541 unsigned verb = *(--fVerbs);
542 const SkPoint* srcPts = fPts;
543
544 switch (verb) {
545 case SkPath::kMove_Verb:
546 pts[0] = srcPts[0];
547 srcPts += 1;
548 break;
549 case SkPath::kLine_Verb:
550 pts[0] = srcPts[-1];
551 pts[1] = srcPts[0];
552 srcPts += 1;
553 break;
554 case SkPath::kConic_Verb:
555 fConicWeights += 1;
556 // fall-through
557 case SkPath::kQuad_Verb:
558 pts[0] = srcPts[-1];
559 pts[1] = srcPts[0];
560 pts[2] = srcPts[1];
561 srcPts += 2;
562 break;
563 case SkPath::kCubic_Verb:
564 pts[0] = srcPts[-1];
565 pts[1] = srcPts[0];
566 pts[2] = srcPts[1];
567 pts[3] = srcPts[2];
568 srcPts += 3;
569 break;
570 case SkPath::kClose_Verb:
571 break;
572 case SkPath::kDone_Verb:
573 SkASSERT(fVerbs == fVerbStop);
574 break;
575 }
576 fPts = srcPts;
577 return (uint8_t) verb;
578}
579
caryclark2028d7f2015-12-09 14:04:46 -0800580uint8_t SkPathRef::Iter::peek() const {
581 const uint8_t* next = fVerbs - 1;
582 return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : *next;
583}
584
robertphillips@google.com03087072013-10-02 16:42:21 +0000585#ifdef SK_DEBUG
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000586void SkPathRef::validate() const {
robertphillips@google.com03087072013-10-02 16:42:21 +0000587 this->INHERITED::validate();
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000588 SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
589 SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) >= 0);
halcanary96fcdcc2015-08-27 07:41:13 -0700590 SkASSERT((nullptr == fPoints) == (nullptr == fVerbs));
591 SkASSERT(!(nullptr == fPoints && 0 != fFreeSpace));
592 SkASSERT(!(nullptr == fPoints && 0 != fFreeSpace));
593 SkASSERT(!(nullptr == fPoints && fPointCnt));
594 SkASSERT(!(nullptr == fVerbs && fVerbCnt));
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000595 SkASSERT(this->currSize() ==
596 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt);
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000597
mtklein5c9c9be2014-12-01 06:59:54 -0800598 if (!fBoundsIsDirty && !fBounds.isEmpty()) {
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000599 bool isFinite = true;
600 for (int i = 0; i < fPointCnt; ++i) {
robertphillipsf1cdead2015-01-05 09:20:04 -0800601#ifdef SK_DEBUG
602 if (fPoints[i].isFinite() &&
603 (fPoints[i].fX < fBounds.fLeft || fPoints[i].fX > fBounds.fRight ||
604 fPoints[i].fY < fBounds.fTop || fPoints[i].fY > fBounds.fBottom)) {
605 SkDebugf("bounds: %f %f %f %f\n",
606 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
607 for (int j = 0; j < fPointCnt; ++j) {
608 if (i == j) {
609 SkDebugf("*");
610 }
611 SkDebugf("%f %f\n", fPoints[j].fX, fPoints[j].fY);
612 }
613 }
614#endif
615
robertphillips0e912462014-12-12 12:47:59 -0800616 SkASSERT(!fPoints[i].isFinite() ||
617 (fPoints[i].fX >= fBounds.fLeft && fPoints[i].fX <= fBounds.fRight &&
618 fPoints[i].fY >= fBounds.fTop && fPoints[i].fY <= fBounds.fBottom));
robertphillips@google.com3e292aa2013-09-27 17:48:49 +0000619 if (!fPoints[i].isFinite()) {
620 isFinite = false;
621 }
622 }
623 SkASSERT(SkToBool(fIsFinite) == isFinite);
624 }
robertphillips@google.com6b8dbb62013-12-12 23:03:51 +0000625
626#ifdef SK_DEBUG_PATH
627 uint32_t mask = 0;
628 for (int i = 0; i < fVerbCnt; ++i) {
629 switch (fVerbs[~i]) {
630 case SkPath::kMove_Verb:
631 break;
632 case SkPath::kLine_Verb:
633 mask |= SkPath::kLine_SegmentMask;
634 break;
635 case SkPath::kQuad_Verb:
636 mask |= SkPath::kQuad_SegmentMask;
637 break;
638 case SkPath::kConic_Verb:
639 mask |= SkPath::kConic_SegmentMask;
640 break;
641 case SkPath::kCubic_Verb:
642 mask |= SkPath::kCubic_SegmentMask;
643 break;
644 case SkPath::kClose_Verb:
645 break;
646 case SkPath::kDone_Verb:
647 SkDEBUGFAIL("Done verb shouldn't be recorded.");
648 break;
649 default:
650 SkDEBUGFAIL("Unknown Verb");
651 break;
652 }
653 }
654 SkASSERT(mask == fSegmentMask);
655#endif // SK_DEBUG_PATH
robertphillips@google.comca0c8382013-09-26 12:18:23 +0000656}
robertphillips@google.com03087072013-10-02 16:42:21 +0000657#endif