LCOV - code coverage report
Current view: top level - gfx/skia/skia/include/core - SkPathRef.h (source / functions) Hit Total Coverage
Test: output.info Lines: 122 170 71.8 %
Date: 2017-07-14 16:53:18 Functions: 28 40 70.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13