• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     using Type = SkEdge::Type;
24     using Winding = SkEdge::Winding;
25 
26     SkAnalyticEdge* fNext;
27     SkAnalyticEdge* fPrev;
28 
29     SkFixed fX;
30     SkFixed fDX;
31     SkFixed fUpperX;        // The x value when y = fUpperY
32     SkFixed fY;             // The current y
33     SkFixed fUpperY;        // The upper bound of y (our edge is from y = fUpperY to y = fLowerY)
34     SkFixed fLowerY;        // The lower bound of y (our edge is from y = fUpperY to y = fLowerY)
35     SkFixed fDY;            // abs(1/fDX); may be SK_MaxS32 when fDX is close to 0.
36                             // fDY is only used for blitting trapezoids.
37 
38     Type fEdgeType;          // Remembers the *initial* edge type
39 
40     int8_t  fCurveCount;    // only used by kQuad(+) and kCubic(-)
41     uint8_t fCurveShift;    // appled to all Dx/DDx/DDDx except for fCubicDShift exception
42     uint8_t fCubicDShift;   // applied to fCDx and fCDy only in cubic
43     Winding fWinding;
44 
45     static constexpr int kDefaultAccuracy = 2;  // default accuracy for snapping
46 
SnapYSkAnalyticEdge47     static inline SkFixed SnapY(SkFixed y) {
48         constexpr int accuracy = kDefaultAccuracy;
49         // This approach is safer than left shift, round, then right shift
50         return ((unsigned)y + (SK_Fixed1 >> (accuracy + 1))) >> (16 - accuracy) << (16 - accuracy);
51     }
52 
53     // Update fX, fY of this edge so fY = y
goYSkAnalyticEdge54     inline void goY(SkFixed y) {
55         if (y == fY + SK_Fixed1) {
56             fX = fX + fDX;
57             fY = y;
58         } else if (y != fY) {
59             // Drop lower digits as our alpha only has 8 bits
60             // (fDX and y - fUpperY may be greater than SK_Fixed1)
61             fX = fUpperX + SkFixedMul(fDX, y - fUpperY);
62             fY = y;
63         }
64     }
65 
goYSkAnalyticEdge66     inline void goY(SkFixed y, int yShift) {
67         SkASSERT(yShift >= 0 && yShift <= kDefaultAccuracy);
68         SkASSERT(fDX == 0 || y - fY == SK_Fixed1 >> yShift);
69         fY = y;
70         fX += fDX >> yShift;
71     }
72 
73     bool setLine(const SkPoint& p0, const SkPoint& p1);
74     bool updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by, SkFixed slope);
75 
76     // return true if we're NOT done with this edge
77     bool update(SkFixed last_y, bool sortY = true);
78 
79 #ifdef SK_DEBUG
dumpSkAnalyticEdge80     void dump() const {
81         SkDebugf("edge: upperY:%d lowerY:%d y:%g x:%g dx:%g w:%d\n",
82                  fUpperY,
83                  fLowerY,
84                  SkFixedToFloat(fY),
85                  SkFixedToFloat(fX),
86                  SkFixedToFloat(fDX),
87                  static_cast<int8_t>(fWinding));
88     }
89 
validateSkAnalyticEdge90     void validate() const {
91          SkASSERT(fPrev && fNext);
92          SkASSERT(fPrev->fNext == this);
93          SkASSERT(fNext->fPrev == this);
94 
95          SkASSERT(fUpperY < fLowerY);
96          SkASSERT(fWinding == Winding::kCW || fWinding == Winding::kCCW);
97     }
98 #endif
99 };
100 
101 struct SkAnalyticQuadraticEdge : public SkAnalyticEdge {
102     SkQuadraticEdge fQEdge;
103 
104     // snap y to integer points in the middle of the curve to accelerate AAA path filling
105     SkFixed fSnappedX, fSnappedY;
106 
107     bool setQuadratic(const SkPoint pts[3]);
108     bool updateQuadratic();
keepContinuousSkAnalyticQuadraticEdge109     inline void keepContinuous() {
110         // We use fX as the starting x to ensure the continuouty.
111         // Without it, we may break the sorted edge list.
112         SkASSERT(SkAbs32(fX - SkFixedMul(fY - fSnappedY, fDX) - fSnappedX) < SK_Fixed1);
113         SkASSERT(SkAbs32(fY - fSnappedY) < SK_Fixed1); // This may differ due to smooth jump
114         fSnappedX = fX;
115         fSnappedY = fY;
116     }
117 };
118 
119 struct SkAnalyticCubicEdge : public SkAnalyticEdge {
120     SkCubicEdge fCEdge;
121 
122     SkFixed fSnappedY; // to make sure that y is increasing with smooth jump and snapping
123 
124     bool setCubic(const SkPoint pts[4], bool sortY = true);
125     bool updateCubic(bool sortY = true);
keepContinuousSkAnalyticCubicEdge126     inline void keepContinuous() {
127         SkASSERT(SkAbs32(fX - SkFixedMul(fDX, fY - SnapY(fCEdge.fCy)) - fCEdge.fCx) < SK_Fixed1);
128         fCEdge.fCx = fX;
129         fSnappedY = fY;
130     }
131 };
132 
133 #endif
134