Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/pathops/SkOpSpan.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
#ifndef SkOpSpan_DEFINED
8
#define SkOpSpan_DEFINED
9
10
#include "include/core/SkPoint.h"
11
#include "src/pathops/SkPathOpsDebug.h"
12
#include "src/pathops/SkPathOpsTypes.h"
13
14
class SkArenaAlloc;
15
class SkOpAngle;
16
class SkOpContour;
17
class SkOpGlobalState;
18
class SkOpSegment;
19
class SkOpSpanBase;
20
class SkOpSpan;
21
struct SkPathOpsBounds;
22
23
// subset of op span used by terminal span (when t is equal to one)
24
class SkOpPtT {
25
public:
26
    enum {
27
        kIsAlias = 1,
28
        kIsDuplicate = 1
29
    };
30
31
    const SkOpPtT* active() const;
32
33
    // please keep in sync with debugAddOpp()
34
29.3M
    void addOpp(SkOpPtT* opp, SkOpPtT* oppPrev) {
35
29.3M
        SkOpPtT* oldNext = this->fNext;
36
29.3M
        SkASSERT(this != opp);
37
29.3M
        this->fNext = opp;
38
29.3M
        SkASSERT(oppPrev != oldNext);
39
29.3M
        oppPrev->fNext = oldNext;
40
29.3M
    }
41
42
    bool alias() const;
43
215M
    bool coincident() const { return fCoincident; }
44
    bool contains(const SkOpPtT* ) const;
45
    bool contains(const SkOpSegment*, const SkPoint& ) const;
46
    bool contains(const SkOpSegment*, double t) const;
47
    const SkOpPtT* contains(const SkOpSegment* ) const;
48
    SkOpContour* contour() const;
49
50
0
    int debugID() const {
51
0
        return SkDEBUGRELEASE(fID, -1);
52
0
    }
53
54
    void debugAddOpp(const SkOpPtT* opp, const SkOpPtT* oppPrev) const;
55
    const SkOpAngle* debugAngle(int id) const;
56
    const SkOpCoincidence* debugCoincidence() const;
57
    bool debugContains(const SkOpPtT* ) const;
58
    const SkOpPtT* debugContains(const SkOpSegment* check) const;
59
    SkOpContour* debugContour(int id) const;
60
    const SkOpPtT* debugEnder(const SkOpPtT* end) const;
61
    int debugLoopLimit(bool report) const;
62
    bool debugMatchID(int id) const;
63
    const SkOpPtT* debugOppPrev(const SkOpPtT* opp) const;
64
    const SkOpPtT* debugPtT(int id) const;
65
    void debugResetCoinT() const;
66
    const SkOpSegment* debugSegment(int id) const;
67
    void debugSetCoinT(int ) const;
68
    const SkOpSpanBase* debugSpan(int id) const;
69
    void debugValidate() const;
70
71
8.73G
    bool deleted() const {
72
8.73G
        return fDeleted;
73
8.73G
    }
74
75
0
    bool duplicate() const {
76
0
        return fDuplicatePt;
77
0
    }
78
79
    void dump() const;  // available to testing only
80
    void dumpAll() const;
81
    void dumpBase() const;
82
83
    const SkOpPtT* find(const SkOpSegment* ) const;
84
    SkOpGlobalState* globalState() const;
85
    void init(SkOpSpanBase* , double t, const SkPoint& , bool dup);
86
87
157k
    void insert(SkOpPtT* span) {
88
157k
        SkASSERT(span != this);
89
157k
        span->fNext = fNext;
90
157k
        fNext = span;
91
157k
    }
92
93
22.0G
    const SkOpPtT* next() const {
94
22.0G
        return fNext;
95
22.0G
    }
96
97
3.67G
    SkOpPtT* next() {
98
3.67G
        return fNext;
99
3.67G
    }
100
101
    bool onEnd() const;
102
103
    // returns nullptr if this is already in the opp ptT loop
104
29.0M
    SkOpPtT* oppPrev(const SkOpPtT* opp) const {
105
        // find the fOpp ptr to opp
106
29.0M
        SkOpPtT* oppPrev = opp->fNext;
107
29.0M
        if (oppPrev == this) {
108
54.5k
            return nullptr;
109
54.5k
        }
110
101M
        while (oppPrev->fNext != opp) {
111
72.9M
            oppPrev = oppPrev->fNext;
112
72.9M
            if (oppPrev == this) {
113
121k
                return nullptr;
114
121k
            }
115
72.9M
        }
116
28.8M
        return oppPrev;
117
28.9M
    }
118
119
    static bool Overlaps(const SkOpPtT* s1, const SkOpPtT* e1, const SkOpPtT* s2,
120
16.3M
            const SkOpPtT* e2, const SkOpPtT** sOut, const SkOpPtT** eOut) {
121
12.3M
        const SkOpPtT* start1 = s1->fT < e1->fT ? s1 : e1;
122
13.0M
        const SkOpPtT* start2 = s2->fT < e2->fT ? s2 : e2;
123
7.45M
        *sOut = between(s1->fT, start2->fT, e1->fT) ? start2
124
8.91M
                : between(s2->fT, start1->fT, e2->fT) ? start1 : nullptr;
125
12.3M
        const SkOpPtT* end1 = s1->fT < e1->fT ? e1 : s1;
126
13.0M
        const SkOpPtT* end2 = s2->fT < e2->fT ? e2 : s2;
127
7.60M
        *eOut = between(s1->fT, end2->fT, e1->fT) ? end2
128
8.76M
                : between(s2->fT, end1->fT, e2->fT) ? end1 : nullptr;
129
16.3M
        if (*sOut == *eOut) {
130
8.61M
            SkOPOBJASSERT(s1, start1->fT >= end2->fT || start2->fT >= end1->fT);
131
8.61M
            return false;
132
8.61M
        }
133
7.75M
        SkASSERT(!*sOut || *sOut != *eOut);
134
7.75M
        return *sOut && *eOut;
135
7.75M
    }
136
137
    bool ptAlreadySeen(const SkOpPtT* head) const;
138
    SkOpPtT* prev();
139
140
    const SkOpSegment* segment() const;
141
    SkOpSegment* segment();
142
143
16.9M
    void setCoincident() const {
144
16.9M
        SkOPASSERT(!fDeleted);
145
16.9M
        fCoincident = true;
146
16.9M
    }
147
148
    void setDeleted();
149
150
4.68M
    void setSpan(const SkOpSpanBase* span) {
151
4.68M
        fSpan = const_cast<SkOpSpanBase*>(span);
152
4.68M
    }
153
154
21.8G
    const SkOpSpanBase* span() const {
155
21.8G
        return fSpan;
156
21.8G
    }
157
158
3.60G
    SkOpSpanBase* span() {
159
3.60G
        return fSpan;
160
3.60G
    }
161
162
52.6M
    const SkOpPtT* starter(const SkOpPtT* end) const {
163
43.8M
        return fT < end->fT ? this : end;
164
52.6M
    }
165
166
    double fT;
167
    SkPoint fPt;   // cache of point value at this t
168
protected:
169
    SkOpSpanBase* fSpan;  // contains winding data
170
    SkOpPtT* fNext;  // intersection on opposite curve or alias on this curve
171
    bool fDeleted;  // set if removed from span list
172
    bool fDuplicatePt;  // set if identical pt is somewhere in the next loop
173
    // below mutable since referrer is otherwise always const
174
    mutable bool fCoincident;  // set if at some point a coincident span pointed here
175
    SkDEBUGCODE(int fID);
176
};
177
178
class SkOpSpanBase {
179
public:
180
    enum class Collapsed {
181
        kNo,
182
        kYes,
183
        kError,
184
    };
185
186
    bool addOpp(SkOpSpanBase* opp);
187
188
89.5M
    void bumpSpanAdds() {
189
89.5M
        ++fSpanAdds;
190
89.5M
    }
191
192
6.79M
    bool chased() const {
193
6.79M
        return fChased;
194
6.79M
    }
195
196
    void checkForCollapsedCoincidence();
197
198
0
    const SkOpSpanBase* coinEnd() const {
199
0
        return fCoinEnd;
200
0
    }
201
202
    Collapsed collapsed(double s, double e) const;
203
    bool contains(const SkOpSpanBase* ) const;
204
    const SkOpPtT* contains(const SkOpSegment* ) const;
205
206
3.67M
    bool containsCoinEnd(const SkOpSpanBase* coin) const {
207
3.67M
        SkASSERT(this != coin);
208
3.67M
        const SkOpSpanBase* next = this;
209
12.0M
        while ((next = next->fCoinEnd) != this) {
210
10.1M
            if (next == coin) {
211
1.68M
                return true;
212
1.68M
            }
213
10.1M
        }
214
1.98M
        return false;
215
3.67M
    }
216
217
    bool containsCoinEnd(const SkOpSegment* ) const;
218
    SkOpContour* contour() const;
219
220
0
    int debugBumpCount() {
221
0
        return SkDEBUGRELEASE(++fCount, -1);
222
0
    }
223
224
0
    int debugID() const {
225
0
        return SkDEBUGRELEASE(fID, -1);
226
0
    }
227
228
#if DEBUG_COIN
229
    void debugAddOpp(SkPathOpsDebug::GlitchLog* , const SkOpSpanBase* opp) const;
230
#endif
231
    bool debugAlignedEnd(double t, const SkPoint& pt) const;
232
    bool debugAlignedInner() const;
233
    const SkOpAngle* debugAngle(int id) const;
234
#if DEBUG_COIN
235
    void debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* ) const;
236
#endif
237
    const SkOpCoincidence* debugCoincidence() const;
238
    bool debugCoinEndLoopCheck() const;
239
    SkOpContour* debugContour(int id) const;
240
#ifdef SK_DEBUG
241
0
    bool debugDeleted() const { return fDebugDeleted; }
242
#endif
243
#if DEBUG_COIN
244
    void debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* ,
245
                            const SkOpSpanBase* ) const;
246
    void debugMergeMatches(SkPathOpsDebug::GlitchLog* log,
247
                           const SkOpSpanBase* opp) const;
248
#endif
249
    const SkOpPtT* debugPtT(int id) const;
250
    void debugResetCoinT() const;
251
    const SkOpSegment* debugSegment(int id) const;
252
    void debugSetCoinT(int ) const;
253
#ifdef SK_DEBUG
254
0
    void debugSetDeleted() { fDebugDeleted = true; }
255
#endif
256
    const SkOpSpanBase* debugSpan(int id) const;
257
    const SkOpSpan* debugStarter(SkOpSpanBase const** endPtr) const;
258
    SkOpGlobalState* globalState() const;
259
    void debugValidate() const;
260
261
260M
    bool deleted() const {
262
260M
        return fPtT.deleted();
263
260M
    }
264
265
    void dump() const;  // available to testing only
266
    void dumpCoin() const;
267
    void dumpAll() const;
268
    void dumpBase() const;
269
    void dumpHead() const;
270
271
1.26G
    bool final() const {
272
1.26G
        return fPtT.fT == 1;
273
1.26G
    }
274
275
245M
    SkOpAngle* fromAngle() const {
276
245M
        return fFromAngle;
277
245M
    }
278
279
    void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
280
281
    // Please keep this in sync with debugInsertCoinEnd()
282
3.67M
    void insertCoinEnd(SkOpSpanBase* coin) {
283
3.67M
        if (containsCoinEnd(coin)) {
284
1.68M
            SkASSERT(coin->containsCoinEnd(this));
285
1.68M
            return;
286
1.68M
        }
287
1.98M
        debugValidate();
288
1.98M
        SkASSERT(this != coin);
289
1.98M
        SkOpSpanBase* coinNext = coin->fCoinEnd;
290
1.98M
        coin->fCoinEnd = this->fCoinEnd;
291
1.98M
        this->fCoinEnd = coinNext;
292
1.98M
        debugValidate();
293
1.98M
    }
294
295
    void merge(SkOpSpan* span);
296
    bool mergeMatches(SkOpSpanBase* opp);
297
298
36.0M
    const SkOpSpan* prev() const {
299
36.0M
        return fPrev;
300
36.0M
    }
301
302
227M
    SkOpSpan* prev() {
303
227M
        return fPrev;
304
227M
    }
305
306
24.6M
    const SkPoint& pt() const {
307
24.6M
        return fPtT.fPt;
308
24.6M
    }
309
310
914M
    const SkOpPtT* ptT() const {
311
914M
        return &fPtT;
312
914M
    }
313
314
750M
    SkOpPtT* ptT() {
315
750M
        return &fPtT;
316
750M
    }
317
318
44.7G
    SkOpSegment* segment() const {
319
44.7G
        return fSegment;
320
44.7G
    }
321
322
0
    void setAligned() {
323
0
        fAligned = true;
324
0
    }
325
326
5.20M
    void setChased(bool chased) {
327
5.20M
        fChased = chased;
328
5.20M
    }
329
330
11.3M
    void setFromAngle(SkOpAngle* angle) {
331
11.3M
        fFromAngle = angle;
332
11.3M
    }
333
334
28.0M
    void setPrev(SkOpSpan* prev) {
335
28.0M
        fPrev = prev;
336
28.0M
    }
337
338
25.6M
    bool simple() const {
339
25.6M
        fPtT.debugValidate();
340
25.6M
        return fPtT.next()->next() == &fPtT;
341
25.6M
    }
342
343
428M
    int spanAddsCount() const {
344
428M
        return fSpanAdds;
345
428M
    }
346
347
25.0M
    const SkOpSpan* starter(const SkOpSpanBase* end) const {
348
13.7M
        const SkOpSpanBase* result = t() < end->t() ? this : end;
349
25.0M
        return result->upCast();
350
25.0M
    }
351
352
133M
    SkOpSpan* starter(SkOpSpanBase* end) {
353
133M
        SkASSERT(this->segment() == end->segment());
354
70.3M
        SkOpSpanBase* result = t() < end->t() ? this : end;
355
133M
        return result->upCast();
356
133M
    }
357
358
0
    SkOpSpan* starter(SkOpSpanBase** endPtr) {
359
0
        SkOpSpanBase* end = *endPtr;
360
0
        SkASSERT(this->segment() == end->segment());
361
0
        SkOpSpanBase* result;
362
0
        if (t() < end->t()) {
363
0
            result = this;
364
0
        } else {
365
0
            result = end;
366
0
            *endPtr = this;
367
0
        }
368
0
        return result->upCast();
369
0
    }
370
371
79.0M
    int step(const SkOpSpanBase* end) const {
372
42.0M
        return t() < end->t() ? 1 : -1;
373
79.0M
    }
374
375
2.69G
    double t() const {
376
2.69G
        return fPtT.fT;
377
2.69G
    }
378
379
9.61M
    void unaligned() {
380
9.61M
        fAligned = false;
381
9.61M
    }
382
383
1.24G
    SkOpSpan* upCast() {
384
1.24G
        SkASSERT(!final());
385
1.24G
        return (SkOpSpan*) this;
386
1.24G
    }
387
388
1.12G
    const SkOpSpan* upCast() const {
389
1.12G
        SkOPASSERT(!final());
390
1.12G
        return (const SkOpSpan*) this;
391
1.12G
    }
392
393
86.1M
    SkOpSpan* upCastable() {
394
75.9M
        return final() ? nullptr : upCast();
395
86.1M
    }
396
397
410M
    const SkOpSpan* upCastable() const {
398
374M
        return final() ? nullptr : upCast();
399
410M
    }
400
401
private:
402
    void alignInner();
403
404
protected:  // no direct access to internals to avoid treating a span base as a span
405
    SkOpPtT fPtT;  // list of points and t values associated with the start of this span
406
    SkOpSegment* fSegment;  // segment that contains this span
407
    SkOpSpanBase* fCoinEnd;  // linked list of coincident spans that end here (may point to itself)
408
    SkOpAngle* fFromAngle;  // points to next angle from span start to end
409
    SkOpSpan* fPrev;  // previous intersection point
410
    int fSpanAdds;  // number of times intersections have been added to span
411
    bool fAligned;
412
    bool fChased;  // set after span has been added to chase array
413
    SkDEBUGCODE(int fCount);  // number of pt/t pairs added
414
    SkDEBUGCODE(int fID);
415
    SkDEBUGCODE(bool fDebugDeleted);  // set when span was merged with another span
416
};
417
418
class SkOpSpan : public SkOpSpanBase {
419
public:
420
12.9M
    bool alreadyAdded() const {
421
12.9M
        if (fAlreadyAdded) {
422
282k
            return true;
423
282k
        }
424
12.6M
        return false;
425
12.6M
    }
426
427
0
    bool clearCoincident() {
428
0
        SkASSERT(!final());
429
0
        if (fCoincident == this) {
430
0
            return false;
431
0
        }
432
0
        fCoincident = this;
433
0
        return true;
434
0
    }
435
436
    int computeWindSum();
437
    bool containsCoincidence(const SkOpSegment* ) const;
438
439
4.79M
    bool containsCoincidence(const SkOpSpan* coin) const {
440
4.79M
        SkASSERT(this != coin);
441
4.79M
        const SkOpSpan* next = this;
442
19.9M
        while ((next = next->fCoincident) != this) {
443
16.9M
            if (next == coin) {
444
1.80M
                return true;
445
1.80M
            }
446
16.9M
        }
447
2.98M
        return false;
448
4.79M
    }
449
450
    bool debugCoinLoopCheck() const;
451
#if DEBUG_COIN
452
    void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* , const SkOpSpan* ) const;
453
    void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* ,
454
                                const SkOpSegment* , bool flipped, bool ordered) const;
455
#endif
456
    void dumpCoin() const;
457
    bool dumpSpan() const;
458
459
134M
    bool done() const {
460
134M
        SkASSERT(!final());
461
134M
        return fDone;
462
134M
    }
463
464
    void init(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
465
    bool insertCoincidence(const SkOpSegment* , bool flipped, bool ordered);
466
467
    // Please keep this in sync with debugInsertCoincidence()
468
4.79M
    void insertCoincidence(SkOpSpan* coin) {
469
4.79M
        if (containsCoincidence(coin)) {
470
1.80M
            SkASSERT(coin->containsCoincidence(this));
471
1.80M
            return;
472
1.80M
        }
473
2.98M
        debugValidate();
474
2.98M
        SkASSERT(this != coin);
475
2.98M
        SkOpSpan* coinNext = coin->fCoincident;
476
2.98M
        coin->fCoincident = this->fCoincident;
477
2.98M
        this->fCoincident = coinNext;
478
2.98M
        debugValidate();
479
2.98M
    }
480
481
23.7M
    bool isCanceled() const {
482
23.7M
        SkASSERT(!final());
483
23.7M
        return fWindValue == 0 && fOppValue == 0;
484
23.7M
    }
485
486
0
    bool isCoincident() const {
487
0
        SkASSERT(!final());
488
0
        return fCoincident != this;
489
0
    }
490
491
12.6M
    void markAdded() {
492
12.6M
        fAlreadyAdded = true;
493
12.6M
    }
494
495
1.56G
    SkOpSpanBase* next() const {
496
1.56G
        SkASSERT(!final());
497
1.56G
        return fNext;
498
1.56G
    }
499
500
14.9M
    int oppSum() const {
501
14.9M
        SkASSERT(!final());
502
14.9M
        return fOppSum;
503
14.9M
    }
504
505
132M
    int oppValue() const {
506
132M
        SkASSERT(!final());
507
132M
        return fOppValue;
508
132M
    }
509
510
    void release(const SkOpPtT* );
511
512
    SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment);
513
514
21.7M
    void setDone(bool done) {
515
21.7M
        SkASSERT(!final());
516
21.7M
        fDone = done;
517
21.7M
    }
518
519
44.3M
    void setNext(SkOpSpanBase* nextT) {
520
44.3M
        SkASSERT(!final());
521
44.3M
        fNext = nextT;
522
44.3M
    }
523
524
    void setOppSum(int oppSum);
525
526
11.1M
    void setOppValue(int oppValue) {
527
11.1M
        SkASSERT(!final());
528
11.1M
        SkASSERT(fOppSum == SK_MinS32);
529
11.1M
        SkOPASSERT(!oppValue || !fDone);
530
11.1M
        fOppValue = oppValue;
531
11.1M
    }
532
533
11.3M
    void setToAngle(SkOpAngle* angle) {
534
11.3M
        SkASSERT(!final());
535
11.3M
        fToAngle = angle;
536
11.3M
    }
537
538
    void setWindSum(int windSum);
539
540
11.1M
    void setWindValue(int windValue) {
541
11.1M
        SkASSERT(!final());
542
11.1M
        SkASSERT(windValue >= 0);
543
11.1M
        SkASSERT(fWindSum == SK_MinS32);
544
11.1M
        SkOPASSERT(!windValue || !fDone);
545
11.1M
        fWindValue = windValue;
546
11.1M
    }
547
548
    bool sortableTop(SkOpContour* );
549
550
179M
    SkOpAngle* toAngle() const {
551
179M
        SkASSERT(!final());
552
179M
        return fToAngle;
553
179M
    }
554
555
96.4M
    int windSum() const {
556
96.4M
        SkASSERT(!final());
557
96.4M
        return fWindSum;
558
96.4M
    }
559
560
207M
    int windValue() const {
561
207M
        SkOPASSERT(!final());
562
207M
        return fWindValue;
563
207M
    }
564
565
private:  // no direct access to internals to avoid treating a span base as a span
566
    SkOpSpan* fCoincident;  // linked list of spans coincident with this one (may point to itself)
567
    SkOpAngle* fToAngle;  // points to next angle from span start to end
568
    SkOpSpanBase* fNext;  // next intersection point
569
    int fWindSum;  // accumulated from contours surrounding this one.
570
    int fOppSum;  // for binary operators: the opposite winding sum
571
    int fWindValue;  // 0 == canceled; 1 == normal; >1 == coincident
572
    int fOppValue;  // normally 0 -- when binary coincident edges combine, opp value goes here
573
    int fTopTTry; // specifies direction and t value to try next
574
    bool fDone;  // if set, this span to next higher T has been processed
575
    bool fAlreadyAdded;
576
};
577
578
#endif