Line data Source code
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 :
9 : #include "SkAnalyticEdge.h"
10 : #include "SkFDot6.h"
11 : #include "SkMathPriv.h"
12 :
13 : // This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here.
14 : // Therefore, we'll let the outter function compute the slope once and send in the value.
15 : // Moreover, we'll compute fDY by quickly lookup the inverse table (if possible).
16 1096 : bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) {
17 : // Since we send in the slope, we can no longer snap y inside this function.
18 : // If we don't send in the slope, or we do some more sophisticated snapping, this function
19 : // could be a performance bottleneck.
20 1096 : SkASSERT(fWinding == 1 || fWinding == -1);
21 1096 : SkASSERT(fCurveCount != 0);
22 :
23 1096 : SkASSERT(y0 <= y1);
24 :
25 1096 : SkFDot6 dx = SkFixedToFDot6(x1 - x0);
26 1096 : SkFDot6 dy = SkFixedToFDot6(y1 - y0);
27 :
28 : // are we a zero-height line?
29 1096 : if (dy == 0) {
30 2 : return false;
31 : }
32 :
33 1094 : SkASSERT(slope < SK_MaxS32);
34 :
35 1094 : SkFDot6 absSlope = SkAbs32(SkFixedToFDot6(slope));
36 1094 : fX = x0;
37 1094 : fDX = slope;
38 1094 : fUpperX = x0;
39 1094 : fY = y0;
40 1094 : fUpperY = y0;
41 1094 : fLowerY = y1;
42 2188 : fDY = (dx == 0 || slope == 0)
43 2188 : ? SK_MaxS32
44 : : absSlope < kInverseTableSize
45 1096 : ? QuickFDot6Inverse::Lookup(absSlope)
46 2 : : SkAbs32(QuickSkFDot6Div(dy, dx));
47 :
48 1094 : return true;
49 : }
50 :
51 0 : bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) {
52 0 : fRiteE = nullptr;
53 :
54 0 : if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) {
55 0 : return false;
56 : }
57 0 : fQEdge.fQx >>= kDefaultAccuracy;
58 0 : fQEdge.fQy >>= kDefaultAccuracy;
59 0 : fQEdge.fQDx >>= kDefaultAccuracy;
60 0 : fQEdge.fQDy >>= kDefaultAccuracy;
61 0 : fQEdge.fQDDx >>= kDefaultAccuracy;
62 0 : fQEdge.fQDDy >>= kDefaultAccuracy;
63 0 : fQEdge.fQLastX >>= kDefaultAccuracy;
64 0 : fQEdge.fQLastY >>= kDefaultAccuracy;
65 0 : fQEdge.fQy = SnapY(fQEdge.fQy);
66 0 : fQEdge.fQLastY = SnapY(fQEdge.fQLastY);
67 :
68 0 : fWinding = fQEdge.fWinding;
69 0 : fCurveCount = fQEdge.fCurveCount;
70 0 : fCurveShift = fQEdge.fCurveShift;
71 :
72 0 : fSnappedX = fQEdge.fQx;
73 0 : fSnappedY = fQEdge.fQy;
74 :
75 0 : return this->updateQuadratic();
76 : }
77 :
78 0 : bool SkAnalyticQuadraticEdge::updateQuadratic() {
79 0 : int success = 0; // initialize to fail!
80 0 : int count = fCurveCount;
81 0 : SkFixed oldx = fQEdge.fQx;
82 0 : SkFixed oldy = fQEdge.fQy;
83 0 : SkFixed dx = fQEdge.fQDx;
84 0 : SkFixed dy = fQEdge.fQDy;
85 : SkFixed newx, newy, newSnappedX, newSnappedY;
86 0 : int shift = fCurveShift;
87 :
88 0 : SkASSERT(count > 0);
89 :
90 0 : do {
91 : SkFixed slope;
92 0 : if (--count > 0)
93 : {
94 0 : newx = oldx + (dx >> shift);
95 0 : newy = oldy + (dy >> shift);
96 0 : if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough
97 0 : SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY);
98 0 : slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
99 : : SK_MaxS32;
100 0 : newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy));
101 0 : newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY);
102 : } else {
103 0 : newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy));
104 0 : newSnappedX = newx;
105 0 : SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY);
106 0 : slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
107 : : SK_MaxS32;
108 : }
109 0 : dx += fQEdge.fQDDx;
110 0 : dy += fQEdge.fQDDy;
111 : }
112 : else // last segment
113 : {
114 0 : newx = fQEdge.fQLastX;
115 0 : newy = fQEdge.fQLastY;
116 0 : newSnappedY = newy;
117 0 : newSnappedX = newx;
118 0 : SkFDot6 diffY = (newy - fSnappedY) >> 10;
119 0 : slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32;
120 : }
121 0 : if (slope < SK_MaxS32) {
122 0 : success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope);
123 : }
124 0 : oldx = newx;
125 0 : oldy = newy;
126 0 : } while (count > 0 && !success);
127 :
128 0 : SkASSERT(newSnappedY <= fQEdge.fQLastY);
129 :
130 0 : fQEdge.fQx = newx;
131 0 : fQEdge.fQy = newy;
132 0 : fQEdge.fQDx = dx;
133 0 : fQEdge.fQDy = dy;
134 0 : fSnappedX = newSnappedX;
135 0 : fSnappedY = newSnappedY;
136 0 : fCurveCount = SkToS8(count);
137 0 : return success;
138 : }
139 :
140 186 : bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) {
141 186 : fRiteE = nullptr;
142 :
143 186 : if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy)) {
144 0 : return false;
145 : }
146 :
147 186 : fCEdge.fCx >>= kDefaultAccuracy;
148 186 : fCEdge.fCy >>= kDefaultAccuracy;
149 186 : fCEdge.fCDx >>= kDefaultAccuracy;
150 186 : fCEdge.fCDy >>= kDefaultAccuracy;
151 186 : fCEdge.fCDDx >>= kDefaultAccuracy;
152 186 : fCEdge.fCDDy >>= kDefaultAccuracy;
153 186 : fCEdge.fCDDDx >>= kDefaultAccuracy;
154 186 : fCEdge.fCDDDy >>= kDefaultAccuracy;
155 186 : fCEdge.fCLastX >>= kDefaultAccuracy;
156 186 : fCEdge.fCLastY >>= kDefaultAccuracy;
157 186 : fCEdge.fCy = SnapY(fCEdge.fCy);
158 186 : fCEdge.fCLastY = SnapY(fCEdge.fCLastY);
159 :
160 186 : fWinding = fCEdge.fWinding;
161 186 : fCurveCount = fCEdge.fCurveCount;
162 186 : fCurveShift = fCEdge.fCurveShift;
163 186 : fCubicDShift = fCEdge.fCubicDShift;
164 :
165 186 : fSnappedY = fCEdge.fCy;
166 :
167 186 : return this->updateCubic();
168 : }
169 :
170 1096 : bool SkAnalyticCubicEdge::updateCubic() {
171 : int success;
172 1096 : int count = fCurveCount;
173 1096 : SkFixed oldx = fCEdge.fCx;
174 1096 : SkFixed oldy = fCEdge.fCy;
175 : SkFixed newx, newy;
176 1096 : const int ddshift = fCurveShift;
177 1096 : const int dshift = fCubicDShift;
178 :
179 1096 : SkASSERT(count < 0);
180 :
181 0 : do {
182 1096 : if (++count < 0) {
183 910 : newx = oldx + (fCEdge.fCDx >> dshift);
184 910 : fCEdge.fCDx += fCEdge.fCDDx >> ddshift;
185 910 : fCEdge.fCDDx += fCEdge.fCDDDx;
186 :
187 910 : newy = oldy + (fCEdge.fCDy >> dshift);
188 910 : fCEdge.fCDy += fCEdge.fCDDy >> ddshift;
189 910 : fCEdge.fCDDy += fCEdge.fCDDDy;
190 : }
191 : else { // last segment
192 186 : newx = fCEdge.fCLastX;
193 186 : newy = fCEdge.fCLastY;
194 : }
195 :
196 : // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint
197 : // doesn't always achieve that, so we have to explicitly pin it here.
198 1096 : if (newy < oldy) {
199 0 : newy = oldy;
200 : }
201 :
202 1096 : SkFixed newSnappedY = SnapY(newy);
203 : // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint
204 : // doesn't always achieve that, so we have to explicitly pin it here.
205 1096 : if (fCEdge.fCLastY < newSnappedY) {
206 0 : newSnappedY = fCEdge.fCLastY;
207 0 : count = 0;
208 : }
209 :
210 1096 : SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0
211 2190 : ? SK_MaxS32
212 1094 : : SkFDot6Div(SkFixedToFDot6(newx - oldx),
213 2190 : SkFixedToFDot6(newSnappedY - fSnappedY));
214 :
215 1096 : success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope);
216 :
217 1096 : oldx = newx;
218 1096 : oldy = newy;
219 1096 : fSnappedY = newSnappedY;
220 1096 : } while (count < 0 && !success);
221 :
222 1096 : fCEdge.fCx = newx;
223 1096 : fCEdge.fCy = newy;
224 1096 : fCurveCount = SkToS8(count);
225 1096 : return success;
226 : }
|