1/* 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" 9#include "SkNx.h" 10#include "SkOnce.h" 11#include "SkPath.h" 12#include "SkPathRef.h" 13#include "SkPathPriv.h" 14#include "SkSafeMath.h" 15 16// Conic weights must be 0 < weight <= finite 17static bool validate_conic_weights(const SkScalar weights[], int count) { 18 for (int i = 0; i < count; ++i) { 19 if (weights[i] <= 0 || !SkScalarIsFinite(weights[i])) { 20 return false; 21 } 22 } 23 return true; 24} 25 26////////////////////////////////////////////////////////////////////////////// 27SkPathRef::Editor::Editor(sk_sp<SkPathRef>* pathRef, 28 int incReserveVerbs, 29 int incReservePoints) 30{ 31 if ((*pathRef)->unique()) { 32 (*pathRef)->incReserve(incReserveVerbs, incReservePoints); 33 } else { 34 SkPathRef* copy = new SkPathRef; 35 copy->copy(**pathRef, incReserveVerbs, incReservePoints); 36 pathRef->reset(copy); 37 } 38 fPathRef = pathRef->get(); 39 fPathRef->callGenIDChangeListeners(); 40 fPathRef->fGenerationID = 0; 41 SkDEBUGCODE(sk_atomic_inc(&fPathRef->fEditorsAttached);) 42} 43 44////////////////////////////////////////////////////////////////////////////// 45 46SkPathRef::~SkPathRef() { 47 // Deliberately don't validate() this path ref, otherwise there's no way 48 // to read one that's not valid and then free its memory without asserting. 49 this->callGenIDChangeListeners(); 50 sk_free(fPoints); 51 52 SkDEBUGCODE(fPoints = nullptr;) 53 SkDEBUGCODE(fVerbs = nullptr;) 54 SkDEBUGCODE(fVerbCnt = 0x9999999;) 55 SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) 56 SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) 57 SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;) 58 SkDEBUGCODE(fEditorsAttached = 0x7777777;) 59} 60 61static SkPathRef* gEmpty = nullptr; 62 63SkPathRef* SkPathRef::CreateEmpty() { 64 static SkOnce once; 65 once([]{ 66 gEmpty = new SkPathRef; 67 gEmpty->computeBounds(); // Avoids races later to be the first to do this. 68 }); 69 return SkRef(gEmpty); 70} 71 72static void transform_dir_and_start(const SkMatrix& matrix, bool isRRect, bool* isCCW, 73 unsigned* start) { 74 int inStart = *start; 75 int rm = 0; 76 if (isRRect) { 77 // Degenerate rrect indices to oval indices and remember the remainder. 78 // Ovals have one index per side whereas rrects have two. 79 rm = inStart & 0b1; 80 inStart /= 2; 81 } 82 // Is the antidiagonal non-zero (otherwise the diagonal is zero) 83 int antiDiag; 84 // Is the non-zero value in the top row (either kMScaleX or kMSkewX) negative 85 int topNeg; 86 // Are the two non-zero diagonal or antidiagonal values the same sign. 87 int sameSign; 88 if (matrix.get(SkMatrix::kMScaleX) != 0) { 89 antiDiag = 0b00; 90 if (matrix.get(SkMatrix::kMScaleX) > 0) { 91 topNeg = 0b00; 92 sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b01 : 0b00; 93 } else { 94 topNeg = 0b10; 95 sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b00 : 0b01; 96 } 97 } else { 98 antiDiag = 0b01; 99 if (matrix.get(SkMatrix::kMSkewX) > 0) { 100 topNeg = 0b00; 101 sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b01 : 0b00; 102 } else { 103 topNeg = 0b10; 104 sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b00 : 0b01; 105 } 106 } 107 if (sameSign != antiDiag) { 108 // This is a rotation (and maybe scale). The direction is unchanged. 109 // Trust me on the start computation (or draw yourself some pictures) 110 *start = (inStart + 4 - (topNeg | antiDiag)) % 4; 111 SkASSERT(*start < 4); 112 if (isRRect) { 113 *start = 2 * *start + rm; 114 } 115 } else { 116 // This is a mirror (and maybe scale). The direction is reversed. 117 *isCCW = !*isCCW; 118 // Trust me on the start computation (or draw yourself some pictures) 119 *start = (6 + (topNeg | antiDiag) - inStart) % 4; 120 SkASSERT(*start < 4); 121 if (isRRect) { 122 *start = 2 * *start + (rm ? 0 : 1); 123 } 124 } 125} 126 127void SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst, 128 const SkPathRef& src, 129 const SkMatrix& matrix) { 130 SkDEBUGCODE(src.validate();) 131 if (matrix.isIdentity()) { 132 if (dst->get() != &src) { 133 src.ref(); 134 dst->reset(const_cast<SkPathRef*>(&src)); 135 SkDEBUGCODE((*dst)->validate();) 136 } 137 return; 138 } 139 140 if (!(*dst)->unique()) { 141 dst->reset(new SkPathRef); 142 } 143 144 if (dst->get() != &src) { 145 (*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count()); 146 sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), 147 src.fVerbCnt * sizeof(uint8_t)); 148 (*dst)->fConicWeights = src.fConicWeights; 149 } 150 151 SkASSERT((*dst)->countPoints() == src.countPoints()); 152 SkASSERT((*dst)->countVerbs() == src.countVerbs()); 153 SkASSERT((*dst)->fConicWeights.count() == src.fConicWeights.count()); 154 155 // Need to check this here in case (&src == dst) 156 bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1; 157 158 matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt); 159 160 /* 161 * Here we optimize the bounds computation, by noting if the bounds are 162 * already known, and if so, we just transform those as well and mark 163 * them as "known", rather than force the transformed path to have to 164 * recompute them. 165 * 166 * Special gotchas if the path is effectively empty (<= 1 point) or 167 * if it is non-finite. In those cases bounds need to stay empty, 168 * regardless of the matrix. 169 */ 170 if (canXformBounds) { 171 (*dst)->fBoundsIsDirty = false; 172 if (src.fIsFinite) { 173 matrix.mapRect(&(*dst)->fBounds, src.fBounds); 174 if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) { 175 (*dst)->fBounds.setEmpty(); 176 } 177 } else { 178 (*dst)->fIsFinite = false; 179 (*dst)->fBounds.setEmpty(); 180 } 181 } else { 182 (*dst)->fBoundsIsDirty = true; 183 } 184 185 (*dst)->fSegmentMask = src.fSegmentMask; 186 187 // It's an oval only if it stays a rect. 188 bool rectStaysRect = matrix.rectStaysRect(); 189 (*dst)->fIsOval = src.fIsOval && rectStaysRect; 190 (*dst)->fIsRRect = src.fIsRRect && rectStaysRect; 191 if ((*dst)->fIsOval || (*dst)->fIsRRect) { 192 unsigned start = src.fRRectOrOvalStartIdx; 193 bool isCCW = SkToBool(src.fRRectOrOvalIsCCW); 194 transform_dir_and_start(matrix, (*dst)->fIsRRect, &isCCW, &start); 195 (*dst)->fRRectOrOvalIsCCW = isCCW; 196 (*dst)->fRRectOrOvalStartIdx = start; 197 } 198 199 SkDEBUGCODE((*dst)->validate();) 200} 201 202static bool validate_verb_sequence(const uint8_t verbs[], int vCount) { 203 // verbs are stored backwards, but we need to visit them in logical order to determine if 204 // they form a valid sequence. 205 206 bool needsMoveTo = true; 207 bool invalidSequence = false; 208 209 for (int i = vCount - 1; i >= 0; --i) { 210 switch (verbs[i]) { 211 case SkPath::kMove_Verb: 212 needsMoveTo = false; 213 break; 214 case SkPath::kLine_Verb: 215 case SkPath::kQuad_Verb: 216 case SkPath::kConic_Verb: 217 case SkPath::kCubic_Verb: 218 invalidSequence |= needsMoveTo; 219 break; 220 case SkPath::kClose_Verb: 221 needsMoveTo = true; 222 break; 223 default: 224 return false; // unknown verb 225 } 226 } 227 return !invalidSequence; 228} 229 230// Given the verb array, deduce the required number of pts and conics, 231// or if an invalid verb is encountered, return false. 232static bool deduce_pts_conics(const uint8_t verbs[], int vCount, int* ptCountPtr, 233 int* conicCountPtr) { 234 // When there is at least one verb, the first is required to be kMove_Verb. 235 if (0 < vCount && verbs[vCount-1] != SkPath::kMove_Verb) { 236 return false; 237 } 238 239 SkSafeMath safe; 240 int ptCount = 0; 241 int conicCount = 0; 242 for (int i = 0; i < vCount; ++i) { 243 switch (verbs[i]) { 244 case SkPath::kMove_Verb: 245 case SkPath::kLine_Verb: 246 ptCount = safe.addInt(ptCount, 1); 247 break; 248 case SkPath::kConic_Verb: 249 conicCount += 1; 250 // fall-through 251 case SkPath::kQuad_Verb: 252 ptCount = safe.addInt(ptCount, 2); 253 break; 254 case SkPath::kCubic_Verb: 255 ptCount = safe.addInt(ptCount, 3); 256 break; 257 case SkPath::kClose_Verb: 258 break; 259 default: 260 return false; 261 } 262 } 263 if (!safe) { 264 return false; 265 } 266 *ptCountPtr = ptCount; 267 *conicCountPtr = conicCount; 268 return true; 269} 270 271SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) { 272 std::unique_ptr<SkPathRef> ref(new SkPathRef); 273 274 int32_t packed; 275 if (!buffer->readS32(&packed)) { 276 return nullptr; 277 } 278 279 ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1; 280 281 int32_t verbCount, pointCount, conicCount; 282 if (!buffer->readU32(&(ref->fGenerationID)) || 283 !buffer->readS32(&verbCount) || (verbCount < 0) || 284 !buffer->readS32(&pointCount) || (pointCount < 0) || 285 !buffer->readS32(&conicCount) || (conicCount < 0)) 286 { 287 return nullptr; 288 } 289 290 uint64_t pointSize64 = sk_64_mul(pointCount, sizeof(SkPoint)); 291 uint64_t conicSize64 = sk_64_mul(conicCount, sizeof(SkScalar)); 292 if (!SkTFitsIn<size_t>(pointSize64) || !SkTFitsIn<size_t>(conicSize64)) { 293 return nullptr; 294 } 295 296 size_t verbSize = verbCount * sizeof(uint8_t); 297 size_t pointSize = SkToSizeT(pointSize64); 298 size_t conicSize = SkToSizeT(conicSize64); 299 300 { 301 uint64_t requiredBufferSize = sizeof(SkRect); 302 requiredBufferSize += verbSize; 303 requiredBufferSize += pointSize; 304 requiredBufferSize += conicSize; 305 if (buffer->available() < requiredBufferSize) { 306 return nullptr; 307 } 308 } 309 310 ref->resetToSize(verbCount, pointCount, conicCount); 311 SkASSERT(verbCount == ref->countVerbs()); 312 SkASSERT(pointCount == ref->countPoints()); 313 SkASSERT(conicCount == ref->fConicWeights.count()); 314 315 if (!buffer->read(ref->verbsMemWritable(), verbSize) || 316 !buffer->read(ref->fPoints, pointSize) || 317 !buffer->read(ref->fConicWeights.begin(), conicSize) || 318 !buffer->read(&ref->fBounds, sizeof(SkRect))) { 319 return nullptr; 320 } 321 322 // Check that the verbs are valid, and imply the correct number of pts and conics 323 { 324 int pCount, cCount; 325 if (!validate_verb_sequence(ref->verbsMemBegin(), ref->countVerbs())) { 326 return nullptr; 327 } 328 if (!deduce_pts_conics(ref->verbsMemBegin(), ref->countVerbs(), &pCount, &cCount) || 329 pCount != ref->countPoints() || cCount != ref->fConicWeights.count()) { 330 return nullptr; 331 } 332 if (!validate_conic_weights(ref->fConicWeights.begin(), ref->fConicWeights.count())) { 333 return nullptr; 334 } 335 // Check that the bounds match the serialized bounds. 336 SkRect bounds; 337 if (ComputePtBounds(&bounds, *ref) != SkToBool(ref->fIsFinite) || bounds != ref->fBounds) { 338 return nullptr; 339 } 340 341 // call this after validate_verb_sequence, since it relies on valid verbs 342 ref->fSegmentMask = ref->computeSegmentMask(); 343 } 344 345 ref->fBoundsIsDirty = false; 346 347 return ref.release(); 348} 349 350void SkPathRef::Rewind(sk_sp<SkPathRef>* pathRef) { 351 if ((*pathRef)->unique()) { 352 SkDEBUGCODE((*pathRef)->validate();) 353 (*pathRef)->callGenIDChangeListeners(); 354 (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite 355 (*pathRef)->fVerbCnt = 0; 356 (*pathRef)->fPointCnt = 0; 357 (*pathRef)->fFreeSpace = (*pathRef)->currSize(); 358 (*pathRef)->fGenerationID = 0; 359 (*pathRef)->fConicWeights.rewind(); 360 (*pathRef)->fSegmentMask = 0; 361 (*pathRef)->fIsOval = false; 362 (*pathRef)->fIsRRect = false; 363 SkDEBUGCODE((*pathRef)->validate();) 364 } else { 365 int oldVCnt = (*pathRef)->countVerbs(); 366 int oldPCnt = (*pathRef)->countPoints(); 367 pathRef->reset(new SkPathRef); 368 (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); 369 } 370} 371 372bool SkPathRef::operator== (const SkPathRef& ref) const { 373 SkDEBUGCODE(this->validate();) 374 SkDEBUGCODE(ref.validate();) 375 376 // We explicitly check fSegmentMask as a quick-reject. We could skip it, 377 // since it is only a cache of info in the fVerbs, but its a fast way to 378 // notice a difference 379 if (fSegmentMask != ref.fSegmentMask) { 380 return false; 381 } 382 383 bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID; 384#ifdef SK_RELEASE 385 if (genIDMatch) { 386 return true; 387 } 388#endif 389 if (fPointCnt != ref.fPointCnt || 390 fVerbCnt != ref.fVerbCnt) { 391 SkASSERT(!genIDMatch); 392 return false; 393 } 394 if (0 == ref.fVerbCnt) { 395 SkASSERT(0 == ref.fPointCnt); 396 return true; 397 } 398 SkASSERT(this->verbsMemBegin() && ref.verbsMemBegin()); 399 if (0 != memcmp(this->verbsMemBegin(), 400 ref.verbsMemBegin(), 401 ref.fVerbCnt * sizeof(uint8_t))) { 402 SkASSERT(!genIDMatch); 403 return false; 404 } 405 SkASSERT(this->points() && ref.points()); 406 if (0 != memcmp(this->points(), 407 ref.points(), 408 ref.fPointCnt * sizeof(SkPoint))) { 409 SkASSERT(!genIDMatch); 410 return false; 411 } 412 if (fConicWeights != ref.fConicWeights) { 413 SkASSERT(!genIDMatch); 414 return false; 415 } 416 return true; 417} 418 419void SkPathRef::writeToBuffer(SkWBuffer* buffer) const { 420 SkDEBUGCODE(this->validate();) 421 SkDEBUGCODE(size_t beforePos = buffer->pos();) 422 423 // Call getBounds() to ensure (as a side-effect) that fBounds 424 // and fIsFinite are computed. 425 const SkRect& bounds = this->getBounds(); 426 427 // We store fSegmentMask for older readers, but current readers can't trust it, so they 428 // don't read it. 429 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | 430 (fSegmentMask << kSegmentMask_SerializationShift); 431 buffer->write32(packed); 432 433 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from 434 // SkWBuffer. Until this is fixed we write 0. 435 buffer->write32(0); 436 buffer->write32(fVerbCnt); 437 buffer->write32(fPointCnt); 438 buffer->write32(fConicWeights.count()); 439 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); 440 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); 441 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); 442 buffer->write(&bounds, sizeof(bounds)); 443 444 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); 445} 446 447uint32_t SkPathRef::writeSize() const { 448 return uint32_t(5 * sizeof(uint32_t) + 449 fVerbCnt * sizeof(uint8_t) + 450 fPointCnt * sizeof(SkPoint) + 451 fConicWeights.bytes() + 452 sizeof(SkRect)); 453} 454 455void SkPathRef::copy(const SkPathRef& ref, 456 int additionalReserveVerbs, 457 int additionalReservePoints) { 458 SkDEBUGCODE(this->validate();) 459 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(), 460 additionalReserveVerbs, additionalReservePoints); 461 sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t)); 462 sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); 463 fConicWeights = ref.fConicWeights; 464 fBoundsIsDirty = ref.fBoundsIsDirty; 465 if (!fBoundsIsDirty) { 466 fBounds = ref.fBounds; 467 fIsFinite = ref.fIsFinite; 468 } 469 fSegmentMask = ref.fSegmentMask; 470 fIsOval = ref.fIsOval; 471 fIsRRect = ref.fIsRRect; 472 fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW; 473 fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx; 474 SkDEBUGCODE(this->validate();) 475} 476 477unsigned SkPathRef::computeSegmentMask() const { 478 const uint8_t* verbs = this->verbsMemBegin(); 479 unsigned mask = 0; 480 for (int i = this->countVerbs() - 1; i >= 0; --i) { 481 switch (verbs[i]) { 482 case SkPath::kLine_Verb: mask |= SkPath::kLine_SegmentMask; break; 483 case SkPath::kQuad_Verb: mask |= SkPath::kQuad_SegmentMask; break; 484 case SkPath::kConic_Verb: mask |= SkPath::kConic_SegmentMask; break; 485 case SkPath::kCubic_Verb: mask |= SkPath::kCubic_SegmentMask; break; 486 default: break; 487 } 488 } 489 return mask; 490} 491 492void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const { 493 const SkScalar* inValues = &ending.getPoints()->fX; 494 SkScalar* outValues = &out->getPoints()->fX; 495 int count = out->countPoints() * 2; 496 for (int index = 0; index < count; ++index) { 497 outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight); 498 } 499 out->fBoundsIsDirty = true; 500 out->fIsOval = false; 501 out->fIsRRect = false; 502} 503 504SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb, 505 int numVbs, 506 SkScalar** weights) { 507 // This value is just made-up for now. When count is 4, calling memset was much 508 // slower than just writing the loop. This seems odd, and hopefully in the 509 // future this will appear to have been a fluke... 510 static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16; 511 512 SkDEBUGCODE(this->validate();) 513 int pCnt; 514 bool dirtyAfterEdit = true; 515 switch (verb) { 516 case SkPath::kMove_Verb: 517 pCnt = numVbs; 518 dirtyAfterEdit = false; 519 break; 520 case SkPath::kLine_Verb: 521 fSegmentMask |= SkPath::kLine_SegmentMask; 522 pCnt = numVbs; 523 break; 524 case SkPath::kQuad_Verb: 525 fSegmentMask |= SkPath::kQuad_SegmentMask; 526 pCnt = 2 * numVbs; 527 break; 528 case SkPath::kConic_Verb: 529 fSegmentMask |= SkPath::kConic_SegmentMask; 530 pCnt = 2 * numVbs; 531 break; 532 case SkPath::kCubic_Verb: 533 fSegmentMask |= SkPath::kCubic_SegmentMask; 534 pCnt = 3 * numVbs; 535 break; 536 case SkPath::kClose_Verb: 537 SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb"); 538 pCnt = 0; 539 dirtyAfterEdit = false; 540 break; 541 case SkPath::kDone_Verb: 542 SkDEBUGFAIL("growForRepeatedVerb called for kDone"); 543 // fall through 544 default: 545 SkDEBUGFAIL("default should not be reached"); 546 pCnt = 0; 547 dirtyAfterEdit = false; 548 } 549 550 size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint); 551 this->makeSpace(space); 552 553 SkPoint* ret = fPoints + fPointCnt; 554 uint8_t* vb = fVerbs - fVerbCnt; 555 556 // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to 557 // be 0, the compiler will remove the test/branch entirely. 558 if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) { 559 memset(vb - numVbs, verb, numVbs); 560 } else { 561 for (int i = 0; i < numVbs; ++i) { 562 vb[~i] = verb; 563 } 564 } 565 566 fVerbCnt += numVbs; 567 fPointCnt += pCnt; 568 fFreeSpace -= space; 569 fBoundsIsDirty = true; // this also invalidates fIsFinite 570 if (dirtyAfterEdit) { 571 fIsOval = false; 572 fIsRRect = false; 573 } 574 575 if (SkPath::kConic_Verb == verb) { 576 SkASSERT(weights); 577 *weights = fConicWeights.append(numVbs); 578 } 579 580 SkDEBUGCODE(this->validate();) 581 return ret; 582} 583 584SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) { 585 SkDEBUGCODE(this->validate();) 586 int pCnt; 587 bool dirtyAfterEdit = true; 588 unsigned mask = 0; 589 switch (verb) { 590 case SkPath::kMove_Verb: 591 pCnt = 1; 592 dirtyAfterEdit = false; 593 break; 594 case SkPath::kLine_Verb: 595 mask = SkPath::kLine_SegmentMask; 596 pCnt = 1; 597 break; 598 case SkPath::kQuad_Verb: 599 mask = SkPath::kQuad_SegmentMask; 600 pCnt = 2; 601 break; 602 case SkPath::kConic_Verb: 603 mask = SkPath::kConic_SegmentMask; 604 pCnt = 2; 605 break; 606 case SkPath::kCubic_Verb: 607 mask = SkPath::kCubic_SegmentMask; 608 pCnt = 3; 609 break; 610 case SkPath::kClose_Verb: 611 pCnt = 0; 612 dirtyAfterEdit = false; 613 break; 614 case SkPath::kDone_Verb: 615 SkDEBUGFAIL("growForVerb called for kDone"); 616 // fall through 617 default: 618 SkDEBUGFAIL("default is not reached"); 619 dirtyAfterEdit = false; 620 pCnt = 0; 621 } 622 SkSafeMath safe; 623 int newPointCnt = safe.addInt(fPointCnt, pCnt); 624 int newVerbCnt = safe.addInt(fVerbCnt, 1); 625 if (!safe) { 626 SK_ABORT("cannot grow path"); 627 } 628 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); 629 this->makeSpace(space); 630 this->fVerbs[~fVerbCnt] = verb; 631 SkPoint* ret = fPoints + fPointCnt; 632 fVerbCnt = newVerbCnt; 633 fPointCnt = newPointCnt; 634 fSegmentMask |= mask; 635 fFreeSpace -= space; 636 fBoundsIsDirty = true; // this also invalidates fIsFinite 637 if (dirtyAfterEdit) { 638 fIsOval = false; 639 fIsRRect = false; 640 } 641 642 if (SkPath::kConic_Verb == verb) { 643 *fConicWeights.append() = weight; 644 } 645 646 SkDEBUGCODE(this->validate();) 647 return ret; 648} 649 650uint32_t SkPathRef::genID() const { 651 SkASSERT(!fEditorsAttached); 652 static const uint32_t kMask = (static_cast<int64_t>(1) << SkPathPriv::kPathRefGenIDBitCnt) - 1; 653 if (!fGenerationID) { 654 if (0 == fPointCnt && 0 == fVerbCnt) { 655 fGenerationID = kEmptyGenID; 656 } else { 657 static int32_t gPathRefGenerationID; 658 // do a loop in case our global wraps around, as we never want to return a 0 or the 659 // empty ID 660 do { 661 fGenerationID = (sk_atomic_inc(&gPathRefGenerationID) + 1) & kMask; 662 } while (fGenerationID <= kEmptyGenID); 663 } 664 } 665 return fGenerationID; 666} 667 668void SkPathRef::addGenIDChangeListener(GenIDChangeListener* listener) { 669 if (nullptr == listener || this == gEmpty) { 670 delete listener; 671 return; 672 } 673 *fGenIDChangeListeners.append() = listener; 674} 675 676// we need to be called *before* the genID gets changed or zerod 677void SkPathRef::callGenIDChangeListeners() { 678 for (int i = 0; i < fGenIDChangeListeners.count(); i++) { 679 fGenIDChangeListeners[i]->onChange(); 680 } 681 682 // Listeners get at most one shot, so whether these triggered or not, blow them away. 683 fGenIDChangeListeners.deleteAll(); 684} 685 686SkRRect SkPathRef::getRRect() const { 687 const SkRect& bounds = this->getBounds(); 688 SkVector radii[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; 689 Iter iter(*this); 690 SkPoint pts[4]; 691 uint8_t verb = iter.next(pts); 692 SkASSERT(SkPath::kMove_Verb == verb); 693 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 694 if (SkPath::kConic_Verb == verb) { 695 SkVector v1_0 = pts[1] - pts[0]; 696 SkVector v2_1 = pts[2] - pts[1]; 697 SkVector dxdy; 698 if (v1_0.fX) { 699 SkASSERT(!v2_1.fX && !v1_0.fY); 700 dxdy.set(SkScalarAbs(v1_0.fX), SkScalarAbs(v2_1.fY)); 701 } else if (!v1_0.fY) { 702 SkASSERT(!v2_1.fX || !v2_1.fY); 703 dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v2_1.fY)); 704 } else { 705 SkASSERT(!v2_1.fY); 706 dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v1_0.fY)); 707 } 708 SkRRect::Corner corner = 709 pts[1].fX == bounds.fLeft ? 710 pts[1].fY == bounds.fTop ? 711 SkRRect::kUpperLeft_Corner : SkRRect::kLowerLeft_Corner : 712 pts[1].fY == bounds.fTop ? 713 SkRRect::kUpperRight_Corner : SkRRect::kLowerRight_Corner; 714 SkASSERT(!radii[corner].fX && !radii[corner].fY); 715 radii[corner] = dxdy; 716 } else { 717 SkASSERT((verb == SkPath::kLine_Verb 718 && (!(pts[1].fX - pts[0].fX) || !(pts[1].fY - pts[0].fY))) 719 || verb == SkPath::kClose_Verb); 720 } 721 } 722 SkRRect rrect; 723 rrect.setRectRadii(bounds, radii); 724 return rrect; 725} 726 727/////////////////////////////////////////////////////////////////////////////// 728 729SkPathRef::Iter::Iter() { 730#ifdef SK_DEBUG 731 fPts = nullptr; 732 fConicWeights = nullptr; 733#endif 734 // need to init enough to make next() harmlessly return kDone_Verb 735 fVerbs = nullptr; 736 fVerbStop = nullptr; 737} 738 739SkPathRef::Iter::Iter(const SkPathRef& path) { 740 this->setPathRef(path); 741} 742 743void SkPathRef::Iter::setPathRef(const SkPathRef& path) { 744 fPts = path.points(); 745 fVerbs = path.verbs(); 746 fVerbStop = path.verbsMemBegin(); 747 fConicWeights = path.conicWeights(); 748 if (fConicWeights) { 749 fConicWeights -= 1; // begin one behind 750 } 751 752 // Don't allow iteration through non-finite points. 753 if (!path.isFinite()) { 754 fVerbStop = fVerbs; 755 } 756} 757 758uint8_t SkPathRef::Iter::next(SkPoint pts[4]) { 759 SkASSERT(pts); 760 if (fVerbs == fVerbStop) { 761 return (uint8_t) SkPath::kDone_Verb; 762 } 763 764 // fVerbs points one beyond next verb so decrement first. 765 unsigned verb = *(--fVerbs); 766 const SkPoint* srcPts = fPts; 767 768 switch (verb) { 769 case SkPath::kMove_Verb: 770 pts[0] = srcPts[0]; 771 srcPts += 1; 772 break; 773 case SkPath::kLine_Verb: 774 pts[0] = srcPts[-1]; 775 pts[1] = srcPts[0]; 776 srcPts += 1; 777 break; 778 case SkPath::kConic_Verb: 779 fConicWeights += 1; 780 // fall-through 781 case SkPath::kQuad_Verb: 782 pts[0] = srcPts[-1]; 783 pts[1] = srcPts[0]; 784 pts[2] = srcPts[1]; 785 srcPts += 2; 786 break; 787 case SkPath::kCubic_Verb: 788 pts[0] = srcPts[-1]; 789 pts[1] = srcPts[0]; 790 pts[2] = srcPts[1]; 791 pts[3] = srcPts[2]; 792 srcPts += 3; 793 break; 794 case SkPath::kClose_Verb: 795 break; 796 case SkPath::kDone_Verb: 797 SkASSERT(fVerbs == fVerbStop); 798 break; 799 } 800 fPts = srcPts; 801 return (uint8_t) verb; 802} 803 804uint8_t SkPathRef::Iter::peek() const { 805 const uint8_t* next = fVerbs - 1; 806 return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : *next; 807} 808 809 810bool SkPathRef::isValid() const { 811 if (static_cast<ptrdiff_t>(fFreeSpace) < 0) { 812 return false; 813 } 814 if (reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) < 0) { 815 return false; 816 } 817 if ((nullptr == fPoints) != (nullptr == fVerbs)) { 818 return false; 819 } 820 if (nullptr == fPoints && 0 != fFreeSpace) { 821 return false; 822 } 823 if (nullptr == fPoints && fPointCnt) { 824 return false; 825 } 826 if (nullptr == fVerbs && fVerbCnt) { 827 return false; 828 } 829 if (this->currSize() != 830 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt) { 831 return false; 832 } 833 834 if (fIsOval || fIsRRect) { 835 // Currently we don't allow both of these to be set, even though ovals are ro 836 if (fIsOval == fIsRRect) { 837 return false; 838 } 839 if (fIsOval) { 840 if (fRRectOrOvalStartIdx >= 4) { 841 return false; 842 } 843 } else { 844 if (fRRectOrOvalStartIdx >= 8) { 845 return false; 846 } 847 } 848 } 849 850 if (!fBoundsIsDirty && !fBounds.isEmpty()) { 851 bool isFinite = true; 852 Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop); 853 Sk2s rightBot = Sk2s(fBounds.fRight, fBounds.fBottom); 854 for (int i = 0; i < fPointCnt; ++i) { 855 Sk2s point = Sk2s(fPoints[i].fX, fPoints[i].fY); 856#ifdef SK_DEBUG 857 if (fPoints[i].isFinite() && 858 ((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) { 859 SkDebugf("bounds: %f %f %f %f\n", 860 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 861 for (int j = 0; j < fPointCnt; ++j) { 862 if (i == j) { 863 SkDebugf("*"); 864 } 865 SkDebugf("%f %f\n", fPoints[j].fX, fPoints[j].fY); 866 } 867 } 868#endif 869 870 if (fPoints[i].isFinite() && (point < leftTop).anyTrue() && !(point > rightBot).anyTrue()) 871 return false; 872 if (!fPoints[i].isFinite()) { 873 isFinite = false; 874 } 875 } 876 if (SkToBool(fIsFinite) != isFinite) { 877 return false; 878 } 879 } 880 return true; 881} 882