xref: /aosp_15_r20/external/skia/src/core/SkAnalyticEdge.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/base/SkAssert.h"
12 #include "include/private/base/SkDebug.h"
13 #include "include/private/base/SkFixed.h"
14 #include "include/private/base/SkSafe32.h"
15 #include "src/core/SkEdge.h"
16 
17 #include <cstdint>
18 
19 struct SkPoint;
20 
21 struct SkAnalyticEdge {
22     // Similar to SkEdge, the conic edges will be converted to quadratic edges
23     enum Type {
24         kLine_Type,
25         kQuad_Type,
26         kCubic_Type
27     };
28 
29     SkAnalyticEdge* fNext;
30     SkAnalyticEdge* fPrev;
31 
32     SkFixed fX;
33     SkFixed fDX;
34     SkFixed fUpperX;        // The x value when y = fUpperY
35     SkFixed fY;             // The current y
36     SkFixed fUpperY;        // The upper bound of y (our edge is from y = fUpperY to y = fLowerY)
37     SkFixed fLowerY;        // The lower bound of y (our edge is from y = fUpperY to y = fLowerY)
38     SkFixed fDY;            // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0.
39                             // fDY is only used for blitting trapezoids.
40 
41     Type    fEdgeType;      // Remembers the *initial* edge type
42 
43     int8_t  fCurveCount;    // only used by kQuad(+) and kCubic(-)
44     uint8_t fCurveShift;    // appled to all Dx/DDx/DDDx except for fCubicDShift exception
45     uint8_t fCubicDShift;   // applied to fCDx and fCDy only in cubic
46     int8_t  fWinding;       // 1 or -1
47 
48     static const int kDefaultAccuracy = 2; // default accuracy for snapping
49 
SnapYSkAnalyticEdge50     static inline SkFixed SnapY(SkFixed y) {
51         const int accuracy = kDefaultAccuracy;
52         // This approach is safer than left shift, round, then right shift
53         return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy);
54     }
55 
56     // Update fX, fY of this edge so fY = y
goYSkAnalyticEdge57     inline void goY(SkFixed y) {
58         if (y == fY + SK_Fixed1) {
59             fX = fX + fDX;
60             fY = y;
61         } else if (y != fY) {
62             // Drop lower digits as our alpha only has 8 bits
63             // (fDX and y - fUpperY may be greater than SK_Fixed1)
64             fX = fUpperX + SkFixedMul(fDX, y - fUpperY);
65             fY = y;
66         }
67     }
68 
goYSkAnalyticEdge69     inline void goY(SkFixed y, int yShift) {
70         SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy);
71         SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift);
72         fY = y;
73         fX += fDX >> yShift;
74     }
75 
76     bool setLine(const SkPoint& p0, const SkPoint& p1);
77     bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope);
78 
79     // return true if we're NOT done with this edge
80     bool update(SkFixed last_y, bool sortY = true);
81 
82 #ifdef SK_DEBUG
dumpSkAnalyticEdge83     void dump() const {
84         SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n",
85                  fUpperY, fLowerY, SkFixedToFloat(fY), SkFixedToFloat(fX),
86                  SkFixedToFloat(fDX), fWinding);
87     }
88 
validateSkAnalyticEdge89     void validate() const {
90          SkASSERT(fPrev && fNext);
91          SkASSERT(fPrev->fNext == this);
92          SkASSERT(fNext->fPrev == this);
93 
94          SkASSERT(fUpperY < fLowerY);
95          SkASSERT(SkAbs32(fWinding) == 1);
96     }
97 #endif
98 };
99 
100 struct SkAnalyticQuadraticEdge : public SkAnalyticEdge {
101     SkQuadraticEdge fQEdge;
102 
103     // snap y to integer points in the middle of the curve to accelerate AAA path filling
104     SkFixed fSnappedX, fSnappedY;
105 
106     bool setQuadratic(const SkPoint pts[3]);
107     bool updateQuadratic();
keepContinuousSkAnalyticQuadraticEdge108     inline void keepContinuous() {
109         // We use fX as the starting x to ensure the continuouty.
110         // Without it, we may break the sorted edge list.
111         SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1);
112         SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump
113         fSnappedX = fX;
114         fSnappedY = fY;
115     }
116 };
117 
118 struct SkAnalyticCubicEdge : public SkAnalyticEdge {
119     SkCubicEdge fCEdge;
120 
121     SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping
122 
123     bool setCubic(const SkPoint pts[4], bool sortY = true);
124     bool updateCubic(bool sortY = true);
keepContinuousSkAnalyticCubicEdge125     inline void keepContinuous() {
126         SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1);
127         fCEdge.fCx = fX;
128         fSnappedY = fY;
129     }
130 };
131 
132 #endif
133