1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/private/SkPathRef.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 11cb93a386Sopenharmony_ci#include "include/private/SkNx.h" 12cb93a386Sopenharmony_ci#include "include/private/SkOnce.h" 13cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 14cb93a386Sopenharmony_ci#include "src/core/SkBuffer.h" 15cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 16cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h" 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 19cb93a386Sopenharmony_ciSkPathRef::Editor::Editor(sk_sp<SkPathRef>* pathRef, 20cb93a386Sopenharmony_ci int incReserveVerbs, 21cb93a386Sopenharmony_ci int incReservePoints) 22cb93a386Sopenharmony_ci{ 23cb93a386Sopenharmony_ci SkASSERT(incReserveVerbs >= 0); 24cb93a386Sopenharmony_ci SkASSERT(incReservePoints >= 0); 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci if ((*pathRef)->unique()) { 27cb93a386Sopenharmony_ci (*pathRef)->incReserve(incReserveVerbs, incReservePoints); 28cb93a386Sopenharmony_ci } else { 29cb93a386Sopenharmony_ci SkPathRef* copy = new SkPathRef; 30cb93a386Sopenharmony_ci copy->copy(**pathRef, incReserveVerbs, incReservePoints); 31cb93a386Sopenharmony_ci pathRef->reset(copy); 32cb93a386Sopenharmony_ci } 33cb93a386Sopenharmony_ci fPathRef = pathRef->get(); 34cb93a386Sopenharmony_ci fPathRef->callGenIDChangeListeners(); 35cb93a386Sopenharmony_ci fPathRef->fGenerationID = 0; 36cb93a386Sopenharmony_ci fPathRef->fBoundsIsDirty = true; 37cb93a386Sopenharmony_ci SkDEBUGCODE(fPathRef->fEditorsAttached++;) 38cb93a386Sopenharmony_ci} 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci// Sort of like makeSpace(0) but the the additional requirement that we actively shrink the 41cb93a386Sopenharmony_ci// allocations to just fit the current needs. makeSpace() will only grow, but never shrinks. 42cb93a386Sopenharmony_ci// 43cb93a386Sopenharmony_civoid SkPath::shrinkToFit() { 44cb93a386Sopenharmony_ci // Since this can relocate the allocated arrays, we have to defensively copy ourselves if 45cb93a386Sopenharmony_ci // we're not the only owner of the pathref... since relocating the arrays will invalidate 46cb93a386Sopenharmony_ci // any existing iterators. 47cb93a386Sopenharmony_ci if (!fPathRef->unique()) { 48cb93a386Sopenharmony_ci SkPathRef* pr = new SkPathRef; 49cb93a386Sopenharmony_ci pr->copy(*fPathRef, 0, 0); 50cb93a386Sopenharmony_ci fPathRef.reset(pr); 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci fPathRef->fPoints.shrinkToFit(); 53cb93a386Sopenharmony_ci fPathRef->fVerbs.shrinkToFit(); 54cb93a386Sopenharmony_ci fPathRef->fConicWeights.shrinkToFit(); 55cb93a386Sopenharmony_ci SkDEBUGCODE(fPathRef->validate();) 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_cisize_t SkPathRef::approximateBytesUsed() const { 61cb93a386Sopenharmony_ci return sizeof(SkPathRef) 62cb93a386Sopenharmony_ci + fPoints .reserved() * sizeof(fPoints [0]) 63cb93a386Sopenharmony_ci + fVerbs .reserved() * sizeof(fVerbs [0]) 64cb93a386Sopenharmony_ci + fConicWeights.reserved() * sizeof(fConicWeights[0]); 65cb93a386Sopenharmony_ci} 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ciSkPathRef::~SkPathRef() { 68cb93a386Sopenharmony_ci // Deliberately don't validate() this path ref, otherwise there's no way 69cb93a386Sopenharmony_ci // to read one that's not valid and then free its memory without asserting. 70cb93a386Sopenharmony_ci SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;) 71cb93a386Sopenharmony_ci SkDEBUGCODE(fEditorsAttached.store(0x7777777);) 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_cistatic SkPathRef* gEmpty = nullptr; 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ciSkPathRef* SkPathRef::CreateEmpty() { 77cb93a386Sopenharmony_ci static SkOnce once; 78cb93a386Sopenharmony_ci once([]{ 79cb93a386Sopenharmony_ci gEmpty = new SkPathRef; 80cb93a386Sopenharmony_ci gEmpty->computeBounds(); // Avoids races later to be the first to do this. 81cb93a386Sopenharmony_ci }); 82cb93a386Sopenharmony_ci return SkRef(gEmpty); 83cb93a386Sopenharmony_ci} 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_cistatic void transform_dir_and_start(const SkMatrix& matrix, bool isRRect, bool* isCCW, 86cb93a386Sopenharmony_ci unsigned* start) { 87cb93a386Sopenharmony_ci int inStart = *start; 88cb93a386Sopenharmony_ci int rm = 0; 89cb93a386Sopenharmony_ci if (isRRect) { 90cb93a386Sopenharmony_ci // Degenerate rrect indices to oval indices and remember the remainder. 91cb93a386Sopenharmony_ci // Ovals have one index per side whereas rrects have two. 92cb93a386Sopenharmony_ci rm = inStart & 0b1; 93cb93a386Sopenharmony_ci inStart /= 2; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci // Is the antidiagonal non-zero (otherwise the diagonal is zero) 96cb93a386Sopenharmony_ci int antiDiag; 97cb93a386Sopenharmony_ci // Is the non-zero value in the top row (either kMScaleX or kMSkewX) negative 98cb93a386Sopenharmony_ci int topNeg; 99cb93a386Sopenharmony_ci // Are the two non-zero diagonal or antidiagonal values the same sign. 100cb93a386Sopenharmony_ci int sameSign; 101cb93a386Sopenharmony_ci if (matrix.get(SkMatrix::kMScaleX) != 0) { 102cb93a386Sopenharmony_ci antiDiag = 0b00; 103cb93a386Sopenharmony_ci if (matrix.get(SkMatrix::kMScaleX) > 0) { 104cb93a386Sopenharmony_ci topNeg = 0b00; 105cb93a386Sopenharmony_ci sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b01 : 0b00; 106cb93a386Sopenharmony_ci } else { 107cb93a386Sopenharmony_ci topNeg = 0b10; 108cb93a386Sopenharmony_ci sameSign = matrix.get(SkMatrix::kMScaleY) > 0 ? 0b00 : 0b01; 109cb93a386Sopenharmony_ci } 110cb93a386Sopenharmony_ci } else { 111cb93a386Sopenharmony_ci antiDiag = 0b01; 112cb93a386Sopenharmony_ci if (matrix.get(SkMatrix::kMSkewX) > 0) { 113cb93a386Sopenharmony_ci topNeg = 0b00; 114cb93a386Sopenharmony_ci sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b01 : 0b00; 115cb93a386Sopenharmony_ci } else { 116cb93a386Sopenharmony_ci topNeg = 0b10; 117cb93a386Sopenharmony_ci sameSign = matrix.get(SkMatrix::kMSkewY) > 0 ? 0b00 : 0b01; 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci if (sameSign != antiDiag) { 121cb93a386Sopenharmony_ci // This is a rotation (and maybe scale). The direction is unchanged. 122cb93a386Sopenharmony_ci // Trust me on the start computation (or draw yourself some pictures) 123cb93a386Sopenharmony_ci *start = (inStart + 4 - (topNeg | antiDiag)) % 4; 124cb93a386Sopenharmony_ci SkASSERT(*start < 4); 125cb93a386Sopenharmony_ci if (isRRect) { 126cb93a386Sopenharmony_ci *start = 2 * *start + rm; 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci } else { 129cb93a386Sopenharmony_ci // This is a mirror (and maybe scale). The direction is reversed. 130cb93a386Sopenharmony_ci *isCCW = !*isCCW; 131cb93a386Sopenharmony_ci // Trust me on the start computation (or draw yourself some pictures) 132cb93a386Sopenharmony_ci *start = (6 + (topNeg | antiDiag) - inStart) % 4; 133cb93a386Sopenharmony_ci SkASSERT(*start < 4); 134cb93a386Sopenharmony_ci if (isRRect) { 135cb93a386Sopenharmony_ci *start = 2 * *start + (rm ? 0 : 1); 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci} 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_civoid SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst, 141cb93a386Sopenharmony_ci const SkPathRef& src, 142cb93a386Sopenharmony_ci const SkMatrix& matrix) { 143cb93a386Sopenharmony_ci SkDEBUGCODE(src.validate();) 144cb93a386Sopenharmony_ci if (matrix.isIdentity()) { 145cb93a386Sopenharmony_ci if (dst->get() != &src) { 146cb93a386Sopenharmony_ci src.ref(); 147cb93a386Sopenharmony_ci dst->reset(const_cast<SkPathRef*>(&src)); 148cb93a386Sopenharmony_ci SkDEBUGCODE((*dst)->validate();) 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci return; 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci sk_sp<const SkPathRef> srcKeepAlive; 154cb93a386Sopenharmony_ci if (!(*dst)->unique()) { 155cb93a386Sopenharmony_ci // If dst and src are the same then we are about to drop our only ref on the common path 156cb93a386Sopenharmony_ci // ref. Some other thread may have owned src when we checked unique() above but it may not 157cb93a386Sopenharmony_ci // continue to do so. Add another ref so we continue to be an owner until we're done. 158cb93a386Sopenharmony_ci if (dst->get() == &src) { 159cb93a386Sopenharmony_ci srcKeepAlive.reset(SkRef(&src)); 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci dst->reset(new SkPathRef); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci if (dst->get() != &src) { 165cb93a386Sopenharmony_ci (*dst)->fVerbs = src.fVerbs; 166cb93a386Sopenharmony_ci (*dst)->fConicWeights = src.fConicWeights; 167cb93a386Sopenharmony_ci (*dst)->callGenIDChangeListeners(); 168cb93a386Sopenharmony_ci (*dst)->fGenerationID = 0; // mark as dirty 169cb93a386Sopenharmony_ci // don't copy, just allocate the points 170cb93a386Sopenharmony_ci (*dst)->fPoints.setCount(src.fPoints.count()); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci matrix.mapPoints((*dst)->fPoints.begin(), src.fPoints.begin(), src.fPoints.count()); 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci // Need to check this here in case (&src == dst) 175cb93a386Sopenharmony_ci bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1; 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci /* 178cb93a386Sopenharmony_ci * Here we optimize the bounds computation, by noting if the bounds are 179cb93a386Sopenharmony_ci * already known, and if so, we just transform those as well and mark 180cb93a386Sopenharmony_ci * them as "known", rather than force the transformed path to have to 181cb93a386Sopenharmony_ci * recompute them. 182cb93a386Sopenharmony_ci * 183cb93a386Sopenharmony_ci * Special gotchas if the path is effectively empty (<= 1 point) or 184cb93a386Sopenharmony_ci * if it is non-finite. In those cases bounds need to stay empty, 185cb93a386Sopenharmony_ci * regardless of the matrix. 186cb93a386Sopenharmony_ci */ 187cb93a386Sopenharmony_ci if (canXformBounds) { 188cb93a386Sopenharmony_ci (*dst)->fBoundsIsDirty = false; 189cb93a386Sopenharmony_ci if (src.fIsFinite) { 190cb93a386Sopenharmony_ci matrix.mapRect(&(*dst)->fBounds, src.fBounds); 191cb93a386Sopenharmony_ci if (!((*dst)->fIsFinite = (*dst)->fBounds.isFinite())) { 192cb93a386Sopenharmony_ci (*dst)->fBounds.setEmpty(); 193cb93a386Sopenharmony_ci } 194cb93a386Sopenharmony_ci } else { 195cb93a386Sopenharmony_ci (*dst)->fIsFinite = false; 196cb93a386Sopenharmony_ci (*dst)->fBounds.setEmpty(); 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci } else { 199cb93a386Sopenharmony_ci (*dst)->fBoundsIsDirty = true; 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci (*dst)->fSegmentMask = src.fSegmentMask; 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci // It's an oval only if it stays a rect. 205cb93a386Sopenharmony_ci bool rectStaysRect = matrix.rectStaysRect(); 206cb93a386Sopenharmony_ci (*dst)->fIsOval = src.fIsOval && rectStaysRect; 207cb93a386Sopenharmony_ci (*dst)->fIsRRect = src.fIsRRect && rectStaysRect; 208cb93a386Sopenharmony_ci if ((*dst)->fIsOval || (*dst)->fIsRRect) { 209cb93a386Sopenharmony_ci unsigned start = src.fRRectOrOvalStartIdx; 210cb93a386Sopenharmony_ci bool isCCW = SkToBool(src.fRRectOrOvalIsCCW); 211cb93a386Sopenharmony_ci transform_dir_and_start(matrix, (*dst)->fIsRRect, &isCCW, &start); 212cb93a386Sopenharmony_ci (*dst)->fRRectOrOvalIsCCW = isCCW; 213cb93a386Sopenharmony_ci (*dst)->fRRectOrOvalStartIdx = start; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci if (dst->get() == &src) { 217cb93a386Sopenharmony_ci (*dst)->callGenIDChangeListeners(); 218cb93a386Sopenharmony_ci (*dst)->fGenerationID = 0; 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci SkDEBUGCODE((*dst)->validate();) 222cb93a386Sopenharmony_ci} 223cb93a386Sopenharmony_ci 224cb93a386Sopenharmony_civoid SkPathRef::Rewind(sk_sp<SkPathRef>* pathRef) { 225cb93a386Sopenharmony_ci if ((*pathRef)->unique()) { 226cb93a386Sopenharmony_ci SkDEBUGCODE((*pathRef)->validate();) 227cb93a386Sopenharmony_ci (*pathRef)->callGenIDChangeListeners(); 228cb93a386Sopenharmony_ci (*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite 229cb93a386Sopenharmony_ci (*pathRef)->fGenerationID = 0; 230cb93a386Sopenharmony_ci (*pathRef)->fPoints.rewind(); 231cb93a386Sopenharmony_ci (*pathRef)->fVerbs.rewind(); 232cb93a386Sopenharmony_ci (*pathRef)->fConicWeights.rewind(); 233cb93a386Sopenharmony_ci (*pathRef)->fSegmentMask = 0; 234cb93a386Sopenharmony_ci (*pathRef)->fIsOval = false; 235cb93a386Sopenharmony_ci (*pathRef)->fIsRRect = false; 236cb93a386Sopenharmony_ci SkDEBUGCODE((*pathRef)->validate();) 237cb93a386Sopenharmony_ci } else { 238cb93a386Sopenharmony_ci int oldVCnt = (*pathRef)->countVerbs(); 239cb93a386Sopenharmony_ci int oldPCnt = (*pathRef)->countPoints(); 240cb93a386Sopenharmony_ci pathRef->reset(new SkPathRef); 241cb93a386Sopenharmony_ci (*pathRef)->resetToSize(0, 0, 0, oldVCnt, oldPCnt); 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci} 244cb93a386Sopenharmony_ci 245cb93a386Sopenharmony_cibool SkPathRef::operator== (const SkPathRef& ref) const { 246cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 247cb93a386Sopenharmony_ci SkDEBUGCODE(ref.validate();) 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci // We explicitly check fSegmentMask as a quick-reject. We could skip it, 250cb93a386Sopenharmony_ci // since it is only a cache of info in the fVerbs, but its a fast way to 251cb93a386Sopenharmony_ci // notice a difference 252cb93a386Sopenharmony_ci if (fSegmentMask != ref.fSegmentMask) { 253cb93a386Sopenharmony_ci return false; 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID; 257cb93a386Sopenharmony_ci#ifdef SK_RELEASE 258cb93a386Sopenharmony_ci if (genIDMatch) { 259cb93a386Sopenharmony_ci return true; 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci#endif 262cb93a386Sopenharmony_ci if (fPoints != ref.fPoints || fConicWeights != ref.fConicWeights || fVerbs != ref.fVerbs) { 263cb93a386Sopenharmony_ci SkASSERT(!genIDMatch); 264cb93a386Sopenharmony_ci return false; 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci if (ref.fVerbs.count() == 0) { 267cb93a386Sopenharmony_ci SkASSERT(ref.fPoints.count() == 0); 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci return true; 270cb93a386Sopenharmony_ci} 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_civoid SkPathRef::writeToBuffer(SkWBuffer* buffer) const { 273cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 274cb93a386Sopenharmony_ci SkDEBUGCODE(size_t beforePos = buffer->pos();) 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci // Call getBounds() to ensure (as a side-effect) that fBounds 277cb93a386Sopenharmony_ci // and fIsFinite are computed. 278cb93a386Sopenharmony_ci const SkRect& bounds = this->getBounds(); 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci // We store fSegmentMask for older readers, but current readers can't trust it, so they 281cb93a386Sopenharmony_ci // don't read it. 282cb93a386Sopenharmony_ci int32_t packed = ((fIsFinite & 1) << kIsFinite_SerializationShift) | 283cb93a386Sopenharmony_ci (fSegmentMask << kSegmentMask_SerializationShift); 284cb93a386Sopenharmony_ci buffer->write32(packed); 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci // TODO: write gen ID here. Problem: We don't know if we're cross process or not from 287cb93a386Sopenharmony_ci // SkWBuffer. Until this is fixed we write 0. 288cb93a386Sopenharmony_ci buffer->write32(0); 289cb93a386Sopenharmony_ci buffer->write32(fVerbs.count()); 290cb93a386Sopenharmony_ci buffer->write32(fPoints.count()); 291cb93a386Sopenharmony_ci buffer->write32(fConicWeights.count()); 292cb93a386Sopenharmony_ci buffer->write(fVerbs.begin(), fVerbs.bytes()); 293cb93a386Sopenharmony_ci buffer->write(fPoints.begin(), fVerbs.bytes()); 294cb93a386Sopenharmony_ci buffer->write(fConicWeights.begin(), fConicWeights.bytes()); 295cb93a386Sopenharmony_ci buffer->write(&bounds, sizeof(bounds)); 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize()); 298cb93a386Sopenharmony_ci} 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ciuint32_t SkPathRef::writeSize() const { 301cb93a386Sopenharmony_ci return uint32_t(5 * sizeof(uint32_t) + 302cb93a386Sopenharmony_ci fVerbs.bytes() + fPoints.bytes() + fConicWeights.bytes() + 303cb93a386Sopenharmony_ci sizeof(SkRect)); 304cb93a386Sopenharmony_ci} 305cb93a386Sopenharmony_ci 306cb93a386Sopenharmony_civoid SkPathRef::copy(const SkPathRef& ref, 307cb93a386Sopenharmony_ci int additionalReserveVerbs, 308cb93a386Sopenharmony_ci int additionalReservePoints) { 309cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 310cb93a386Sopenharmony_ci this->resetToSize(ref.fVerbs.count(), ref.fPoints.count(), ref.fConicWeights.count(), 311cb93a386Sopenharmony_ci additionalReserveVerbs, additionalReservePoints); 312cb93a386Sopenharmony_ci fVerbs = ref.fVerbs; 313cb93a386Sopenharmony_ci fPoints = ref.fPoints; 314cb93a386Sopenharmony_ci fConicWeights = ref.fConicWeights; 315cb93a386Sopenharmony_ci fBoundsIsDirty = ref.fBoundsIsDirty; 316cb93a386Sopenharmony_ci if (!fBoundsIsDirty) { 317cb93a386Sopenharmony_ci fBounds = ref.fBounds; 318cb93a386Sopenharmony_ci fIsFinite = ref.fIsFinite; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci fSegmentMask = ref.fSegmentMask; 321cb93a386Sopenharmony_ci fIsOval = ref.fIsOval; 322cb93a386Sopenharmony_ci fIsRRect = ref.fIsRRect; 323cb93a386Sopenharmony_ci fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW; 324cb93a386Sopenharmony_ci fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx; 325cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 326cb93a386Sopenharmony_ci} 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_civoid SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const { 329cb93a386Sopenharmony_ci const SkScalar* inValues = &ending.getPoints()->fX; 330cb93a386Sopenharmony_ci SkScalar* outValues = &out->getWritablePoints()->fX; 331cb93a386Sopenharmony_ci int count = out->countPoints() * 2; 332cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 333cb93a386Sopenharmony_ci outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight); 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci out->fBoundsIsDirty = true; 336cb93a386Sopenharmony_ci out->fIsOval = false; 337cb93a386Sopenharmony_ci out->fIsRRect = false; 338cb93a386Sopenharmony_ci} 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_cistd::tuple<SkPoint*, SkScalar*> SkPathRef::growForVerbsInPath(const SkPathRef& path) { 341cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 342cb93a386Sopenharmony_ci 343cb93a386Sopenharmony_ci fSegmentMask |= path.fSegmentMask; 344cb93a386Sopenharmony_ci fBoundsIsDirty = true; // this also invalidates fIsFinite 345cb93a386Sopenharmony_ci fIsOval = false; 346cb93a386Sopenharmony_ci fIsRRect = false; 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci if (int numVerbs = path.countVerbs()) { 349cb93a386Sopenharmony_ci memcpy(fVerbs.append(numVerbs), path.fVerbs.begin(), numVerbs * sizeof(fVerbs[0])); 350cb93a386Sopenharmony_ci } 351cb93a386Sopenharmony_ci 352cb93a386Sopenharmony_ci SkPoint* pts = nullptr; 353cb93a386Sopenharmony_ci if (int numPts = path.countPoints()) { 354cb93a386Sopenharmony_ci pts = fPoints.append(numPts); 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci 357cb93a386Sopenharmony_ci SkScalar* weights = nullptr; 358cb93a386Sopenharmony_ci if (int numConics = path.countWeights()) { 359cb93a386Sopenharmony_ci weights = fConicWeights.append(numConics); 360cb93a386Sopenharmony_ci } 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 363cb93a386Sopenharmony_ci return {pts, weights}; 364cb93a386Sopenharmony_ci} 365cb93a386Sopenharmony_ci 366cb93a386Sopenharmony_ciSkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb, 367cb93a386Sopenharmony_ci int numVbs, 368cb93a386Sopenharmony_ci SkScalar** weights) { 369cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 370cb93a386Sopenharmony_ci int pCnt; 371cb93a386Sopenharmony_ci switch (verb) { 372cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 373cb93a386Sopenharmony_ci pCnt = numVbs; 374cb93a386Sopenharmony_ci break; 375cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 376cb93a386Sopenharmony_ci fSegmentMask |= SkPath::kLine_SegmentMask; 377cb93a386Sopenharmony_ci pCnt = numVbs; 378cb93a386Sopenharmony_ci break; 379cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 380cb93a386Sopenharmony_ci fSegmentMask |= SkPath::kQuad_SegmentMask; 381cb93a386Sopenharmony_ci pCnt = 2 * numVbs; 382cb93a386Sopenharmony_ci break; 383cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 384cb93a386Sopenharmony_ci fSegmentMask |= SkPath::kConic_SegmentMask; 385cb93a386Sopenharmony_ci pCnt = 2 * numVbs; 386cb93a386Sopenharmony_ci break; 387cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 388cb93a386Sopenharmony_ci fSegmentMask |= SkPath::kCubic_SegmentMask; 389cb93a386Sopenharmony_ci pCnt = 3 * numVbs; 390cb93a386Sopenharmony_ci break; 391cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 392cb93a386Sopenharmony_ci SkDEBUGFAIL("growForRepeatedVerb called for kClose_Verb"); 393cb93a386Sopenharmony_ci pCnt = 0; 394cb93a386Sopenharmony_ci break; 395cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 396cb93a386Sopenharmony_ci SkDEBUGFAIL("growForRepeatedVerb called for kDone"); 397cb93a386Sopenharmony_ci pCnt = 0; 398cb93a386Sopenharmony_ci break; 399cb93a386Sopenharmony_ci default: 400cb93a386Sopenharmony_ci SkDEBUGFAIL("default should not be reached"); 401cb93a386Sopenharmony_ci pCnt = 0; 402cb93a386Sopenharmony_ci break; 403cb93a386Sopenharmony_ci } 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci fBoundsIsDirty = true; // this also invalidates fIsFinite 406cb93a386Sopenharmony_ci fIsOval = false; 407cb93a386Sopenharmony_ci fIsRRect = false; 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_ci memset(fVerbs.append(numVbs), verb, numVbs); 410cb93a386Sopenharmony_ci if (SkPath::kConic_Verb == verb) { 411cb93a386Sopenharmony_ci SkASSERT(weights); 412cb93a386Sopenharmony_ci *weights = fConicWeights.append(numVbs); 413cb93a386Sopenharmony_ci } 414cb93a386Sopenharmony_ci SkPoint* pts = fPoints.append(pCnt); 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 417cb93a386Sopenharmony_ci return pts; 418cb93a386Sopenharmony_ci} 419cb93a386Sopenharmony_ci 420cb93a386Sopenharmony_ciSkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) { 421cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 422cb93a386Sopenharmony_ci int pCnt; 423cb93a386Sopenharmony_ci unsigned mask = 0; 424cb93a386Sopenharmony_ci switch (verb) { 425cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 426cb93a386Sopenharmony_ci pCnt = 1; 427cb93a386Sopenharmony_ci break; 428cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 429cb93a386Sopenharmony_ci mask = SkPath::kLine_SegmentMask; 430cb93a386Sopenharmony_ci pCnt = 1; 431cb93a386Sopenharmony_ci break; 432cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 433cb93a386Sopenharmony_ci mask = SkPath::kQuad_SegmentMask; 434cb93a386Sopenharmony_ci pCnt = 2; 435cb93a386Sopenharmony_ci break; 436cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 437cb93a386Sopenharmony_ci mask = SkPath::kConic_SegmentMask; 438cb93a386Sopenharmony_ci pCnt = 2; 439cb93a386Sopenharmony_ci break; 440cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 441cb93a386Sopenharmony_ci mask = SkPath::kCubic_SegmentMask; 442cb93a386Sopenharmony_ci pCnt = 3; 443cb93a386Sopenharmony_ci break; 444cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 445cb93a386Sopenharmony_ci pCnt = 0; 446cb93a386Sopenharmony_ci break; 447cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 448cb93a386Sopenharmony_ci SkDEBUGFAIL("growForVerb called for kDone"); 449cb93a386Sopenharmony_ci pCnt = 0; 450cb93a386Sopenharmony_ci break; 451cb93a386Sopenharmony_ci default: 452cb93a386Sopenharmony_ci SkDEBUGFAIL("default is not reached"); 453cb93a386Sopenharmony_ci pCnt = 0; 454cb93a386Sopenharmony_ci break; 455cb93a386Sopenharmony_ci } 456cb93a386Sopenharmony_ci 457cb93a386Sopenharmony_ci fSegmentMask |= mask; 458cb93a386Sopenharmony_ci fBoundsIsDirty = true; // this also invalidates fIsFinite 459cb93a386Sopenharmony_ci fIsOval = false; 460cb93a386Sopenharmony_ci fIsRRect = false; 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci *fVerbs.append() = verb; 463cb93a386Sopenharmony_ci if (SkPath::kConic_Verb == verb) { 464cb93a386Sopenharmony_ci *fConicWeights.append() = weight; 465cb93a386Sopenharmony_ci } 466cb93a386Sopenharmony_ci SkPoint* pts = fPoints.append(pCnt); 467cb93a386Sopenharmony_ci 468cb93a386Sopenharmony_ci SkDEBUGCODE(this->validate();) 469cb93a386Sopenharmony_ci return pts; 470cb93a386Sopenharmony_ci} 471cb93a386Sopenharmony_ci 472cb93a386Sopenharmony_ciuint32_t SkPathRef::genID() const { 473cb93a386Sopenharmony_ci SkASSERT(fEditorsAttached.load() == 0); 474cb93a386Sopenharmony_ci static const uint32_t kMask = (static_cast<int64_t>(1) << SkPathPriv::kPathRefGenIDBitCnt) - 1; 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ci if (fGenerationID == 0) { 477cb93a386Sopenharmony_ci if (fPoints.count() == 0 && fVerbs.count() == 0) { 478cb93a386Sopenharmony_ci fGenerationID = kEmptyGenID; 479cb93a386Sopenharmony_ci } else { 480cb93a386Sopenharmony_ci static std::atomic<uint32_t> nextID{kEmptyGenID + 1}; 481cb93a386Sopenharmony_ci do { 482cb93a386Sopenharmony_ci fGenerationID = nextID.fetch_add(1, std::memory_order_relaxed) & kMask; 483cb93a386Sopenharmony_ci } while (fGenerationID == 0 || fGenerationID == kEmptyGenID); 484cb93a386Sopenharmony_ci } 485cb93a386Sopenharmony_ci } 486cb93a386Sopenharmony_ci return fGenerationID; 487cb93a386Sopenharmony_ci} 488cb93a386Sopenharmony_ci 489cb93a386Sopenharmony_civoid SkPathRef::addGenIDChangeListener(sk_sp<SkIDChangeListener> listener) { 490cb93a386Sopenharmony_ci if (this == gEmpty) { 491cb93a386Sopenharmony_ci return; 492cb93a386Sopenharmony_ci } 493cb93a386Sopenharmony_ci fGenIDChangeListeners.add(std::move(listener)); 494cb93a386Sopenharmony_ci} 495cb93a386Sopenharmony_ci 496cb93a386Sopenharmony_ciint SkPathRef::genIDChangeListenerCount() { return fGenIDChangeListeners.count(); } 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_ci// we need to be called *before* the genID gets changed or zerod 499cb93a386Sopenharmony_civoid SkPathRef::callGenIDChangeListeners() { 500cb93a386Sopenharmony_ci fGenIDChangeListeners.changed(); 501cb93a386Sopenharmony_ci} 502cb93a386Sopenharmony_ci 503cb93a386Sopenharmony_ciSkRRect SkPathRef::getRRect() const { 504cb93a386Sopenharmony_ci const SkRect& bounds = this->getBounds(); 505cb93a386Sopenharmony_ci SkVector radii[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; 506cb93a386Sopenharmony_ci Iter iter(*this); 507cb93a386Sopenharmony_ci SkPoint pts[4]; 508cb93a386Sopenharmony_ci uint8_t verb = iter.next(pts); 509cb93a386Sopenharmony_ci SkASSERT(SkPath::kMove_Verb == verb); 510cb93a386Sopenharmony_ci while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 511cb93a386Sopenharmony_ci if (SkPath::kConic_Verb == verb) { 512cb93a386Sopenharmony_ci SkVector v1_0 = pts[1] - pts[0]; 513cb93a386Sopenharmony_ci SkVector v2_1 = pts[2] - pts[1]; 514cb93a386Sopenharmony_ci SkVector dxdy; 515cb93a386Sopenharmony_ci if (v1_0.fX) { 516cb93a386Sopenharmony_ci SkASSERT(!v2_1.fX && !v1_0.fY); 517cb93a386Sopenharmony_ci dxdy.set(SkScalarAbs(v1_0.fX), SkScalarAbs(v2_1.fY)); 518cb93a386Sopenharmony_ci } else if (!v1_0.fY) { 519cb93a386Sopenharmony_ci SkASSERT(!v2_1.fX || !v2_1.fY); 520cb93a386Sopenharmony_ci dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v2_1.fY)); 521cb93a386Sopenharmony_ci } else { 522cb93a386Sopenharmony_ci SkASSERT(!v2_1.fY); 523cb93a386Sopenharmony_ci dxdy.set(SkScalarAbs(v2_1.fX), SkScalarAbs(v1_0.fY)); 524cb93a386Sopenharmony_ci } 525cb93a386Sopenharmony_ci SkRRect::Corner corner = 526cb93a386Sopenharmony_ci pts[1].fX == bounds.fLeft ? 527cb93a386Sopenharmony_ci pts[1].fY == bounds.fTop ? 528cb93a386Sopenharmony_ci SkRRect::kUpperLeft_Corner : SkRRect::kLowerLeft_Corner : 529cb93a386Sopenharmony_ci pts[1].fY == bounds.fTop ? 530cb93a386Sopenharmony_ci SkRRect::kUpperRight_Corner : SkRRect::kLowerRight_Corner; 531cb93a386Sopenharmony_ci SkASSERT(!radii[corner].fX && !radii[corner].fY); 532cb93a386Sopenharmony_ci radii[corner] = dxdy; 533cb93a386Sopenharmony_ci } else { 534cb93a386Sopenharmony_ci SkASSERT((verb == SkPath::kLine_Verb 535cb93a386Sopenharmony_ci && (!(pts[1].fX - pts[0].fX) || !(pts[1].fY - pts[0].fY))) 536cb93a386Sopenharmony_ci || verb == SkPath::kClose_Verb); 537cb93a386Sopenharmony_ci } 538cb93a386Sopenharmony_ci } 539cb93a386Sopenharmony_ci SkRRect rrect; 540cb93a386Sopenharmony_ci rrect.setRectRadii(bounds, radii); 541cb93a386Sopenharmony_ci return rrect; 542cb93a386Sopenharmony_ci} 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ciSkPathRef::Iter::Iter() { 547cb93a386Sopenharmony_ci#ifdef SK_DEBUG 548cb93a386Sopenharmony_ci fPts = nullptr; 549cb93a386Sopenharmony_ci fConicWeights = nullptr; 550cb93a386Sopenharmony_ci#endif 551cb93a386Sopenharmony_ci // need to init enough to make next() harmlessly return kDone_Verb 552cb93a386Sopenharmony_ci fVerbs = nullptr; 553cb93a386Sopenharmony_ci fVerbStop = nullptr; 554cb93a386Sopenharmony_ci} 555cb93a386Sopenharmony_ci 556cb93a386Sopenharmony_ciSkPathRef::Iter::Iter(const SkPathRef& path) { 557cb93a386Sopenharmony_ci this->setPathRef(path); 558cb93a386Sopenharmony_ci} 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_civoid SkPathRef::Iter::setPathRef(const SkPathRef& path) { 561cb93a386Sopenharmony_ci fPts = path.points(); 562cb93a386Sopenharmony_ci fVerbs = path.verbsBegin(); 563cb93a386Sopenharmony_ci fVerbStop = path.verbsEnd(); 564cb93a386Sopenharmony_ci fConicWeights = path.conicWeights(); 565cb93a386Sopenharmony_ci if (fConicWeights) { 566cb93a386Sopenharmony_ci fConicWeights -= 1; // begin one behind 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci // Don't allow iteration through non-finite points. 570cb93a386Sopenharmony_ci if (!path.isFinite()) { 571cb93a386Sopenharmony_ci fVerbStop = fVerbs; 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci} 574cb93a386Sopenharmony_ci 575cb93a386Sopenharmony_ciuint8_t SkPathRef::Iter::next(SkPoint pts[4]) { 576cb93a386Sopenharmony_ci SkASSERT(pts); 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ci SkDEBUGCODE(unsigned peekResult = this->peek();) 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci if (fVerbs == fVerbStop) { 581cb93a386Sopenharmony_ci SkASSERT(peekResult == SkPath::kDone_Verb); 582cb93a386Sopenharmony_ci return (uint8_t) SkPath::kDone_Verb; 583cb93a386Sopenharmony_ci } 584cb93a386Sopenharmony_ci 585cb93a386Sopenharmony_ci // fVerbs points one beyond next verb so decrement first. 586cb93a386Sopenharmony_ci unsigned verb = *fVerbs++; 587cb93a386Sopenharmony_ci const SkPoint* srcPts = fPts; 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ci switch (verb) { 590cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 591cb93a386Sopenharmony_ci pts[0] = srcPts[0]; 592cb93a386Sopenharmony_ci srcPts += 1; 593cb93a386Sopenharmony_ci break; 594cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 595cb93a386Sopenharmony_ci pts[0] = srcPts[-1]; 596cb93a386Sopenharmony_ci pts[1] = srcPts[0]; 597cb93a386Sopenharmony_ci srcPts += 1; 598cb93a386Sopenharmony_ci break; 599cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 600cb93a386Sopenharmony_ci fConicWeights += 1; 601cb93a386Sopenharmony_ci [[fallthrough]]; 602cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 603cb93a386Sopenharmony_ci pts[0] = srcPts[-1]; 604cb93a386Sopenharmony_ci pts[1] = srcPts[0]; 605cb93a386Sopenharmony_ci pts[2] = srcPts[1]; 606cb93a386Sopenharmony_ci srcPts += 2; 607cb93a386Sopenharmony_ci break; 608cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 609cb93a386Sopenharmony_ci pts[0] = srcPts[-1]; 610cb93a386Sopenharmony_ci pts[1] = srcPts[0]; 611cb93a386Sopenharmony_ci pts[2] = srcPts[1]; 612cb93a386Sopenharmony_ci pts[3] = srcPts[2]; 613cb93a386Sopenharmony_ci srcPts += 3; 614cb93a386Sopenharmony_ci break; 615cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 616cb93a386Sopenharmony_ci break; 617cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 618cb93a386Sopenharmony_ci SkASSERT(fVerbs == fVerbStop); 619cb93a386Sopenharmony_ci break; 620cb93a386Sopenharmony_ci } 621cb93a386Sopenharmony_ci fPts = srcPts; 622cb93a386Sopenharmony_ci SkASSERT(peekResult == verb); 623cb93a386Sopenharmony_ci return (uint8_t) verb; 624cb93a386Sopenharmony_ci} 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ciuint8_t SkPathRef::Iter::peek() const { 627cb93a386Sopenharmony_ci return fVerbs < fVerbStop ? *fVerbs : (uint8_t) SkPath::kDone_Verb; 628cb93a386Sopenharmony_ci} 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_ci 631cb93a386Sopenharmony_cibool SkPathRef::isValid() const { 632cb93a386Sopenharmony_ci if (fIsOval || fIsRRect) { 633cb93a386Sopenharmony_ci // Currently we don't allow both of these to be set, even though ovals are ro 634cb93a386Sopenharmony_ci if (fIsOval == fIsRRect) { 635cb93a386Sopenharmony_ci return false; 636cb93a386Sopenharmony_ci } 637cb93a386Sopenharmony_ci if (fIsOval) { 638cb93a386Sopenharmony_ci if (fRRectOrOvalStartIdx >= 4) { 639cb93a386Sopenharmony_ci return false; 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci } else { 642cb93a386Sopenharmony_ci if (fRRectOrOvalStartIdx >= 8) { 643cb93a386Sopenharmony_ci return false; 644cb93a386Sopenharmony_ci } 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci } 647cb93a386Sopenharmony_ci 648cb93a386Sopenharmony_ci if (!fBoundsIsDirty && !fBounds.isEmpty()) { 649cb93a386Sopenharmony_ci bool isFinite = true; 650cb93a386Sopenharmony_ci Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop); 651cb93a386Sopenharmony_ci Sk2s rightBot = Sk2s(fBounds.fRight, fBounds.fBottom); 652cb93a386Sopenharmony_ci for (int i = 0; i < fPoints.count(); ++i) { 653cb93a386Sopenharmony_ci Sk2s point = Sk2s(fPoints[i].fX, fPoints[i].fY); 654cb93a386Sopenharmony_ci#ifdef SK_DEBUG 655cb93a386Sopenharmony_ci if (fPoints[i].isFinite() && 656cb93a386Sopenharmony_ci ((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) { 657cb93a386Sopenharmony_ci SkDebugf("bad SkPathRef bounds: %g %g %g %g\n", 658cb93a386Sopenharmony_ci fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 659cb93a386Sopenharmony_ci for (int j = 0; j < fPoints.count(); ++j) { 660cb93a386Sopenharmony_ci if (i == j) { 661cb93a386Sopenharmony_ci SkDebugf("*** bounds do not contain: "); 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci SkDebugf("%g %g\n", fPoints[j].fX, fPoints[j].fY); 664cb93a386Sopenharmony_ci } 665cb93a386Sopenharmony_ci return false; 666cb93a386Sopenharmony_ci } 667cb93a386Sopenharmony_ci#endif 668cb93a386Sopenharmony_ci 669cb93a386Sopenharmony_ci if (fPoints[i].isFinite() && (point < leftTop).anyTrue() && !(point > rightBot).anyTrue()) 670cb93a386Sopenharmony_ci return false; 671cb93a386Sopenharmony_ci if (!fPoints[i].isFinite()) { 672cb93a386Sopenharmony_ci isFinite = false; 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci } 675cb93a386Sopenharmony_ci if (SkToBool(fIsFinite) != isFinite) { 676cb93a386Sopenharmony_ci return false; 677cb93a386Sopenharmony_ci } 678cb93a386Sopenharmony_ci } 679cb93a386Sopenharmony_ci return true; 680cb93a386Sopenharmony_ci} 681cb93a386Sopenharmony_ci 682cb93a386Sopenharmony_cibool SkPathRef::dataMatchesVerbs() const { 683cb93a386Sopenharmony_ci const auto info = sk_path_analyze_verbs(fVerbs.begin(), fVerbs.count()); 684cb93a386Sopenharmony_ci return info.valid && 685cb93a386Sopenharmony_ci info.segmentMask == fSegmentMask && 686cb93a386Sopenharmony_ci info.points == fPoints.count() && 687cb93a386Sopenharmony_ci info.weights == fConicWeights.count(); 688cb93a386Sopenharmony_ci} 689cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////////////////////// 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ciSkPathEdgeIter::SkPathEdgeIter(const SkPath& path) { 692cb93a386Sopenharmony_ci fMoveToPtr = fPts = path.fPathRef->points(); 693cb93a386Sopenharmony_ci fVerbs = path.fPathRef->verbsBegin(); 694cb93a386Sopenharmony_ci fVerbsStop = path.fPathRef->verbsEnd(); 695cb93a386Sopenharmony_ci fConicWeights = path.fPathRef->conicWeights(); 696cb93a386Sopenharmony_ci if (fConicWeights) { 697cb93a386Sopenharmony_ci fConicWeights -= 1; // begin one behind 698cb93a386Sopenharmony_ci } 699cb93a386Sopenharmony_ci 700cb93a386Sopenharmony_ci fNeedsCloseLine = false; 701cb93a386Sopenharmony_ci fNextIsNewContour = false; 702cb93a386Sopenharmony_ci SkDEBUGCODE(fIsConic = false;) 703cb93a386Sopenharmony_ci} 704