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 SkEdge_DEFINED
9 #define SkEdge_DEFINED
10
11 #include "include/core/SkRect.h"
12 #include "include/private/base/SkMath.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/core/SkFDot6.h"
15
16 #include <utility>
17
18 // This correctly favors the lower-pixel when y0 is on a 1/2 pixel boundary
19 #define SkEdge_Compute_DY(top, y0) (SkLeftShift(top, 6) + 32 - (y0))
20
21 struct SkEdge {
22 enum Type {
23 kLine_Type,
24 kQuad_Type,
25 kCubic_Type
26 };
27
28 SkEdge* fNext;
29 SkEdge* fPrev;
30
31 SkFixed fX;
32 SkFixed fDX;
33 int32_t fFirstY;
34 int32_t fLastY;
35 Type fEdgeType; // Remembers the *initial* edge type
36 int8_t fCurveCount; // only used by kQuad(+) and kCubic(-)
37 uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception
38 uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic
39 int8_t fWinding; // 1 or -1
40
41 int setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, int shiftUp);
42 // call this version if you know you don't have a clip
43 inline int setLine(const SkPoint& p0, const SkPoint& p1, int shiftUp);
44 inline int updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by);
45 void chopLineWithClip(const SkIRect& clip);
46
intersectsClipSkEdge47 inline bool intersectsClip(const SkIRect& clip) const {
48 SkASSERT(fFirstY < clip.fBottom);
49 return fLastY >= clip.fTop;
50 }
51
52 #ifdef SK_DEBUG
53 void dump() const;
validateSkEdge54 void validate() const {
55 SkASSERT(fPrev && fNext);
56 SkASSERT(fPrev->fNext == this);
57 SkASSERT(fNext->fPrev == this);
58
59 SkASSERT(fFirstY <= fLastY);
60 SkASSERT(SkAbs32(fWinding) == 1);
61 }
62 #endif
63 };
64
65 struct SkQuadraticEdge : public SkEdge {
66 SkFixed fQx, fQy;
67 SkFixed fQDx, fQDy;
68 SkFixed fQDDx, fQDDy;
69 SkFixed fQLastX, fQLastY;
70
71 bool setQuadraticWithoutUpdate(const SkPoint pts[3], int shiftUp);
72 int setQuadratic(const SkPoint pts[3], int shiftUp);
73 int updateQuadratic();
74 };
75
76 struct SkCubicEdge : public SkEdge {
77 SkFixed fCx, fCy;
78 SkFixed fCDx, fCDy;
79 SkFixed fCDDx, fCDDy;
80 SkFixed fCDDDx, fCDDDy;
81 SkFixed fCLastX, fCLastY;
82
83 bool setCubicWithoutUpdate(const SkPoint pts[4], int shiftUp, bool sortY = true);
84 int setCubic(const SkPoint pts[4], int shiftUp);
85 int updateCubic();
86 };
87
setLine(const SkPoint & p0,const SkPoint & p1,int shift)88 int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) {
89 SkFDot6 x0, y0, x1, y1;
90
91 {
92 #ifdef SK_RASTERIZE_EVEN_ROUNDING
93 x0 = SkScalarRoundToFDot6(p0.fX, shift);
94 y0 = SkScalarRoundToFDot6(p0.fY, shift);
95 x1 = SkScalarRoundToFDot6(p1.fX, shift);
96 y1 = SkScalarRoundToFDot6(p1.fY, shift);
97 #else
98 float scale = float(1 << (shift + 6));
99 x0 = int(p0.fX * scale);
100 y0 = int(p0.fY * scale);
101 x1 = int(p1.fX * scale);
102 y1 = int(p1.fY * scale);
103 #endif
104 }
105
106 int winding = 1;
107
108 if (y0 > y1) {
109 using std::swap;
110 swap(x0, x1);
111 swap(y0, y1);
112 winding = -1;
113 }
114
115 int top = SkFDot6Round(y0);
116 int bot = SkFDot6Round(y1);
117
118 // are we a zero-height line?
119 if (top == bot) {
120 return 0;
121 }
122
123 SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
124 const SkFDot6 dy = SkEdge_Compute_DY(top, y0);
125
126 fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy)); // + SK_Fixed1/2
127 fDX = slope;
128 fFirstY = top;
129 fLastY = bot - 1;
130 fEdgeType = kLine_Type;
131 fCurveCount = 0;
132 fWinding = SkToS8(winding);
133 fCurveShift = 0;
134 return 1;
135 }
136
137 #endif
138