blob: 60c956aaf8f6e6ed004484e5af81de10e2421edc [file] [log] [blame]
liyuqian38911a72016-10-04 11:23:22 -07001/*
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
liyuqian38911a72016-10-04 11:23:22 -07008#include "SkAnalyticEdge.h"
Hal Canary2a2f6752018-06-11 21:44:01 -04009
liyuqian38911a72016-10-04 11:23:22 -070010#include "SkFDot6.h"
11#include "SkMathPriv.h"
Hal Canary2a2f6752018-06-11 21:44:01 -040012#include "SkTo.h"
liyuqian38911a72016-10-04 11:23:22 -070013
14// This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here.
15// Therefore, we'll let the outter function compute the slope once and send in the value.
16// Moreover, we'll compute fDY by quickly lookup the inverse table (if possible).
17bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) {
18 // Since we send in the slope, we can no longer snap y inside this function.
19 // If we don't send in the slope, or we do some more sophisticated snapping, this function
20 // could be a performance bottleneck.
21 SkASSERT(fWinding == 1 || fWinding == -1);
22 SkASSERT(fCurveCount != 0);
23
Yuqian Li5eb8fc52017-08-08 14:00:52 -040024 // We don't chop at y extrema for cubics so the y is not guaranteed to be increasing for them.
25 // In that case, we have to swap x/y and negate the winding.
26 if (y0 > y1) {
27 SkTSwap(x0, x1);
28 SkTSwap(y0, y1);
29 fWinding = -fWinding;
30 }
31
liyuqian38911a72016-10-04 11:23:22 -070032 SkASSERT(y0 <= y1);
33
34 SkFDot6 dx = SkFixedToFDot6(x1 - x0);
35 SkFDot6 dy = SkFixedToFDot6(y1 - y0);
36
37 // are we a zero-height line?
38 if (dy == 0) {
39 return false;
40 }
41
42 SkASSERT(slope < SK_MaxS32);
43
44 SkFDot6 absSlope = SkAbs32(SkFixedToFDot6(slope));
45 fX = x0;
46 fDX = slope;
47 fUpperX = x0;
48 fY = y0;
49 fUpperY = y0;
50 fLowerY = y1;
Yuqian Li98cf99b2017-01-17 16:15:06 -050051 fDY = (dx == 0 || slope == 0)
liyuqian38911a72016-10-04 11:23:22 -070052 ? SK_MaxS32
53 : absSlope < kInverseTableSize
54 ? QuickFDot6Inverse::Lookup(absSlope)
Yuqian Lice1d2932016-11-18 10:18:15 -050055 : SkAbs32(QuickSkFDot6Div(dy, dx));
liyuqian38911a72016-10-04 11:23:22 -070056
57 return true;
58}
59
Yuqian Li5eb8fc52017-08-08 14:00:52 -040060bool SkAnalyticEdge::update(SkFixed last_y, bool sortY) {
Yuqian Li7877d322017-07-18 10:11:05 -040061 SkASSERT(last_y >= fLowerY); // we shouldn't update edge if last_y < fLowerY
62 if (fCurveCount < 0) {
Yuqian Li5eb8fc52017-08-08 14:00:52 -040063 return static_cast<SkAnalyticCubicEdge*>(this)->updateCubic(sortY);
Yuqian Li7877d322017-07-18 10:11:05 -040064 } else if (fCurveCount > 0) {
65 return static_cast<SkAnalyticQuadraticEdge*>(this)->updateQuadratic();
66 }
67 return false;
68}
69
Yuqian Liaeef5612017-01-12 23:37:38 +000070bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) {
Yuqian Li550148b2017-01-13 10:13:13 -050071 fRiteE = nullptr;
72
73 if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) {
liyuqian38911a72016-10-04 11:23:22 -070074 return false;
75 }
Yuqian Li550148b2017-01-13 10:13:13 -050076 fQEdge.fQx >>= kDefaultAccuracy;
77 fQEdge.fQy >>= kDefaultAccuracy;
78 fQEdge.fQDx >>= kDefaultAccuracy;
79 fQEdge.fQDy >>= kDefaultAccuracy;
80 fQEdge.fQDDx >>= kDefaultAccuracy;
81 fQEdge.fQDDy >>= kDefaultAccuracy;
82 fQEdge.fQLastX >>= kDefaultAccuracy;
83 fQEdge.fQLastY >>= kDefaultAccuracy;
84 fQEdge.fQy = SnapY(fQEdge.fQy);
85 fQEdge.fQLastY = SnapY(fQEdge.fQLastY);
liyuqian38911a72016-10-04 11:23:22 -070086
87 fWinding = fQEdge.fWinding;
88 fCurveCount = fQEdge.fCurveCount;
89 fCurveShift = fQEdge.fCurveShift;
90
91 fSnappedX = fQEdge.fQx;
92 fSnappedY = fQEdge.fQy;
93
94 return this->updateQuadratic();
95}
96
97bool SkAnalyticQuadraticEdge::updateQuadratic() {
98 int success = 0; // initialize to fail!
99 int count = fCurveCount;
100 SkFixed oldx = fQEdge.fQx;
101 SkFixed oldy = fQEdge.fQy;
102 SkFixed dx = fQEdge.fQDx;
103 SkFixed dy = fQEdge.fQDy;
104 SkFixed newx, newy, newSnappedX, newSnappedY;
105 int shift = fCurveShift;
106
107 SkASSERT(count > 0);
108
109 do {
110 SkFixed slope;
111 if (--count > 0)
112 {
113 newx = oldx + (dx >> shift);
Yuqian Li0038b7f2016-11-14 11:51:41 -0500114 newy = oldy + (dy >> shift);
Yuqian Li79252f72016-11-29 15:02:49 -0500115 if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough
Yuqian Li550148b2017-01-13 10:13:13 -0500116 SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY);
117 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
118 : SK_MaxS32;
liyuqian38911a72016-10-04 11:23:22 -0700119 newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy));
Yuqian Li9939bd62016-11-29 10:27:16 -0500120 newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY);
liyuqian38911a72016-10-04 11:23:22 -0700121 } else {
Yuqian Li550148b2017-01-13 10:13:13 -0500122 newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy));
liyuqian38911a72016-10-04 11:23:22 -0700123 newSnappedX = newx;
Yuqian Li550148b2017-01-13 10:13:13 -0500124 SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY);
Yuqian Li550148b2017-01-13 10:13:13 -0500125 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
126 : SK_MaxS32;
liyuqian38911a72016-10-04 11:23:22 -0700127 }
128 dx += fQEdge.fQDDx;
129 dy += fQEdge.fQDDy;
130 }
131 else // last segment
132 {
133 newx = fQEdge.fQLastX;
134 newy = fQEdge.fQLastY;
135 newSnappedY = newy;
136 newSnappedX = newx;
Yuqian Li9939bd62016-11-29 10:27:16 -0500137 SkFDot6 diffY = (newy - fSnappedY) >> 10;
138 slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32;
liyuqian38911a72016-10-04 11:23:22 -0700139 }
140 if (slope < SK_MaxS32) {
141 success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope);
142 }
143 oldx = newx;
144 oldy = newy;
145 } while (count > 0 && !success);
146
147 SkASSERT(newSnappedY <= fQEdge.fQLastY);
148
149 fQEdge.fQx = newx;
150 fQEdge.fQy = newy;
151 fQEdge.fQDx = dx;
152 fQEdge.fQDy = dy;
153 fSnappedX = newSnappedX;
154 fSnappedY = newSnappedY;
155 fCurveCount = SkToS8(count);
156 return success;
157}
158
Yuqian Li5eb8fc52017-08-08 14:00:52 -0400159bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4], bool sortY) {
Yuqian Li550148b2017-01-13 10:13:13 -0500160 fRiteE = nullptr;
161
Yuqian Li5eb8fc52017-08-08 14:00:52 -0400162 if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy, sortY)) {
liyuqian38911a72016-10-04 11:23:22 -0700163 return false;
164 }
165
Yuqian Li550148b2017-01-13 10:13:13 -0500166 fCEdge.fCx >>= kDefaultAccuracy;
167 fCEdge.fCy >>= kDefaultAccuracy;
168 fCEdge.fCDx >>= kDefaultAccuracy;
169 fCEdge.fCDy >>= kDefaultAccuracy;
170 fCEdge.fCDDx >>= kDefaultAccuracy;
171 fCEdge.fCDDy >>= kDefaultAccuracy;
172 fCEdge.fCDDDx >>= kDefaultAccuracy;
173 fCEdge.fCDDDy >>= kDefaultAccuracy;
174 fCEdge.fCLastX >>= kDefaultAccuracy;
175 fCEdge.fCLastY >>= kDefaultAccuracy;
176 fCEdge.fCy = SnapY(fCEdge.fCy);
177 fCEdge.fCLastY = SnapY(fCEdge.fCLastY);
liyuqian38911a72016-10-04 11:23:22 -0700178
179 fWinding = fCEdge.fWinding;
180 fCurveCount = fCEdge.fCurveCount;
181 fCurveShift = fCEdge.fCurveShift;
182 fCubicDShift = fCEdge.fCubicDShift;
183
Yuqian Li550148b2017-01-13 10:13:13 -0500184 fSnappedY = fCEdge.fCy;
185
Yuqian Li5eb8fc52017-08-08 14:00:52 -0400186 return this->updateCubic(sortY);
liyuqian38911a72016-10-04 11:23:22 -0700187}
188
Yuqian Li5eb8fc52017-08-08 14:00:52 -0400189bool SkAnalyticCubicEdge::updateCubic(bool sortY) {
liyuqian38911a72016-10-04 11:23:22 -0700190 int success;
191 int count = fCurveCount;
192 SkFixed oldx = fCEdge.fCx;
193 SkFixed oldy = fCEdge.fCy;
194 SkFixed newx, newy;
195 const int ddshift = fCurveShift;
196 const int dshift = fCubicDShift;
197
198 SkASSERT(count < 0);
199
200 do {
201 if (++count < 0) {
202 newx = oldx + (fCEdge.fCDx >> dshift);
203 fCEdge.fCDx += fCEdge.fCDDx >> ddshift;
204 fCEdge.fCDDx += fCEdge.fCDDDx;
205
206 newy = oldy + (fCEdge.fCDy >> dshift);
207 fCEdge.fCDy += fCEdge.fCDDy >> ddshift;
208 fCEdge.fCDDy += fCEdge.fCDDDy;
209 }
210 else { // last segment
211 newx = fCEdge.fCLastX;
212 newy = fCEdge.fCLastY;
213 }
214
215 // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint
216 // doesn't always achieve that, so we have to explicitly pin it here.
Yuqian Li5eb8fc52017-08-08 14:00:52 -0400217 if (sortY && newy < oldy) {
liyuqian38911a72016-10-04 11:23:22 -0700218 newy = oldy;
219 }
220
Yuqian Li550148b2017-01-13 10:13:13 -0500221 SkFixed newSnappedY = SnapY(newy);
222 // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint
223 // doesn't always achieve that, so we have to explicitly pin it here.
Yuqian Li5eb8fc52017-08-08 14:00:52 -0400224 if (sortY && fCEdge.fCLastY < newSnappedY) {
Yuqian Li550148b2017-01-13 10:13:13 -0500225 newSnappedY = fCEdge.fCLastY;
226 count = 0;
227 }
228
229 SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0
Yuqian Lidc944812016-11-11 12:37:45 -0500230 ? SK_MaxS32
231 : SkFDot6Div(SkFixedToFDot6(newx - oldx),
Yuqian Li550148b2017-01-13 10:13:13 -0500232 SkFixedToFDot6(newSnappedY - fSnappedY));
Yuqian Lidc944812016-11-11 12:37:45 -0500233
Yuqian Li550148b2017-01-13 10:13:13 -0500234 success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope);
Yuqian Lidc944812016-11-11 12:37:45 -0500235
liyuqian38911a72016-10-04 11:23:22 -0700236 oldx = newx;
237 oldy = newy;
Yuqian Li550148b2017-01-13 10:13:13 -0500238 fSnappedY = newSnappedY;
liyuqian38911a72016-10-04 11:23:22 -0700239 } while (count < 0 && !success);
240
241 fCEdge.fCx = newx;
242 fCEdge.fCy = newy;
243 fCurveCount = SkToS8(count);
244 return success;
245}