SkPathRef.h 20 KB

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