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 17 static 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 ////////////////////////////////////////////////////////////////////////////// 27 SkPathRef::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 46 SkPathRef::~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 61 static SkPathRef* gEmpty = nullptr; 62 63 SkPathRef* 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 72 static 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 127 void 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 202 static 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. 232 static 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 271 SkPathRef* 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 uint8_t segmentMask = (packed >> kSegmentMask_SerializationShift) & 0xF; 281 282 int32_t verbCount, pointCount, conicCount; 283 if (!buffer->readU32(&(ref->fGenerationID)) || 284 !buffer->readS32(&verbCount) || (verbCount < 0) || 285 !buffer->readS32(&pointCount) || (pointCount < 0) || 286 !buffer->readS32(&conicCount) || (conicCount < 0)) 287 { 288 return nullptr; 289 } 290 291 uint64_t pointSize64 = sk_64_mul(pointCount, sizeof(SkPoint)); 292 uint64_t conicSize64 = sk_64_mul(conicCount, sizeof(SkScalar)); 293 if (!SkTFitsIn<size_t>(pointSize64) || !SkTFitsIn<size_t>(conicSize64)) { 294 return nullptr; 295 } 296 297 size_t verbSize = verbCount * sizeof(uint8_t); 298 size_t pointSize = SkToSizeT(pointSize64); 299 size_t conicSize = SkToSizeT(conicSize64); 300 301 { 302 uint64_t requiredBufferSize = sizeof(SkRect); 303 requiredBufferSize += verbSize; 304 requiredBufferSize += pointSize; 305 requiredBufferSize += conicSize; 306 if (buffer->available() < requiredBufferSize) { 307 return nullptr; 308 } 309 } 310 311 ref->resetToSize(verbCount, pointCount, conicCount); 312 SkASSERT(verbCount == ref->countVerbs()); 313 SkASSERT(pointCount == ref->countPoints()); 314 SkASSERT(conicCount == ref->fConicWeights.count()); 315 316 if (!buffer->read(ref->verbsMemWritable(), verbSize) || 317 !buffer->read(ref->fPoints, pointSize) || 318 !buffer->read(ref->fConicWeights.begin(), conicSize) || 319 !buffer->read(&ref->fBounds, sizeof(SkRect))) { 320 return nullptr; 321 } 322 323 // Check that the verbs are valid, and imply the correct number of pts and conics 324 { 325 int pCount, cCount; 326 if (!validate_verb_sequence(ref->verbsMemBegin(), ref->countVerbs())) { 327 return nullptr; 328 } 329 if (!deduce_pts_conics(ref->verbsMemBegin(), ref->countVerbs(), &pCount, &cCount) || 330 pCount != ref->countPoints() || cCount != ref->fConicWeights.count()) { 331 return nullptr; 332 } 333 if (!validate_conic_weights(ref->fConicWeights.begin(), ref->fConicWeights.count())) { 334 return nullptr; 335 } 336 // Check that the bounds match the serialized bounds. 337 SkRect bounds; 338 if (ComputePtBounds(&bounds, *ref) != SkToBool(ref->fIsFinite) || bounds != ref->fBounds) { 339 return nullptr; 340 } 341 } 342 343 ref->fBoundsIsDirty = false; 344 345 // resetToSize clears fSegmentMask and fIsOval 346 ref->fSegmentMask = segmentMask; 347 return ref.release(); 348 } 349 350 void 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 372 bool 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 419 void 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 int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | 428 (fSegmentMask << kSegmentMask_SerializationShift); 429 buffer->write32(packed); 430 431 // TODO: write gen ID here. Problem: We don't know if we're cross process or not from 432 // SkWBuffer. Until this is fixed we write 0. 433 buffer->write32(0); 434 buffer->write32(fVerbCnt); 435 buffer->write32(fPointCnt); 436 buffer->write32(fConicWeights.count()); 437 buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t)); 438 buffer->write(fPoints, fPointCnt * sizeof(SkPoint)); 439 buffer->write(fConicWeights.begin(), fConicWeights.bytes()); 440 buffer->write(&bounds, sizeof(bounds)); 441 442 SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); 443 } 444 445 uint32_t SkPathRef::writeSize() const { 446 return uint32_t(5 * sizeof(uint32_t) + 447 fVerbCnt * sizeof(uint8_t) + 448 fPointCnt * sizeof(SkPoint) + 449 fConicWeights.bytes() + 450 sizeof(SkRect)); 451 } 452 453 void SkPathRef::copy(const SkPathRef& ref, 454 int additionalReserveVerbs, 455 int additionalReservePoints) { 456 SkDEBUGCODE(this->validate();) 457 this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(), 458 additionalReserveVerbs, additionalReservePoints); 459 sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t)); 460 sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint)); 461 fConicWeights = ref.fConicWeights; 462 fBoundsIsDirty = ref.fBoundsIsDirty; 463 if (!fBoundsIsDirty) { 464 fBounds = ref.fBounds; 465 fIsFinite = ref.fIsFinite; 466 } 467 fSegmentMask = ref.fSegmentMask; 468 fIsOval = ref.fIsOval; 469 fIsRRect = ref.fIsRRect; 470 fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW; 471 fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx; 472 SkDEBUGCODE(this->validate();) 473 } 474 475 476 void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const { 477 const SkScalar* inValues = &ending.getPoints()->fX; 478 SkScalar* outValues = &out->getPoints()->fX; 479 int count = out->countPoints() * 2; 480 for (int index = 0; index < count; ++index) { 481 outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight); 482 } 483 out->fBoundsIsDirty = true; 484 out->fIsOval = false; 485 out->fIsRRect = false; 486 } 487 488 SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb, 489 int numVbs, 490 SkScalar** weights) { 491 // This value is just made-up for now. When count is 4, calling memset was much 492 // slower than just writing the loop. This seems odd, and hopefully in the 493 // future this will appear to have been a fluke... 494 static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16; 495 496 SkDEBUGCODE(this->validate();) 497 int pCnt; 498 bool dirtyAfterEdit = true; 499 switch (verb) { 500 case SkPath::kMove_Verb: 501 pCnt = numVbs; 502 dirtyAfterEdit = false; 503 break; 504 case SkPath::kLine_Verb: 505 fSegmentMask |= SkPath::kLine_SegmentMask; 506 pCnt = numVbs; 507 break; 508 case SkPath::kQuad_Verb: 509 fSegmentMask |= SkPath::kQuad_SegmentMask; 510 pCnt = 2 * numVbs; 511 break; 512 case SkPath::kConic_Verb: 513 fSegmentMask |= SkPath::kConic_SegmentMask; 514 pCnt = 2 * numVbs; 515 break; 516 case SkPath::kCubic_Verb: 517 fSegmentMask |= SkPath::kCubic_SegmentMask; 518 pCnt = 3 * numVbs; 519 break; 520 case SkPath::kClose_Verb: 521 SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb"); 522 pCnt = 0; 523 dirtyAfterEdit = false; 524 break; 525 case SkPath::kDone_Verb: 526 SkDEBUGFAIL("growForRepeatedVerb called for kDone"); 527 // fall through 528 default: 529 SkDEBUGFAIL("default should not be reached"); 530 pCnt = 0; 531 dirtyAfterEdit = false; 532 } 533 534 size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint); 535 this->makeSpace(space); 536 537 SkPoint* ret = fPoints + fPointCnt; 538 uint8_t* vb = fVerbs - fVerbCnt; 539 540 // cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to 541 // be 0, the compiler will remove the test/branch entirely. 542 if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) { 543 memset(vb - numVbs, verb, numVbs); 544 } else { 545 for (int i = 0; i < numVbs; ++i) { 546 vb[~i] = verb; 547 } 548 } 549 550 fVerbCnt += numVbs; 551 fPointCnt += pCnt; 552 fFreeSpace -= space; 553 fBoundsIsDirty = true; // this also invalidates fIsFinite 554 if (dirtyAfterEdit) { 555 fIsOval = false; 556 fIsRRect = false; 557 } 558 559 if (SkPath::kConic_Verb == verb) { 560 SkASSERT(weights); 561 *weights = fConicWeights.append(numVbs); 562 } 563 564 SkDEBUGCODE(this->validate();) 565 return ret; 566 } 567 568 SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) { 569 SkDEBUGCODE(this->validate();) 570 int pCnt; 571 bool dirtyAfterEdit = true; 572 switch (verb) { 573 case SkPath::kMove_Verb: 574 pCnt = 1; 575 dirtyAfterEdit = false; 576 break; 577 case SkPath::kLine_Verb: 578 fSegmentMask |= SkPath::kLine_SegmentMask; 579 pCnt = 1; 580 break; 581 case SkPath::kQuad_Verb: 582 fSegmentMask |= SkPath::kQuad_SegmentMask; 583 pCnt = 2; 584 break; 585 case SkPath::kConic_Verb: 586 fSegmentMask |= SkPath::kConic_SegmentMask; 587 pCnt = 2; 588 break; 589 case SkPath::kCubic_Verb: 590 fSegmentMask |= SkPath::kCubic_SegmentMask; 591 pCnt = 3; 592 break; 593 case SkPath::kClose_Verb: 594 pCnt = 0; 595 dirtyAfterEdit = false; 596 break; 597 case SkPath::kDone_Verb: 598 SkDEBUGFAIL("growForVerb called for kDone"); 599 // fall through 600 default: 601 SkDEBUGFAIL("default is not reached"); 602 dirtyAfterEdit = false; 603 pCnt = 0; 604 } 605 SkSafeMath safe; 606 int newPointCnt = safe.addInt(fPointCnt, pCnt); 607 int newVerbCnt = safe.addInt(fVerbCnt, 1); 608 if (!safe) { 609 SK_ABORT("cannot grow path"); 610 } 611 size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint); 612 this->makeSpace(space); 613 this->fVerbs[~fVerbCnt] = verb; 614 SkPoint* ret = fPoints + fPointCnt; 615 fVerbCnt = newVerbCnt; 616 fPointCnt = newPointCnt; 617 fFreeSpace -= space; 618 fBoundsIsDirty = true; // this also invalidates fIsFinite 619 if (dirtyAfterEdit) { 620 fIsOval = false; 621 fIsRRect = false; 622 } 623 624 if (SkPath::kConic_Verb == verb) { 625 *fConicWeights.append() = weight; 626 } 627 628 SkDEBUGCODE(this->validate();) 629 return ret; 630 } 631 632 uint32_t SkPathRef::genID() const { 633 SkASSERT(!fEditorsAttached); 634 static const uint32_t kMask = (static_cast<int64_t>(1) << SkPathPriv::kPathRefGenIDBitCnt) - 1; 635 if (!fGenerationID) { 636 if (0 == fPointCnt && 0 == fVerbCnt) { 637 fGenerationID = kEmptyGenID; 638 } else { 639 static int32_t gPathRefGenerationID; 640 // do a loop in case our global wraps around, as we never want to return a 0 or the 641 // empty ID 642 do { 643 fGenerationID = (sk_atomic_inc(&gPathRefGenerationID) + 1) & kMask; 644 } while (fGenerationID <= kEmptyGenID); 645 } 646 } 647 return fGenerationID; 648 } 649 650 void SkPathRef::addGenIDChangeListener(GenIDChangeListener* listener) { 651 if (nullptr == listener || this == gEmpty) { 652 delete listener; 653 return; 654 } 655 *fGenIDChangeListeners.append() = listener; 656 } 657 658 // we need to be called *before* the genID gets changed or zerod 659 void SkPathRef::callGenIDChangeListeners() { 660 for (int i = 0; i < fGenIDChangeListeners.count(); i++) { 661 fGenIDChangeListeners[i]->onChange(); 662 } 663 664 // Listeners get at most one shot, so whether these triggered or not, blow them away. 665 fGenIDChangeListeners.deleteAll(); 666 } 667 668 SkRRect SkPathRef::getRRect() const { 669 const SkRect& bounds = this->getBounds(); 670 SkVector radii[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; 671 Iter iter(*this); 672 SkPoint pts[4]; 673 uint8_t verb = iter.next(pts); 674 SkASSERT(SkPath::kMove_Verb == verb); 675 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 676 if (SkPath::kConic_Verb == verb) { 677 SkVector v1_0 = pts[1] - pts[0]; 678 SkVector v2_1 = pts[2] - pts[1]; 679 SkVector dxdy; 680 if (v1_0.fX) { 681 SkASSERT(!v2_1.fX && !v1_0.fY); 682 dxdy.set(SkScalarAbs(v1_0.fX), SkScalarAbs(v2_1.fY)); 683 } else if (!v1_0.fY) { 684 SkASSERT(!v2_1.fX || !v2_1.fY); 685 dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v2_1.fY)); 686 } else { 687 SkASSERT(!v2_1.fY); 688 dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v1_0.fY)); 689 } 690 SkRRect::Corner corner = 691 pts[1].fX == bounds.fLeft ? 692 pts[1].fY == bounds.fTop ? 693 SkRRect::kUpperLeft_Corner : SkRRect::kLowerLeft_Corner : 694 pts[1].fY == bounds.fTop ? 695 SkRRect::kUpperRight_Corner : SkRRect::kLowerRight_Corner; 696 SkASSERT(!radii[corner].fX && !radii[corner].fY); 697 radii[corner] = dxdy; 698 } else { 699 SkASSERT((verb == SkPath::kLine_Verb 700 && (!(pts[1].fX - pts[0].fX) || !(pts[1].fY - pts[0].fY))) 701 || verb == SkPath::kClose_Verb); 702 } 703 } 704 SkRRect rrect; 705 rrect.setRectRadii(bounds, radii); 706 return rrect; 707 } 708 709 /////////////////////////////////////////////////////////////////////////////// 710 711 SkPathRef::Iter::Iter() { 712 #ifdef SK_DEBUG 713 fPts = nullptr; 714 fConicWeights = nullptr; 715 #endif 716 // need to init enough to make next() harmlessly return kDone_Verb 717 fVerbs = nullptr; 718 fVerbStop = nullptr; 719 } 720 721 SkPathRef::Iter::Iter(const SkPathRef& path) { 722 this->setPathRef(path); 723 } 724 725 void SkPathRef::Iter::setPathRef(const SkPathRef& path) { 726 fPts = path.points(); 727 fVerbs = path.verbs(); 728 fVerbStop = path.verbsMemBegin(); 729 fConicWeights = path.conicWeights(); 730 if (fConicWeights) { 731 fConicWeights -= 1; // begin one behind 732 } 733 734 // Don't allow iteration through non-finite points. 735 if (!path.isFinite()) { 736 fVerbStop = fVerbs; 737 } 738 } 739 740 uint8_t SkPathRef::Iter::next(SkPoint pts[4]) { 741 SkASSERT(pts); 742 if (fVerbs == fVerbStop) { 743 return (uint8_t) SkPath::kDone_Verb; 744 } 745 746 // fVerbs points one beyond next verb so decrement first. 747 unsigned verb = *(--fVerbs); 748 const SkPoint* srcPts = fPts; 749 750 switch (verb) { 751 case SkPath::kMove_Verb: 752 pts[0] = srcPts[0]; 753 srcPts += 1; 754 break; 755 case SkPath::kLine_Verb: 756 pts[0] = srcPts[-1]; 757 pts[1] = srcPts[0]; 758 srcPts += 1; 759 break; 760 case SkPath::kConic_Verb: 761 fConicWeights += 1; 762 // fall-through 763 case SkPath::kQuad_Verb: 764 pts[0] = srcPts[-1]; 765 pts[1] = srcPts[0]; 766 pts[2] = srcPts[1]; 767 srcPts += 2; 768 break; 769 case SkPath::kCubic_Verb: 770 pts[0] = srcPts[-1]; 771 pts[1] = srcPts[0]; 772 pts[2] = srcPts[1]; 773 pts[3] = srcPts[2]; 774 srcPts += 3; 775 break; 776 case SkPath::kClose_Verb: 777 break; 778 case SkPath::kDone_Verb: 779 SkASSERT(fVerbs == fVerbStop); 780 break; 781 } 782 fPts = srcPts; 783 return (uint8_t) verb; 784 } 785 786 uint8_t SkPathRef::Iter::peek() const { 787 const uint8_t* next = fVerbs - 1; 788 return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : *next; 789 } 790 791 792 bool SkPathRef::isValid() const { 793 if (static_cast<ptrdiff_t>(fFreeSpace) < 0) { 794 return false; 795 } 796 if (reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) < 0) { 797 return false; 798 } 799 if ((nullptr == fPoints) != (nullptr == fVerbs)) { 800 return false; 801 } 802 if (nullptr == fPoints && 0 != fFreeSpace) { 803 return false; 804 } 805 if (nullptr == fPoints && fPointCnt) { 806 return false; 807 } 808 if (nullptr == fVerbs && fVerbCnt) { 809 return false; 810 } 811 if (this->currSize() != 812 fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt) { 813 return false; 814 } 815 816 if (fIsOval || fIsRRect) { 817 // Currently we don't allow both of these to be set, even though ovals are ro 818 if (fIsOval == fIsRRect) { 819 return false; 820 } 821 if (fIsOval) { 822 if (fRRectOrOvalStartIdx >= 4) { 823 return false; 824 } 825 } else { 826 if (fRRectOrOvalStartIdx >= 8) { 827 return false; 828 } 829 } 830 } 831 832 if (!fBoundsIsDirty && !fBounds.isEmpty()) { 833 bool isFinite = true; 834 Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop); 835 Sk2s rightBot = Sk2s(fBounds.fRight, fBounds.fBottom); 836 for (int i = 0; i < fPointCnt; ++i) { 837 Sk2s point = Sk2s(fPoints[i].fX, fPoints[i].fY); 838 #ifdef SK_DEBUG 839 if (fPoints[i].isFinite() && 840 ((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) { 841 SkDebugf("bounds: %f %f %f %f\n", 842 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 843 for (int j = 0; j < fPointCnt; ++j) { 844 if (i == j) { 845 SkDebugf("*"); 846 } 847 SkDebugf("%f %f\n", fPoints[j].fX, fPoints[j].fY); 848 } 849 } 850 #endif 851 852 if (fPoints[i].isFinite() && (point < leftTop).anyTrue() && !(point > rightBot).anyTrue()) 853 return false; 854 if (!fPoints[i].isFinite()) { 855 isFinite = false; 856 } 857 } 858 if (SkToBool(fIsFinite) != isFinite) { 859 return false; 860 } 861 } 862 863 #ifdef SK_DEBUG_PATH 864 uint32_t mask = 0; 865 for (int i = 0; i < fVerbCnt; ++i) { 866 switch (fVerbs[~i]) { 867 case SkPath::kMove_Verb: 868 break; 869 case SkPath::kLine_Verb: 870 mask |= SkPath::kLine_SegmentMask; 871 break; 872 case SkPath::kQuad_Verb: 873 mask |= SkPath::kQuad_SegmentMask; 874 break; 875 case SkPath::kConic_Verb: 876 mask |= SkPath::kConic_SegmentMask; 877 break; 878 case SkPath::kCubic_Verb: 879 mask |= SkPath::kCubic_SegmentMask; 880 break; 881 case SkPath::kClose_Verb: 882 break; 883 case SkPath::kDone_Verb: 884 SkDEBUGFAIL("Done verb shouldn't be recorded."); 885 break; 886 default: 887 SkDEBUGFAIL("Unknown Verb"); 888 break; 889 } 890 } 891 if (mask != fSegmentMask) { 892 return false; 893 } 894 #endif // SK_DEBUG_PATH 895 return true; 896 } 897