1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2012 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkPathRef_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkPathRef_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkArc.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkIDChangeListener.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkSpan_impl.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h" 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker #include <atomic> 24*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 25*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 26*c8dee2aaSAndroid Build Coastguard Worker #include <tuple> 27*c8dee2aaSAndroid Build Coastguard Worker 28*c8dee2aaSAndroid Build Coastguard Worker class SkMatrix; 29*c8dee2aaSAndroid Build Coastguard Worker class SkRRect; 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker /** 32*c8dee2aaSAndroid Build Coastguard Worker * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods 33*c8dee2aaSAndroid Build Coastguard Worker * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an 34*c8dee2aaSAndroid Build Coastguard Worker * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs 35*c8dee2aaSAndroid Build Coastguard Worker * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's 36*c8dee2aaSAndroid Build Coastguard Worker * constructor a pointer to a sk_sp<SkPathRef>, which may be updated to point to a new SkPathRef 37*c8dee2aaSAndroid Build Coastguard Worker * after the editor's constructor returns. 38*c8dee2aaSAndroid Build Coastguard Worker * 39*c8dee2aaSAndroid Build Coastguard Worker * The points and verbs are stored in a single allocation. The points are at the begining of the 40*c8dee2aaSAndroid Build Coastguard Worker * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points 41*c8dee2aaSAndroid Build Coastguard Worker * and verbs both grow into the middle of the allocation until the meet. To access verb i in the 42*c8dee2aaSAndroid Build Coastguard Worker * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first 43*c8dee2aaSAndroid Build Coastguard Worker * logical verb or the last verb in memory). 44*c8dee2aaSAndroid Build Coastguard Worker */ 45*c8dee2aaSAndroid Build Coastguard Worker 46*c8dee2aaSAndroid Build Coastguard Worker class SK_API SkPathRef final : public SkNVRefCnt<SkPathRef> { 47*c8dee2aaSAndroid Build Coastguard Worker public: 48*c8dee2aaSAndroid Build Coastguard Worker // See https://bugs.chromium.org/p/skia/issues/detail?id=13817 for how these sizes were 49*c8dee2aaSAndroid Build Coastguard Worker // determined. 50*c8dee2aaSAndroid Build Coastguard Worker using PointsArray = skia_private::STArray<4, SkPoint>; 51*c8dee2aaSAndroid Build Coastguard Worker using VerbsArray = skia_private::STArray<4, uint8_t>; 52*c8dee2aaSAndroid Build Coastguard Worker using ConicWeightsArray = skia_private::STArray<2, SkScalar>; 53*c8dee2aaSAndroid Build Coastguard Worker 54*c8dee2aaSAndroid Build Coastguard Worker enum class PathType : uint8_t { 55*c8dee2aaSAndroid Build Coastguard Worker kGeneral, 56*c8dee2aaSAndroid Build Coastguard Worker kOval, 57*c8dee2aaSAndroid Build Coastguard Worker kRRect, 58*c8dee2aaSAndroid Build Coastguard Worker kArc, 59*c8dee2aaSAndroid Build Coastguard Worker }; 60*c8dee2aaSAndroid Build Coastguard Worker SkPathRef(SkSpan<const SkPoint> points,SkSpan<const uint8_t> verbs,SkSpan<const SkScalar> weights,unsigned segmentMask)61*c8dee2aaSAndroid Build Coastguard Worker SkPathRef(SkSpan<const SkPoint> points, SkSpan<const uint8_t> verbs, 62*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkScalar> weights, unsigned segmentMask) 63*c8dee2aaSAndroid Build Coastguard Worker : fPoints(points) 64*c8dee2aaSAndroid Build Coastguard Worker , fVerbs(verbs) 65*c8dee2aaSAndroid Build Coastguard Worker , fConicWeights(weights) 66*c8dee2aaSAndroid Build Coastguard Worker { 67*c8dee2aaSAndroid Build Coastguard Worker fBoundsIsDirty = true; // this also invalidates fIsFinite 68*c8dee2aaSAndroid Build Coastguard Worker fGenerationID = 0; // recompute 69*c8dee2aaSAndroid Build Coastguard Worker fSegmentMask = segmentMask; 70*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kGeneral; 71*c8dee2aaSAndroid Build Coastguard Worker // The next two values don't matter unless fType is kOval or kRRect 72*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalIsCCW = false; 73*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalStartIdx = 0xAC; 74*c8dee2aaSAndroid Build Coastguard Worker fArcOval.setEmpty(); 75*c8dee2aaSAndroid Build Coastguard Worker fArcStartAngle = fArcSweepAngle = 0.0f; 76*c8dee2aaSAndroid Build Coastguard Worker fArcType = SkArc::Type::kArc; 77*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fEditorsAttached.store(0);) 78*c8dee2aaSAndroid Build Coastguard Worker 79*c8dee2aaSAndroid Build Coastguard Worker this->computeBounds(); // do this now, before we worry about multiple owners/threads 80*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 81*c8dee2aaSAndroid Build Coastguard Worker } 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker class Editor { 84*c8dee2aaSAndroid Build Coastguard Worker public: 85*c8dee2aaSAndroid Build Coastguard Worker Editor(sk_sp<SkPathRef>* pathRef, 86*c8dee2aaSAndroid Build Coastguard Worker int incReserveVerbs = 0, 87*c8dee2aaSAndroid Build Coastguard Worker int incReservePoints = 0, 88*c8dee2aaSAndroid Build Coastguard Worker int incReserveConics = 0); 89*c8dee2aaSAndroid Build Coastguard Worker ~Editor()90*c8dee2aaSAndroid Build Coastguard Worker ~Editor() { SkDEBUGCODE(fPathRef->fEditorsAttached--;) } 91*c8dee2aaSAndroid Build Coastguard Worker 92*c8dee2aaSAndroid Build Coastguard Worker /** 93*c8dee2aaSAndroid Build Coastguard Worker * Returns the array of points. 94*c8dee2aaSAndroid Build Coastguard Worker */ writablePoints()95*c8dee2aaSAndroid Build Coastguard Worker SkPoint* writablePoints() { return fPathRef->getWritablePoints(); } points()96*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* points() const { return fPathRef->points(); } 97*c8dee2aaSAndroid Build Coastguard Worker 98*c8dee2aaSAndroid Build Coastguard Worker /** 99*c8dee2aaSAndroid Build Coastguard Worker * Gets the ith point. Shortcut for this->points() + i 100*c8dee2aaSAndroid Build Coastguard Worker */ atPoint(int i)101*c8dee2aaSAndroid Build Coastguard Worker SkPoint* atPoint(int i) { return fPathRef->getWritablePoints() + i; } atPoint(int i)102*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* atPoint(int i) const { return &fPathRef->fPoints[i]; } 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker /** 105*c8dee2aaSAndroid Build Coastguard Worker * Adds the verb and allocates space for the number of points indicated by the verb. The 106*c8dee2aaSAndroid Build Coastguard Worker * return value is a pointer to where the points for the verb should be written. 107*c8dee2aaSAndroid Build Coastguard Worker * 'weight' is only used if 'verb' is kConic_Verb 108*c8dee2aaSAndroid Build Coastguard Worker */ 109*c8dee2aaSAndroid Build Coastguard Worker SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) { 110*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fPathRef->validate();) 111*c8dee2aaSAndroid Build Coastguard Worker return fPathRef->growForVerb(verb, weight); 112*c8dee2aaSAndroid Build Coastguard Worker } 113*c8dee2aaSAndroid Build Coastguard Worker 114*c8dee2aaSAndroid Build Coastguard Worker /** 115*c8dee2aaSAndroid Build Coastguard Worker * Allocates space for multiple instances of a particular verb and the 116*c8dee2aaSAndroid Build Coastguard Worker * requisite points & weights. 117*c8dee2aaSAndroid Build Coastguard Worker * The return pointer points at the first new point (indexed normally [<i>]). 118*c8dee2aaSAndroid Build Coastguard Worker * If 'verb' is kConic_Verb, 'weights' will return a pointer to the 119*c8dee2aaSAndroid Build Coastguard Worker * space for the conic weights (indexed normally). 120*c8dee2aaSAndroid Build Coastguard Worker */ 121*c8dee2aaSAndroid Build Coastguard Worker SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, 122*c8dee2aaSAndroid Build Coastguard Worker int numVbs, 123*c8dee2aaSAndroid Build Coastguard Worker SkScalar** weights = nullptr) { 124*c8dee2aaSAndroid Build Coastguard Worker return fPathRef->growForRepeatedVerb(verb, numVbs, weights); 125*c8dee2aaSAndroid Build Coastguard Worker } 126*c8dee2aaSAndroid Build Coastguard Worker 127*c8dee2aaSAndroid Build Coastguard Worker /** 128*c8dee2aaSAndroid Build Coastguard Worker * Concatenates all verbs from 'path' onto the pathRef's verbs array. Increases the point 129*c8dee2aaSAndroid Build Coastguard Worker * count by the number of points in 'path', and the conic weight count by the number of 130*c8dee2aaSAndroid Build Coastguard Worker * conics in 'path'. 131*c8dee2aaSAndroid Build Coastguard Worker * 132*c8dee2aaSAndroid Build Coastguard Worker * Returns pointers to the uninitialized points and conic weights data. 133*c8dee2aaSAndroid Build Coastguard Worker */ growForVerbsInPath(const SkPathRef & path)134*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkPoint*, SkScalar*> growForVerbsInPath(const SkPathRef& path) { 135*c8dee2aaSAndroid Build Coastguard Worker return fPathRef->growForVerbsInPath(path); 136*c8dee2aaSAndroid Build Coastguard Worker } 137*c8dee2aaSAndroid Build Coastguard Worker 138*c8dee2aaSAndroid Build Coastguard Worker /** 139*c8dee2aaSAndroid Build Coastguard Worker * Resets the path ref to a new verb and point count. The new verbs and points are 140*c8dee2aaSAndroid Build Coastguard Worker * uninitialized. 141*c8dee2aaSAndroid Build Coastguard Worker */ resetToSize(int newVerbCnt,int newPointCnt,int newConicCount)142*c8dee2aaSAndroid Build Coastguard Worker void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { 143*c8dee2aaSAndroid Build Coastguard Worker fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); 144*c8dee2aaSAndroid Build Coastguard Worker } 145*c8dee2aaSAndroid Build Coastguard Worker 146*c8dee2aaSAndroid Build Coastguard Worker /** 147*c8dee2aaSAndroid Build Coastguard Worker * Gets the path ref that is wrapped in the Editor. 148*c8dee2aaSAndroid Build Coastguard Worker */ pathRef()149*c8dee2aaSAndroid Build Coastguard Worker SkPathRef* pathRef() { return fPathRef; } 150*c8dee2aaSAndroid Build Coastguard Worker setIsOval(bool isCCW,unsigned start)151*c8dee2aaSAndroid Build Coastguard Worker void setIsOval(bool isCCW, unsigned start) { 152*c8dee2aaSAndroid Build Coastguard Worker fPathRef->setIsOval(isCCW, start); 153*c8dee2aaSAndroid Build Coastguard Worker } 154*c8dee2aaSAndroid Build Coastguard Worker setIsRRect(bool isCCW,unsigned start)155*c8dee2aaSAndroid Build Coastguard Worker void setIsRRect(bool isCCW, unsigned start) { 156*c8dee2aaSAndroid Build Coastguard Worker fPathRef->setIsRRect(isCCW, start); 157*c8dee2aaSAndroid Build Coastguard Worker } 158*c8dee2aaSAndroid Build Coastguard Worker setIsArc(const SkArc & arc)159*c8dee2aaSAndroid Build Coastguard Worker void setIsArc(const SkArc& arc) { 160*c8dee2aaSAndroid Build Coastguard Worker fPathRef->setIsArc(arc); 161*c8dee2aaSAndroid Build Coastguard Worker } 162*c8dee2aaSAndroid Build Coastguard Worker setBounds(const SkRect & rect)163*c8dee2aaSAndroid Build Coastguard Worker void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } 164*c8dee2aaSAndroid Build Coastguard Worker 165*c8dee2aaSAndroid Build Coastguard Worker private: 166*c8dee2aaSAndroid Build Coastguard Worker SkPathRef* fPathRef; 167*c8dee2aaSAndroid Build Coastguard Worker }; 168*c8dee2aaSAndroid Build Coastguard Worker 169*c8dee2aaSAndroid Build Coastguard Worker class SK_API Iter { 170*c8dee2aaSAndroid Build Coastguard Worker public: 171*c8dee2aaSAndroid Build Coastguard Worker Iter(); 172*c8dee2aaSAndroid Build Coastguard Worker Iter(const SkPathRef&); 173*c8dee2aaSAndroid Build Coastguard Worker 174*c8dee2aaSAndroid Build Coastguard Worker void setPathRef(const SkPathRef&); 175*c8dee2aaSAndroid Build Coastguard Worker 176*c8dee2aaSAndroid Build Coastguard Worker /** Return the next verb in this iteration of the path. When all 177*c8dee2aaSAndroid Build Coastguard Worker segments have been visited, return kDone_Verb. 178*c8dee2aaSAndroid Build Coastguard Worker 179*c8dee2aaSAndroid Build Coastguard Worker If any point in the path is non-finite, return kDone_Verb immediately. 180*c8dee2aaSAndroid Build Coastguard Worker 181*c8dee2aaSAndroid Build Coastguard Worker @param pts The points representing the current verb and/or segment 182*c8dee2aaSAndroid Build Coastguard Worker This must not be NULL. 183*c8dee2aaSAndroid Build Coastguard Worker @return The verb for the current segment 184*c8dee2aaSAndroid Build Coastguard Worker */ 185*c8dee2aaSAndroid Build Coastguard Worker uint8_t next(SkPoint pts[4]); 186*c8dee2aaSAndroid Build Coastguard Worker uint8_t peek() const; 187*c8dee2aaSAndroid Build Coastguard Worker conicWeight()188*c8dee2aaSAndroid Build Coastguard Worker SkScalar conicWeight() const { return *fConicWeights; } 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker private: 191*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* fPts; 192*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* fVerbs; 193*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* fVerbStop; 194*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* fConicWeights; 195*c8dee2aaSAndroid Build Coastguard Worker }; 196*c8dee2aaSAndroid Build Coastguard Worker 197*c8dee2aaSAndroid Build Coastguard Worker public: 198*c8dee2aaSAndroid Build Coastguard Worker /** 199*c8dee2aaSAndroid Build Coastguard Worker * Gets a path ref with no verbs or points. 200*c8dee2aaSAndroid Build Coastguard Worker */ 201*c8dee2aaSAndroid Build Coastguard Worker static SkPathRef* CreateEmpty(); 202*c8dee2aaSAndroid Build Coastguard Worker 203*c8dee2aaSAndroid Build Coastguard Worker /** 204*c8dee2aaSAndroid Build Coastguard Worker * Returns true if all of the points in this path are finite, meaning there 205*c8dee2aaSAndroid Build Coastguard Worker * are no infinities and no NaNs. 206*c8dee2aaSAndroid Build Coastguard Worker */ isFinite()207*c8dee2aaSAndroid Build Coastguard Worker bool isFinite() const { 208*c8dee2aaSAndroid Build Coastguard Worker if (fBoundsIsDirty) { 209*c8dee2aaSAndroid Build Coastguard Worker this->computeBounds(); 210*c8dee2aaSAndroid Build Coastguard Worker } 211*c8dee2aaSAndroid Build Coastguard Worker return SkToBool(fIsFinite); 212*c8dee2aaSAndroid Build Coastguard Worker } 213*c8dee2aaSAndroid Build Coastguard Worker 214*c8dee2aaSAndroid Build Coastguard Worker /** 215*c8dee2aaSAndroid Build Coastguard Worker * Returns a mask, where each bit corresponding to a SegmentMask is 216*c8dee2aaSAndroid Build Coastguard Worker * set if the path contains 1 or more segments of that type. 217*c8dee2aaSAndroid Build Coastguard Worker * Returns 0 for an empty path (no segments). 218*c8dee2aaSAndroid Build Coastguard Worker */ getSegmentMasks()219*c8dee2aaSAndroid Build Coastguard Worker uint32_t getSegmentMasks() const { return fSegmentMask; } 220*c8dee2aaSAndroid Build Coastguard Worker 221*c8dee2aaSAndroid Build Coastguard Worker /** Returns true if the path is an oval. 222*c8dee2aaSAndroid Build Coastguard Worker * 223*c8dee2aaSAndroid Build Coastguard Worker * @param rect returns the bounding rect of this oval. It's a circle 224*c8dee2aaSAndroid Build Coastguard Worker * if the height and width are the same. 225*c8dee2aaSAndroid Build Coastguard Worker * @param isCCW is the oval CCW (or CW if false). 226*c8dee2aaSAndroid Build Coastguard Worker * @param start indicates where the contour starts on the oval (see 227*c8dee2aaSAndroid Build Coastguard Worker * SkPath::addOval for intepretation of the index). 228*c8dee2aaSAndroid Build Coastguard Worker * 229*c8dee2aaSAndroid Build Coastguard Worker * @return true if this path is an oval. 230*c8dee2aaSAndroid Build Coastguard Worker * Tracking whether a path is an oval is considered an 231*c8dee2aaSAndroid Build Coastguard Worker * optimization for performance and so some paths that are in 232*c8dee2aaSAndroid Build Coastguard Worker * fact ovals can report false. 233*c8dee2aaSAndroid Build Coastguard Worker */ isOval(SkRect * rect,bool * isCCW,unsigned * start)234*c8dee2aaSAndroid Build Coastguard Worker bool isOval(SkRect* rect, bool* isCCW, unsigned* start) const { 235*c8dee2aaSAndroid Build Coastguard Worker if (fType == PathType::kOval) { 236*c8dee2aaSAndroid Build Coastguard Worker if (rect) { 237*c8dee2aaSAndroid Build Coastguard Worker *rect = this->getBounds(); 238*c8dee2aaSAndroid Build Coastguard Worker } 239*c8dee2aaSAndroid Build Coastguard Worker if (isCCW) { 240*c8dee2aaSAndroid Build Coastguard Worker *isCCW = SkToBool(fRRectOrOvalIsCCW); 241*c8dee2aaSAndroid Build Coastguard Worker } 242*c8dee2aaSAndroid Build Coastguard Worker if (start) { 243*c8dee2aaSAndroid Build Coastguard Worker *start = fRRectOrOvalStartIdx; 244*c8dee2aaSAndroid Build Coastguard Worker } 245*c8dee2aaSAndroid Build Coastguard Worker } 246*c8dee2aaSAndroid Build Coastguard Worker 247*c8dee2aaSAndroid Build Coastguard Worker return fType == PathType::kOval; 248*c8dee2aaSAndroid Build Coastguard Worker } 249*c8dee2aaSAndroid Build Coastguard Worker 250*c8dee2aaSAndroid Build Coastguard Worker bool isRRect(SkRRect* rrect, bool* isCCW, unsigned* start) const; 251*c8dee2aaSAndroid Build Coastguard Worker isArc(SkArc * arc)252*c8dee2aaSAndroid Build Coastguard Worker bool isArc(SkArc* arc) const { 253*c8dee2aaSAndroid Build Coastguard Worker if (fType == PathType::kArc) { 254*c8dee2aaSAndroid Build Coastguard Worker if (arc) { 255*c8dee2aaSAndroid Build Coastguard Worker *arc = SkArc::Make(fArcOval, fArcStartAngle, fArcSweepAngle, fArcType); 256*c8dee2aaSAndroid Build Coastguard Worker } 257*c8dee2aaSAndroid Build Coastguard Worker } 258*c8dee2aaSAndroid Build Coastguard Worker 259*c8dee2aaSAndroid Build Coastguard Worker return fType == PathType::kArc; 260*c8dee2aaSAndroid Build Coastguard Worker } 261*c8dee2aaSAndroid Build Coastguard Worker hasComputedBounds()262*c8dee2aaSAndroid Build Coastguard Worker bool hasComputedBounds() const { 263*c8dee2aaSAndroid Build Coastguard Worker return !fBoundsIsDirty; 264*c8dee2aaSAndroid Build Coastguard Worker } 265*c8dee2aaSAndroid Build Coastguard Worker 266*c8dee2aaSAndroid Build Coastguard Worker /** Returns the bounds of the path's points. If the path contains 0 or 1 267*c8dee2aaSAndroid Build Coastguard Worker points, the bounds is set to (0,0,0,0), and isEmpty() will return true. 268*c8dee2aaSAndroid Build Coastguard Worker Note: this bounds may be larger than the actual shape, since curves 269*c8dee2aaSAndroid Build Coastguard Worker do not extend as far as their control points. 270*c8dee2aaSAndroid Build Coastguard Worker */ getBounds()271*c8dee2aaSAndroid Build Coastguard Worker const SkRect& getBounds() const { 272*c8dee2aaSAndroid Build Coastguard Worker if (fBoundsIsDirty) { 273*c8dee2aaSAndroid Build Coastguard Worker this->computeBounds(); 274*c8dee2aaSAndroid Build Coastguard Worker } 275*c8dee2aaSAndroid Build Coastguard Worker return fBounds; 276*c8dee2aaSAndroid Build Coastguard Worker } 277*c8dee2aaSAndroid Build Coastguard Worker 278*c8dee2aaSAndroid Build Coastguard Worker SkRRect getRRect() const; 279*c8dee2aaSAndroid Build Coastguard Worker 280*c8dee2aaSAndroid Build Coastguard Worker /** 281*c8dee2aaSAndroid Build Coastguard Worker * Transforms a path ref by a matrix, allocating a new one only if necessary. 282*c8dee2aaSAndroid Build Coastguard Worker */ 283*c8dee2aaSAndroid Build Coastguard Worker static void CreateTransformedCopy(sk_sp<SkPathRef>* dst, 284*c8dee2aaSAndroid Build Coastguard Worker const SkPathRef& src, 285*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& matrix); 286*c8dee2aaSAndroid Build Coastguard Worker 287*c8dee2aaSAndroid Build Coastguard Worker // static SkPathRef* CreateFromBuffer(SkRBuffer* buffer); 288*c8dee2aaSAndroid Build Coastguard Worker 289*c8dee2aaSAndroid Build Coastguard Worker /** 290*c8dee2aaSAndroid Build Coastguard Worker * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be 291*c8dee2aaSAndroid Build Coastguard Worker * repopulated with approximately the same number of verbs and points. A new path ref is created 292*c8dee2aaSAndroid Build Coastguard Worker * only if necessary. 293*c8dee2aaSAndroid Build Coastguard Worker */ 294*c8dee2aaSAndroid Build Coastguard Worker static void Rewind(sk_sp<SkPathRef>* pathRef); 295*c8dee2aaSAndroid Build Coastguard Worker 296*c8dee2aaSAndroid Build Coastguard Worker ~SkPathRef(); countPoints()297*c8dee2aaSAndroid Build Coastguard Worker int countPoints() const { return fPoints.size(); } countVerbs()298*c8dee2aaSAndroid Build Coastguard Worker int countVerbs() const { return fVerbs.size(); } countWeights()299*c8dee2aaSAndroid Build Coastguard Worker int countWeights() const { return fConicWeights.size(); } 300*c8dee2aaSAndroid Build Coastguard Worker 301*c8dee2aaSAndroid Build Coastguard Worker size_t approximateBytesUsed() const; 302*c8dee2aaSAndroid Build Coastguard Worker 303*c8dee2aaSAndroid Build Coastguard Worker /** 304*c8dee2aaSAndroid Build Coastguard Worker * Returns a pointer one beyond the first logical verb (last verb in memory order). 305*c8dee2aaSAndroid Build Coastguard Worker */ verbsBegin()306*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* verbsBegin() const { return fVerbs.begin(); } 307*c8dee2aaSAndroid Build Coastguard Worker 308*c8dee2aaSAndroid Build Coastguard Worker /** 309*c8dee2aaSAndroid Build Coastguard Worker * Returns a const pointer to the first verb in memory (which is the last logical verb). 310*c8dee2aaSAndroid Build Coastguard Worker */ verbsEnd()311*c8dee2aaSAndroid Build Coastguard Worker const uint8_t* verbsEnd() const { return fVerbs.end(); } 312*c8dee2aaSAndroid Build Coastguard Worker 313*c8dee2aaSAndroid Build Coastguard Worker /** 314*c8dee2aaSAndroid Build Coastguard Worker * Returns a const pointer to the first point. 315*c8dee2aaSAndroid Build Coastguard Worker */ points()316*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* points() const { return fPoints.begin(); } 317*c8dee2aaSAndroid Build Coastguard Worker 318*c8dee2aaSAndroid Build Coastguard Worker /** 319*c8dee2aaSAndroid Build Coastguard Worker * Shortcut for this->points() + this->countPoints() 320*c8dee2aaSAndroid Build Coastguard Worker */ pointsEnd()321*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } 322*c8dee2aaSAndroid Build Coastguard Worker conicWeights()323*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* conicWeights() const { return fConicWeights.begin(); } conicWeightsEnd()324*c8dee2aaSAndroid Build Coastguard Worker const SkScalar* conicWeightsEnd() const { return fConicWeights.end(); } 325*c8dee2aaSAndroid Build Coastguard Worker 326*c8dee2aaSAndroid Build Coastguard Worker /** 327*c8dee2aaSAndroid Build Coastguard Worker * Convenience methods for getting to a verb or point by index. 328*c8dee2aaSAndroid Build Coastguard Worker */ atVerb(int index)329*c8dee2aaSAndroid Build Coastguard Worker uint8_t atVerb(int index) const { return fVerbs[index]; } atPoint(int index)330*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& atPoint(int index) const { return fPoints[index]; } 331*c8dee2aaSAndroid Build Coastguard Worker 332*c8dee2aaSAndroid Build Coastguard Worker bool operator== (const SkPathRef& ref) const; 333*c8dee2aaSAndroid Build Coastguard Worker 334*c8dee2aaSAndroid Build Coastguard Worker void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const; 335*c8dee2aaSAndroid Build Coastguard Worker 336*c8dee2aaSAndroid Build Coastguard Worker /** 337*c8dee2aaSAndroid Build Coastguard Worker * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the 338*c8dee2aaSAndroid Build Coastguard Worker * same ID then they have the same verbs and points. However, two path refs may have the same 339*c8dee2aaSAndroid Build Coastguard Worker * contents but different genIDs. 340*c8dee2aaSAndroid Build Coastguard Worker * skbug.com/1762 for background on why fillType is necessary (for now). 341*c8dee2aaSAndroid Build Coastguard Worker */ 342*c8dee2aaSAndroid Build Coastguard Worker uint32_t genID(uint8_t fillType) const; 343*c8dee2aaSAndroid Build Coastguard Worker 344*c8dee2aaSAndroid Build Coastguard Worker void addGenIDChangeListener(sk_sp<SkIDChangeListener>); // Threadsafe. 345*c8dee2aaSAndroid Build Coastguard Worker int genIDChangeListenerCount(); // Threadsafe 346*c8dee2aaSAndroid Build Coastguard Worker 347*c8dee2aaSAndroid Build Coastguard Worker bool dataMatchesVerbs() const; 348*c8dee2aaSAndroid Build Coastguard Worker bool isValid() const; 349*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(void validate() const { SkASSERT(this->isValid()); } ) 350*c8dee2aaSAndroid Build Coastguard Worker 351*c8dee2aaSAndroid Build Coastguard Worker /** 352*c8dee2aaSAndroid Build Coastguard Worker * Resets this SkPathRef to a clean state. 353*c8dee2aaSAndroid Build Coastguard Worker */ 354*c8dee2aaSAndroid Build Coastguard Worker void reset(); 355*c8dee2aaSAndroid Build Coastguard Worker isInitialEmptyPathRef()356*c8dee2aaSAndroid Build Coastguard Worker bool isInitialEmptyPathRef() const { 357*c8dee2aaSAndroid Build Coastguard Worker return fGenerationID == kEmptyGenID; 358*c8dee2aaSAndroid Build Coastguard Worker } 359*c8dee2aaSAndroid Build Coastguard Worker 360*c8dee2aaSAndroid Build Coastguard Worker private: 361*c8dee2aaSAndroid Build Coastguard Worker enum SerializationOffsets { 362*c8dee2aaSAndroid Build Coastguard Worker kLegacyRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits, ignored. 363*c8dee2aaSAndroid Build Coastguard Worker kLegacyRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit, ignored. 364*c8dee2aaSAndroid Build Coastguard Worker kLegacyIsRRect_SerializationShift = 26, // requires 1 bit, ignored. 365*c8dee2aaSAndroid Build Coastguard Worker kIsFinite_SerializationShift = 25, // requires 1 bit 366*c8dee2aaSAndroid Build Coastguard Worker kLegacyIsOval_SerializationShift = 24, // requires 1 bit, ignored. 367*c8dee2aaSAndroid Build Coastguard Worker kSegmentMask_SerializationShift = 0 // requires 4 bits (deprecated) 368*c8dee2aaSAndroid Build Coastguard Worker }; 369*c8dee2aaSAndroid Build Coastguard Worker 370*c8dee2aaSAndroid Build Coastguard Worker SkPathRef(int numVerbs = 0, int numPoints = 0, int numConics = 0) { 371*c8dee2aaSAndroid Build Coastguard Worker fBoundsIsDirty = true; // this also invalidates fIsFinite 372*c8dee2aaSAndroid Build Coastguard Worker fGenerationID = kEmptyGenID; 373*c8dee2aaSAndroid Build Coastguard Worker fSegmentMask = 0; 374*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kGeneral; 375*c8dee2aaSAndroid Build Coastguard Worker // The next two values don't matter unless fType is kOval or kRRect 376*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalIsCCW = false; 377*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalStartIdx = 0xAC; 378*c8dee2aaSAndroid Build Coastguard Worker fArcOval.setEmpty(); 379*c8dee2aaSAndroid Build Coastguard Worker fArcStartAngle = fArcSweepAngle = 0.0f; 380*c8dee2aaSAndroid Build Coastguard Worker fArcType = SkArc::Type::kArc; 381*c8dee2aaSAndroid Build Coastguard Worker if (numPoints > 0) { 382*c8dee2aaSAndroid Build Coastguard Worker fPoints.reserve_exact(numPoints); 383*c8dee2aaSAndroid Build Coastguard Worker } 384*c8dee2aaSAndroid Build Coastguard Worker if (numVerbs > 0) { 385*c8dee2aaSAndroid Build Coastguard Worker fVerbs.reserve_exact(numVerbs); 386*c8dee2aaSAndroid Build Coastguard Worker } 387*c8dee2aaSAndroid Build Coastguard Worker if (numConics > 0) { 388*c8dee2aaSAndroid Build Coastguard Worker fConicWeights.reserve_exact(numConics); 389*c8dee2aaSAndroid Build Coastguard Worker } 390*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(fEditorsAttached.store(0);) 391*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 392*c8dee2aaSAndroid Build Coastguard Worker } 393*c8dee2aaSAndroid Build Coastguard Worker 394*c8dee2aaSAndroid Build Coastguard Worker void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints, int additionalReserveConics); 395*c8dee2aaSAndroid Build Coastguard Worker 396*c8dee2aaSAndroid Build Coastguard Worker // Return true if the computed bounds are finite. ComputePtBounds(SkRect * bounds,const SkPathRef & ref)397*c8dee2aaSAndroid Build Coastguard Worker static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { 398*c8dee2aaSAndroid Build Coastguard Worker return bounds->setBoundsCheck(ref.points(), ref.countPoints()); 399*c8dee2aaSAndroid Build Coastguard Worker } 400*c8dee2aaSAndroid Build Coastguard Worker 401*c8dee2aaSAndroid Build Coastguard Worker // called, if dirty, by getBounds() computeBounds()402*c8dee2aaSAndroid Build Coastguard Worker void computeBounds() const { 403*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 404*c8dee2aaSAndroid Build Coastguard Worker // TODO: remove fBoundsIsDirty and fIsFinite, 405*c8dee2aaSAndroid Build Coastguard Worker // using an inverted rect instead of fBoundsIsDirty and always recalculating fIsFinite. 406*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fBoundsIsDirty); 407*c8dee2aaSAndroid Build Coastguard Worker 408*c8dee2aaSAndroid Build Coastguard Worker fIsFinite = ComputePtBounds(&fBounds, *this); 409*c8dee2aaSAndroid Build Coastguard Worker fBoundsIsDirty = false; 410*c8dee2aaSAndroid Build Coastguard Worker } 411*c8dee2aaSAndroid Build Coastguard Worker setBounds(const SkRect & rect)412*c8dee2aaSAndroid Build Coastguard Worker void setBounds(const SkRect& rect) { 413*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); 414*c8dee2aaSAndroid Build Coastguard Worker fBounds = rect; 415*c8dee2aaSAndroid Build Coastguard Worker fBoundsIsDirty = false; 416*c8dee2aaSAndroid Build Coastguard Worker fIsFinite = fBounds.isFinite(); 417*c8dee2aaSAndroid Build Coastguard Worker } 418*c8dee2aaSAndroid Build Coastguard Worker 419*c8dee2aaSAndroid Build Coastguard Worker /** Makes additional room but does not change the counts or change the genID */ incReserve(int additionalVerbs,int additionalPoints,int additionalConics)420*c8dee2aaSAndroid Build Coastguard Worker void incReserve(int additionalVerbs, int additionalPoints, int additionalConics) { 421*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 422*c8dee2aaSAndroid Build Coastguard Worker // Use reserve() so that if there is not enough space, the array will grow with some 423*c8dee2aaSAndroid Build Coastguard Worker // additional space. This ensures repeated calls to grow won't always allocate. 424*c8dee2aaSAndroid Build Coastguard Worker if (additionalPoints > 0) { 425*c8dee2aaSAndroid Build Coastguard Worker fPoints.reserve(fPoints.size() + additionalPoints); 426*c8dee2aaSAndroid Build Coastguard Worker } 427*c8dee2aaSAndroid Build Coastguard Worker if (additionalVerbs > 0) { 428*c8dee2aaSAndroid Build Coastguard Worker fVerbs.reserve(fVerbs.size() + additionalVerbs); 429*c8dee2aaSAndroid Build Coastguard Worker } 430*c8dee2aaSAndroid Build Coastguard Worker if (additionalConics > 0) { 431*c8dee2aaSAndroid Build Coastguard Worker fConicWeights.reserve(fConicWeights.size() + additionalConics); 432*c8dee2aaSAndroid Build Coastguard Worker } 433*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 434*c8dee2aaSAndroid Build Coastguard Worker } 435*c8dee2aaSAndroid Build Coastguard Worker 436*c8dee2aaSAndroid Build Coastguard Worker /** 437*c8dee2aaSAndroid Build Coastguard Worker * Resets all state except that of the verbs, points, and conic-weights. 438*c8dee2aaSAndroid Build Coastguard Worker * Intended to be called from other functions that reset state. 439*c8dee2aaSAndroid Build Coastguard Worker */ commonReset()440*c8dee2aaSAndroid Build Coastguard Worker void commonReset() { 441*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 442*c8dee2aaSAndroid Build Coastguard Worker this->callGenIDChangeListeners(); 443*c8dee2aaSAndroid Build Coastguard Worker fBoundsIsDirty = true; // this also invalidates fIsFinite 444*c8dee2aaSAndroid Build Coastguard Worker fGenerationID = 0; 445*c8dee2aaSAndroid Build Coastguard Worker 446*c8dee2aaSAndroid Build Coastguard Worker fSegmentMask = 0; 447*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kGeneral; 448*c8dee2aaSAndroid Build Coastguard Worker } 449*c8dee2aaSAndroid Build Coastguard Worker 450*c8dee2aaSAndroid Build Coastguard Worker /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also 451*c8dee2aaSAndroid Build Coastguard Worker * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ 452*c8dee2aaSAndroid Build Coastguard Worker void resetToSize(int verbCount, int pointCount, int conicCount, 453*c8dee2aaSAndroid Build Coastguard Worker int reserveVerbs = 0, int reservePoints = 0, 454*c8dee2aaSAndroid Build Coastguard Worker int reserveConics = 0) { 455*c8dee2aaSAndroid Build Coastguard Worker this->commonReset(); 456*c8dee2aaSAndroid Build Coastguard Worker // Use reserve_exact() so the arrays are sized to exactly fit the data. 457*c8dee2aaSAndroid Build Coastguard Worker fPoints.reserve_exact(pointCount + reservePoints); 458*c8dee2aaSAndroid Build Coastguard Worker fPoints.resize_back(pointCount); 459*c8dee2aaSAndroid Build Coastguard Worker 460*c8dee2aaSAndroid Build Coastguard Worker fVerbs.reserve_exact(verbCount + reserveVerbs); 461*c8dee2aaSAndroid Build Coastguard Worker fVerbs.resize_back(verbCount); 462*c8dee2aaSAndroid Build Coastguard Worker 463*c8dee2aaSAndroid Build Coastguard Worker fConicWeights.reserve_exact(conicCount + reserveConics); 464*c8dee2aaSAndroid Build Coastguard Worker fConicWeights.resize_back(conicCount); 465*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 466*c8dee2aaSAndroid Build Coastguard Worker } 467*c8dee2aaSAndroid Build Coastguard Worker 468*c8dee2aaSAndroid Build Coastguard Worker /** 469*c8dee2aaSAndroid Build Coastguard Worker * Increases the verb count by numVbs and point count by the required amount. 470*c8dee2aaSAndroid Build Coastguard Worker * The new points are uninitialized. All the new verbs are set to the specified 471*c8dee2aaSAndroid Build Coastguard Worker * verb. If 'verb' is kConic_Verb, 'weights' will return a pointer to the 472*c8dee2aaSAndroid Build Coastguard Worker * uninitialized conic weights. 473*c8dee2aaSAndroid Build Coastguard Worker */ 474*c8dee2aaSAndroid Build Coastguard Worker SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights); 475*c8dee2aaSAndroid Build Coastguard Worker 476*c8dee2aaSAndroid Build Coastguard Worker /** 477*c8dee2aaSAndroid Build Coastguard Worker * Increases the verb count 1, records the new verb, and creates room for the requisite number 478*c8dee2aaSAndroid Build Coastguard Worker * of additional points. A pointer to the first point is returned. Any new points are 479*c8dee2aaSAndroid Build Coastguard Worker * uninitialized. 480*c8dee2aaSAndroid Build Coastguard Worker */ 481*c8dee2aaSAndroid Build Coastguard Worker SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight); 482*c8dee2aaSAndroid Build Coastguard Worker 483*c8dee2aaSAndroid Build Coastguard Worker /** 484*c8dee2aaSAndroid Build Coastguard Worker * Concatenates all verbs from 'path' onto our own verbs array. Increases the point count by the 485*c8dee2aaSAndroid Build Coastguard Worker * number of points in 'path', and the conic weight count by the number of conics in 'path'. 486*c8dee2aaSAndroid Build Coastguard Worker * 487*c8dee2aaSAndroid Build Coastguard Worker * Returns pointers to the uninitialized points and conic weights data. 488*c8dee2aaSAndroid Build Coastguard Worker */ 489*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkPoint*, SkScalar*> growForVerbsInPath(const SkPathRef& path); 490*c8dee2aaSAndroid Build Coastguard Worker 491*c8dee2aaSAndroid Build Coastguard Worker /** 492*c8dee2aaSAndroid Build Coastguard Worker * Private, non-const-ptr version of the public function verbsMemBegin(). 493*c8dee2aaSAndroid Build Coastguard Worker */ verbsBeginWritable()494*c8dee2aaSAndroid Build Coastguard Worker uint8_t* verbsBeginWritable() { return fVerbs.begin(); } 495*c8dee2aaSAndroid Build Coastguard Worker 496*c8dee2aaSAndroid Build Coastguard Worker /** 497*c8dee2aaSAndroid Build Coastguard Worker * Called the first time someone calls CreateEmpty to actually create the singleton. 498*c8dee2aaSAndroid Build Coastguard Worker */ 499*c8dee2aaSAndroid Build Coastguard Worker friend SkPathRef* sk_create_empty_pathref(); 500*c8dee2aaSAndroid Build Coastguard Worker setIsOval(bool isCCW,unsigned start)501*c8dee2aaSAndroid Build Coastguard Worker void setIsOval(bool isCCW, unsigned start) { 502*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kOval; 503*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalIsCCW = isCCW; 504*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalStartIdx = SkToU8(start); 505*c8dee2aaSAndroid Build Coastguard Worker } 506*c8dee2aaSAndroid Build Coastguard Worker setIsRRect(bool isCCW,unsigned start)507*c8dee2aaSAndroid Build Coastguard Worker void setIsRRect(bool isCCW, unsigned start) { 508*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kRRect; 509*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalIsCCW = isCCW; 510*c8dee2aaSAndroid Build Coastguard Worker fRRectOrOvalStartIdx = SkToU8(start); 511*c8dee2aaSAndroid Build Coastguard Worker } 512*c8dee2aaSAndroid Build Coastguard Worker setIsArc(const SkArc & arc)513*c8dee2aaSAndroid Build Coastguard Worker void setIsArc(const SkArc& arc) { 514*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kArc; 515*c8dee2aaSAndroid Build Coastguard Worker fArcOval = arc.fOval; 516*c8dee2aaSAndroid Build Coastguard Worker fArcStartAngle = arc.fStartAngle; 517*c8dee2aaSAndroid Build Coastguard Worker fArcSweepAngle = arc.fSweepAngle; 518*c8dee2aaSAndroid Build Coastguard Worker fArcType = arc.fType; 519*c8dee2aaSAndroid Build Coastguard Worker } 520*c8dee2aaSAndroid Build Coastguard Worker 521*c8dee2aaSAndroid Build Coastguard Worker // called only by the editor. Note that this is not a const function. getWritablePoints()522*c8dee2aaSAndroid Build Coastguard Worker SkPoint* getWritablePoints() { 523*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 524*c8dee2aaSAndroid Build Coastguard Worker fType = PathType::kGeneral; 525*c8dee2aaSAndroid Build Coastguard Worker return fPoints.begin(); 526*c8dee2aaSAndroid Build Coastguard Worker } 527*c8dee2aaSAndroid Build Coastguard Worker getPoints()528*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* getPoints() const { 529*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(this->validate();) 530*c8dee2aaSAndroid Build Coastguard Worker return fPoints.begin(); 531*c8dee2aaSAndroid Build Coastguard Worker } 532*c8dee2aaSAndroid Build Coastguard Worker 533*c8dee2aaSAndroid Build Coastguard Worker void callGenIDChangeListeners(); 534*c8dee2aaSAndroid Build Coastguard Worker 535*c8dee2aaSAndroid Build Coastguard Worker PointsArray fPoints; 536*c8dee2aaSAndroid Build Coastguard Worker VerbsArray fVerbs; 537*c8dee2aaSAndroid Build Coastguard Worker ConicWeightsArray fConicWeights; 538*c8dee2aaSAndroid Build Coastguard Worker 539*c8dee2aaSAndroid Build Coastguard Worker mutable SkRect fBounds; 540*c8dee2aaSAndroid Build Coastguard Worker SkRect fArcOval; 541*c8dee2aaSAndroid Build Coastguard Worker 542*c8dee2aaSAndroid Build Coastguard Worker enum { 543*c8dee2aaSAndroid Build Coastguard Worker kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. 544*c8dee2aaSAndroid Build Coastguard Worker }; 545*c8dee2aaSAndroid Build Coastguard Worker mutable uint32_t fGenerationID; 546*c8dee2aaSAndroid Build Coastguard Worker SkIDChangeListener::List fGenIDChangeListeners; 547*c8dee2aaSAndroid Build Coastguard Worker 548*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(std::atomic<int> fEditorsAttached;) // assert only one editor in use at any time. 549*c8dee2aaSAndroid Build Coastguard Worker 550*c8dee2aaSAndroid Build Coastguard Worker SkScalar fArcStartAngle; 551*c8dee2aaSAndroid Build Coastguard Worker SkScalar fArcSweepAngle; 552*c8dee2aaSAndroid Build Coastguard Worker 553*c8dee2aaSAndroid Build Coastguard Worker PathType fType; 554*c8dee2aaSAndroid Build Coastguard Worker 555*c8dee2aaSAndroid Build Coastguard Worker mutable uint8_t fBoundsIsDirty; 556*c8dee2aaSAndroid Build Coastguard Worker 557*c8dee2aaSAndroid Build Coastguard Worker uint8_t fRRectOrOvalStartIdx; 558*c8dee2aaSAndroid Build Coastguard Worker uint8_t fSegmentMask; 559*c8dee2aaSAndroid Build Coastguard Worker // If the path is an arc, these four variables store that information. 560*c8dee2aaSAndroid Build Coastguard Worker // We should just store an SkArc, but alignment would cost us 8 more bytes. 561*c8dee2aaSAndroid Build Coastguard Worker SkArc::Type fArcType; 562*c8dee2aaSAndroid Build Coastguard Worker 563*c8dee2aaSAndroid Build Coastguard Worker mutable bool fIsFinite; // only meaningful if bounds are valid 564*c8dee2aaSAndroid Build Coastguard Worker // Both the circle and rrect special cases have a notion of direction and starting point 565*c8dee2aaSAndroid Build Coastguard Worker // The next two variables store that information for either. 566*c8dee2aaSAndroid Build Coastguard Worker bool fRRectOrOvalIsCCW; 567*c8dee2aaSAndroid Build Coastguard Worker 568*c8dee2aaSAndroid Build Coastguard Worker friend class PathRefTest_Private; 569*c8dee2aaSAndroid Build Coastguard Worker friend class ForceIsRRect_Private; // unit test isRRect 570*c8dee2aaSAndroid Build Coastguard Worker friend class SkPath; 571*c8dee2aaSAndroid Build Coastguard Worker friend class SkPathBuilder; 572*c8dee2aaSAndroid Build Coastguard Worker friend class SkPathPriv; 573*c8dee2aaSAndroid Build Coastguard Worker }; 574*c8dee2aaSAndroid Build Coastguard Worker 575*c8dee2aaSAndroid Build Coastguard Worker #endif 576