Coverage Report

Created: 2024-09-14 07:19

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