1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkPathRef.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,458 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2012 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#ifndef SkPathRef_DEFINED 1.13 +#define SkPathRef_DEFINED 1.14 + 1.15 +#include "SkMatrix.h" 1.16 +#include "SkPoint.h" 1.17 +#include "SkRect.h" 1.18 +#include "SkRefCnt.h" 1.19 +#include "SkTDArray.h" 1.20 +#include <stddef.h> // ptrdiff_t 1.21 + 1.22 +class SkRBuffer; 1.23 +class SkWBuffer; 1.24 + 1.25 +/** 1.26 + * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods 1.27 + * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an 1.28 + * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs 1.29 + * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's 1.30 + * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's 1.31 + * constructor returns. 1.32 + * 1.33 + * The points and verbs are stored in a single allocation. The points are at the begining of the 1.34 + * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points 1.35 + * and verbs both grow into the middle of the allocation until the meet. To access verb i in the 1.36 + * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first 1.37 + * logical verb or the last verb in memory). 1.38 + */ 1.39 + 1.40 +class SK_API SkPathRef : public ::SkRefCnt { 1.41 +public: 1.42 + SK_DECLARE_INST_COUNT(SkPathRef); 1.43 + 1.44 + class Editor { 1.45 + public: 1.46 + Editor(SkAutoTUnref<SkPathRef>* pathRef, 1.47 + int incReserveVerbs = 0, 1.48 + int incReservePoints = 0); 1.49 + 1.50 + ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } 1.51 + 1.52 + /** 1.53 + * Returns the array of points. 1.54 + */ 1.55 + SkPoint* points() { return fPathRef->getPoints(); } 1.56 + const SkPoint* points() const { return fPathRef->points(); } 1.57 + 1.58 + /** 1.59 + * Gets the ith point. Shortcut for this->points() + i 1.60 + */ 1.61 + SkPoint* atPoint(int i) { 1.62 + SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); 1.63 + return this->points() + i; 1.64 + }; 1.65 + const SkPoint* atPoint(int i) const { 1.66 + SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); 1.67 + return this->points() + i; 1.68 + }; 1.69 + 1.70 + /** 1.71 + * Adds the verb and allocates space for the number of points indicated by the verb. The 1.72 + * return value is a pointer to where the points for the verb should be written. 1.73 + * 'weight' is only used if 'verb' is kConic_Verb 1.74 + */ 1.75 + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) { 1.76 + SkDEBUGCODE(fPathRef->validate();) 1.77 + return fPathRef->growForVerb(verb, weight); 1.78 + } 1.79 + 1.80 + /** 1.81 + * Allocates space for multiple instances of a particular verb and the 1.82 + * requisite points & weights. 1.83 + * The return pointer points at the first new point (indexed normally [<i>]). 1.84 + * If 'verb' is kConic_Verb, 'weights' will return a pointer to the 1.85 + * space for the conic weights (indexed normally). 1.86 + */ 1.87 + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, 1.88 + int numVbs, 1.89 + SkScalar** weights = NULL) { 1.90 + return fPathRef->growForRepeatedVerb(verb, numVbs, weights); 1.91 + } 1.92 + 1.93 + /** 1.94 + * Resets the path ref to a new verb and point count. The new verbs and points are 1.95 + * uninitialized. 1.96 + */ 1.97 + void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { 1.98 + fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); 1.99 + } 1.100 + 1.101 + /** 1.102 + * Gets the path ref that is wrapped in the Editor. 1.103 + */ 1.104 + SkPathRef* pathRef() { return fPathRef; } 1.105 + 1.106 + void setIsOval(bool isOval) { fPathRef->setIsOval(isOval); } 1.107 + 1.108 + void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } 1.109 + 1.110 + private: 1.111 + SkPathRef* fPathRef; 1.112 + }; 1.113 + 1.114 +public: 1.115 + /** 1.116 + * Gets a path ref with no verbs or points. 1.117 + */ 1.118 + static SkPathRef* CreateEmpty(); 1.119 + 1.120 + /** 1.121 + * Returns true if all of the points in this path are finite, meaning there 1.122 + * are no infinities and no NaNs. 1.123 + */ 1.124 + bool isFinite() const { 1.125 + if (fBoundsIsDirty) { 1.126 + this->computeBounds(); 1.127 + } 1.128 + return SkToBool(fIsFinite); 1.129 + } 1.130 + 1.131 + /** 1.132 + * Returns a mask, where each bit corresponding to a SegmentMask is 1.133 + * set if the path contains 1 or more segments of that type. 1.134 + * Returns 0 for an empty path (no segments). 1.135 + */ 1.136 + uint32_t getSegmentMasks() const { return fSegmentMask; } 1.137 + 1.138 + /** Returns true if the path is an oval. 1.139 + * 1.140 + * @param rect returns the bounding rect of this oval. It's a circle 1.141 + * if the height and width are the same. 1.142 + * 1.143 + * @return true if this path is an oval. 1.144 + * Tracking whether a path is an oval is considered an 1.145 + * optimization for performance and so some paths that are in 1.146 + * fact ovals can report false. 1.147 + */ 1.148 + bool isOval(SkRect* rect) const { 1.149 + if (fIsOval && NULL != rect) { 1.150 + *rect = getBounds(); 1.151 + } 1.152 + 1.153 + return SkToBool(fIsOval); 1.154 + } 1.155 + 1.156 + bool hasComputedBounds() const { 1.157 + return !fBoundsIsDirty; 1.158 + } 1.159 + 1.160 + /** Returns the bounds of the path's points. If the path contains 0 or 1 1.161 + points, the bounds is set to (0,0,0,0), and isEmpty() will return true. 1.162 + Note: this bounds may be larger than the actual shape, since curves 1.163 + do not extend as far as their control points. 1.164 + */ 1.165 + const SkRect& getBounds() const { 1.166 + if (fBoundsIsDirty) { 1.167 + this->computeBounds(); 1.168 + } 1.169 + return fBounds; 1.170 + } 1.171 + 1.172 + /** 1.173 + * Transforms a path ref by a matrix, allocating a new one only if necessary. 1.174 + */ 1.175 + static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, 1.176 + const SkPathRef& src, 1.177 + const SkMatrix& matrix); 1.178 + 1.179 + static SkPathRef* CreateFromBuffer(SkRBuffer* buffer); 1.180 + 1.181 + /** 1.182 + * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be 1.183 + * repopulated with approximately the same number of verbs and points. A new path ref is created 1.184 + * only if necessary. 1.185 + */ 1.186 + static void Rewind(SkAutoTUnref<SkPathRef>* pathRef); 1.187 + 1.188 + virtual ~SkPathRef() { 1.189 + SkDEBUGCODE(this->validate();) 1.190 + sk_free(fPoints); 1.191 + 1.192 + SkDEBUGCODE(fPoints = NULL;) 1.193 + SkDEBUGCODE(fVerbs = NULL;) 1.194 + SkDEBUGCODE(fVerbCnt = 0x9999999;) 1.195 + SkDEBUGCODE(fPointCnt = 0xAAAAAAA;) 1.196 + SkDEBUGCODE(fPointCnt = 0xBBBBBBB;) 1.197 + SkDEBUGCODE(fGenerationID = 0xEEEEEEEE;) 1.198 + SkDEBUGCODE(fEditorsAttached = 0x7777777;) 1.199 + } 1.200 + 1.201 + int countPoints() const { SkDEBUGCODE(this->validate();) return fPointCnt; } 1.202 + int countVerbs() const { SkDEBUGCODE(this->validate();) return fVerbCnt; } 1.203 + int countWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.count(); } 1.204 + 1.205 + /** 1.206 + * Returns a pointer one beyond the first logical verb (last verb in memory order). 1.207 + */ 1.208 + const uint8_t* verbs() const { SkDEBUGCODE(this->validate();) return fVerbs; } 1.209 + 1.210 + /** 1.211 + * Returns a const pointer to the first verb in memory (which is the last logical verb). 1.212 + */ 1.213 + const uint8_t* verbsMemBegin() const { return this->verbs() - fVerbCnt; } 1.214 + 1.215 + /** 1.216 + * Returns a const pointer to the first point. 1.217 + */ 1.218 + const SkPoint* points() const { SkDEBUGCODE(this->validate();) return fPoints; } 1.219 + 1.220 + /** 1.221 + * Shortcut for this->points() + this->countPoints() 1.222 + */ 1.223 + const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } 1.224 + 1.225 + const SkScalar* conicWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.begin(); } 1.226 + const SkScalar* conicWeightsEnd() const { SkDEBUGCODE(this->validate();) return fConicWeights.end(); } 1.227 + 1.228 + /** 1.229 + * Convenience methods for getting to a verb or point by index. 1.230 + */ 1.231 + uint8_t atVerb(int index) const { 1.232 + SkASSERT((unsigned) index < (unsigned) fVerbCnt); 1.233 + return this->verbs()[~index]; 1.234 + } 1.235 + const SkPoint& atPoint(int index) const { 1.236 + SkASSERT((unsigned) index < (unsigned) fPointCnt); 1.237 + return this->points()[index]; 1.238 + } 1.239 + 1.240 + bool operator== (const SkPathRef& ref) const; 1.241 + 1.242 + /** 1.243 + * Writes the path points and verbs to a buffer. 1.244 + */ 1.245 + void writeToBuffer(SkWBuffer* buffer) const; 1.246 + 1.247 + /** 1.248 + * Gets the number of bytes that would be written in writeBuffer() 1.249 + */ 1.250 + uint32_t writeSize() const; 1.251 + 1.252 + /** 1.253 + * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the 1.254 + * same ID then they have the same verbs and points. However, two path refs may have the same 1.255 + * contents but different genIDs. 1.256 + */ 1.257 + uint32_t genID() const; 1.258 + 1.259 +private: 1.260 + enum SerializationOffsets { 1.261 + kIsFinite_SerializationShift = 25, // requires 1 bit 1.262 + kIsOval_SerializationShift = 24, // requires 1 bit 1.263 + kSegmentMask_SerializationShift = 0 // requires 4 bits 1.264 + }; 1.265 + 1.266 + SkPathRef() { 1.267 + fBoundsIsDirty = true; // this also invalidates fIsFinite 1.268 + fPointCnt = 0; 1.269 + fVerbCnt = 0; 1.270 + fVerbs = NULL; 1.271 + fPoints = NULL; 1.272 + fFreeSpace = 0; 1.273 + fGenerationID = kEmptyGenID; 1.274 + fSegmentMask = 0; 1.275 + fIsOval = false; 1.276 + SkDEBUGCODE(fEditorsAttached = 0;) 1.277 + SkDEBUGCODE(this->validate();) 1.278 + } 1.279 + 1.280 + void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints); 1.281 + 1.282 + // Return true if the computed bounds are finite. 1.283 + static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { 1.284 + int count = ref.countPoints(); 1.285 + if (count <= 1) { // we ignore just 1 point (moveto) 1.286 + bounds->setEmpty(); 1.287 + return count ? ref.points()->isFinite() : true; 1.288 + } else { 1.289 + return bounds->setBoundsCheck(ref.points(), count); 1.290 + } 1.291 + } 1.292 + 1.293 + // called, if dirty, by getBounds() 1.294 + void computeBounds() const { 1.295 + SkDEBUGCODE(this->validate();) 1.296 + SkASSERT(fBoundsIsDirty); 1.297 + 1.298 + fIsFinite = ComputePtBounds(&fBounds, *this); 1.299 + fBoundsIsDirty = false; 1.300 + } 1.301 + 1.302 + void setBounds(const SkRect& rect) { 1.303 + SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); 1.304 + fBounds = rect; 1.305 + fBoundsIsDirty = false; 1.306 + fIsFinite = fBounds.isFinite(); 1.307 + } 1.308 + 1.309 + /** Makes additional room but does not change the counts or change the genID */ 1.310 + void incReserve(int additionalVerbs, int additionalPoints) { 1.311 + SkDEBUGCODE(this->validate();) 1.312 + size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint); 1.313 + this->makeSpace(space); 1.314 + SkDEBUGCODE(this->validate();) 1.315 + } 1.316 + 1.317 + /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also 1.318 + * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ 1.319 + void resetToSize(int verbCount, int pointCount, int conicCount, 1.320 + int reserveVerbs = 0, int reservePoints = 0) { 1.321 + SkDEBUGCODE(this->validate();) 1.322 + fBoundsIsDirty = true; // this also invalidates fIsFinite 1.323 + fGenerationID = 0; 1.324 + 1.325 + fSegmentMask = 0; 1.326 + fIsOval = false; 1.327 + 1.328 + size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount; 1.329 + size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints; 1.330 + size_t minSize = newSize + newReserve; 1.331 + 1.332 + ptrdiff_t sizeDelta = this->currSize() - minSize; 1.333 + 1.334 + if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { 1.335 + sk_free(fPoints); 1.336 + fPoints = NULL; 1.337 + fVerbs = NULL; 1.338 + fFreeSpace = 0; 1.339 + fVerbCnt = 0; 1.340 + fPointCnt = 0; 1.341 + this->makeSpace(minSize); 1.342 + fVerbCnt = verbCount; 1.343 + fPointCnt = pointCount; 1.344 + fFreeSpace -= newSize; 1.345 + } else { 1.346 + fPointCnt = pointCount; 1.347 + fVerbCnt = verbCount; 1.348 + fFreeSpace = this->currSize() - minSize; 1.349 + } 1.350 + fConicWeights.setCount(conicCount); 1.351 + SkDEBUGCODE(this->validate();) 1.352 + } 1.353 + 1.354 + /** 1.355 + * Increases the verb count by numVbs and point count by the required amount. 1.356 + * The new points are uninitialized. All the new verbs are set to the specified 1.357 + * verb. If 'verb' is kConic_Verb, 'weights' will return a pointer to the 1.358 + * uninitialized conic weights. 1.359 + */ 1.360 + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights); 1.361 + 1.362 + /** 1.363 + * Increases the verb count 1, records the new verb, and creates room for the requisite number 1.364 + * of additional points. A pointer to the first point is returned. Any new points are 1.365 + * uninitialized. 1.366 + */ 1.367 + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight); 1.368 + 1.369 + /** 1.370 + * Ensures that the free space available in the path ref is >= size. The verb and point counts 1.371 + * are not changed. 1.372 + */ 1.373 + void makeSpace(size_t size) { 1.374 + SkDEBUGCODE(this->validate();) 1.375 + ptrdiff_t growSize = size - fFreeSpace; 1.376 + if (growSize <= 0) { 1.377 + return; 1.378 + } 1.379 + size_t oldSize = this->currSize(); 1.380 + // round to next multiple of 8 bytes 1.381 + growSize = (growSize + 7) & ~static_cast<size_t>(7); 1.382 + // we always at least double the allocation 1.383 + if (static_cast<size_t>(growSize) < oldSize) { 1.384 + growSize = oldSize; 1.385 + } 1.386 + if (growSize < kMinSize) { 1.387 + growSize = kMinSize; 1.388 + } 1.389 + size_t newSize = oldSize + growSize; 1.390 + // Note that realloc could memcpy more than we need. It seems to be a win anyway. TODO: 1.391 + // encapsulate this. 1.392 + fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize)); 1.393 + size_t oldVerbSize = fVerbCnt * sizeof(uint8_t); 1.394 + void* newVerbsDst = reinterpret_cast<void*>( 1.395 + reinterpret_cast<intptr_t>(fPoints) + newSize - oldVerbSize); 1.396 + void* oldVerbsSrc = reinterpret_cast<void*>( 1.397 + reinterpret_cast<intptr_t>(fPoints) + oldSize - oldVerbSize); 1.398 + memmove(newVerbsDst, oldVerbsSrc, oldVerbSize); 1.399 + fVerbs = reinterpret_cast<uint8_t*>(reinterpret_cast<intptr_t>(fPoints) + newSize); 1.400 + fFreeSpace += growSize; 1.401 + SkDEBUGCODE(this->validate();) 1.402 + } 1.403 + 1.404 + /** 1.405 + * Private, non-const-ptr version of the public function verbsMemBegin(). 1.406 + */ 1.407 + uint8_t* verbsMemWritable() { 1.408 + SkDEBUGCODE(this->validate();) 1.409 + return fVerbs - fVerbCnt; 1.410 + } 1.411 + 1.412 + /** 1.413 + * Gets the total amount of space allocated for verbs, points, and reserve. 1.414 + */ 1.415 + size_t currSize() const { 1.416 + return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints); 1.417 + } 1.418 + 1.419 + SkDEBUGCODE(void validate() const;) 1.420 + 1.421 + /** 1.422 + * Called the first time someone calls CreateEmpty to actually create the singleton. 1.423 + */ 1.424 + static void CreateEmptyImpl(int/*unused*/); 1.425 + 1.426 + void setIsOval(bool isOval) { fIsOval = isOval; } 1.427 + 1.428 + SkPoint* getPoints() { 1.429 + SkDEBUGCODE(this->validate();) 1.430 + fIsOval = false; 1.431 + return fPoints; 1.432 + } 1.433 + 1.434 + enum { 1.435 + kMinSize = 256, 1.436 + }; 1.437 + 1.438 + mutable SkRect fBounds; 1.439 + uint8_t fSegmentMask; 1.440 + mutable uint8_t fBoundsIsDirty; 1.441 + mutable SkBool8 fIsFinite; // only meaningful if bounds are valid 1.442 + mutable SkBool8 fIsOval; 1.443 + 1.444 + SkPoint* fPoints; // points to begining of the allocation 1.445 + uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards) 1.446 + int fVerbCnt; 1.447 + int fPointCnt; 1.448 + size_t fFreeSpace; // redundant but saves computation 1.449 + SkTDArray<SkScalar> fConicWeights; 1.450 + 1.451 + enum { 1.452 + kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. 1.453 + }; 1.454 + mutable uint32_t fGenerationID; 1.455 + SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. 1.456 + 1.457 + friend class PathRefTest_Private; 1.458 + typedef SkRefCnt INHERITED; 1.459 +}; 1.460 + 1.461 +#endif