reverse/restore order of verbs in path to be forward (normal)
As part of this (clean up), also removed support for serialized-paths older than version-4, which was introduced Feb 2018. Change-Id: I2dc74a52bb8bdd7ea0cb2d8a78b644ca783eb31f Reviewed-on: https://skia-review.googlesource.com/c/skia/+/239102 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
parent
59ed3b9880
commit
8fda88ed6d
@ -1685,8 +1685,7 @@ private:
|
||||
|
||||
size_t writeToMemoryAsRRect(void* buffer) const;
|
||||
size_t readAsRRect(const void*, size_t);
|
||||
size_t readFromMemory_LE3(const void*, size_t);
|
||||
size_t readFromMemory_EQ4(const void*, size_t);
|
||||
size_t readFromMemory_EQ4Or5(const void*, size_t);
|
||||
|
||||
friend class Iter;
|
||||
friend class SkPathPriv;
|
||||
|
@ -51,20 +51,14 @@ public:
|
||||
/**
|
||||
* Returns the array of points.
|
||||
*/
|
||||
SkPoint* points() { return fPathRef->getPoints(); }
|
||||
SkPoint* writablePoints() { return fPathRef->getWritablePoints(); }
|
||||
const SkPoint* points() const { return fPathRef->points(); }
|
||||
|
||||
/**
|
||||
* Gets the ith point. Shortcut for this->points() + i
|
||||
*/
|
||||
SkPoint* atPoint(int i) {
|
||||
SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
|
||||
return this->points() + i;
|
||||
}
|
||||
const SkPoint* atPoint(int i) const {
|
||||
SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
|
||||
return this->points() + i;
|
||||
}
|
||||
SkPoint* atPoint(int i) { return fPathRef->getWritablePoints() + i; }
|
||||
const SkPoint* atPoint(int i) const { return &fPathRef->fPoints[i]; }
|
||||
|
||||
/**
|
||||
* Adds the verb and allocates space for the number of points indicated by the verb. The
|
||||
@ -238,7 +232,7 @@ public:
|
||||
const SkPathRef& src,
|
||||
const SkMatrix& matrix);
|
||||
|
||||
static SkPathRef* CreateFromBuffer(SkRBuffer* buffer);
|
||||
// static SkPathRef* CreateFromBuffer(SkRBuffer* buffer);
|
||||
|
||||
/**
|
||||
* Rollsback a path ref to zero verbs and points with the assumption that the path ref will be
|
||||
@ -248,24 +242,24 @@ public:
|
||||
static void Rewind(sk_sp<SkPathRef>* pathRef);
|
||||
|
||||
~SkPathRef();
|
||||
int countPoints() const { return fPointCnt; }
|
||||
int countVerbs() const { return fVerbCnt; }
|
||||
int countPoints() const { return fPoints.count(); }
|
||||
int countVerbs() const { return fVerbs.count(); }
|
||||
int countWeights() const { return fConicWeights.count(); }
|
||||
|
||||
/**
|
||||
* Returns a pointer one beyond the first logical verb (last verb in memory order).
|
||||
*/
|
||||
const uint8_t* verbs() const { return fVerbs; }
|
||||
const uint8_t* verbsBegin() const { return fVerbs.begin(); }
|
||||
|
||||
/**
|
||||
* Returns a const pointer to the first verb in memory (which is the last logical verb).
|
||||
*/
|
||||
const uint8_t* verbsMemBegin() const { return this->verbs() - fVerbCnt; }
|
||||
const uint8_t* verbsEnd() const { return fVerbs.end(); }
|
||||
|
||||
/**
|
||||
* Returns a const pointer to the first point.
|
||||
*/
|
||||
const SkPoint* points() const { return fPoints; }
|
||||
const SkPoint* points() const { return fPoints.begin(); }
|
||||
|
||||
/**
|
||||
* Shortcut for this->points() + this->countPoints()
|
||||
@ -278,14 +272,8 @@ public:
|
||||
/**
|
||||
* Convenience methods for getting to a verb or point by index.
|
||||
*/
|
||||
uint8_t atVerb(int index) const {
|
||||
SkASSERT((unsigned) index < (unsigned) fVerbCnt);
|
||||
return this->verbs()[~index];
|
||||
}
|
||||
const SkPoint& atPoint(int index) const {
|
||||
SkASSERT((unsigned) index < (unsigned) fPointCnt);
|
||||
return this->points()[index];
|
||||
}
|
||||
uint8_t atVerb(int index) const { return fVerbs[index]; }
|
||||
const SkPoint& atPoint(int index) const { return fPoints[index]; }
|
||||
|
||||
bool operator== (const SkPathRef& ref) const;
|
||||
|
||||
@ -345,11 +333,6 @@ private:
|
||||
|
||||
SkPathRef() {
|
||||
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||
fPointCnt = 0;
|
||||
fVerbCnt = 0;
|
||||
fVerbs = nullptr;
|
||||
fPoints = nullptr;
|
||||
fFreeSpace = 0;
|
||||
fGenerationID = kEmptyGenID;
|
||||
fSegmentMask = 0;
|
||||
fIsOval = false;
|
||||
@ -392,8 +375,8 @@ private:
|
||||
/** Makes additional room but does not change the counts or change the genID */
|
||||
void incReserve(int additionalVerbs, int additionalPoints) {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint);
|
||||
this->makeSpace(space);
|
||||
fPoints.setReserve(fPoints.count() + additionalPoints);
|
||||
fVerbs.setReserve(fVerbs.count() + additionalVerbs);
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
@ -410,28 +393,10 @@ private:
|
||||
fIsOval = false;
|
||||
fIsRRect = false;
|
||||
|
||||
size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount;
|
||||
size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints;
|
||||
size_t minSize = newSize + newReserve;
|
||||
|
||||
ptrdiff_t sizeDelta = this->currSize() - minSize;
|
||||
|
||||
if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) {
|
||||
sk_free(fPoints);
|
||||
fPoints = nullptr;
|
||||
fVerbs = nullptr;
|
||||
fFreeSpace = 0;
|
||||
fVerbCnt = 0;
|
||||
fPointCnt = 0;
|
||||
this->makeSpace(minSize, true);
|
||||
fVerbCnt = verbCount;
|
||||
fPointCnt = pointCount;
|
||||
fFreeSpace -= newSize;
|
||||
} else {
|
||||
fPointCnt = pointCount;
|
||||
fVerbCnt = verbCount;
|
||||
fFreeSpace = this->currSize() - minSize;
|
||||
}
|
||||
fPoints.setReserve(pointCount + reservePoints);
|
||||
fPoints.setCount(pointCount);
|
||||
fVerbs.setReserve(verbCount + reserveVerbs);
|
||||
fVerbs.setCount(verbCount);
|
||||
fConicWeights.setCount(conicCount);
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
@ -451,63 +416,10 @@ private:
|
||||
*/
|
||||
SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight);
|
||||
|
||||
/**
|
||||
* Ensures that the free space available in the path ref is >= size. The verb and point counts
|
||||
* are not changed. May allocate extra capacity, unless |exact| is true.
|
||||
*/
|
||||
void makeSpace(size_t size, bool exact = false) {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
if (size <= fFreeSpace) {
|
||||
return;
|
||||
}
|
||||
size_t growSize = size - fFreeSpace;
|
||||
size_t oldSize = this->currSize();
|
||||
|
||||
if (!exact) {
|
||||
// round to next multiple of 8 bytes
|
||||
growSize = (growSize + 7) & ~static_cast<size_t>(7);
|
||||
// we always at least double the allocation
|
||||
if (growSize < oldSize) {
|
||||
growSize = oldSize;
|
||||
}
|
||||
if (growSize < kMinSize) {
|
||||
growSize = kMinSize;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t maxSize = std::numeric_limits<size_t>::max();
|
||||
size_t newSize;
|
||||
if (growSize <= maxSize - oldSize) {
|
||||
newSize = oldSize + growSize;
|
||||
} else {
|
||||
SK_ABORT("Path too big.");
|
||||
}
|
||||
// Note that realloc could memcpy more than we need. It seems to be a win anyway. TODO:
|
||||
// encapsulate this.
|
||||
fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize));
|
||||
size_t oldVerbSize = fVerbCnt * sizeof(uint8_t);
|
||||
void* newVerbsDst = SkTAddOffset<void>(fPoints, newSize - oldVerbSize);
|
||||
void* oldVerbsSrc = SkTAddOffset<void>(fPoints, oldSize - oldVerbSize);
|
||||
memmove(newVerbsDst, oldVerbsSrc, oldVerbSize);
|
||||
fVerbs = SkTAddOffset<uint8_t>(fPoints, newSize);
|
||||
fFreeSpace += growSize;
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
/**
|
||||
* Private, non-const-ptr version of the public function verbsMemBegin().
|
||||
*/
|
||||
uint8_t* verbsMemWritable() {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
return fVerbs - fVerbCnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total amount of space allocated for verbs, points, and reserve.
|
||||
*/
|
||||
size_t currSize() const {
|
||||
return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints);
|
||||
}
|
||||
uint8_t* verbsBeginWritable() { return fVerbs.begin(); }
|
||||
|
||||
/**
|
||||
* Called the first time someone calls CreateEmpty to actually create the singleton.
|
||||
@ -527,16 +439,16 @@ private:
|
||||
}
|
||||
|
||||
// called only by the editor. Note that this is not a const function.
|
||||
SkPoint* getPoints() {
|
||||
SkPoint* getWritablePoints() {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
fIsOval = false;
|
||||
fIsRRect = false;
|
||||
return fPoints;
|
||||
return fPoints.begin();
|
||||
}
|
||||
|
||||
const SkPoint* getPoints() const {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
return fPoints;
|
||||
return fPoints.begin();
|
||||
}
|
||||
|
||||
void callGenIDChangeListeners();
|
||||
@ -547,11 +459,8 @@ private:
|
||||
|
||||
mutable SkRect fBounds;
|
||||
|
||||
SkPoint* fPoints; // points to begining of the allocation
|
||||
uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards)
|
||||
int fVerbCnt;
|
||||
int fPointCnt;
|
||||
size_t fFreeSpace; // redundant but saves computation
|
||||
SkTDArray<SkPoint> fPoints;
|
||||
SkTDArray<uint8_t> fVerbs;
|
||||
SkTDArray<SkScalar> fConicWeights;
|
||||
|
||||
enum {
|
||||
|
@ -325,8 +325,8 @@ public:
|
||||
|
||||
private:
|
||||
T* fArray;
|
||||
int fReserve;
|
||||
int fCount;
|
||||
int fReserve; // size of the allocation in fArray (#elements)
|
||||
int fCount; // logical number of elements (fCount <= fReserve)
|
||||
|
||||
/**
|
||||
* Adjusts the number of elements in the array.
|
||||
|
@ -235,20 +235,10 @@ void SkPath::swap(SkPath& that) {
|
||||
}
|
||||
|
||||
bool SkPath::isInterpolatable(const SkPath& compare) const {
|
||||
int count = fPathRef->countVerbs();
|
||||
if (count != compare.fPathRef->countVerbs()) {
|
||||
return false;
|
||||
}
|
||||
if (!count) {
|
||||
return true;
|
||||
}
|
||||
if (memcmp(fPathRef->verbsMemBegin(), compare.fPathRef->verbsMemBegin(),
|
||||
count)) {
|
||||
return false;
|
||||
}
|
||||
return !fPathRef->countWeights() ||
|
||||
!SkToBool(memcmp(fPathRef->conicWeights(), compare.fPathRef->conicWeights(),
|
||||
fPathRef->countWeights() * sizeof(*fPathRef->conicWeights())));
|
||||
// need the same structure (verbs, conicweights) and same point-count
|
||||
return fPathRef->fPoints.count() == compare.fPathRef->fPoints.count() &&
|
||||
fPathRef->fVerbs == compare.fPathRef->fVerbs &&
|
||||
fPathRef->fConicWeights == compare.fPathRef->fConicWeights;
|
||||
}
|
||||
|
||||
bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
|
||||
@ -690,21 +680,15 @@ int SkPath::countVerbs() const {
|
||||
return fPathRef->countVerbs();
|
||||
}
|
||||
|
||||
static inline void copy_verbs_reverse(uint8_t* inorderDst,
|
||||
const uint8_t* reversedSrc,
|
||||
int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
inorderDst[i] = reversedSrc[~i];
|
||||
}
|
||||
}
|
||||
|
||||
int SkPath::getVerbs(uint8_t dst[], int max) const {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
||||
SkASSERT(max >= 0);
|
||||
SkASSERT(!max || dst);
|
||||
int count = SkMin32(max, fPathRef->countVerbs());
|
||||
copy_verbs_reverse(dst, fPathRef->verbs(), count);
|
||||
if (count) {
|
||||
memcpy(dst, fPathRef->verbsBegin(), count);
|
||||
}
|
||||
return fPathRef->countVerbs();
|
||||
}
|
||||
|
||||
@ -1256,7 +1240,7 @@ SkPath& SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startInde
|
||||
|
||||
bool SkPath::hasOnlyMoveTos() const {
|
||||
int count = fPathRef->countVerbs();
|
||||
const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin();
|
||||
const uint8_t* verbs = fPathRef->verbsBegin();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (*verbs == kLine_Verb ||
|
||||
*verbs == kQuad_Verb ||
|
||||
@ -1702,17 +1686,18 @@ static int pts_in_verb(unsigned verb) {
|
||||
|
||||
// ignore the last point of the 1st contour
|
||||
SkPath& SkPath::reversePathTo(const SkPath& path) {
|
||||
const uint8_t* verbs = path.fPathRef->verbsMemBegin(); // points at the last verb
|
||||
if (!verbs) { // empty path returns nullptr
|
||||
if (path.fPathRef->fVerbs.count() == 0) {
|
||||
return *this;
|
||||
}
|
||||
const uint8_t* verbsEnd = path.fPathRef->verbs() - 1; // points just past the first verb
|
||||
SkASSERT(verbsEnd[0] == kMove_Verb);
|
||||
|
||||
const uint8_t* verbs = path.fPathRef->verbsEnd();
|
||||
const uint8_t* verbsBegin = path.fPathRef->verbsBegin();
|
||||
SkASSERT(verbsBegin[0] == kMove_Verb);
|
||||
const SkPoint* pts = path.fPathRef->pointsEnd() - 1;
|
||||
const SkScalar* conicWeights = path.fPathRef->conicWeightsEnd();
|
||||
|
||||
while (verbs < verbsEnd) {
|
||||
uint8_t v = *verbs++;
|
||||
while (verbs > verbsBegin) {
|
||||
uint8_t v = *--verbs;
|
||||
pts -= pts_in_verb(v);
|
||||
switch (v) {
|
||||
case kMove_Verb:
|
||||
@ -1731,7 +1716,6 @@ SkPath& SkPath::reversePathTo(const SkPath& path) {
|
||||
this->cubicTo(pts[2], pts[1], pts[0]);
|
||||
break;
|
||||
case kClose_Verb:
|
||||
SkASSERT(verbs - path.fPathRef->verbsMemBegin() == 1);
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("bad verb");
|
||||
@ -1751,16 +1735,15 @@ SkPath& SkPath::reverseAddPath(const SkPath& srcPath) {
|
||||
|
||||
SkPathRef::Editor ed(&fPathRef, src->countVerbs(), src->countPoints());
|
||||
|
||||
const uint8_t* verbsBegin = src->fPathRef->verbsBegin();
|
||||
const uint8_t* verbs = src->fPathRef->verbsEnd();
|
||||
const SkPoint* pts = src->fPathRef->pointsEnd();
|
||||
// we will iterate through src's verbs backwards
|
||||
const uint8_t* verbs = src->fPathRef->verbsMemBegin(); // points at the last verb
|
||||
const uint8_t* verbsEnd = src->fPathRef->verbs(); // points just past the first verb
|
||||
const SkScalar* conicWeights = src->fPathRef->conicWeightsEnd();
|
||||
|
||||
bool needMove = true;
|
||||
bool needClose = false;
|
||||
while (verbs < verbsEnd) {
|
||||
uint8_t v = *(verbs++);
|
||||
while (verbs > verbsBegin) {
|
||||
uint8_t v = *--verbs;
|
||||
int n = pts_in_verb(v);
|
||||
|
||||
if (needMove) {
|
||||
@ -1874,7 +1857,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
|
||||
|
||||
dst->swap(tmp);
|
||||
SkPathRef::Editor ed(&dst->fPathRef);
|
||||
matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
|
||||
matrix.mapPoints(ed.writablePoints(), ed.pathRef()->countPoints());
|
||||
dst->setFirstDirection(SkPathPriv::kUnknown_FirstDirection);
|
||||
} else {
|
||||
Convexity convexity = this->getConvexityOrUnknown();
|
||||
@ -1946,8 +1929,8 @@ SkPath::Iter::Iter(const SkPath& path, bool forceClose) {
|
||||
|
||||
void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
|
||||
fPts = path.fPathRef->points();
|
||||
fVerbs = path.fPathRef->verbs();
|
||||
fVerbStop = path.fPathRef->verbsMemBegin();
|
||||
fVerbs = path.fPathRef->verbsBegin();
|
||||
fVerbStop = path.fPathRef->verbsEnd();
|
||||
fConicWeights = path.fPathRef->conicWeights();
|
||||
if (fConicWeights) {
|
||||
fConicWeights -= 1; // begin one behind
|
||||
@ -1970,13 +1953,13 @@ bool SkPath::Iter::isClosedContour() const {
|
||||
const uint8_t* verbs = fVerbs;
|
||||
const uint8_t* stop = fVerbStop;
|
||||
|
||||
if (kMove_Verb == *(verbs - 1)) {
|
||||
verbs -= 1; // skip the initial moveto
|
||||
if (kMove_Verb == *verbs) {
|
||||
verbs += 1; // skip the initial moveto
|
||||
}
|
||||
|
||||
while (verbs > stop) {
|
||||
while (verbs < stop) {
|
||||
// verbs points one beyond the current verb, decrement first.
|
||||
unsigned v = *(--verbs);
|
||||
unsigned v = *verbs++;
|
||||
if (kMove_Verb == v) {
|
||||
break;
|
||||
}
|
||||
@ -2036,15 +2019,14 @@ SkPath::Verb SkPath::Iter::next(SkPoint ptsParam[4]) {
|
||||
return kDone_Verb;
|
||||
}
|
||||
|
||||
// fVerbs is one beyond the current verb, decrement first
|
||||
unsigned verb = *(--fVerbs);
|
||||
unsigned verb = *fVerbs++;
|
||||
const SkPoint* SK_RESTRICT srcPts = fPts;
|
||||
SkPoint* SK_RESTRICT pts = ptsParam;
|
||||
|
||||
switch (verb) {
|
||||
case kMove_Verb:
|
||||
if (fNeedClose) {
|
||||
fVerbs++; // move back one verb
|
||||
fVerbs--; // move back one verb
|
||||
verb = this->autoClose(pts);
|
||||
if (verb == kClose_Verb) {
|
||||
fNeedClose = false;
|
||||
@ -2086,7 +2068,7 @@ SkPath::Verb SkPath::Iter::next(SkPoint ptsParam[4]) {
|
||||
case kClose_Verb:
|
||||
verb = this->autoClose(pts);
|
||||
if (verb == kLine_Verb) {
|
||||
fVerbs++; // move back one verb
|
||||
fVerbs--; // move back one verb
|
||||
} else {
|
||||
fNeedClose = false;
|
||||
fSegmentState = kEmptyContour_SegmentState;
|
||||
@ -2828,10 +2810,10 @@ private:
|
||||
};
|
||||
|
||||
ContourIter::ContourIter(const SkPathRef& pathRef) {
|
||||
fStopVerbs = pathRef.verbsMemBegin();
|
||||
fStopVerbs = pathRef.verbsEnd();
|
||||
fDone = false;
|
||||
fCurrPt = pathRef.points();
|
||||
fCurrVerb = pathRef.verbs();
|
||||
fCurrVerb = pathRef.verbsBegin();
|
||||
fCurrConicWeight = pathRef.conicWeights();
|
||||
fCurrPtCount = 0;
|
||||
SkDEBUGCODE(fContourCounter = 0;)
|
||||
@ -2839,7 +2821,7 @@ ContourIter::ContourIter(const SkPathRef& pathRef) {
|
||||
}
|
||||
|
||||
void ContourIter::next() {
|
||||
if (fCurrVerb <= fStopVerbs) {
|
||||
if (fCurrVerb >= fStopVerbs) {
|
||||
fDone = true;
|
||||
}
|
||||
if (fDone) {
|
||||
@ -2849,12 +2831,12 @@ void ContourIter::next() {
|
||||
// skip pts of prev contour
|
||||
fCurrPt += fCurrPtCount;
|
||||
|
||||
SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
|
||||
SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
|
||||
int ptCount = 1; // moveTo
|
||||
const uint8_t* verbs = fCurrVerb;
|
||||
|
||||
for (--verbs; verbs > fStopVerbs; --verbs) {
|
||||
switch (verbs[~0]) {
|
||||
for (verbs++; verbs < fStopVerbs; verbs++) {
|
||||
switch (*verbs) {
|
||||
case SkPath::kMove_Verb:
|
||||
goto CONTOUR_END;
|
||||
case SkPath::kLine_Verb:
|
||||
|
@ -66,9 +66,9 @@ public:
|
||||
if (verbCount == 0)
|
||||
return false;
|
||||
int moveCount = 0;
|
||||
auto verbs = path.fPathRef->verbs();
|
||||
auto verbs = path.fPathRef->verbsBegin();
|
||||
for (int i = 0; i < verbCount; i++) {
|
||||
switch (verbs[~i]) { // verbs are stored backwards; we use [~i] to get the i'th verb
|
||||
switch (verbs[i]) {
|
||||
case SkPath::Verb::kMove_Verb:
|
||||
moveCount += 1;
|
||||
if (moveCount > 1) {
|
||||
@ -123,13 +123,13 @@ public:
|
||||
public:
|
||||
Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {}
|
||||
struct Iter {
|
||||
void operator++() { --fVerb; } // verbs are laid out backwards in memory.
|
||||
void operator++() { fVerb++; }
|
||||
bool operator!=(const Iter& b) { return fVerb != b.fVerb; }
|
||||
SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); }
|
||||
const uint8_t* fVerb;
|
||||
};
|
||||
Iter begin() { return Iter{fPathRef->verbs() - 1}; }
|
||||
Iter end() { return Iter{fPathRef->verbs() - fPathRef->countVerbs() - 1}; }
|
||||
Iter begin() { return Iter{fPathRef->verbsBegin()}; }
|
||||
Iter end() { return Iter{fPathRef->verbsEnd()}; }
|
||||
private:
|
||||
Verbs(const Verbs&) = delete;
|
||||
Verbs& operator=(const Verbs&) = delete;
|
||||
@ -137,11 +137,10 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a pointer to the verb data. Note that the verbs are stored backwards in memory and
|
||||
* thus the returned pointer is the last verb.
|
||||
* Returns a pointer to the verb data.
|
||||
*/
|
||||
static const uint8_t* VerbData(const SkPath& path) {
|
||||
return path.fPathRef->verbsMemBegin();
|
||||
return path.fPathRef->verbsBegin();
|
||||
}
|
||||
|
||||
/** Returns a raw pointer to the path points */
|
||||
@ -289,8 +288,8 @@ public:
|
||||
// Roughly the same as SkPath::Iter(path, true), but does not return moves or closes
|
||||
//
|
||||
class SkPathEdgeIter {
|
||||
const uint8_t* fVerbsStart;
|
||||
const uint8_t* fVerbs; // reverse
|
||||
const uint8_t* fVerbs;
|
||||
const uint8_t* fVerbsStop;
|
||||
const SkPoint* fPts;
|
||||
const SkPoint* fMoveToPtr;
|
||||
const SkScalar* fConicWeights;
|
||||
@ -338,8 +337,8 @@ public:
|
||||
};
|
||||
|
||||
for (;;) {
|
||||
SkASSERT(fVerbs >= fVerbsStart);
|
||||
if (fVerbs == fVerbsStart) {
|
||||
SkASSERT(fVerbs <= fVerbsStop);
|
||||
if (fVerbs == fVerbsStop) {
|
||||
return fNeedsCloseLine
|
||||
? closeline()
|
||||
: Result{ nullptr, Edge(kIllegalEdgeValue) };
|
||||
@ -347,7 +346,7 @@ public:
|
||||
|
||||
SkDEBUGCODE(fIsConic = false;)
|
||||
|
||||
const auto v = *--fVerbs;
|
||||
const auto v = *fVerbs++;
|
||||
switch (v) {
|
||||
case SkPath::kMove_Verb: {
|
||||
if (fNeedsCloseLine) {
|
||||
|
@ -15,16 +15,6 @@
|
||||
#include "src/core/SkPathPriv.h"
|
||||
#include "src/core/SkSafeMath.h"
|
||||
|
||||
// Conic weights must be 0 < weight <= finite
|
||||
static bool validate_conic_weights(const SkScalar weights[], int count) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (weights[i] <= 0 || !SkScalarIsFinite(weights[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
SkPathRef::Editor::Editor(sk_sp<SkPathRef>* pathRef,
|
||||
int incReserveVerbs,
|
||||
@ -51,39 +41,9 @@ SkPathRef::Editor::Editor(sk_sp<SkPathRef>* pathRef,
|
||||
// allocations to just fit the current needs. makeSpace() will only grow, but never shrinks.
|
||||
//
|
||||
void SkPath::shrinkToFit() {
|
||||
const size_t kMinFreeSpaceForShrink = 8; // just made up a small number
|
||||
|
||||
if (fPathRef->fFreeSpace <= kMinFreeSpaceForShrink) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fPathRef->unique()) {
|
||||
int pointCount = fPathRef->fPointCnt;
|
||||
int verbCount = fPathRef->fVerbCnt;
|
||||
|
||||
size_t ptsSize = sizeof(SkPoint) * pointCount;
|
||||
size_t vrbSize = sizeof(uint8_t) * verbCount;
|
||||
size_t minSize = ptsSize + vrbSize;
|
||||
|
||||
void* newAlloc = sk_malloc_canfail(minSize);
|
||||
if (!newAlloc) {
|
||||
return; // couldn't allocate the smaller buffer, but that's ok
|
||||
}
|
||||
|
||||
sk_careful_memcpy(newAlloc, fPathRef->fPoints, ptsSize);
|
||||
sk_careful_memcpy((char*)newAlloc + minSize - vrbSize, fPathRef->verbsMemBegin(), vrbSize);
|
||||
|
||||
sk_free(fPathRef->fPoints);
|
||||
fPathRef->fPoints = static_cast<SkPoint*>(newAlloc);
|
||||
fPathRef->fVerbs = (uint8_t*)newAlloc + minSize;
|
||||
fPathRef->fFreeSpace = 0;
|
||||
fPathRef->fConicWeights.shrinkToFit();
|
||||
} else {
|
||||
sk_sp<SkPathRef> pr(new SkPathRef);
|
||||
pr->copy(*fPathRef, 0, 0);
|
||||
fPathRef = std::move(pr);
|
||||
}
|
||||
|
||||
fPathRef->fPoints.shrinkToFit();
|
||||
fPathRef->fVerbs.shrinkToFit();
|
||||
fPathRef->fConicWeights.shrinkToFit();
|
||||
SkDEBUGCODE(fPathRef->validate();)
|
||||
}
|
||||
|
||||
@ -94,13 +54,6 @@ SkPathRef::~SkPathRef() {
|
||||
// to read one that's not valid and then free its memory without asserting.
|
||||
this->callGenIDChangeListeners();
|
||||
SkASSERT(fGenIDChangeListeners.empty()); // These are raw ptrs.
|
||||
sk_free(fPoints);
|
||||
|
||||
SkDEBUGCODE(fPoints = nullptr;)
|
||||
SkDEBUGCODE(fVerbs = nullptr;)
|
||||
SkDEBUGCODE(fVerbCnt = 0x9999999;)
|
||||
SkDEBUGCODE(fPointCnt = 0xAAAAAAA;)
|
||||
SkDEBUGCODE(fPointCnt = 0xBBBBBBB;)
|
||||
SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;)
|
||||
SkDEBUGCODE(fEditorsAttached.store(0x7777777);)
|
||||
}
|
||||
@ -189,20 +142,17 @@ void SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst,
|
||||
}
|
||||
|
||||
if (dst->get() != &src) {
|
||||
(*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
|
||||
sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(),
|
||||
src.fVerbCnt * sizeof(uint8_t));
|
||||
(*dst)->fPoints = src.fPoints;
|
||||
(*dst)->fVerbs = src.fVerbs;
|
||||
(*dst)->fConicWeights = src.fConicWeights;
|
||||
(*dst)->callGenIDChangeListeners();
|
||||
(*dst)->fGenerationID = 0; // mark as dirty
|
||||
}
|
||||
|
||||
SkASSERT((*dst)->countPoints() == src.countPoints());
|
||||
SkASSERT((*dst)->countVerbs() == src.countVerbs());
|
||||
SkASSERT((*dst)->fConicWeights.count() == src.fConicWeights.count());
|
||||
|
||||
// Need to check this here in case (&src == dst)
|
||||
bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1;
|
||||
|
||||
matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
|
||||
matrix.mapPoints((*dst)->fPoints.begin(), src.fPoints.begin(), src.fPoints.count());
|
||||
|
||||
/*
|
||||
* Here we optimize the bounds computation, by noting if the bounds are
|
||||
@ -251,163 +201,14 @@ void SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst,
|
||||
SkDEBUGCODE((*dst)->validate();)
|
||||
}
|
||||
|
||||
static bool validate_verb_sequence(const uint8_t verbs[], int vCount) {
|
||||
// verbs are stored backwards, but we need to visit them in logical order to determine if
|
||||
// they form a valid sequence.
|
||||
|
||||
bool needsMoveTo = true;
|
||||
bool invalidSequence = false;
|
||||
|
||||
for (int i = vCount - 1; i >= 0; --i) {
|
||||
switch (verbs[i]) {
|
||||
case SkPath::kMove_Verb:
|
||||
needsMoveTo = false;
|
||||
break;
|
||||
case SkPath::kLine_Verb:
|
||||
case SkPath::kQuad_Verb:
|
||||
case SkPath::kConic_Verb:
|
||||
case SkPath::kCubic_Verb:
|
||||
invalidSequence |= needsMoveTo;
|
||||
break;
|
||||
case SkPath::kClose_Verb:
|
||||
needsMoveTo = true;
|
||||
break;
|
||||
default:
|
||||
return false; // unknown verb
|
||||
}
|
||||
}
|
||||
return !invalidSequence;
|
||||
}
|
||||
|
||||
// Given the verb array, deduce the required number of pts and conics,
|
||||
// or if an invalid verb is encountered, return false.
|
||||
static bool deduce_pts_conics(const uint8_t verbs[], int vCount, int* ptCountPtr,
|
||||
int* conicCountPtr) {
|
||||
// When there is at least one verb, the first is required to be kMove_Verb.
|
||||
if (0 < vCount && verbs[vCount-1] != SkPath::kMove_Verb) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkSafeMath safe;
|
||||
int ptCount = 0;
|
||||
int conicCount = 0;
|
||||
for (int i = 0; i < vCount; ++i) {
|
||||
switch (verbs[i]) {
|
||||
case SkPath::kMove_Verb:
|
||||
case SkPath::kLine_Verb:
|
||||
ptCount = safe.addInt(ptCount, 1);
|
||||
break;
|
||||
case SkPath::kConic_Verb:
|
||||
conicCount += 1;
|
||||
// fall-through
|
||||
case SkPath::kQuad_Verb:
|
||||
ptCount = safe.addInt(ptCount, 2);
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
ptCount = safe.addInt(ptCount, 3);
|
||||
break;
|
||||
case SkPath::kClose_Verb:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!safe) {
|
||||
return false;
|
||||
}
|
||||
*ptCountPtr = ptCount;
|
||||
*conicCountPtr = conicCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
SkPathRef* SkPathRef::CreateFromBuffer(SkRBuffer* buffer) {
|
||||
std::unique_ptr<SkPathRef> ref(new SkPathRef);
|
||||
|
||||
int32_t packed;
|
||||
if (!buffer->readS32(&packed)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ref->fIsFinite = (packed >> kIsFinite_SerializationShift) & 1;
|
||||
|
||||
int32_t verbCount, pointCount, conicCount;
|
||||
if (!buffer->readU32(&(ref->fGenerationID)) ||
|
||||
!buffer->readS32(&verbCount) || (verbCount < 0) ||
|
||||
!buffer->readS32(&pointCount) || (pointCount < 0) ||
|
||||
!buffer->readS32(&conicCount) || (conicCount < 0))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint64_t pointSize64 = sk_64_mul(pointCount, sizeof(SkPoint));
|
||||
uint64_t conicSize64 = sk_64_mul(conicCount, sizeof(SkScalar));
|
||||
if (!SkTFitsIn<size_t>(pointSize64) || !SkTFitsIn<size_t>(conicSize64)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t verbSize = verbCount * sizeof(uint8_t);
|
||||
size_t pointSize = SkToSizeT(pointSize64);
|
||||
size_t conicSize = SkToSizeT(conicSize64);
|
||||
|
||||
{
|
||||
uint64_t requiredBufferSize = sizeof(SkRect);
|
||||
requiredBufferSize += verbSize;
|
||||
requiredBufferSize += pointSize;
|
||||
requiredBufferSize += conicSize;
|
||||
if (buffer->available() < requiredBufferSize) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ref->resetToSize(verbCount, pointCount, conicCount);
|
||||
SkASSERT(verbCount == ref->countVerbs());
|
||||
SkASSERT(pointCount == ref->countPoints());
|
||||
SkASSERT(conicCount == ref->fConicWeights.count());
|
||||
|
||||
if (!buffer->read(ref->verbsMemWritable(), verbSize) ||
|
||||
!buffer->read(ref->fPoints, pointSize) ||
|
||||
!buffer->read(ref->fConicWeights.begin(), conicSize) ||
|
||||
!buffer->read(&ref->fBounds, sizeof(SkRect))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check that the verbs are valid, and imply the correct number of pts and conics
|
||||
{
|
||||
int pCount, cCount;
|
||||
if (!validate_verb_sequence(ref->verbsMemBegin(), ref->countVerbs())) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!deduce_pts_conics(ref->verbsMemBegin(), ref->countVerbs(), &pCount, &cCount) ||
|
||||
pCount != ref->countPoints() || cCount != ref->fConicWeights.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!validate_conic_weights(ref->fConicWeights.begin(), ref->fConicWeights.count())) {
|
||||
return nullptr;
|
||||
}
|
||||
// Check that the bounds match the serialized bounds.
|
||||
SkRect bounds;
|
||||
if (ComputePtBounds(&bounds, *ref) != SkToBool(ref->fIsFinite) || bounds != ref->fBounds) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// call this after validate_verb_sequence, since it relies on valid verbs
|
||||
ref->fSegmentMask = ref->computeSegmentMask();
|
||||
}
|
||||
|
||||
ref->fBoundsIsDirty = false;
|
||||
|
||||
return ref.release();
|
||||
}
|
||||
|
||||
void SkPathRef::Rewind(sk_sp<SkPathRef>* pathRef) {
|
||||
if ((*pathRef)->unique()) {
|
||||
SkDEBUGCODE((*pathRef)->validate();)
|
||||
(*pathRef)->callGenIDChangeListeners();
|
||||
(*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||
(*pathRef)->fVerbCnt = 0;
|
||||
(*pathRef)->fPointCnt = 0;
|
||||
(*pathRef)->fFreeSpace = (*pathRef)->currSize();
|
||||
(*pathRef)->fGenerationID = 0;
|
||||
(*pathRef)->fPoints.rewind();
|
||||
(*pathRef)->fVerbs.rewind();
|
||||
(*pathRef)->fConicWeights.rewind();
|
||||
(*pathRef)->fSegmentMask = 0;
|
||||
(*pathRef)->fIsOval = false;
|
||||
@ -438,32 +239,12 @@ bool SkPathRef::operator== (const SkPathRef& ref) const {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (fPointCnt != ref.fPointCnt ||
|
||||
fVerbCnt != ref.fVerbCnt) {
|
||||
if (fPoints != ref.fPoints || fConicWeights != ref.fConicWeights || fVerbs != ref.fVerbs) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
}
|
||||
if (0 == ref.fVerbCnt) {
|
||||
SkASSERT(0 == ref.fPointCnt);
|
||||
return true;
|
||||
}
|
||||
SkASSERT(this->verbsMemBegin() && ref.verbsMemBegin());
|
||||
if (0 != memcmp(this->verbsMemBegin(),
|
||||
ref.verbsMemBegin(),
|
||||
ref.fVerbCnt * sizeof(uint8_t))) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
}
|
||||
SkASSERT(this->points() && ref.points());
|
||||
if (0 != memcmp(this->points(),
|
||||
ref.points(),
|
||||
ref.fPointCnt * sizeof(SkPoint))) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
}
|
||||
if (fConicWeights != ref.fConicWeights) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
if (ref.fVerbs.count() == 0) {
|
||||
SkASSERT(ref.fPoints.count() == 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -485,11 +266,11 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
|
||||
// TODO: write gen ID here. Problem: We don't know if we're cross process or not from
|
||||
// SkWBuffer. Until this is fixed we write 0.
|
||||
buffer->write32(0);
|
||||
buffer->write32(fVerbCnt);
|
||||
buffer->write32(fPointCnt);
|
||||
buffer->write32(fVerbs.count());
|
||||
buffer->write32(fPoints.count());
|
||||
buffer->write32(fConicWeights.count());
|
||||
buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
|
||||
buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
|
||||
buffer->write(fVerbs.begin(), fVerbs.bytes());
|
||||
buffer->write(fPoints.begin(), fVerbs.bytes());
|
||||
buffer->write(fConicWeights.begin(), fConicWeights.bytes());
|
||||
buffer->write(&bounds, sizeof(bounds));
|
||||
|
||||
@ -498,9 +279,7 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
|
||||
|
||||
uint32_t SkPathRef::writeSize() const {
|
||||
return uint32_t(5 * sizeof(uint32_t) +
|
||||
fVerbCnt * sizeof(uint8_t) +
|
||||
fPointCnt * sizeof(SkPoint) +
|
||||
fConicWeights.bytes() +
|
||||
fVerbs.bytes() + fPoints.bytes() + fConicWeights.bytes() +
|
||||
sizeof(SkRect));
|
||||
}
|
||||
|
||||
@ -508,10 +287,10 @@ void SkPathRef::copy(const SkPathRef& ref,
|
||||
int additionalReserveVerbs,
|
||||
int additionalReservePoints) {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
|
||||
additionalReserveVerbs, additionalReservePoints);
|
||||
sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t));
|
||||
sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
|
||||
this->resetToSize(ref.fVerbs.count(), ref.fPoints.count(), ref.fConicWeights.count(),
|
||||
additionalReserveVerbs, additionalReservePoints);
|
||||
fVerbs = ref.fVerbs;
|
||||
fPoints = ref.fPoints;
|
||||
fConicWeights = ref.fConicWeights;
|
||||
fBoundsIsDirty = ref.fBoundsIsDirty;
|
||||
if (!fBoundsIsDirty) {
|
||||
@ -527,9 +306,9 @@ void SkPathRef::copy(const SkPathRef& ref,
|
||||
}
|
||||
|
||||
unsigned SkPathRef::computeSegmentMask() const {
|
||||
const uint8_t* verbs = this->verbsMemBegin();
|
||||
const uint8_t* verbs = fVerbs.begin();
|
||||
unsigned mask = 0;
|
||||
for (int i = this->countVerbs() - 1; i >= 0; --i) {
|
||||
for (int i = 0; i < fVerbs.count(); ++i) {
|
||||
switch (verbs[i]) {
|
||||
case SkPath::kLine_Verb: mask |= SkPath::kLine_SegmentMask; break;
|
||||
case SkPath::kQuad_Verb: mask |= SkPath::kQuad_SegmentMask; break;
|
||||
@ -543,7 +322,7 @@ unsigned SkPathRef::computeSegmentMask() const {
|
||||
|
||||
void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const {
|
||||
const SkScalar* inValues = &ending.getPoints()->fX;
|
||||
SkScalar* outValues = &out->getPoints()->fX;
|
||||
SkScalar* outValues = &out->getWritablePoints()->fX;
|
||||
int count = out->countPoints() * 2;
|
||||
for (int index = 0; index < count; ++index) {
|
||||
outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight);
|
||||
@ -556,11 +335,6 @@ void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef*
|
||||
SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
|
||||
int numVbs,
|
||||
SkScalar** weights) {
|
||||
// This value is just made-up for now. When count is 4, calling memset was much
|
||||
// slower than just writing the loop. This seems odd, and hopefully in the
|
||||
// future this will appear to have been a fluke...
|
||||
static const unsigned int kMIN_COUNT_FOR_MEMSET_TO_BE_FAST = 16;
|
||||
|
||||
SkDEBUGCODE(this->validate();)
|
||||
int pCnt;
|
||||
switch (verb) {
|
||||
@ -595,40 +369,19 @@ SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
|
||||
pCnt = 0;
|
||||
}
|
||||
|
||||
size_t space = numVbs * sizeof(uint8_t) + pCnt * sizeof (SkPoint);
|
||||
this->makeSpace(space);
|
||||
|
||||
SkPoint* ret = fPoints + fPointCnt;
|
||||
uint8_t* vb = fVerbs - fVerbCnt;
|
||||
|
||||
// cast to unsigned, so if kMIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
|
||||
// be 0, the compiler will remove the test/branch entirely.
|
||||
if ((unsigned)numVbs >= kMIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
|
||||
memset(vb - numVbs, verb, numVbs);
|
||||
} else {
|
||||
for (int i = 0; i < numVbs; ++i) {
|
||||
vb[~i] = verb;
|
||||
}
|
||||
}
|
||||
|
||||
SkSafeMath safe;
|
||||
fVerbCnt = safe.addInt(fVerbCnt, numVbs);
|
||||
fPointCnt = safe.addInt(fPointCnt, pCnt);
|
||||
if (!safe) {
|
||||
SK_ABORT("cannot grow path");
|
||||
}
|
||||
fFreeSpace -= space;
|
||||
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||
fIsOval = false;
|
||||
fIsRRect = false;
|
||||
|
||||
memset(fVerbs.append(numVbs), verb, numVbs);
|
||||
if (SkPath::kConic_Verb == verb) {
|
||||
SkASSERT(weights);
|
||||
*weights = fConicWeights.append(numVbs);
|
||||
}
|
||||
SkPoint* pts = fPoints.append(pCnt);
|
||||
|
||||
SkDEBUGCODE(this->validate();)
|
||||
return ret;
|
||||
return pts;
|
||||
}
|
||||
|
||||
SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) {
|
||||
@ -665,30 +418,20 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) {
|
||||
SkDEBUGFAIL("default is not reached");
|
||||
pCnt = 0;
|
||||
}
|
||||
SkSafeMath safe;
|
||||
int newPointCnt = safe.addInt(fPointCnt, pCnt);
|
||||
int newVerbCnt = safe.addInt(fVerbCnt, 1);
|
||||
if (!safe) {
|
||||
SK_ABORT("cannot grow path");
|
||||
}
|
||||
size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
|
||||
this->makeSpace(space);
|
||||
this->fVerbs[~fVerbCnt] = verb;
|
||||
SkPoint* ret = fPoints + fPointCnt;
|
||||
fVerbCnt = newVerbCnt;
|
||||
fPointCnt = newPointCnt;
|
||||
|
||||
fSegmentMask |= mask;
|
||||
fFreeSpace -= space;
|
||||
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||
fIsOval = false;
|
||||
fIsRRect = false;
|
||||
|
||||
*fVerbs.append() = verb;
|
||||
if (SkPath::kConic_Verb == verb) {
|
||||
*fConicWeights.append() = weight;
|
||||
}
|
||||
SkPoint* pts = fPoints.append(pCnt);
|
||||
|
||||
SkDEBUGCODE(this->validate();)
|
||||
return ret;
|
||||
return pts;
|
||||
}
|
||||
|
||||
uint32_t SkPathRef::genID() const {
|
||||
@ -696,7 +439,7 @@ uint32_t SkPathRef::genID() const {
|
||||
static const uint32_t kMask = (static_cast<int64_t>(1) << SkPathPriv::kPathRefGenIDBitCnt) - 1;
|
||||
|
||||
if (fGenerationID == 0) {
|
||||
if (fPointCnt == 0 && fVerbCnt == 0) {
|
||||
if (fPoints.count() == 0 && fVerbs.count() == 0) {
|
||||
fGenerationID = kEmptyGenID;
|
||||
} else {
|
||||
static std::atomic<uint32_t> nextID{kEmptyGenID + 1};
|
||||
@ -800,11 +543,11 @@ SkPathRef::Iter::Iter(const SkPathRef& path) {
|
||||
|
||||
void SkPathRef::Iter::setPathRef(const SkPathRef& path) {
|
||||
fPts = path.points();
|
||||
fVerbs = path.verbs();
|
||||
fVerbStop = path.verbsMemBegin();
|
||||
fVerbs = path.verbsBegin();
|
||||
fVerbStop = path.verbsEnd();
|
||||
fConicWeights = path.conicWeights();
|
||||
if (fConicWeights) {
|
||||
fConicWeights -= 1; // begin one behind
|
||||
fConicWeights -= 1; // begin one behind
|
||||
}
|
||||
|
||||
// Don't allow iteration through non-finite points.
|
||||
@ -824,7 +567,7 @@ uint8_t SkPathRef::Iter::next(SkPoint pts[4]) {
|
||||
}
|
||||
|
||||
// fVerbs points one beyond next verb so decrement first.
|
||||
unsigned verb = *(--fVerbs);
|
||||
unsigned verb = *fVerbs++;
|
||||
const SkPoint* srcPts = fPts;
|
||||
|
||||
switch (verb) {
|
||||
@ -865,35 +608,11 @@ uint8_t SkPathRef::Iter::next(SkPoint pts[4]) {
|
||||
}
|
||||
|
||||
uint8_t SkPathRef::Iter::peek() const {
|
||||
const uint8_t* next = fVerbs;
|
||||
return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : next[-1];
|
||||
return fVerbs < fVerbStop ? *fVerbs : (uint8_t) SkPath::kDone_Verb;
|
||||
}
|
||||
|
||||
|
||||
bool SkPathRef::isValid() const {
|
||||
if (static_cast<ptrdiff_t>(fFreeSpace) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) < 0) {
|
||||
return false;
|
||||
}
|
||||
if ((nullptr == fPoints) != (nullptr == fVerbs)) {
|
||||
return false;
|
||||
}
|
||||
if (nullptr == fPoints && 0 != fFreeSpace) {
|
||||
return false;
|
||||
}
|
||||
if (nullptr == fPoints && fPointCnt) {
|
||||
return false;
|
||||
}
|
||||
if (nullptr == fVerbs && fVerbCnt) {
|
||||
return false;
|
||||
}
|
||||
if (this->currSize() !=
|
||||
fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fIsOval || fIsRRect) {
|
||||
// Currently we don't allow both of these to be set, even though ovals are ro
|
||||
if (fIsOval == fIsRRect) {
|
||||
@ -914,14 +633,14 @@ bool SkPathRef::isValid() const {
|
||||
bool isFinite = true;
|
||||
Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop);
|
||||
Sk2s rightBot = Sk2s(fBounds.fRight, fBounds.fBottom);
|
||||
for (int i = 0; i < fPointCnt; ++i) {
|
||||
for (int i = 0; i < fPoints.count(); ++i) {
|
||||
Sk2s point = Sk2s(fPoints[i].fX, fPoints[i].fY);
|
||||
#ifdef SK_DEBUG
|
||||
if (fPoints[i].isFinite() &&
|
||||
((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) {
|
||||
SkDebugf("bad SkPathRef bounds: %g %g %g %g\n",
|
||||
fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
|
||||
for (int j = 0; j < fPointCnt; ++j) {
|
||||
for (int j = 0; j < fPoints.count(); ++j) {
|
||||
if (i == j) {
|
||||
SkDebugf("*** bounds do not contain: ");
|
||||
}
|
||||
@ -948,8 +667,8 @@ bool SkPathRef::isValid() const {
|
||||
|
||||
SkPathEdgeIter::SkPathEdgeIter(const SkPath& path) {
|
||||
fMoveToPtr = fPts = path.fPathRef->points();
|
||||
fVerbs = path.fPathRef->verbs();
|
||||
fVerbsStart = path.fPathRef->verbsMemBegin();
|
||||
fVerbs = path.fPathRef->verbsBegin();
|
||||
fVerbsStop = path.fPathRef->verbsEnd();
|
||||
fConicWeights = path.fPathRef->conicWeights();
|
||||
if (fConicWeights) {
|
||||
fConicWeights -= 1; // begin one behind
|
||||
|
@ -26,11 +26,13 @@ enum SerializationOffsets {
|
||||
|
||||
enum SerializationVersions {
|
||||
// kPathPrivFirstDirection_Version = 1,
|
||||
kPathPrivLastMoveToIndex_Version = 2,
|
||||
kPathPrivTypeEnumVersion = 3,
|
||||
kJustPublicData_Version = 4, // introduced Feb/2018
|
||||
// kPathPrivLastMoveToIndex_Version = 2,
|
||||
// kPathPrivTypeEnumVersion = 3,
|
||||
kJustPublicData_Version = 4, // introduced Feb/2018
|
||||
kVerbsAreStoredForward_Version = 5, // introduced Sept/2019
|
||||
|
||||
kCurrent_Version = kJustPublicData_Version
|
||||
kMin_Version = kJustPublicData_Version,
|
||||
kCurrent_Version = kVerbsAreStoredForward_Version
|
||||
};
|
||||
|
||||
enum SerializationType {
|
||||
@ -121,7 +123,7 @@ size_t SkPath::writeToMemory(void* storage) const {
|
||||
buffer.write32(vbs);
|
||||
buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
|
||||
buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
|
||||
buffer.write(fPathRef->verbsMemBegin(), vbs * sizeof(uint8_t));
|
||||
buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t));
|
||||
buffer.padToAlign4();
|
||||
|
||||
SkASSERT(buffer.pos() == size);
|
||||
@ -145,11 +147,12 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) {
|
||||
return 0;
|
||||
}
|
||||
unsigned version = extract_version(packed);
|
||||
if (version <= kPathPrivTypeEnumVersion) {
|
||||
return this->readFromMemory_LE3(storage, length);
|
||||
if (version < kMin_Version || version > kCurrent_Version) {
|
||||
return 0;
|
||||
}
|
||||
if (version == kJustPublicData_Version) {
|
||||
return this->readFromMemory_EQ4(storage, length);
|
||||
|
||||
if (version == kJustPublicData_Version || version == kVerbsAreStoredForward_Version) {
|
||||
return this->readFromMemory_EQ4Or5(storage, length);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -192,14 +195,17 @@ size_t SkPath::readAsRRect(const void* storage, size_t length) {
|
||||
return buffer.pos();
|
||||
}
|
||||
|
||||
size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
||||
size_t SkPath::readFromMemory_EQ4Or5(const void* storage, size_t length) {
|
||||
SkRBuffer buffer(storage, length);
|
||||
uint32_t packed;
|
||||
if (!buffer.readU32(&packed)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkASSERT(extract_version(packed) == 4);
|
||||
bool verbsAreReversed = true;
|
||||
if (extract_version(packed) == kVerbsAreStoredForward_Version) {
|
||||
verbsAreReversed = false;
|
||||
}
|
||||
|
||||
switch (extract_serializationtype(packed)) {
|
||||
case SerializationType::kRRect:
|
||||
@ -234,11 +240,17 @@ size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int verbsStep = 1;
|
||||
if (verbsAreReversed) {
|
||||
verbs += vbs - 1;
|
||||
verbsStep = -1;
|
||||
}
|
||||
|
||||
SkPath tmp;
|
||||
tmp.setFillType(extract_filltype(packed));
|
||||
tmp.incReserve(pts);
|
||||
for (int i = vbs - 1; i >= 0; --i) {
|
||||
switch (verbs[i]) {
|
||||
for (int i = 0; i < vbs; ++i) {
|
||||
switch (*verbs) {
|
||||
case kMove_Verb:
|
||||
CHECK_POINTS_CONICS(1, 0);
|
||||
tmp.moveTo(*points++);
|
||||
@ -268,6 +280,7 @@ size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
||||
default:
|
||||
return 0; // bad verb
|
||||
}
|
||||
verbs += verbsStep;
|
||||
}
|
||||
#undef CHECK_POINTS_CONICS
|
||||
if (pts || cnx) {
|
||||
@ -277,51 +290,3 @@ size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
||||
*this = std::move(tmp);
|
||||
return buffer.pos();
|
||||
}
|
||||
|
||||
size_t SkPath::readFromMemory_LE3(const void* storage, size_t length) {
|
||||
SkRBuffer buffer(storage, length);
|
||||
|
||||
int32_t packed;
|
||||
if (!buffer.readS32(&packed)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned version = extract_version(packed);
|
||||
SkASSERT(version <= 3);
|
||||
|
||||
FillType fillType = extract_filltype(packed);
|
||||
if (version >= kPathPrivTypeEnumVersion) {
|
||||
switch (extract_serializationtype(packed)) {
|
||||
case SerializationType::kRRect:
|
||||
return this->readAsRRect(storage, length);
|
||||
case SerializationType::kGeneral:
|
||||
// Fall through to general path deserialization
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These are written into the serialized data but we no longer use them in the deserialized
|
||||
// path. If convexity is corrupted it may cause the GPU backend to make incorrect
|
||||
// rendering choices, possibly crashing. We set them to unknown so that they'll be recomputed if
|
||||
// requested.
|
||||
fConvexity = kUnknown_Convexity;
|
||||
fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
|
||||
|
||||
fFillType = fillType;
|
||||
fIsVolatile = 0;
|
||||
SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer);
|
||||
if (!pathRef) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fPathRef.reset(pathRef);
|
||||
SkDEBUGCODE(this->validate();)
|
||||
buffer.skipToAlign4();
|
||||
return buffer.pos();
|
||||
}
|
||||
|
||||
|
@ -2797,12 +2797,14 @@ static void test_transform(skiatest::Reporter* reporter) {
|
||||
p2.addRect({ 10, 20, 30, 40 });
|
||||
uint32_t id1 = p1.getGenerationID();
|
||||
uint32_t id2 = p2.getGenerationID();
|
||||
REPORTER_ASSERT(reporter, id1 != id2);
|
||||
SkMatrix matrix;
|
||||
matrix.setScale(2, 2);
|
||||
p1.transform(matrix, &p2);
|
||||
REPORTER_ASSERT(reporter, id1 == p1.getGenerationID());
|
||||
REPORTER_ASSERT(reporter, id2 != p2.getGenerationID());
|
||||
p1.transform(matrix);
|
||||
REPORTER_ASSERT(reporter, id1 != p1.getGenerationID());
|
||||
REPORTER_ASSERT(reporter, id2 != p2.getGenerationID());
|
||||
}
|
||||
}
|
||||
|
||||
@ -4174,7 +4176,8 @@ static void test_contains(skiatest::Reporter* reporter) {
|
||||
class PathRefTest_Private {
|
||||
public:
|
||||
static size_t GetFreeSpace(const SkPathRef& ref) {
|
||||
return ref.fFreeSpace;
|
||||
return (ref.fPoints.reserved() - ref.fPoints.count()) * sizeof(SkPoint)
|
||||
+ (ref.fVerbs.reserved() - ref.fVerbs.count()) * sizeof(uint8_t);
|
||||
}
|
||||
|
||||
static void TestPathRef(skiatest::Reporter* reporter) {
|
||||
|
Loading…
Reference in New Issue
Block a user