| 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 |