1 2 /* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #ifndef SkPathRef_DEFINED 10 #define SkPathRef_DEFINED 11 12 #include "../private/SkTDArray.h" 13 #include "SkMatrix.h" 14 #include "SkPoint.h" 15 #include "SkRRect.h" 16 #include "SkRect.h" 17 #include "SkRefCnt.h" 18 #include <stddef.h> // ptrdiff_t 19 20 class SkRBuffer; 21 class SkWBuffer; 22 23 /** 24 * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods 25 * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an 26 * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs 27 * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's 28 * constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's 29 * constructor returns. 30 * 31 * The points and verbs are stored in a single allocation. The points are at the begining of the 32 * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points 33 * and verbs both grow into the middle of the allocation until the meet. To access verb i in the 34 * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first 35 * logical verb or the last verb in memory). 36 */ 37 38 class SK_API SkPathRef : public ::SkRefCnt { 39 public: 40 class Editor { 41 public: 42 Editor(SkAutoTUnref<SkPathRef>* pathRef, 43 int incReserveVerbs = 0, 44 int incReservePoints = 0); 45 ~Editor()46 ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } 47 48 /** 49 * Returns the array of points. 50 */ points()51 SkPoint* points() { return fPathRef->getPoints(); } points()52 const SkPoint* points() const { return fPathRef->points(); } 53 54 /** 55 * Gets the ith point. Shortcut for this->points() + i 56 */ atPoint(int i)57 SkPoint* atPoint(int i) { 58 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); 59 return this->points() + i; 60 }; atPoint(int i)61 const SkPoint* atPoint(int i) const { 62 SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); 63 return this->points() + i; 64 }; 65 66 /** 67 * Adds the verb and allocates space for the number of points indicated by the verb. The 68 * return value is a pointer to where the points for the verb should be written. 69 * 'weight' is only used if 'verb' is kConic_Verb 70 */ 71 SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) { 72 SkDEBUGCODE(fPathRef->validate();) 73 return fPathRef->growForVerb(verb, weight); 74 } 75 76 /** 77 * Allocates space for multiple instances of a particular verb and the 78 * requisite points & weights. 79 * The return pointer points at the first new point (indexed normally [<i>]). 80 * If 'verb' is kConic_Verb, 'weights' will return a pointer to the 81 * space for the conic weights (indexed normally). 82 */ 83 SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, 84 int numVbs, 85 SkScalar** weights = NULL) { 86 return fPathRef->growForRepeatedVerb(verb, numVbs, weights); 87 } 88 89 /** 90 * Resets the path ref to a new verb and point count. The new verbs and points are 91 * uninitialized. 92 */ resetToSize(int newVerbCnt,int newPointCnt,int newConicCount)93 void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { 94 fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); 95 } 96 97 /** 98 * Gets the path ref that is wrapped in the Editor. 99 */ pathRef()100 SkPathRef* pathRef() { return fPathRef; } 101 setIsOval(bool isOval)102 void setIsOval(bool isOval) { fPathRef->setIsOval(isOval); } 103 setIsRRect(bool isRRect)104 void setIsRRect(bool isRRect) { fPathRef->setIsRRect(isRRect); } 105 setBounds(const SkRect & rect)106 void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } 107 108 private: 109 SkPathRef* fPathRef; 110 }; 111 112 class SK_API Iter { 113 public: 114 Iter(); 115 Iter(const SkPathRef&); 116 117 void setPathRef(const SkPathRef&); 118 119 /** Return the next verb in this iteration of the path. When all 120 segments have been visited, return kDone_Verb. 121 122 @param pts The points representing the current verb and/or segment 123 This must not be NULL. 124 @return The verb for the current segment 125 */ 126 uint8_t next(SkPoint pts[4]); 127 uint8_t peek() const; 128 conicWeight()129 SkScalar conicWeight() const { return *fConicWeights; } 130 131 private: 132 const SkPoint* fPts; 133 const uint8_t* fVerbs; 134 const uint8_t* fVerbStop; 135 const SkScalar* fConicWeights; 136 }; 137 138 public: 139 /** 140 * Gets a path ref with no verbs or points. 141 */ 142 static SkPathRef* CreateEmpty(); 143 144 /** 145 * Returns true if all of the points in this path are finite, meaning there 146 * are no infinities and no NaNs. 147 */ isFinite()148 bool isFinite() const { 149 if (fBoundsIsDirty) { 150 this->computeBounds(); 151 } 152 return SkToBool(fIsFinite); 153 } 154 155 /** 156 * Returns a mask, where each bit corresponding to a SegmentMask is 157 * set if the path contains 1 or more segments of that type. 158 * Returns 0 for an empty path (no segments). 159 */ getSegmentMasks()160 uint32_t getSegmentMasks() const { return fSegmentMask; } 161 162 /** Returns true if the path is an oval. 163 * 164 * @param rect returns the bounding rect of this oval. It's a circle 165 * if the height and width are the same. 166 * 167 * @return true if this path is an oval. 168 * Tracking whether a path is an oval is considered an 169 * optimization for performance and so some paths that are in 170 * fact ovals can report false. 171 */ isOval(SkRect * rect)172 bool isOval(SkRect* rect) const { 173 if (fIsOval && rect) { 174 *rect = this->getBounds(); 175 } 176 177 return SkToBool(fIsOval); 178 } 179 isRRect(SkRRect * rrect)180 bool isRRect(SkRRect* rrect) const { 181 if (fIsRRect && rrect) { 182 *rrect = this->getRRect(); 183 } 184 return SkToBool(fIsRRect); 185 } 186 187 hasComputedBounds()188 bool hasComputedBounds() const { 189 return !fBoundsIsDirty; 190 } 191 192 /** Returns the bounds of the path's points. If the path contains 0 or 1 193 points, the bounds is set to (0,0,0,0), and isEmpty() will return true. 194 Note: this bounds may be larger than the actual shape, since curves 195 do not extend as far as their control points. 196 */ getBounds()197 const SkRect& getBounds() const { 198 if (fBoundsIsDirty) { 199 this->computeBounds(); 200 } 201 return fBounds; 202 } 203 204 SkRRect getRRect() const; 205 206 /** 207 * Transforms a path ref by a matrix, allocating a new one only if necessary. 208 */ 209 static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst, 210 const SkPathRef& src, 211 const SkMatrix& matrix); 212 213 static SkPathRef* CreateFromBuffer(SkRBuffer* buffer); 214 215 /** 216 * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be 217 * repopulated with approximately the same number of verbs and points. A new path ref is created 218 * only if necessary. 219 */ 220 static void Rewind(SkAutoTUnref<SkPathRef>* pathRef); 221 222 virtual ~SkPathRef(); countPoints()223 int countPoints() const { SkDEBUGCODE(this->validate();) return fPointCnt; } countVerbs()224 int countVerbs() const { SkDEBUGCODE(this->validate();) return fVerbCnt; } countWeights()225 int countWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.count(); } 226 227 /** 228 * Returns a pointer one beyond the first logical verb (last verb in memory order). 229 */ verbs()230 const uint8_t* verbs() const { SkDEBUGCODE(this->validate();) return fVerbs; } 231 232 /** 233 * Returns a const pointer to the first verb in memory (which is the last logical verb). 234 */ verbsMemBegin()235 const uint8_t* verbsMemBegin() const { return this->verbs() - fVerbCnt; } 236 237 /** 238 * Returns a const pointer to the first point. 239 */ points()240 const SkPoint* points() const { SkDEBUGCODE(this->validate();) return fPoints; } 241 242 /** 243 * Shortcut for this->points() + this->countPoints() 244 */ pointsEnd()245 const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } 246 conicWeights()247 const SkScalar* conicWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.begin(); } conicWeightsEnd()248 const SkScalar* conicWeightsEnd() const { SkDEBUGCODE(this->validate();) return fConicWeights.end(); } 249 250 /** 251 * Convenience methods for getting to a verb or point by index. 252 */ atVerb(int index)253 uint8_t atVerb(int index) const { 254 SkASSERT((unsigned) index < (unsigned) fVerbCnt); 255 return this->verbs()[~index]; 256 } atPoint(int index)257 const SkPoint& atPoint(int index) const { 258 SkASSERT((unsigned) index < (unsigned) fPointCnt); 259 return this->points()[index]; 260 } 261 262 bool operator== (const SkPathRef& ref) const; 263 264 /** 265 * Writes the path points and verbs to a buffer. 266 */ 267 void writeToBuffer(SkWBuffer* buffer) const; 268 269 /** 270 * Gets the number of bytes that would be written in writeBuffer() 271 */ 272 uint32_t writeSize() const; 273 274 void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const; 275 276 /** 277 * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the 278 * same ID then they have the same verbs and points. However, two path refs may have the same 279 * contents but different genIDs. 280 */ 281 uint32_t genID() const; 282 283 struct GenIDChangeListener { ~GenIDChangeListenerGenIDChangeListener284 virtual ~GenIDChangeListener() {} 285 virtual void onChange() = 0; 286 }; 287 288 void addGenIDChangeListener(GenIDChangeListener* listener); 289 290 SkDEBUGCODE(void validate() const;) 291 292 private: 293 enum SerializationOffsets { 294 kIsRRect_SerializationShift = 26, // requires 1 bit 295 kIsFinite_SerializationShift = 25, // requires 1 bit 296 kIsOval_SerializationShift = 24, // requires 1 bit 297 kSegmentMask_SerializationShift = 0 // requires 4 bits 298 }; 299 SkPathRef()300 SkPathRef() { 301 fBoundsIsDirty = true; // this also invalidates fIsFinite 302 fPointCnt = 0; 303 fVerbCnt = 0; 304 fVerbs = NULL; 305 fPoints = NULL; 306 fFreeSpace = 0; 307 fGenerationID = kEmptyGenID; 308 fSegmentMask = 0; 309 fIsOval = false; 310 fIsRRect = false; 311 SkDEBUGCODE(fEditorsAttached = 0;) 312 SkDEBUGCODE(this->validate();) 313 } 314 315 void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints); 316 317 // Return true if the computed bounds are finite. ComputePtBounds(SkRect * bounds,const SkPathRef & ref)318 static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { 319 return bounds->setBoundsCheck(ref.points(), ref.countPoints()); 320 } 321 322 // called, if dirty, by getBounds() computeBounds()323 void computeBounds() const { 324 SkDEBUGCODE(this->validate();) 325 // TODO(mtklein): remove fBoundsIsDirty and fIsFinite, 326 // using an inverted rect instead of fBoundsIsDirty and always recalculating fIsFinite. 327 SkASSERT(fBoundsIsDirty); 328 329 fIsFinite = ComputePtBounds(&fBounds, *this); 330 fBoundsIsDirty = false; 331 } 332 setBounds(const SkRect & rect)333 void setBounds(const SkRect& rect) { 334 SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); 335 fBounds = rect; 336 fBoundsIsDirty = false; 337 fIsFinite = fBounds.isFinite(); 338 } 339 340 /** Makes additional room but does not change the counts or change the genID */ incReserve(int additionalVerbs,int additionalPoints)341 void incReserve(int additionalVerbs, int additionalPoints) { 342 SkDEBUGCODE(this->validate();) 343 size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint); 344 this->makeSpace(space); 345 SkDEBUGCODE(this->validate();) 346 } 347 348 /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also 349 * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ 350 void resetToSize(int verbCount, int pointCount, int conicCount, 351 int reserveVerbs = 0, int reservePoints = 0) { 352 SkDEBUGCODE(this->validate();) 353 fBoundsIsDirty = true; // this also invalidates fIsFinite 354 fGenerationID = 0; 355 356 fSegmentMask = 0; 357 fIsOval = false; 358 fIsRRect = false; 359 360 size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount; 361 size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints; 362 size_t minSize = newSize + newReserve; 363 364 ptrdiff_t sizeDelta = this->currSize() - minSize; 365 366 if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) { 367 sk_free(fPoints); 368 fPoints = NULL; 369 fVerbs = NULL; 370 fFreeSpace = 0; 371 fVerbCnt = 0; 372 fPointCnt = 0; 373 this->makeSpace(minSize); 374 fVerbCnt = verbCount; 375 fPointCnt = pointCount; 376 fFreeSpace -= newSize; 377 } else { 378 fPointCnt = pointCount; 379 fVerbCnt = verbCount; 380 fFreeSpace = this->currSize() - minSize; 381 } 382 fConicWeights.setCount(conicCount); 383 SkDEBUGCODE(this->validate();) 384 } 385 386 /** 387 * Increases the verb count by numVbs and point count by the required amount. 388 * The new points are uninitialized. All the new verbs are set to the specified 389 * verb. If 'verb' is kConic_Verb, 'weights' will return a pointer to the 390 * uninitialized conic weights. 391 */ 392 SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights); 393 394 /** 395 * Increases the verb count 1, records the new verb, and creates room for the requisite number 396 * of additional points. A pointer to the first point is returned. Any new points are 397 * uninitialized. 398 */ 399 SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight); 400 401 /** 402 * Ensures that the free space available in the path ref is >= size. The verb and point counts 403 * are not changed. 404 */ makeSpace(size_t size)405 void makeSpace(size_t size) { 406 SkDEBUGCODE(this->validate();) 407 ptrdiff_t growSize = size - fFreeSpace; 408 if (growSize <= 0) { 409 return; 410 } 411 size_t oldSize = this->currSize(); 412 // round to next multiple of 8 bytes 413 growSize = (growSize + 7) & ~static_cast<size_t>(7); 414 // we always at least double the allocation 415 if (static_cast<size_t>(growSize) < oldSize) { 416 growSize = oldSize; 417 } 418 if (growSize < kMinSize) { 419 growSize = kMinSize; 420 } 421 size_t newSize = oldSize + growSize; 422 // Note that realloc could memcpy more than we need. It seems to be a win anyway. TODO: 423 // encapsulate this. 424 fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize)); 425 size_t oldVerbSize = fVerbCnt * sizeof(uint8_t); 426 void* newVerbsDst = reinterpret_cast<void*>( 427 reinterpret_cast<intptr_t>(fPoints) + newSize - oldVerbSize); 428 void* oldVerbsSrc = reinterpret_cast<void*>( 429 reinterpret_cast<intptr_t>(fPoints) + oldSize - oldVerbSize); 430 memmove(newVerbsDst, oldVerbsSrc, oldVerbSize); 431 fVerbs = reinterpret_cast<uint8_t*>(reinterpret_cast<intptr_t>(fPoints) + newSize); 432 fFreeSpace += growSize; 433 SkDEBUGCODE(this->validate();) 434 } 435 436 /** 437 * Private, non-const-ptr version of the public function verbsMemBegin(). 438 */ verbsMemWritable()439 uint8_t* verbsMemWritable() { 440 SkDEBUGCODE(this->validate();) 441 return fVerbs - fVerbCnt; 442 } 443 444 /** 445 * Gets the total amount of space allocated for verbs, points, and reserve. 446 */ currSize()447 size_t currSize() const { 448 return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints); 449 } 450 451 /** 452 * Called the first time someone calls CreateEmpty to actually create the singleton. 453 */ 454 friend SkPathRef* sk_create_empty_pathref(); 455 setIsOval(bool isOval)456 void setIsOval(bool isOval) { fIsOval = isOval; } 457 setIsRRect(bool isRRect)458 void setIsRRect(bool isRRect) { fIsRRect = isRRect; } 459 460 // called only by the editor. Note that this is not a const function. getPoints()461 SkPoint* getPoints() { 462 SkDEBUGCODE(this->validate();) 463 fIsOval = false; 464 fIsRRect = false; 465 return fPoints; 466 } 467 getPoints()468 const SkPoint* getPoints() const { 469 SkDEBUGCODE(this->validate();) 470 return fPoints; 471 } 472 473 void callGenIDChangeListeners(); 474 475 enum { 476 kMinSize = 256, 477 }; 478 479 mutable SkRect fBounds; 480 481 SkPoint* fPoints; // points to begining of the allocation 482 uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards) 483 int fVerbCnt; 484 int fPointCnt; 485 size_t fFreeSpace; // redundant but saves computation 486 SkTDArray<SkScalar> fConicWeights; 487 488 enum { 489 kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. 490 }; 491 mutable uint32_t fGenerationID; 492 SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. 493 494 SkTDArray<GenIDChangeListener*> fGenIDChangeListeners; // pointers are owned 495 496 mutable uint8_t fBoundsIsDirty; 497 mutable SkBool8 fIsFinite; // only meaningful if bounds are valid 498 499 SkBool8 fIsOval; 500 SkBool8 fIsRRect; 501 uint8_t fSegmentMask; 502 503 friend class PathRefTest_Private; 504 friend class ForceIsRRect_Private; // unit test isRRect 505 typedef SkRefCnt INHERITED; 506 }; 507 508 #endif 509