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 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     SkASSERT(fWinding == 1 || fWinding == -1);
21     SkASSERT(fCurveCount != 0);
22 
23     // We don't chop at y extrema for cubics so the y is not guaranteed to be increasing for them.
24     // In that case, we have to swap x/y and negate the winding.
25     if (y0 > y1) {
26         SkTSwap(x0, x1);
27         SkTSwap(y0, y1);
28         fWinding = -fWinding;
29     }
30 
31     SkASSERT(y0 <= y1);
32 
33     SkFDot6 dx = SkFixedToFDot6(x1 - x0);
34     SkFDot6 dy = SkFixedToFDot6(y1 - y0);
35 
36     // are we a zero-height line?
37     if (dy == 0) {
38         return false;
39     }
40 
41     SkASSERT(slope < SK_MaxS32);
42 
43     SkFDot6     absSlope = SkAbs32(SkFixedToFDot6(slope));
44     fX          = x0;
45     fDX         = slope;
46     fUpperX     = x0;
47     fY          = y0;
48     fUpperY     = y0;
49     fLowerY     = y1;
50     fDY         = (dx == 0 || slope == 0)
51                   ? SK_MaxS32
52                   : absSlope < kInverseTableSize
53                     ? QuickFDot6Inverse::Lookup(absSlope)
54                     : SkAbs32(QuickSkFDot6Div(dy, dx));
55 
56     return true;
57 }
58 
59 bool SkAnalyticEdge::update(SkFixed last_y, bool sortY) {
60     SkASSERT(last_y >= fLowerY); // we shouldn't update edge if last_y < fLowerY
61     if (fCurveCount < 0) {
62         return static_cast<SkAnalyticCubicEdge*>(this)->updateCubic(sortY);
63     } else if (fCurveCount > 0) {
64         return static_cast<SkAnalyticQuadraticEdge*>(this)->updateQuadratic();
65     }
66     return false;
67 }
68 
69 bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) {
70     fRiteE = nullptr;
71 
72     if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) {
73         return false;
74     }
75     fQEdge.fQx >>= kDefaultAccuracy;
76     fQEdge.fQy >>= kDefaultAccuracy;
77     fQEdge.fQDx >>= kDefaultAccuracy;
78     fQEdge.fQDy >>= kDefaultAccuracy;
79     fQEdge.fQDDx >>= kDefaultAccuracy;
80     fQEdge.fQDDy >>= kDefaultAccuracy;
81     fQEdge.fQLastX >>= kDefaultAccuracy;
82     fQEdge.fQLastY >>= kDefaultAccuracy;
83     fQEdge.fQy = SnapY(fQEdge.fQy);
84     fQEdge.fQLastY = SnapY(fQEdge.fQLastY);
85 
86     fWinding = fQEdge.fWinding;
87     fCurveCount = fQEdge.fCurveCount;
88     fCurveShift = fQEdge.fCurveShift;
89 
90     fSnappedX = fQEdge.fQx;
91     fSnappedY = fQEdge.fQy;
92 
93     return this->updateQuadratic();
94 }
95 
96 bool SkAnalyticQuadraticEdge::updateQuadratic() {
97     int     success = 0; // initialize to fail!
98     int     count = fCurveCount;
99     SkFixed oldx = fQEdge.fQx;
100     SkFixed oldy = fQEdge.fQy;
101     SkFixed dx = fQEdge.fQDx;
102     SkFixed dy = fQEdge.fQDy;
103     SkFixed newx, newy, newSnappedX, newSnappedY;
104     int     shift = fCurveShift;
105 
106     SkASSERT(count > 0);
107 
108     do {
109         SkFixed slope;
110         if (--count > 0)
111         {
112             newx    = oldx + (dx >> shift);
113             newy    = oldy + (dy >> shift);
114             if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough
115                 SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY);
116                 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
117                               : SK_MaxS32;
118                 newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy));
119                 newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY);
120             } else {
121                 newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy));
122                 newSnappedX = newx;
123                 SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY);
124                 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
125                               : SK_MaxS32;
126             }
127             dx += fQEdge.fQDDx;
128             dy += fQEdge.fQDDy;
129         }
130         else    // last segment
131         {
132             newx    = fQEdge.fQLastX;
133             newy    = fQEdge.fQLastY;
134             newSnappedY = newy;
135             newSnappedX = newx;
136             SkFDot6 diffY = (newy - fSnappedY) >> 10;
137             slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32;
138         }
139         if (slope < SK_MaxS32) {
140             success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope);
141         }
142         oldx = newx;
143         oldy = newy;
144     } while (count > 0 && !success);
145 
146     SkASSERT(newSnappedY <= fQEdge.fQLastY);
147 
148     fQEdge.fQx  = newx;
149     fQEdge.fQy  = newy;
150     fQEdge.fQDx = dx;
151     fQEdge.fQDy = dy;
152     fSnappedX   = newSnappedX;
153     fSnappedY   = newSnappedY;
154     fCurveCount = SkToS8(count);
155     return success;
156 }
157 
158 bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4], bool sortY) {
159     fRiteE = nullptr;
160 
161     if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy, sortY)) {
162         return false;
163     }
164 
165     fCEdge.fCx >>= kDefaultAccuracy;
166     fCEdge.fCy >>= kDefaultAccuracy;
167     fCEdge.fCDx >>= kDefaultAccuracy;
168     fCEdge.fCDy >>= kDefaultAccuracy;
169     fCEdge.fCDDx >>= kDefaultAccuracy;
170     fCEdge.fCDDy >>= kDefaultAccuracy;
171     fCEdge.fCDDDx >>= kDefaultAccuracy;
172     fCEdge.fCDDDy >>= kDefaultAccuracy;
173     fCEdge.fCLastX >>= kDefaultAccuracy;
174     fCEdge.fCLastY >>= kDefaultAccuracy;
175     fCEdge.fCy = SnapY(fCEdge.fCy);
176     fCEdge.fCLastY = SnapY(fCEdge.fCLastY);
177 
178     fWinding = fCEdge.fWinding;
179     fCurveCount = fCEdge.fCurveCount;
180     fCurveShift = fCEdge.fCurveShift;
181     fCubicDShift = fCEdge.fCubicDShift;
182 
183     fSnappedY = fCEdge.fCy;
184 
185     return this->updateCubic(sortY);
186 }
187 
188 bool SkAnalyticCubicEdge::updateCubic(bool sortY) {
189     int     success;
190     int     count = fCurveCount;
191     SkFixed oldx = fCEdge.fCx;
192     SkFixed oldy = fCEdge.fCy;
193     SkFixed newx, newy;
194     const int ddshift = fCurveShift;
195     const int dshift = fCubicDShift;
196 
197     SkASSERT(count < 0);
198 
199     do {
200         if (++count < 0) {
201             newx    = oldx + (fCEdge.fCDx >> dshift);
202             fCEdge.fCDx    += fCEdge.fCDDx >> ddshift;
203             fCEdge.fCDDx   += fCEdge.fCDDDx;
204 
205             newy    = oldy + (fCEdge.fCDy >> dshift);
206             fCEdge.fCDy    += fCEdge.fCDDy >> ddshift;
207             fCEdge.fCDDy   += fCEdge.fCDDDy;
208         }
209         else {    // last segment
210             newx    = fCEdge.fCLastX;
211             newy    = fCEdge.fCLastY;
212         }
213 
214         // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint
215         // doesn't always achieve that, so we have to explicitly pin it here.
216         if (sortY && newy < oldy) {
217             newy = oldy;
218         }
219 
220         SkFixed newSnappedY = SnapY(newy);
221         // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint
222         // doesn't always achieve that, so we have to explicitly pin it here.
223         if (sortY && fCEdge.fCLastY < newSnappedY) {
224             newSnappedY = fCEdge.fCLastY;
225             count = 0;
226         }
227 
228         SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0
229                         ? SK_MaxS32
230                         : SkFDot6Div(SkFixedToFDot6(newx - oldx),
231                                      SkFixedToFDot6(newSnappedY - fSnappedY));
232 
233         success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope);
234 
235         oldx = newx;
236         oldy = newy;
237         fSnappedY = newSnappedY;
238     } while (count < 0 && !success);
239 
240     fCEdge.fCx  = newx;
241     fCEdge.fCy  = newy;
242     fCurveCount = SkToS8(count);
243     return success;
244 }
245