| Index: include/core/SkPathRef.h
|
| ===================================================================
|
| --- include/core/SkPathRef.h (revision 11888)
|
| +++ include/core/SkPathRef.h (working copy)
|
| @@ -23,7 +23,7 @@
|
| * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods
|
| * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an
|
| * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs
|
| - * copy-on-write if the SkPathRef is shared by multipls SkPaths. The caller passes the Editor's
|
| + * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's
|
| * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's
|
| * constructor returns.
|
| *
|
| @@ -71,21 +71,12 @@
|
| SkPoint* growForConic(SkScalar w);
|
|
|
| /**
|
| - * Allocates space for additional verbs and points and returns pointers to the new verbs and
|
| - * points. verbs will point one beyond the first new verb (index it using [~<i>]). pts points
|
| - * at the first new point (indexed normally [<i>]).
|
| + * Allocates space for additional lines and returns a pointer to the new
|
| + * points. The return pointer points at the first new point (indexed normally [<i>]).
|
| */
|
| - void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) {
|
| - SkASSERT(NULL != verbs);
|
| - SkASSERT(NULL != pts);
|
| + SkPoint* growForLines(int numLines) {
|
| SkDEBUGCODE(fPathRef->validate();)
|
| - int oldVerbCnt = fPathRef->fVerbCnt;
|
| - int oldPointCnt = fPathRef->fPointCnt;
|
| - SkASSERT(verbs && pts);
|
| - fPathRef->grow(newVerbs, newPts);
|
| - *verbs = fPathRef->fVerbs - oldVerbCnt;
|
| - *pts = fPathRef->fPoints + oldPointCnt;
|
| - SkDEBUGCODE(fPathRef->validate();)
|
| + return fPathRef->growForLines(numLines);
|
| }
|
|
|
| /**
|
| @@ -95,11 +86,23 @@
|
| void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) {
|
| fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount);
|
| }
|
| +
|
| /**
|
| * Gets the path ref that is wrapped in the Editor.
|
| */
|
| SkPathRef* pathRef() { return fPathRef; }
|
|
|
| + void setDirection(int /* SkPath::Direction */ dir) { fPathRef->setDirection(dir); }
|
| +
|
| + void setIsOval(bool isOval) { fPathRef->setIsOval(isOval); }
|
| +
|
| + void setConvexity(int /*SkPath::Convexity*/ convexity) {
|
| + fPathRef->setConvexity(convexity);
|
| + }
|
| +
|
| + // 'rect' needs to be sorted
|
| + void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); }
|
| +
|
| private:
|
| SkPathRef* fPathRef;
|
| };
|
| @@ -117,7 +120,51 @@
|
| return SkRef(gEmptyPathRef);
|
| }
|
|
|
| + uint8_t /*SkPath::Direction*/ getDirection() const { return fDirection; }
|
| +
|
| /**
|
| + * Tries to quickly compute the direction of the first non-degenerate
|
| + * contour. If it can be computed, return true and set dir to that
|
| + * direction. If it cannot be (quickly) determined, return false and ignore
|
| + * the dir parameter. If the direction was determined, it is cached to make
|
| + * subsequent calls return quickly.
|
| + */
|
| + bool cheapComputeDirection(int* dir) const;
|
| +
|
| + /**
|
| + * Return the path's convexity, as stored in the path. If it is currently unknown,
|
| + * then this function will attempt to compute the convexity (and cache the result).
|
| + */
|
| + int /*SkPath::Convexity*/ getConvexity() const;
|
| +
|
| + /**
|
| + * Return the currently cached value for convexity, even if that is set to
|
| + * kUnknown_Convexity. Note: getConvexity() will automatically call
|
| + * ComputeConvexity and cache its return value if the current setting is
|
| + * kUnknown.
|
| + */
|
| + int /*SkPath::Convexity*/ getConvexityOrUnknown() const {
|
| + return fConvexity;
|
| + }
|
| +
|
| + /** Returns true if the path is an oval.
|
| + *
|
| + * @param rect returns the bounding rect of this oval. It's a circle
|
| + * if the height and width are the same.
|
| + *
|
| + * @return true if this path is an oval.
|
| + * Tracking whether a path is an oval is considered an
|
| + * optimization for performance and so some paths that are in
|
| + * fact ovals can report false.
|
| + */
|
| + bool isOval(SkRect* rect) const {
|
| + if (fIsOval && NULL != rect) {
|
| + *rect = this->getBounds();
|
| + }
|
| + return SkToBool(fIsOval);
|
| + }
|
| +
|
| + /**
|
| * Returns true if all of the points in this path are finite, meaning there
|
| * are no infinities and no NaNs.
|
| */
|
| @@ -128,6 +175,13 @@
|
| return SkToBool(fIsFinite);
|
| }
|
|
|
| + /**
|
| + * Returns a mask, where each bit corresponding to a SegmentMask is
|
| + * set if the path contains 1 or more segments of that type.
|
| + * Returns 0 for an empty path (no segments).
|
| + */
|
| + uint32_t getSegmentMasks() const { return fSegmentMask; }
|
| +
|
| bool hasComputedBounds() const {
|
| return !fBoundsIsDirty;
|
| }
|
| @@ -144,13 +198,6 @@
|
| return fBounds;
|
| }
|
|
|
| - void setBounds(const SkRect& rect) {
|
| - SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom);
|
| - fBounds = rect;
|
| - fBoundsIsDirty = false;
|
| - fIsFinite = fBounds.isFinite();
|
| - }
|
| -
|
| /**
|
| * Transforms a path ref by a matrix, allocating a new one only if necessary.
|
| */
|
| @@ -213,7 +260,7 @@
|
| /**
|
| * Convenience methods for getting to a verb or point by index.
|
| */
|
| - uint8_t atVerb(int index) {
|
| + uint8_t atVerb(int index) const {
|
| SkASSERT((unsigned) index < (unsigned) fVerbCnt);
|
| return this->verbs()[~index];
|
| }
|
| @@ -227,40 +274,58 @@
|
| /**
|
| * Writes the path points and verbs to a buffer.
|
| */
|
| - void writeToBuffer(SkWBuffer* buffer);
|
| + void writeToBuffer(SkWBuffer* buffer) const;
|
|
|
| /**
|
| * Gets the number of bytes that would be written in writeBuffer()
|
| */
|
| - uint32_t writeSize();
|
| + uint32_t writeSize() const;
|
|
|
| private:
|
| enum SerializationOffsets {
|
| + kDirection_SerializationShift = 26, // requires 2 bits
|
| kIsFinite_SerializationShift = 25, // requires 1 bit
|
| + kIsOval_SerializationShift = 24, // requires 1 bit
|
| + kConvexity_SerializationShift = 16, // requires 8 bits
|
| + // FillType (in SkPath) takes up 8
|
| + kSegmentMask_SerializationShift = 0 // requires 4 bits
|
| };
|
|
|
| - SkPathRef() {
|
| - fBoundsIsDirty = true; // this also invalidates fIsFinite
|
| - fPointCnt = 0;
|
| - fVerbCnt = 0;
|
| - fVerbs = NULL;
|
| - fPoints = NULL;
|
| - fFreeSpace = 0;
|
| - fGenerationID = kEmptyGenID;
|
| - SkDEBUGCODE(fEditorsAttached = 0;)
|
| - SkDEBUGCODE(this->validate();)
|
| + // flag to require a moveTo if we begin with something else, like lineTo etc.
|
| + static const int kINITIAL_LASTMOVETOINDEX_VALUE = ~0;
|
| +
|
| + SkPathRef();
|
| +
|
| + /**
|
| + * Store a convexity setting in the path. There is no automatic check to
|
| + * see if this value actually agrees with the return value that would be
|
| + * computed by getConvexity().
|
| + *
|
| + * Note: even if this is set to a "known" value, if the path is later
|
| + * changed (e.g. lineTo(), addRect(), etc.) then the cached value will be
|
| + * reset to kUnknown_Convexity.
|
| + */
|
| + void setConvexity(int /*SkPath::Convexity*/ convexity) {
|
| + fConvexity = convexity;
|
| }
|
|
|
| + // 'rect' needs to be sorted
|
| + void setBounds(const SkRect& rect) {
|
| + SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom);
|
| + fBounds = rect;
|
| + fBoundsIsDirty = false;
|
| + fIsFinite = fBounds.isFinite();
|
| + }
|
| +
|
| void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints);
|
|
|
| // Return true if the computed bounds are finite.
|
| - static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) {
|
| - int count = ref.countPoints();
|
| + static bool ComputePtBounds(SkRect* bounds, const SkPoint* points, int count) {
|
| if (count <= 1) { // we ignore just 1 point (moveto)
|
| bounds->setEmpty();
|
| - return count ? ref.points()->isFinite() : true;
|
| + return count ? points->isFinite() : true;
|
| } else {
|
| - return bounds->setBoundsCheck(ref.points(), count);
|
| + return bounds->setBoundsCheck(points, count);
|
| }
|
| }
|
|
|
| @@ -269,7 +334,7 @@
|
| SkDEBUGCODE(this->validate();)
|
| SkASSERT(fBoundsIsDirty);
|
|
|
| - fIsFinite = ComputePtBounds(&fBounds, *this);
|
| + fIsFinite = ComputePtBounds(&fBounds, this->points(), this->countPoints());
|
| fBoundsIsDirty = false;
|
| }
|
|
|
| @@ -284,58 +349,24 @@
|
| /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also
|
| * allocates space for reserveVerb additional verbs and reservePoints additional points.*/
|
| void resetToSize(int verbCount, int pointCount, int conicCount,
|
| - int reserveVerbs = 0, int reservePoints = 0) {
|
| - SkDEBUGCODE(this->validate();)
|
| - fBoundsIsDirty = true; // this also invalidates fIsFinite
|
| - fGenerationID = 0;
|
| + int reserveVerbs = 0, int reservePoints = 0);
|
|
|
| - 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;
|
| + // This method assumes space has already been allocated for the new
|
| + // verb and point.
|
| + void injectMove();
|
|
|
| - ptrdiff_t sizeDelta = this->currSize() - minSize;
|
| -
|
| - if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) {
|
| - sk_free(fPoints);
|
| - fPoints = NULL;
|
| - fVerbs = NULL;
|
| - fFreeSpace = 0;
|
| - fVerbCnt = 0;
|
| - fPointCnt = 0;
|
| - this->makeSpace(minSize);
|
| - fVerbCnt = verbCount;
|
| - fPointCnt = pointCount;
|
| - fFreeSpace -= newSize;
|
| - } else {
|
| - fPointCnt = pointCount;
|
| - fVerbCnt = verbCount;
|
| - fFreeSpace = this->currSize() - minSize;
|
| - }
|
| - fConicWeights.setCount(conicCount);
|
| - SkDEBUGCODE(this->validate();)
|
| - }
|
| -
|
| /**
|
| - * Increases the verb count by newVerbs and the point count be newPoints. New verbs and points
|
| - * are uninitialized.
|
| + * Increases the verb and point count by numLines. The new points
|
| + * are uninitialized. All the new verbs are set to kLine_SegmentMask.
|
| */
|
| - void grow(int newVerbs, int newPoints) {
|
| - SkDEBUGCODE(this->validate();)
|
| - size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint);
|
| - this->makeSpace(space);
|
| - fVerbCnt += newVerbs;
|
| - fPointCnt += newPoints;
|
| - fFreeSpace -= space;
|
| - fBoundsIsDirty = true; // this also invalidates fIsFinite
|
| - SkDEBUGCODE(this->validate();)
|
| - }
|
| + SkPoint* growForLines(int numLines);
|
|
|
| /**
|
| * Increases the verb count 1, records the new verb, and creates room for the requisite number
|
| * of additional points. A pointer to the first point is returned. Any new points are
|
| * uninitialized.
|
| */
|
| - SkPoint* growForVerb(int /*SkPath::Verb*/ verb);
|
| + SkPoint* growForVerb(int /* SkPath::Verb */ verb);
|
|
|
| /**
|
| * Ensures that the free space available in the path ref is >= size. The verb and point counts
|
| @@ -397,13 +428,24 @@
|
|
|
| SkDEBUGCODE(void validate() const;)
|
|
|
| + int internalGetConvexity() const;
|
| +
|
| + void setIsOval(bool isOval) { fIsOval = isOval; }
|
| + void setDirection(int direction) { fDirection = direction; }
|
| +
|
| enum {
|
| kMinSize = 256,
|
| };
|
|
|
| mutable SkRect fBounds;
|
| + int fLastMoveToIndex;
|
| +
|
| + uint8_t fSegmentMask;
|
| mutable uint8_t fBoundsIsDirty;
|
| + mutable uint8_t fConvexity;
|
| + mutable uint8_t fDirection;
|
| mutable SkBool8 fIsFinite; // only meaningful if bounds are valid
|
| + mutable SkBool8 fIsOval;
|
|
|
| SkPoint* fPoints; // points to begining of the allocation
|
| uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards)
|
|
|