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 writeToMemoryAsRRect(void* buffer) const;
|
||||||
size_t readAsRRect(const void*, size_t);
|
size_t readAsRRect(const void*, size_t);
|
||||||
size_t readFromMemory_LE3(const void*, size_t);
|
size_t readFromMemory_EQ4Or5(const void*, size_t);
|
||||||
size_t readFromMemory_EQ4(const void*, size_t);
|
|
||||||
|
|
||||||
friend class Iter;
|
friend class Iter;
|
||||||
friend class SkPathPriv;
|
friend class SkPathPriv;
|
||||||
|
@ -51,20 +51,14 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Returns the array of points.
|
* Returns the array of points.
|
||||||
*/
|
*/
|
||||||
SkPoint* points() { return fPathRef->getPoints(); }
|
SkPoint* writablePoints() { return fPathRef->getWritablePoints(); }
|
||||||
const SkPoint* points() const { return fPathRef->points(); }
|
const SkPoint* points() const { return fPathRef->points(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ith point. Shortcut for this->points() + i
|
* Gets the ith point. Shortcut for this->points() + i
|
||||||
*/
|
*/
|
||||||
SkPoint* atPoint(int i) {
|
SkPoint* atPoint(int i) { return fPathRef->getWritablePoints() + i; }
|
||||||
SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
|
const SkPoint* atPoint(int i) const { return &fPathRef->fPoints[i]; }
|
||||||
return this->points() + i;
|
|
||||||
}
|
|
||||||
const SkPoint* atPoint(int i) const {
|
|
||||||
SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
|
|
||||||
return this->points() + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the verb and allocates space for the number of points indicated by the verb. The
|
* 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 SkPathRef& src,
|
||||||
const SkMatrix& matrix);
|
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
|
* 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);
|
static void Rewind(sk_sp<SkPathRef>* pathRef);
|
||||||
|
|
||||||
~SkPathRef();
|
~SkPathRef();
|
||||||
int countPoints() const { return fPointCnt; }
|
int countPoints() const { return fPoints.count(); }
|
||||||
int countVerbs() const { return fVerbCnt; }
|
int countVerbs() const { return fVerbs.count(); }
|
||||||
int countWeights() const { return fConicWeights.count(); }
|
int countWeights() const { return fConicWeights.count(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a pointer one beyond the first logical verb (last verb in memory order).
|
* 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).
|
* 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.
|
* 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()
|
* Shortcut for this->points() + this->countPoints()
|
||||||
@ -278,14 +272,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Convenience methods for getting to a verb or point by index.
|
* Convenience methods for getting to a verb or point by index.
|
||||||
*/
|
*/
|
||||||
uint8_t atVerb(int index) const {
|
uint8_t atVerb(int index) const { return fVerbs[index]; }
|
||||||
SkASSERT((unsigned) index < (unsigned) fVerbCnt);
|
const SkPoint& atPoint(int index) const { return fPoints[index]; }
|
||||||
return this->verbs()[~index];
|
|
||||||
}
|
|
||||||
const SkPoint& atPoint(int index) const {
|
|
||||||
SkASSERT((unsigned) index < (unsigned) fPointCnt);
|
|
||||||
return this->points()[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator== (const SkPathRef& ref) const;
|
bool operator== (const SkPathRef& ref) const;
|
||||||
|
|
||||||
@ -345,11 +333,6 @@ private:
|
|||||||
|
|
||||||
SkPathRef() {
|
SkPathRef() {
|
||||||
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||||
fPointCnt = 0;
|
|
||||||
fVerbCnt = 0;
|
|
||||||
fVerbs = nullptr;
|
|
||||||
fPoints = nullptr;
|
|
||||||
fFreeSpace = 0;
|
|
||||||
fGenerationID = kEmptyGenID;
|
fGenerationID = kEmptyGenID;
|
||||||
fSegmentMask = 0;
|
fSegmentMask = 0;
|
||||||
fIsOval = false;
|
fIsOval = false;
|
||||||
@ -392,8 +375,8 @@ private:
|
|||||||
/** Makes additional room but does not change the counts or change the genID */
|
/** Makes additional room but does not change the counts or change the genID */
|
||||||
void incReserve(int additionalVerbs, int additionalPoints) {
|
void incReserve(int additionalVerbs, int additionalPoints) {
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint);
|
fPoints.setReserve(fPoints.count() + additionalPoints);
|
||||||
this->makeSpace(space);
|
fVerbs.setReserve(fVerbs.count() + additionalVerbs);
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,28 +393,10 @@ private:
|
|||||||
fIsOval = false;
|
fIsOval = false;
|
||||||
fIsRRect = false;
|
fIsRRect = false;
|
||||||
|
|
||||||
size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount;
|
fPoints.setReserve(pointCount + reservePoints);
|
||||||
size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints;
|
fPoints.setCount(pointCount);
|
||||||
size_t minSize = newSize + newReserve;
|
fVerbs.setReserve(verbCount + reserveVerbs);
|
||||||
|
fVerbs.setCount(verbCount);
|
||||||
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;
|
|
||||||
}
|
|
||||||
fConicWeights.setCount(conicCount);
|
fConicWeights.setCount(conicCount);
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
}
|
}
|
||||||
@ -451,63 +416,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight);
|
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().
|
* Private, non-const-ptr version of the public function verbsMemBegin().
|
||||||
*/
|
*/
|
||||||
uint8_t* verbsMemWritable() {
|
uint8_t* verbsBeginWritable() { return fVerbs.begin(); }
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called the first time someone calls CreateEmpty to actually create the singleton.
|
* 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.
|
// called only by the editor. Note that this is not a const function.
|
||||||
SkPoint* getPoints() {
|
SkPoint* getWritablePoints() {
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
fIsOval = false;
|
fIsOval = false;
|
||||||
fIsRRect = false;
|
fIsRRect = false;
|
||||||
return fPoints;
|
return fPoints.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkPoint* getPoints() const {
|
const SkPoint* getPoints() const {
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
return fPoints;
|
return fPoints.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void callGenIDChangeListeners();
|
void callGenIDChangeListeners();
|
||||||
@ -547,11 +459,8 @@ private:
|
|||||||
|
|
||||||
mutable SkRect fBounds;
|
mutable SkRect fBounds;
|
||||||
|
|
||||||
SkPoint* fPoints; // points to begining of the allocation
|
SkTDArray<SkPoint> fPoints;
|
||||||
uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards)
|
SkTDArray<uint8_t> fVerbs;
|
||||||
int fVerbCnt;
|
|
||||||
int fPointCnt;
|
|
||||||
size_t fFreeSpace; // redundant but saves computation
|
|
||||||
SkTDArray<SkScalar> fConicWeights;
|
SkTDArray<SkScalar> fConicWeights;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -325,8 +325,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
T* fArray;
|
T* fArray;
|
||||||
int fReserve;
|
int fReserve; // size of the allocation in fArray (#elements)
|
||||||
int fCount;
|
int fCount; // logical number of elements (fCount <= fReserve)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the number of elements in the array.
|
* Adjusts the number of elements in the array.
|
||||||
|
@ -235,20 +235,10 @@ void SkPath::swap(SkPath& that) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SkPath::isInterpolatable(const SkPath& compare) const {
|
bool SkPath::isInterpolatable(const SkPath& compare) const {
|
||||||
int count = fPathRef->countVerbs();
|
// need the same structure (verbs, conicweights) and same point-count
|
||||||
if (count != compare.fPathRef->countVerbs()) {
|
return fPathRef->fPoints.count() == compare.fPathRef->fPoints.count() &&
|
||||||
return false;
|
fPathRef->fVerbs == compare.fPathRef->fVerbs &&
|
||||||
}
|
fPathRef->fConicWeights == compare.fPathRef->fConicWeights;
|
||||||
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())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
|
bool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const {
|
||||||
@ -690,21 +680,15 @@ int SkPath::countVerbs() const {
|
|||||||
return fPathRef->countVerbs();
|
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 {
|
int SkPath::getVerbs(uint8_t dst[], int max) const {
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
|
|
||||||
SkASSERT(max >= 0);
|
SkASSERT(max >= 0);
|
||||||
SkASSERT(!max || dst);
|
SkASSERT(!max || dst);
|
||||||
int count = SkMin32(max, fPathRef->countVerbs());
|
int count = SkMin32(max, fPathRef->countVerbs());
|
||||||
copy_verbs_reverse(dst, fPathRef->verbs(), count);
|
if (count) {
|
||||||
|
memcpy(dst, fPathRef->verbsBegin(), count);
|
||||||
|
}
|
||||||
return fPathRef->countVerbs();
|
return fPathRef->countVerbs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1256,7 +1240,7 @@ SkPath& SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startInde
|
|||||||
|
|
||||||
bool SkPath::hasOnlyMoveTos() const {
|
bool SkPath::hasOnlyMoveTos() const {
|
||||||
int count = fPathRef->countVerbs();
|
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) {
|
for (int i = 0; i < count; ++i) {
|
||||||
if (*verbs == kLine_Verb ||
|
if (*verbs == kLine_Verb ||
|
||||||
*verbs == kQuad_Verb ||
|
*verbs == kQuad_Verb ||
|
||||||
@ -1702,17 +1686,18 @@ static int pts_in_verb(unsigned verb) {
|
|||||||
|
|
||||||
// ignore the last point of the 1st contour
|
// ignore the last point of the 1st contour
|
||||||
SkPath& SkPath::reversePathTo(const SkPath& path) {
|
SkPath& SkPath::reversePathTo(const SkPath& path) {
|
||||||
const uint8_t* verbs = path.fPathRef->verbsMemBegin(); // points at the last verb
|
if (path.fPathRef->fVerbs.count() == 0) {
|
||||||
if (!verbs) { // empty path returns nullptr
|
|
||||||
return *this;
|
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 SkPoint* pts = path.fPathRef->pointsEnd() - 1;
|
||||||
const SkScalar* conicWeights = path.fPathRef->conicWeightsEnd();
|
const SkScalar* conicWeights = path.fPathRef->conicWeightsEnd();
|
||||||
|
|
||||||
while (verbs < verbsEnd) {
|
while (verbs > verbsBegin) {
|
||||||
uint8_t v = *verbs++;
|
uint8_t v = *--verbs;
|
||||||
pts -= pts_in_verb(v);
|
pts -= pts_in_verb(v);
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case kMove_Verb:
|
case kMove_Verb:
|
||||||
@ -1731,7 +1716,6 @@ SkPath& SkPath::reversePathTo(const SkPath& path) {
|
|||||||
this->cubicTo(pts[2], pts[1], pts[0]);
|
this->cubicTo(pts[2], pts[1], pts[0]);
|
||||||
break;
|
break;
|
||||||
case kClose_Verb:
|
case kClose_Verb:
|
||||||
SkASSERT(verbs - path.fPathRef->verbsMemBegin() == 1);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SkDEBUGFAIL("bad verb");
|
SkDEBUGFAIL("bad verb");
|
||||||
@ -1751,16 +1735,15 @@ SkPath& SkPath::reverseAddPath(const SkPath& srcPath) {
|
|||||||
|
|
||||||
SkPathRef::Editor ed(&fPathRef, src->countVerbs(), src->countPoints());
|
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();
|
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();
|
const SkScalar* conicWeights = src->fPathRef->conicWeightsEnd();
|
||||||
|
|
||||||
bool needMove = true;
|
bool needMove = true;
|
||||||
bool needClose = false;
|
bool needClose = false;
|
||||||
while (verbs < verbsEnd) {
|
while (verbs > verbsBegin) {
|
||||||
uint8_t v = *(verbs++);
|
uint8_t v = *--verbs;
|
||||||
int n = pts_in_verb(v);
|
int n = pts_in_verb(v);
|
||||||
|
|
||||||
if (needMove) {
|
if (needMove) {
|
||||||
@ -1874,7 +1857,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
|
|||||||
|
|
||||||
dst->swap(tmp);
|
dst->swap(tmp);
|
||||||
SkPathRef::Editor ed(&dst->fPathRef);
|
SkPathRef::Editor ed(&dst->fPathRef);
|
||||||
matrix.mapPoints(ed.points(), ed.pathRef()->countPoints());
|
matrix.mapPoints(ed.writablePoints(), ed.pathRef()->countPoints());
|
||||||
dst->setFirstDirection(SkPathPriv::kUnknown_FirstDirection);
|
dst->setFirstDirection(SkPathPriv::kUnknown_FirstDirection);
|
||||||
} else {
|
} else {
|
||||||
Convexity convexity = this->getConvexityOrUnknown();
|
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) {
|
void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
|
||||||
fPts = path.fPathRef->points();
|
fPts = path.fPathRef->points();
|
||||||
fVerbs = path.fPathRef->verbs();
|
fVerbs = path.fPathRef->verbsBegin();
|
||||||
fVerbStop = path.fPathRef->verbsMemBegin();
|
fVerbStop = path.fPathRef->verbsEnd();
|
||||||
fConicWeights = path.fPathRef->conicWeights();
|
fConicWeights = path.fPathRef->conicWeights();
|
||||||
if (fConicWeights) {
|
if (fConicWeights) {
|
||||||
fConicWeights -= 1; // begin one behind
|
fConicWeights -= 1; // begin one behind
|
||||||
@ -1970,13 +1953,13 @@ bool SkPath::Iter::isClosedContour() const {
|
|||||||
const uint8_t* verbs = fVerbs;
|
const uint8_t* verbs = fVerbs;
|
||||||
const uint8_t* stop = fVerbStop;
|
const uint8_t* stop = fVerbStop;
|
||||||
|
|
||||||
if (kMove_Verb == *(verbs - 1)) {
|
if (kMove_Verb == *verbs) {
|
||||||
verbs -= 1; // skip the initial moveto
|
verbs += 1; // skip the initial moveto
|
||||||
}
|
}
|
||||||
|
|
||||||
while (verbs > stop) {
|
while (verbs < stop) {
|
||||||
// verbs points one beyond the current verb, decrement first.
|
// verbs points one beyond the current verb, decrement first.
|
||||||
unsigned v = *(--verbs);
|
unsigned v = *verbs++;
|
||||||
if (kMove_Verb == v) {
|
if (kMove_Verb == v) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2036,15 +2019,14 @@ SkPath::Verb SkPath::Iter::next(SkPoint ptsParam[4]) {
|
|||||||
return kDone_Verb;
|
return kDone_Verb;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fVerbs is one beyond the current verb, decrement first
|
unsigned verb = *fVerbs++;
|
||||||
unsigned verb = *(--fVerbs);
|
|
||||||
const SkPoint* SK_RESTRICT srcPts = fPts;
|
const SkPoint* SK_RESTRICT srcPts = fPts;
|
||||||
SkPoint* SK_RESTRICT pts = ptsParam;
|
SkPoint* SK_RESTRICT pts = ptsParam;
|
||||||
|
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
case kMove_Verb:
|
case kMove_Verb:
|
||||||
if (fNeedClose) {
|
if (fNeedClose) {
|
||||||
fVerbs++; // move back one verb
|
fVerbs--; // move back one verb
|
||||||
verb = this->autoClose(pts);
|
verb = this->autoClose(pts);
|
||||||
if (verb == kClose_Verb) {
|
if (verb == kClose_Verb) {
|
||||||
fNeedClose = false;
|
fNeedClose = false;
|
||||||
@ -2086,7 +2068,7 @@ SkPath::Verb SkPath::Iter::next(SkPoint ptsParam[4]) {
|
|||||||
case kClose_Verb:
|
case kClose_Verb:
|
||||||
verb = this->autoClose(pts);
|
verb = this->autoClose(pts);
|
||||||
if (verb == kLine_Verb) {
|
if (verb == kLine_Verb) {
|
||||||
fVerbs++; // move back one verb
|
fVerbs--; // move back one verb
|
||||||
} else {
|
} else {
|
||||||
fNeedClose = false;
|
fNeedClose = false;
|
||||||
fSegmentState = kEmptyContour_SegmentState;
|
fSegmentState = kEmptyContour_SegmentState;
|
||||||
@ -2828,10 +2810,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
ContourIter::ContourIter(const SkPathRef& pathRef) {
|
ContourIter::ContourIter(const SkPathRef& pathRef) {
|
||||||
fStopVerbs = pathRef.verbsMemBegin();
|
fStopVerbs = pathRef.verbsEnd();
|
||||||
fDone = false;
|
fDone = false;
|
||||||
fCurrPt = pathRef.points();
|
fCurrPt = pathRef.points();
|
||||||
fCurrVerb = pathRef.verbs();
|
fCurrVerb = pathRef.verbsBegin();
|
||||||
fCurrConicWeight = pathRef.conicWeights();
|
fCurrConicWeight = pathRef.conicWeights();
|
||||||
fCurrPtCount = 0;
|
fCurrPtCount = 0;
|
||||||
SkDEBUGCODE(fContourCounter = 0;)
|
SkDEBUGCODE(fContourCounter = 0;)
|
||||||
@ -2839,7 +2821,7 @@ ContourIter::ContourIter(const SkPathRef& pathRef) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ContourIter::next() {
|
void ContourIter::next() {
|
||||||
if (fCurrVerb <= fStopVerbs) {
|
if (fCurrVerb >= fStopVerbs) {
|
||||||
fDone = true;
|
fDone = true;
|
||||||
}
|
}
|
||||||
if (fDone) {
|
if (fDone) {
|
||||||
@ -2849,12 +2831,12 @@ void ContourIter::next() {
|
|||||||
// skip pts of prev contour
|
// skip pts of prev contour
|
||||||
fCurrPt += fCurrPtCount;
|
fCurrPt += fCurrPtCount;
|
||||||
|
|
||||||
SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]);
|
SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
|
||||||
int ptCount = 1; // moveTo
|
int ptCount = 1; // moveTo
|
||||||
const uint8_t* verbs = fCurrVerb;
|
const uint8_t* verbs = fCurrVerb;
|
||||||
|
|
||||||
for (--verbs; verbs > fStopVerbs; --verbs) {
|
for (verbs++; verbs < fStopVerbs; verbs++) {
|
||||||
switch (verbs[~0]) {
|
switch (*verbs) {
|
||||||
case SkPath::kMove_Verb:
|
case SkPath::kMove_Verb:
|
||||||
goto CONTOUR_END;
|
goto CONTOUR_END;
|
||||||
case SkPath::kLine_Verb:
|
case SkPath::kLine_Verb:
|
||||||
|
@ -66,9 +66,9 @@ public:
|
|||||||
if (verbCount == 0)
|
if (verbCount == 0)
|
||||||
return false;
|
return false;
|
||||||
int moveCount = 0;
|
int moveCount = 0;
|
||||||
auto verbs = path.fPathRef->verbs();
|
auto verbs = path.fPathRef->verbsBegin();
|
||||||
for (int i = 0; i < verbCount; i++) {
|
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:
|
case SkPath::Verb::kMove_Verb:
|
||||||
moveCount += 1;
|
moveCount += 1;
|
||||||
if (moveCount > 1) {
|
if (moveCount > 1) {
|
||||||
@ -123,13 +123,13 @@ public:
|
|||||||
public:
|
public:
|
||||||
Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {}
|
Verbs(const SkPath& path) : fPathRef(path.fPathRef.get()) {}
|
||||||
struct Iter {
|
struct Iter {
|
||||||
void operator++() { --fVerb; } // verbs are laid out backwards in memory.
|
void operator++() { fVerb++; }
|
||||||
bool operator!=(const Iter& b) { return fVerb != b.fVerb; }
|
bool operator!=(const Iter& b) { return fVerb != b.fVerb; }
|
||||||
SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); }
|
SkPath::Verb operator*() { return static_cast<SkPath::Verb>(*fVerb); }
|
||||||
const uint8_t* fVerb;
|
const uint8_t* fVerb;
|
||||||
};
|
};
|
||||||
Iter begin() { return Iter{fPathRef->verbs() - 1}; }
|
Iter begin() { return Iter{fPathRef->verbsBegin()}; }
|
||||||
Iter end() { return Iter{fPathRef->verbs() - fPathRef->countVerbs() - 1}; }
|
Iter end() { return Iter{fPathRef->verbsEnd()}; }
|
||||||
private:
|
private:
|
||||||
Verbs(const Verbs&) = delete;
|
Verbs(const Verbs&) = delete;
|
||||||
Verbs& operator=(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
|
* Returns a pointer to the verb data.
|
||||||
* thus the returned pointer is the last verb.
|
|
||||||
*/
|
*/
|
||||||
static const uint8_t* VerbData(const SkPath& path) {
|
static const uint8_t* VerbData(const SkPath& path) {
|
||||||
return path.fPathRef->verbsMemBegin();
|
return path.fPathRef->verbsBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a raw pointer to the path points */
|
/** 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
|
// Roughly the same as SkPath::Iter(path, true), but does not return moves or closes
|
||||||
//
|
//
|
||||||
class SkPathEdgeIter {
|
class SkPathEdgeIter {
|
||||||
const uint8_t* fVerbsStart;
|
const uint8_t* fVerbs;
|
||||||
const uint8_t* fVerbs; // reverse
|
const uint8_t* fVerbsStop;
|
||||||
const SkPoint* fPts;
|
const SkPoint* fPts;
|
||||||
const SkPoint* fMoveToPtr;
|
const SkPoint* fMoveToPtr;
|
||||||
const SkScalar* fConicWeights;
|
const SkScalar* fConicWeights;
|
||||||
@ -338,8 +337,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
SkASSERT(fVerbs >= fVerbsStart);
|
SkASSERT(fVerbs <= fVerbsStop);
|
||||||
if (fVerbs == fVerbsStart) {
|
if (fVerbs == fVerbsStop) {
|
||||||
return fNeedsCloseLine
|
return fNeedsCloseLine
|
||||||
? closeline()
|
? closeline()
|
||||||
: Result{ nullptr, Edge(kIllegalEdgeValue) };
|
: Result{ nullptr, Edge(kIllegalEdgeValue) };
|
||||||
@ -347,7 +346,7 @@ public:
|
|||||||
|
|
||||||
SkDEBUGCODE(fIsConic = false;)
|
SkDEBUGCODE(fIsConic = false;)
|
||||||
|
|
||||||
const auto v = *--fVerbs;
|
const auto v = *fVerbs++;
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case SkPath::kMove_Verb: {
|
case SkPath::kMove_Verb: {
|
||||||
if (fNeedsCloseLine) {
|
if (fNeedsCloseLine) {
|
||||||
|
@ -15,16 +15,6 @@
|
|||||||
#include "src/core/SkPathPriv.h"
|
#include "src/core/SkPathPriv.h"
|
||||||
#include "src/core/SkSafeMath.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,
|
SkPathRef::Editor::Editor(sk_sp<SkPathRef>* pathRef,
|
||||||
int incReserveVerbs,
|
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.
|
// allocations to just fit the current needs. makeSpace() will only grow, but never shrinks.
|
||||||
//
|
//
|
||||||
void SkPath::shrinkToFit() {
|
void SkPath::shrinkToFit() {
|
||||||
const size_t kMinFreeSpaceForShrink = 8; // just made up a small number
|
fPathRef->fPoints.shrinkToFit();
|
||||||
|
fPathRef->fVerbs.shrinkToFit();
|
||||||
if (fPathRef->fFreeSpace <= kMinFreeSpaceForShrink) {
|
fPathRef->fConicWeights.shrinkToFit();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
SkDEBUGCODE(fPathRef->validate();)
|
SkDEBUGCODE(fPathRef->validate();)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,13 +54,6 @@ SkPathRef::~SkPathRef() {
|
|||||||
// to read one that's not valid and then free its memory without asserting.
|
// to read one that's not valid and then free its memory without asserting.
|
||||||
this->callGenIDChangeListeners();
|
this->callGenIDChangeListeners();
|
||||||
SkASSERT(fGenIDChangeListeners.empty()); // These are raw ptrs.
|
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(fGenerationID = 0xEEEEEEEE;)
|
||||||
SkDEBUGCODE(fEditorsAttached.store(0x7777777);)
|
SkDEBUGCODE(fEditorsAttached.store(0x7777777);)
|
||||||
}
|
}
|
||||||
@ -189,20 +142,17 @@ void SkPathRef::CreateTransformedCopy(sk_sp<SkPathRef>* dst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dst->get() != &src) {
|
if (dst->get() != &src) {
|
||||||
(*dst)->resetToSize(src.fVerbCnt, src.fPointCnt, src.fConicWeights.count());
|
(*dst)->fPoints = src.fPoints;
|
||||||
sk_careful_memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(),
|
(*dst)->fVerbs = src.fVerbs;
|
||||||
src.fVerbCnt * sizeof(uint8_t));
|
|
||||||
(*dst)->fConicWeights = src.fConicWeights;
|
(*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)
|
// Need to check this here in case (&src == dst)
|
||||||
bool canXformBounds = !src.fBoundsIsDirty && matrix.rectStaysRect() && src.countPoints() > 1;
|
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
|
* 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();)
|
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) {
|
void SkPathRef::Rewind(sk_sp<SkPathRef>* pathRef) {
|
||||||
if ((*pathRef)->unique()) {
|
if ((*pathRef)->unique()) {
|
||||||
SkDEBUGCODE((*pathRef)->validate();)
|
SkDEBUGCODE((*pathRef)->validate();)
|
||||||
(*pathRef)->callGenIDChangeListeners();
|
(*pathRef)->callGenIDChangeListeners();
|
||||||
(*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
|
(*pathRef)->fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||||
(*pathRef)->fVerbCnt = 0;
|
|
||||||
(*pathRef)->fPointCnt = 0;
|
|
||||||
(*pathRef)->fFreeSpace = (*pathRef)->currSize();
|
|
||||||
(*pathRef)->fGenerationID = 0;
|
(*pathRef)->fGenerationID = 0;
|
||||||
|
(*pathRef)->fPoints.rewind();
|
||||||
|
(*pathRef)->fVerbs.rewind();
|
||||||
(*pathRef)->fConicWeights.rewind();
|
(*pathRef)->fConicWeights.rewind();
|
||||||
(*pathRef)->fSegmentMask = 0;
|
(*pathRef)->fSegmentMask = 0;
|
||||||
(*pathRef)->fIsOval = false;
|
(*pathRef)->fIsOval = false;
|
||||||
@ -438,32 +239,12 @@ bool SkPathRef::operator== (const SkPathRef& ref) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (fPointCnt != ref.fPointCnt ||
|
if (fPoints != ref.fPoints || fConicWeights != ref.fConicWeights || fVerbs != ref.fVerbs) {
|
||||||
fVerbCnt != ref.fVerbCnt) {
|
|
||||||
SkASSERT(!genIDMatch);
|
SkASSERT(!genIDMatch);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (0 == ref.fVerbCnt) {
|
if (ref.fVerbs.count() == 0) {
|
||||||
SkASSERT(0 == ref.fPointCnt);
|
SkASSERT(ref.fPoints.count() == 0);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return true;
|
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
|
// 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.
|
// SkWBuffer. Until this is fixed we write 0.
|
||||||
buffer->write32(0);
|
buffer->write32(0);
|
||||||
buffer->write32(fVerbCnt);
|
buffer->write32(fVerbs.count());
|
||||||
buffer->write32(fPointCnt);
|
buffer->write32(fPoints.count());
|
||||||
buffer->write32(fConicWeights.count());
|
buffer->write32(fConicWeights.count());
|
||||||
buffer->write(verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
|
buffer->write(fVerbs.begin(), fVerbs.bytes());
|
||||||
buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
|
buffer->write(fPoints.begin(), fVerbs.bytes());
|
||||||
buffer->write(fConicWeights.begin(), fConicWeights.bytes());
|
buffer->write(fConicWeights.begin(), fConicWeights.bytes());
|
||||||
buffer->write(&bounds, sizeof(bounds));
|
buffer->write(&bounds, sizeof(bounds));
|
||||||
|
|
||||||
@ -498,9 +279,7 @@ void SkPathRef::writeToBuffer(SkWBuffer* buffer) const {
|
|||||||
|
|
||||||
uint32_t SkPathRef::writeSize() const {
|
uint32_t SkPathRef::writeSize() const {
|
||||||
return uint32_t(5 * sizeof(uint32_t) +
|
return uint32_t(5 * sizeof(uint32_t) +
|
||||||
fVerbCnt * sizeof(uint8_t) +
|
fVerbs.bytes() + fPoints.bytes() + fConicWeights.bytes() +
|
||||||
fPointCnt * sizeof(SkPoint) +
|
|
||||||
fConicWeights.bytes() +
|
|
||||||
sizeof(SkRect));
|
sizeof(SkRect));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,10 +287,10 @@ void SkPathRef::copy(const SkPathRef& ref,
|
|||||||
int additionalReserveVerbs,
|
int additionalReserveVerbs,
|
||||||
int additionalReservePoints) {
|
int additionalReservePoints) {
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
this->resetToSize(ref.fVerbCnt, ref.fPointCnt, ref.fConicWeights.count(),
|
this->resetToSize(ref.fVerbs.count(), ref.fPoints.count(), ref.fConicWeights.count(),
|
||||||
additionalReserveVerbs, additionalReservePoints);
|
additionalReserveVerbs, additionalReservePoints);
|
||||||
sk_careful_memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt*sizeof(uint8_t));
|
fVerbs = ref.fVerbs;
|
||||||
sk_careful_memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
|
fPoints = ref.fPoints;
|
||||||
fConicWeights = ref.fConicWeights;
|
fConicWeights = ref.fConicWeights;
|
||||||
fBoundsIsDirty = ref.fBoundsIsDirty;
|
fBoundsIsDirty = ref.fBoundsIsDirty;
|
||||||
if (!fBoundsIsDirty) {
|
if (!fBoundsIsDirty) {
|
||||||
@ -527,9 +306,9 @@ void SkPathRef::copy(const SkPathRef& ref,
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned SkPathRef::computeSegmentMask() const {
|
unsigned SkPathRef::computeSegmentMask() const {
|
||||||
const uint8_t* verbs = this->verbsMemBegin();
|
const uint8_t* verbs = fVerbs.begin();
|
||||||
unsigned mask = 0;
|
unsigned mask = 0;
|
||||||
for (int i = this->countVerbs() - 1; i >= 0; --i) {
|
for (int i = 0; i < fVerbs.count(); ++i) {
|
||||||
switch (verbs[i]) {
|
switch (verbs[i]) {
|
||||||
case SkPath::kLine_Verb: mask |= SkPath::kLine_SegmentMask; break;
|
case SkPath::kLine_Verb: mask |= SkPath::kLine_SegmentMask; break;
|
||||||
case SkPath::kQuad_Verb: mask |= SkPath::kQuad_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 {
|
void SkPathRef::interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const {
|
||||||
const SkScalar* inValues = &ending.getPoints()->fX;
|
const SkScalar* inValues = &ending.getPoints()->fX;
|
||||||
SkScalar* outValues = &out->getPoints()->fX;
|
SkScalar* outValues = &out->getWritablePoints()->fX;
|
||||||
int count = out->countPoints() * 2;
|
int count = out->countPoints() * 2;
|
||||||
for (int index = 0; index < count; ++index) {
|
for (int index = 0; index < count; ++index) {
|
||||||
outValues[index] = outValues[index] * weight + inValues[index] * (1 - weight);
|
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,
|
SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
|
||||||
int numVbs,
|
int numVbs,
|
||||||
SkScalar** weights) {
|
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();)
|
SkDEBUGCODE(this->validate();)
|
||||||
int pCnt;
|
int pCnt;
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
@ -595,40 +369,19 @@ SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb,
|
|||||||
pCnt = 0;
|
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
|
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||||
fIsOval = false;
|
fIsOval = false;
|
||||||
fIsRRect = false;
|
fIsRRect = false;
|
||||||
|
|
||||||
|
memset(fVerbs.append(numVbs), verb, numVbs);
|
||||||
if (SkPath::kConic_Verb == verb) {
|
if (SkPath::kConic_Verb == verb) {
|
||||||
SkASSERT(weights);
|
SkASSERT(weights);
|
||||||
*weights = fConicWeights.append(numVbs);
|
*weights = fConicWeights.append(numVbs);
|
||||||
}
|
}
|
||||||
|
SkPoint* pts = fPoints.append(pCnt);
|
||||||
|
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
return ret;
|
return pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) {
|
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");
|
SkDEBUGFAIL("default is not reached");
|
||||||
pCnt = 0;
|
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;
|
fSegmentMask |= mask;
|
||||||
fFreeSpace -= space;
|
|
||||||
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
fBoundsIsDirty = true; // this also invalidates fIsFinite
|
||||||
fIsOval = false;
|
fIsOval = false;
|
||||||
fIsRRect = false;
|
fIsRRect = false;
|
||||||
|
|
||||||
|
*fVerbs.append() = verb;
|
||||||
if (SkPath::kConic_Verb == verb) {
|
if (SkPath::kConic_Verb == verb) {
|
||||||
*fConicWeights.append() = weight;
|
*fConicWeights.append() = weight;
|
||||||
}
|
}
|
||||||
|
SkPoint* pts = fPoints.append(pCnt);
|
||||||
|
|
||||||
SkDEBUGCODE(this->validate();)
|
SkDEBUGCODE(this->validate();)
|
||||||
return ret;
|
return pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SkPathRef::genID() const {
|
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;
|
static const uint32_t kMask = (static_cast<int64_t>(1) << SkPathPriv::kPathRefGenIDBitCnt) - 1;
|
||||||
|
|
||||||
if (fGenerationID == 0) {
|
if (fGenerationID == 0) {
|
||||||
if (fPointCnt == 0 && fVerbCnt == 0) {
|
if (fPoints.count() == 0 && fVerbs.count() == 0) {
|
||||||
fGenerationID = kEmptyGenID;
|
fGenerationID = kEmptyGenID;
|
||||||
} else {
|
} else {
|
||||||
static std::atomic<uint32_t> nextID{kEmptyGenID + 1};
|
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) {
|
void SkPathRef::Iter::setPathRef(const SkPathRef& path) {
|
||||||
fPts = path.points();
|
fPts = path.points();
|
||||||
fVerbs = path.verbs();
|
fVerbs = path.verbsBegin();
|
||||||
fVerbStop = path.verbsMemBegin();
|
fVerbStop = path.verbsEnd();
|
||||||
fConicWeights = path.conicWeights();
|
fConicWeights = path.conicWeights();
|
||||||
if (fConicWeights) {
|
if (fConicWeights) {
|
||||||
fConicWeights -= 1; // begin one behind
|
fConicWeights -= 1; // begin one behind
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow iteration through non-finite points.
|
// 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.
|
// fVerbs points one beyond next verb so decrement first.
|
||||||
unsigned verb = *(--fVerbs);
|
unsigned verb = *fVerbs++;
|
||||||
const SkPoint* srcPts = fPts;
|
const SkPoint* srcPts = fPts;
|
||||||
|
|
||||||
switch (verb) {
|
switch (verb) {
|
||||||
@ -865,35 +608,11 @@ uint8_t SkPathRef::Iter::next(SkPoint pts[4]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SkPathRef::Iter::peek() const {
|
uint8_t SkPathRef::Iter::peek() const {
|
||||||
const uint8_t* next = fVerbs;
|
return fVerbs < fVerbStop ? *fVerbs : (uint8_t) SkPath::kDone_Verb;
|
||||||
return next <= fVerbStop ? (uint8_t) SkPath::kDone_Verb : next[-1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SkPathRef::isValid() const {
|
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) {
|
if (fIsOval || fIsRRect) {
|
||||||
// Currently we don't allow both of these to be set, even though ovals are ro
|
// Currently we don't allow both of these to be set, even though ovals are ro
|
||||||
if (fIsOval == fIsRRect) {
|
if (fIsOval == fIsRRect) {
|
||||||
@ -914,14 +633,14 @@ bool SkPathRef::isValid() const {
|
|||||||
bool isFinite = true;
|
bool isFinite = true;
|
||||||
Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop);
|
Sk2s leftTop = Sk2s(fBounds.fLeft, fBounds.fTop);
|
||||||
Sk2s rightBot = Sk2s(fBounds.fRight, fBounds.fBottom);
|
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);
|
Sk2s point = Sk2s(fPoints[i].fX, fPoints[i].fY);
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
if (fPoints[i].isFinite() &&
|
if (fPoints[i].isFinite() &&
|
||||||
((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) {
|
((point < leftTop).anyTrue() || (point > rightBot).anyTrue())) {
|
||||||
SkDebugf("bad SkPathRef bounds: %g %g %g %g\n",
|
SkDebugf("bad SkPathRef bounds: %g %g %g %g\n",
|
||||||
fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
|
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) {
|
if (i == j) {
|
||||||
SkDebugf("*** bounds do not contain: ");
|
SkDebugf("*** bounds do not contain: ");
|
||||||
}
|
}
|
||||||
@ -948,8 +667,8 @@ bool SkPathRef::isValid() const {
|
|||||||
|
|
||||||
SkPathEdgeIter::SkPathEdgeIter(const SkPath& path) {
|
SkPathEdgeIter::SkPathEdgeIter(const SkPath& path) {
|
||||||
fMoveToPtr = fPts = path.fPathRef->points();
|
fMoveToPtr = fPts = path.fPathRef->points();
|
||||||
fVerbs = path.fPathRef->verbs();
|
fVerbs = path.fPathRef->verbsBegin();
|
||||||
fVerbsStart = path.fPathRef->verbsMemBegin();
|
fVerbsStop = path.fPathRef->verbsEnd();
|
||||||
fConicWeights = path.fPathRef->conicWeights();
|
fConicWeights = path.fPathRef->conicWeights();
|
||||||
if (fConicWeights) {
|
if (fConicWeights) {
|
||||||
fConicWeights -= 1; // begin one behind
|
fConicWeights -= 1; // begin one behind
|
||||||
|
@ -26,11 +26,13 @@ enum SerializationOffsets {
|
|||||||
|
|
||||||
enum SerializationVersions {
|
enum SerializationVersions {
|
||||||
// kPathPrivFirstDirection_Version = 1,
|
// kPathPrivFirstDirection_Version = 1,
|
||||||
kPathPrivLastMoveToIndex_Version = 2,
|
// kPathPrivLastMoveToIndex_Version = 2,
|
||||||
kPathPrivTypeEnumVersion = 3,
|
// kPathPrivTypeEnumVersion = 3,
|
||||||
kJustPublicData_Version = 4, // introduced Feb/2018
|
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 {
|
enum SerializationType {
|
||||||
@ -121,7 +123,7 @@ size_t SkPath::writeToMemory(void* storage) const {
|
|||||||
buffer.write32(vbs);
|
buffer.write32(vbs);
|
||||||
buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
|
buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
|
||||||
buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
|
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();
|
buffer.padToAlign4();
|
||||||
|
|
||||||
SkASSERT(buffer.pos() == size);
|
SkASSERT(buffer.pos() == size);
|
||||||
@ -145,11 +147,12 @@ size_t SkPath::readFromMemory(const void* storage, size_t length) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
unsigned version = extract_version(packed);
|
unsigned version = extract_version(packed);
|
||||||
if (version <= kPathPrivTypeEnumVersion) {
|
if (version < kMin_Version || version > kCurrent_Version) {
|
||||||
return this->readFromMemory_LE3(storage, length);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -192,14 +195,17 @@ size_t SkPath::readAsRRect(const void* storage, size_t length) {
|
|||||||
return buffer.pos();
|
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);
|
SkRBuffer buffer(storage, length);
|
||||||
uint32_t packed;
|
uint32_t packed;
|
||||||
if (!buffer.readU32(&packed)) {
|
if (!buffer.readU32(&packed)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkASSERT(extract_version(packed) == 4);
|
bool verbsAreReversed = true;
|
||||||
|
if (extract_version(packed) == kVerbsAreStoredForward_Version) {
|
||||||
|
verbsAreReversed = false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (extract_serializationtype(packed)) {
|
switch (extract_serializationtype(packed)) {
|
||||||
case SerializationType::kRRect:
|
case SerializationType::kRRect:
|
||||||
@ -234,11 +240,17 @@ size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
int verbsStep = 1;
|
||||||
|
if (verbsAreReversed) {
|
||||||
|
verbs += vbs - 1;
|
||||||
|
verbsStep = -1;
|
||||||
|
}
|
||||||
|
|
||||||
SkPath tmp;
|
SkPath tmp;
|
||||||
tmp.setFillType(extract_filltype(packed));
|
tmp.setFillType(extract_filltype(packed));
|
||||||
tmp.incReserve(pts);
|
tmp.incReserve(pts);
|
||||||
for (int i = vbs - 1; i >= 0; --i) {
|
for (int i = 0; i < vbs; ++i) {
|
||||||
switch (verbs[i]) {
|
switch (*verbs) {
|
||||||
case kMove_Verb:
|
case kMove_Verb:
|
||||||
CHECK_POINTS_CONICS(1, 0);
|
CHECK_POINTS_CONICS(1, 0);
|
||||||
tmp.moveTo(*points++);
|
tmp.moveTo(*points++);
|
||||||
@ -268,6 +280,7 @@ size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
|||||||
default:
|
default:
|
||||||
return 0; // bad verb
|
return 0; // bad verb
|
||||||
}
|
}
|
||||||
|
verbs += verbsStep;
|
||||||
}
|
}
|
||||||
#undef CHECK_POINTS_CONICS
|
#undef CHECK_POINTS_CONICS
|
||||||
if (pts || cnx) {
|
if (pts || cnx) {
|
||||||
@ -277,51 +290,3 @@ size_t SkPath::readFromMemory_EQ4(const void* storage, size_t length) {
|
|||||||
*this = std::move(tmp);
|
*this = std::move(tmp);
|
||||||
return buffer.pos();
|
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 });
|
p2.addRect({ 10, 20, 30, 40 });
|
||||||
uint32_t id1 = p1.getGenerationID();
|
uint32_t id1 = p1.getGenerationID();
|
||||||
uint32_t id2 = p2.getGenerationID();
|
uint32_t id2 = p2.getGenerationID();
|
||||||
|
REPORTER_ASSERT(reporter, id1 != id2);
|
||||||
SkMatrix matrix;
|
SkMatrix matrix;
|
||||||
matrix.setScale(2, 2);
|
matrix.setScale(2, 2);
|
||||||
p1.transform(matrix, &p2);
|
p1.transform(matrix, &p2);
|
||||||
|
REPORTER_ASSERT(reporter, id1 == p1.getGenerationID());
|
||||||
|
REPORTER_ASSERT(reporter, id2 != p2.getGenerationID());
|
||||||
p1.transform(matrix);
|
p1.transform(matrix);
|
||||||
REPORTER_ASSERT(reporter, id1 != p1.getGenerationID());
|
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 {
|
class PathRefTest_Private {
|
||||||
public:
|
public:
|
||||||
static size_t GetFreeSpace(const SkPathRef& ref) {
|
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) {
|
static void TestPathRef(skiatest::Reporter* reporter) {
|
||||||
|
Loading…
Reference in New Issue
Block a user