Coverage Report

Created: 2024-05-20 07:14

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