Skia
2DGraphicsLibrary
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SkPathRef.h
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/SkAtomics.h"
13 #include "../private/SkTDArray.h"
14 #include "SkMatrix.h"
15 #include "SkPoint.h"
16 #include "SkRRect.h"
17 #include "SkRect.h"
18 #include "SkRefCnt.h"
19 #include <stddef.h> // ptrdiff_t
20 
21 class SkRBuffer;
22 class SkWBuffer;
23 
39 class SK_API SkPathRef final : public SkNVRefCnt<SkPathRef> {
40 public:
41  class Editor {
42  public:
44  int incReserveVerbs = 0,
45  int incReservePoints = 0);
46 
47  ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) }
48 
52  SkPoint* points() { return fPathRef->getPoints(); }
53  const SkPoint* points() const { return fPathRef->points(); }
54 
58  SkPoint* atPoint(int i) {
59  SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
60  return this->points() + i;
61  };
62  const SkPoint* atPoint(int i) const {
63  SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
64  return this->points() + i;
65  };
66 
72  SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) {
73  SkDEBUGCODE(fPathRef->validate();)
74  return fPathRef->growForVerb(verb, weight);
75  }
76 
84  SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb,
85  int numVbs,
86  SkScalar** weights = NULL) {
87  return fPathRef->growForRepeatedVerb(verb, numVbs, weights);
88  }
89 
94  void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) {
95  fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount);
96  }
97 
101  SkPathRef* pathRef() { return fPathRef; }
102 
103  void setIsOval(bool isOval, bool isCCW, unsigned start) {
104  fPathRef->setIsOval(isOval, isCCW, start);
105  }
106 
107  void setIsRRect(bool isRRect, bool isCCW, unsigned start) {
108  fPathRef->setIsRRect(isRRect, isCCW, start);
109  }
110 
111  void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); }
112 
113  private:
114  SkPathRef* fPathRef;
115  };
116 
117  class SK_API Iter {
118  public:
119  Iter();
120  Iter(const SkPathRef&);
121 
122  void setPathRef(const SkPathRef&);
123 
131  uint8_t next(SkPoint pts[4]);
132  uint8_t peek() const;
133 
134  SkScalar conicWeight() const { return *fConicWeights; }
135 
136  private:
137  const SkPoint* fPts;
138  const uint8_t* fVerbs;
139  const uint8_t* fVerbStop;
140  const SkScalar* fConicWeights;
141  };
142 
143 public:
147  static SkPathRef* CreateEmpty();
148 
153  bool isFinite() const {
154  if (fBoundsIsDirty) {
155  this->computeBounds();
156  }
157  return SkToBool(fIsFinite);
158  }
159 
165  uint32_t getSegmentMasks() const { return fSegmentMask; }
166 
180  bool isOval(SkRect* rect, bool* isCCW, unsigned* start) const {
181  if (fIsOval) {
182  if (rect) {
183  *rect = this->getBounds();
184  }
185  if (isCCW) {
186  *isCCW = SkToBool(fRRectOrOvalIsCCW);
187  }
188  if (start) {
189  *start = fRRectOrOvalStartIdx;
190  }
191  }
192 
193  return SkToBool(fIsOval);
194  }
195 
196  bool isRRect(SkRRect* rrect, bool* isCCW, unsigned* start) const {
197  if (fIsRRect) {
198  if (rrect) {
199  *rrect = this->getRRect();
200  }
201  if (isCCW) {
202  *isCCW = SkToBool(fRRectOrOvalIsCCW);
203  }
204  if (start) {
205  *start = fRRectOrOvalStartIdx;
206  }
207  }
208  return SkToBool(fIsRRect);
209  }
210 
211 
212  bool hasComputedBounds() const {
213  return !fBoundsIsDirty;
214  }
215 
221  const SkRect& getBounds() const {
222  if (fBoundsIsDirty) {
223  this->computeBounds();
224  }
225  return fBounds;
226  }
227 
228  SkRRect getRRect() const;
229 
233  static void CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
234  const SkPathRef& src,
235  const SkMatrix& matrix);
236 
237  static SkPathRef* CreateFromBuffer(SkRBuffer* buffer);
238 
244  static void Rewind(SkAutoTUnref<SkPathRef>* pathRef);
245 
246  ~SkPathRef();
247  int countPoints() const { SkDEBUGCODE(this->validate();) return fPointCnt; }
248  int countVerbs() const { SkDEBUGCODE(this->validate();) return fVerbCnt; }
249  int countWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.count(); }
250 
254  const uint8_t* verbs() const { SkDEBUGCODE(this->validate();) return fVerbs; }
255 
259  const uint8_t* verbsMemBegin() const { return this->verbs() - fVerbCnt; }
260 
264  const SkPoint* points() const { SkDEBUGCODE(this->validate();) return fPoints; }
265 
269  const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); }
270 
271  const SkScalar* conicWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.begin(); }
272  const SkScalar* conicWeightsEnd() const { SkDEBUGCODE(this->validate();) return fConicWeights.end(); }
273 
277  uint8_t atVerb(int index) const {
278  SkASSERT((unsigned) index < (unsigned) fVerbCnt);
279  return this->verbs()[~index];
280  }
281  const SkPoint& atPoint(int index) const {
282  SkASSERT((unsigned) index < (unsigned) fPointCnt);
283  return this->points()[index];
284  }
285 
286  bool operator== (const SkPathRef& ref) const;
287 
291  void writeToBuffer(SkWBuffer* buffer) const;
292 
296  uint32_t writeSize() const;
297 
298  void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const;
299 
305  uint32_t genID() const;
306 
308  virtual ~GenIDChangeListener() {}
309  virtual void onChange() = 0;
310  };
311 
312  void addGenIDChangeListener(GenIDChangeListener* listener);
313 
314  SkDEBUGCODE(void validate() const;)
315 
316 private:
317  enum SerializationOffsets {
318  kRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits
319  kRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit
320  kIsRRect_SerializationShift = 26, // requires 1 bit
321  kIsFinite_SerializationShift = 25, // requires 1 bit
322  kIsOval_SerializationShift = 24, // requires 1 bit
323  kSegmentMask_SerializationShift = 0 // requires 4 bits
324  };
325 
326  SkPathRef() {
327  fBoundsIsDirty = true; // this also invalidates fIsFinite
328  fPointCnt = 0;
329  fVerbCnt = 0;
330  fVerbs = NULL;
331  fPoints = NULL;
332  fFreeSpace = 0;
333  fGenerationID = kEmptyGenID;
334  fSegmentMask = 0;
335  fIsOval = false;
336  fIsRRect = false;
337  // The next two values don't matter unless fIsOval or fIsRRect are true.
338  fRRectOrOvalIsCCW = false;
339  fRRectOrOvalStartIdx = 0xAC;
340  SkDEBUGCODE(fEditorsAttached = 0;)
341  SkDEBUGCODE(this->validate();)
342  }
343 
344  void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints);
345 
346  // Return true if the computed bounds are finite.
347  static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) {
348  return bounds->setBoundsCheck(ref.points(), ref.countPoints());
349  }
350 
351  // called, if dirty, by getBounds()
352  void computeBounds() const {
353  SkDEBUGCODE(this->validate();)
354  // TODO(mtklein): remove fBoundsIsDirty and fIsFinite,
355  // using an inverted rect instead of fBoundsIsDirty and always recalculating fIsFinite.
356  SkASSERT(fBoundsIsDirty);
357 
358  fIsFinite = ComputePtBounds(&fBounds, *this);
359  fBoundsIsDirty = false;
360  }
361 
362  void setBounds(const SkRect& rect) {
363  SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom);
364  fBounds = rect;
365  fBoundsIsDirty = false;
366  fIsFinite = fBounds.isFinite();
367  }
368 
370  void incReserve(int additionalVerbs, int additionalPoints) {
371  SkDEBUGCODE(this->validate();)
372  size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint);
373  this->makeSpace(space);
374  SkDEBUGCODE(this->validate();)
375  }
376 
379  void resetToSize(int verbCount, int pointCount, int conicCount,
380  int reserveVerbs = 0, int reservePoints = 0) {
381  SkDEBUGCODE(this->validate();)
382  fBoundsIsDirty = true; // this also invalidates fIsFinite
383  fGenerationID = 0;
384 
385  fSegmentMask = 0;
386  fIsOval = false;
387  fIsRRect = false;
388 
389  size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount;
390  size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints;
391  size_t minSize = newSize + newReserve;
392 
393  ptrdiff_t sizeDelta = this->currSize() - minSize;
394 
395  if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) {
396  sk_free(fPoints);
397  fPoints = NULL;
398  fVerbs = NULL;
399  fFreeSpace = 0;
400  fVerbCnt = 0;
401  fPointCnt = 0;
402  this->makeSpace(minSize);
403  fVerbCnt = verbCount;
404  fPointCnt = pointCount;
405  fFreeSpace -= newSize;
406  } else {
407  fPointCnt = pointCount;
408  fVerbCnt = verbCount;
409  fFreeSpace = this->currSize() - minSize;
410  }
411  fConicWeights.setCount(conicCount);
412  SkDEBUGCODE(this->validate();)
413  }
414 
421  SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights);
422 
428  SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight);
429 
434  void makeSpace(size_t size) {
435  SkDEBUGCODE(this->validate();)
436  ptrdiff_t growSize = size - fFreeSpace;
437  if (growSize <= 0) {
438  return;
439  }
440  size_t oldSize = this->currSize();
441  // round to next multiple of 8 bytes
442  growSize = (growSize + 7) & ~static_cast<size_t>(7);
443  // we always at least double the allocation
444  if (static_cast<size_t>(growSize) < oldSize) {
445  growSize = oldSize;
446  }
447  if (growSize < kMinSize) {
448  growSize = kMinSize;
449  }
450  size_t newSize = oldSize + growSize;
451  // Note that realloc could memcpy more than we need. It seems to be a win anyway. TODO:
452  // encapsulate this.
453  fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize));
454  size_t oldVerbSize = fVerbCnt * sizeof(uint8_t);
455  void* newVerbsDst = reinterpret_cast<void*>(
456  reinterpret_cast<intptr_t>(fPoints) + newSize - oldVerbSize);
457  void* oldVerbsSrc = reinterpret_cast<void*>(
458  reinterpret_cast<intptr_t>(fPoints) + oldSize - oldVerbSize);
459  memmove(newVerbsDst, oldVerbsSrc, oldVerbSize);
460  fVerbs = reinterpret_cast<uint8_t*>(reinterpret_cast<intptr_t>(fPoints) + newSize);
461  fFreeSpace += growSize;
462  SkDEBUGCODE(this->validate();)
463  }
464 
468  uint8_t* verbsMemWritable() {
469  SkDEBUGCODE(this->validate();)
470  return fVerbs - fVerbCnt;
471  }
472 
476  size_t currSize() const {
477  return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints);
478  }
479 
483  friend SkPathRef* sk_create_empty_pathref();
484 
485  void setIsOval(bool isOval, bool isCCW, unsigned start) {
486  fIsOval = isOval;
487  fRRectOrOvalIsCCW = isCCW;
488  fRRectOrOvalStartIdx = start;
489  }
490 
491  void setIsRRect(bool isRRect, bool isCCW, unsigned start) {
492  fIsRRect = isRRect;
493  fRRectOrOvalIsCCW = isCCW;
494  fRRectOrOvalStartIdx = start;
495  }
496 
497  // called only by the editor. Note that this is not a const function.
498  SkPoint* getPoints() {
499  SkDEBUGCODE(this->validate();)
500  fIsOval = false;
501  fIsRRect = false;
502  return fPoints;
503  }
504 
505  const SkPoint* getPoints() const {
506  SkDEBUGCODE(this->validate();)
507  return fPoints;
508  }
509 
510  void callGenIDChangeListeners();
511 
512  enum {
513  kMinSize = 256,
514  };
515 
516  mutable SkRect fBounds;
517 
518  SkPoint* fPoints; // points to begining of the allocation
519  uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards)
520  int fVerbCnt;
521  int fPointCnt;
522  size_t fFreeSpace; // redundant but saves computation
523  SkTDArray<SkScalar> fConicWeights;
524 
525  enum {
526  kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs.
527  };
528  mutable uint32_t fGenerationID;
529  SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time.
530 
531  SkTDArray<GenIDChangeListener*> fGenIDChangeListeners; // pointers are owned
532 
533  mutable uint8_t fBoundsIsDirty;
534  mutable SkBool8 fIsFinite; // only meaningful if bounds are valid
535 
536  SkBool8 fIsOval;
537  SkBool8 fIsRRect;
538  // Both the circle and rrect special cases have a notion of direction and starting point
539  // The next two variables store that information for either.
540  SkBool8 fRRectOrOvalIsCCW;
541  uint8_t fRRectOrOvalStartIdx;
542  uint8_t fSegmentMask;
543 
544  friend class PathRefTest_Private;
545  friend class ForceIsRRect_Private; // unit test isRRect
546 };
547 
548 #endif
The SkRRect class represents a rounded rect with a potentially different radii for each corner...
Definition: SkRRect.h:48
Definition: SkPathRef.h:41
uint8_t atVerb(int index) const
Convenience methods for getting to a verb or point by index.
Definition: SkPathRef.h:277
const SkRect & getBounds() const
Returns the bounds of the path's points.
Definition: SkPathRef.h:221
bool isFinite() const
Returns true if all of the points in this path are finite, meaning there are no infinities and no NaN...
Definition: SkPathRef.h:153
void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount)
Resets the path ref to a new verb and point count.
Definition: SkPathRef.h:94
SkPoint * atPoint(int i)
Gets the ith point.
Definition: SkPathRef.h:58
Definition: SkPoint.h:156
bool isOval(SkRect *rect, bool *isCCW, unsigned *start) const
Returns true if the path is an oval.
Definition: SkPathRef.h:180
The SkMatrix class holds a 3x3 matrix for transforming coordinates.
Definition: SkMatrix.h:26
uint8_t SkBool8
Meant to be a small version of bool, for storage purposes.
Definition: SkTypes.h:268
bool isFinite() const
Returns true iff all values in the rect are finite.
Definition: SkRect.h:465
Holds the path verbs and points.
Definition: SkPathRef.h:39
SK_API void sk_free(void *)
Free memory returned by sk_malloc().
SkPoint * points()
Returns the array of points.
Definition: SkPathRef.h:52
#define SkToBool(cond)
Returns 0 or 1 based on the condition.
Definition: SkTypes.h:287
void incReserve(int additionalVerbs, int additionalPoints)
Makes additional room but does not change the counts or change the genID.
Definition: SkPathRef.h:370
Definition: SkPathRef.h:307
void makeSpace(size_t size)
Ensures that the free space available in the path ref is >= size.
Definition: SkPathRef.h:434
uint32_t getSegmentMasks() const
Returns a mask, where each bit corresponding to a SegmentMask is set if the path contains 1 or more s...
Definition: SkPathRef.h:165
const uint8_t * verbsMemBegin() const
Returns a const pointer to the first verb in memory (which is the last logical verb).
Definition: SkPathRef.h:259
SkPoint * growForRepeatedVerb(intverb, int numVbs, SkScalar **weights=NULL)
Allocates space for multiple instances of a particular verb and the requisite points & weights...
Definition: SkPathRef.h:84
SkPoint * growForVerb(intverb, SkScalar weight=0)
Adds the verb and allocates space for the number of points indicated by the verb. ...
Definition: SkPathRef.h:72
Definition: SkPathRef.h:117
Definition: SkRect.h:390
SkPathRef * pathRef()
Gets the path ref that is wrapped in the Editor.
Definition: SkPathRef.h:101
const SkPoint * points() const
Returns a const pointer to the first point.
Definition: SkPathRef.h:264
const SkPoint * pointsEnd() const
Shortcut for this->points() + this->countPoints()
Definition: SkPathRef.h:269
SK_API void * sk_realloc_throw(void *buffer, size_t size)
Same as standard realloc(), but this one never returns null on failure.
Definition: SkRefCnt.h:221
bool setBoundsCheck(const SkPoint pts[], int count)
Compute the bounds of the array of points, and set this rect to that bounds and return true...
const uint8_t * verbs() const
Returns a pointer one beyond the first logical verb (last verb in memory order).
Definition: SkPathRef.h:254
uint8_t * verbsMemWritable()
Private, non-const-ptr version of the public function verbsMemBegin().
Definition: SkPathRef.h:468
size_t currSize() const
Gets the total amount of space allocated for verbs, points, and reserve.
Definition: SkPathRef.h:476
void resetToSize(int verbCount, int pointCount, int conicCount, int reserveVerbs=0, int reservePoints=0)
Resets the path ref with verbCount verbs and pointCount points, all uninitialized.
Definition: SkPathRef.h:379