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