Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/core/SkAnalyticEdge.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2006 The Android Open Source Project
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 SkAnalyticEdge_DEFINED
9
#define SkAnalyticEdge_DEFINED
10
11
#include "include/private/SkTo.h"
12
#include "src/core/SkEdge.h"
13
14
#include <utility>
15
16
struct SkAnalyticEdge {
17
    // Similar to SkEdge, the conic edges will be converted to quadratic edges
18
    enum Type {
19
        kLine_Type,
20
        kQuad_Type,
21
        kCubic_Type
22
    };
23
24
    SkAnalyticEdge* fNext;
25
    SkAnalyticEdge* fPrev;
26
27
    // During aaa_walk_edges, if this edge is a left edge,
28
    // then fRiteE is its corresponding right edge. Otherwise it's nullptr.
29
    SkAnalyticEdge* fRiteE;
30
31
    SkFixed fX;
32
    SkFixed fDX;
33
    SkFixed fUpperX;        // The x value when y = fUpperY
34
    SkFixed fY;             // The current y
35
    SkFixed fUpperY;        // The upper bound of y (our edge is from y = fUpperY to y = fLowerY)
36
    SkFixed fLowerY;        // The lower bound of y (our edge is from y = fUpperY to y = fLowerY)
37
    SkFixed fDY;            // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0.
38
                            // fDY is only used for blitting trapezoids.
39
40
    SkFixed fSavedX;        // For deferred blitting
41
    SkFixed fSavedY;        // For deferred blitting
42
    SkFixed fSavedDY;       // For deferred blitting
43
44
    int8_t  fCurveCount;    // only used by kQuad(+) and kCubic(-)
45
    uint8_t fCurveShift;    // appled to all Dx/DDx/DDDx except for fCubicDShift exception
46
    uint8_t fCubicDShift;   // applied to fCDx and fCDy only in cubic
47
    int8_t  fWinding;       // 1 or -1
48
49
    static const int kDefaultAccuracy = 2; // default accuracy for snapping
50
51
47.5M
    static inline SkFixed SnapY(SkFixed y) {
52
47.5M
        const int accuracy = kDefaultAccuracy;
53
        // This approach is safer than left shift, round, then right shift
54
47.5M
        return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy);
55
47.5M
    }
56
57
    // Update fX, fY of this edge so fY = y
58
2.19M
    inline void goY(SkFixed y) {
59
2.19M
        if (y == fY + SK_Fixed1) {
60
0
            fX = fX + fDX;
61
0
            fY = y;
62
2.19M
        } else if (y != fY) {
63
            // Drop lower digits as our alpha only has 8 bits
64
            // (fDX and y - fUpperY may be greater than SK_Fixed1)
65
26.7k
            fX = fUpperX + SkFixedMul(fDX, y - fUpperY);
66
26.7k
            fY = y;
67
26.7k
        }
68
2.19M
    }
69
70
183M
    inline void goY(SkFixed y, int yShift) {
71
183M
        SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy);
72
183M
        SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift);
73
183M
        fY = y;
74
183M
        fX += fDX >> yShift;
75
183M
    }
76
77
17.0M
    inline void saveXY(SkFixed x, SkFixed y, SkFixed dY) {
78
17.0M
        fSavedX = x;
79
17.0M
        fSavedY = y;
80
17.0M
        fSavedDY = dY;
81
17.0M
    }
82
83
    bool setLine(const SkPoint& p0, const SkPoint& p1);
84
    bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope);
85
86
    // return true if we're NOT done with this edge
87
    bool update(SkFixed last_y, bool sortY = true);
88
89
#ifdef SK_DEBUG
90
0
    void dump() const {
91
0
        SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n",
92
0
                 fUpperY, fLowerY, SkFixedToFloat(fY), SkFixedToFloat(fX),
93
0
                 SkFixedToFloat(fDX), fWinding);
94
0
    }
95
96
0
    void validate() const {
97
0
         SkASSERT(fPrev && fNext);
98
0
         SkASSERT(fPrev->fNext == this);
99
0
         SkASSERT(fNext->fPrev == this);
100
101
0
         SkASSERT(fUpperY < fLowerY);
102
0
         SkASSERT(SkAbs32(fWinding) == 1);
103
0
    }
104
#endif
105
};
106
107
struct SkAnalyticQuadraticEdge : public SkAnalyticEdge {
108
    SkQuadraticEdge fQEdge;
109
110
    // snap y to integer points in the middle of the curve to accelerate AAA path filling
111
    SkFixed fSnappedX, fSnappedY;
112
113
    bool setQuadratic(const SkPoint pts[3]);
114
    bool updateQuadratic();
115
1.35M
    inline void keepContinuous() {
116
        // We use fX as the starting x to ensure the continuouty.
117
        // Without it, we may break the sorted edge list.
118
1.35M
        SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1);
119
1.35M
        SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump
120
1.35M
        fSnappedX = fX;
121
1.35M
        fSnappedY = fY;
122
1.35M
    }
123
};
124
125
struct SkAnalyticCubicEdge : public SkAnalyticEdge {
126
    SkCubicEdge fCEdge;
127
128
    SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping
129
130
    bool setCubic(const SkPoint pts[4], bool sortY = true);
131
    bool updateCubic(bool sortY = true);
132
1.42M
    inline void keepContinuous() {
133
1.42M
        SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1);
134
1.42M
        fCEdge.fCx = fX;
135
1.42M
        fSnappedY = fY;
136
1.42M
    }
137
};
138
139
struct SkBezier {
140
    int fCount; // 2 line, 3 quad, 4 cubic
141
    SkPoint fP0;
142
    SkPoint fP1;
143
144
    // See if left shift, covert to SkFDot6, and round has the same top and bottom y.
145
    // If so, the edge will be empty.
146
0
    static inline bool IsEmpty(SkScalar y0, SkScalar y1, int shift = 2) {
147
0
#ifdef SK_RASTERIZE_EVEN_ROUNDING
148
0
        return SkScalarRoundToFDot6(y0, shift) == SkScalarRoundToFDot6(y1, shift);
149
0
#else
150
0
        SkScalar scale = (1 << (shift + 6));
151
0
        return SkFDot6Round(int(y0 * scale)) == SkFDot6Round(int(y1 * scale));
152
0
#endif
153
0
    }
154
};
155
156
struct SkLine : public SkBezier {
157
0
    bool set(const SkPoint pts[2]){
158
0
        if (IsEmpty(pts[0].fY, pts[1].fY)) {
159
0
            return false;
160
0
        }
161
0
        fCount = 2;
162
0
        fP0 = pts[0];
163
0
        fP1 = pts[1];
164
0
        return true;
165
0
    }
166
};
167
168
struct SkQuad : public SkBezier {
169
    SkPoint fP2;
170
171
0
    bool set(const SkPoint pts[3]){
172
0
        if (IsEmpty(pts[0].fY, pts[2].fY)) {
173
0
            return false;
174
0
        }
175
0
        fCount = 3;
176
0
        fP0 = pts[0];
177
0
        fP1 = pts[1];
178
0
        fP2 = pts[2];
179
0
        return true;
180
0
    }
181
};
182
183
struct SkCubic : public SkBezier {
184
    SkPoint fP2;
185
    SkPoint fP3;
186
187
0
    bool set(const SkPoint pts[4]){
188
0
        // We do not chop at y extrema for cubics so pts[0], pts[1], pts[2], pts[3] may not be
189
0
        // monotonic. Therefore, we have to check the emptiness for all three pairs, instead of just
190
0
        // checking IsEmpty(pts[0].fY, pts[3].fY).
191
0
        if (IsEmpty(pts[0].fY, pts[1].fY) && IsEmpty(pts[1].fY, pts[2].fY) &&
192
0
                IsEmpty(pts[2].fY, pts[3].fY)) {
193
0
            return false;
194
0
        }
195
0
        fCount = 4;
196
0
        fP0 = pts[0];
197
0
        fP1 = pts[1];
198
0
        fP2 = pts[2];
199
0
        fP3 = pts[3];
200
0
        return true;
201
0
    }
202
};
203
204
#endif