OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkTwoPointConicalGradient.h" | 8 #include "SkTwoPointConicalGradient.h" |
9 | 9 |
10 #include "SkTwoPointConicalGradient_gpu.h" | 10 #include "SkTwoPointConicalGradient_gpu.h" |
11 | 11 |
| 12 struct TwoPtRadialContext { |
| 13 const TwoPtRadial& fRec; |
| 14 float fRelX, fRelY; |
| 15 const float fIncX, fIncY; |
| 16 float fB; |
| 17 const float fDB; |
| 18 |
| 19 TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkScalar fy, |
| 20 SkScalar dfx, SkScalar dfy); |
| 21 SkFixed nextT(); |
| 22 }; |
| 23 |
12 static int valid_divide(float numer, float denom, float* ratio) { | 24 static int valid_divide(float numer, float denom, float* ratio) { |
13 SkASSERT(ratio); | 25 SkASSERT(ratio); |
14 if (0 == denom) { | 26 if (0 == denom) { |
15 return 0; | 27 return 0; |
16 } | 28 } |
17 *ratio = numer / denom; | 29 *ratio = numer / denom; |
18 return 1; | 30 return 1; |
19 } | 31 } |
20 | 32 |
21 // Return the number of distinct real roots, and write them into roots[] in | 33 // Return the number of distinct real roots, and write them into roots[] in |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 fRadius = SkScalarToFloat(rad0); | 88 fRadius = SkScalarToFloat(rad0); |
77 fDRadius = SkScalarToFloat(rad1) - fRadius; | 89 fDRadius = SkScalarToFloat(rad1) - fRadius; |
78 | 90 |
79 fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); | 91 fA = sqr(fDCenterX) + sqr(fDCenterY) - sqr(fDRadius); |
80 fRadius2 = sqr(fRadius); | 92 fRadius2 = sqr(fRadius); |
81 fRDR = fRadius * fDRadius; | 93 fRDR = fRadius * fDRadius; |
82 | 94 |
83 fFlipped = flipped; | 95 fFlipped = flipped; |
84 } | 96 } |
85 | 97 |
86 void TwoPtRadial::setup(SkScalar fx, SkScalar fy, SkScalar dfx, SkScalar dfy) { | 98 TwoPtRadialContext::TwoPtRadialContext(const TwoPtRadial& rec, SkScalar fx, SkSc
alar fy, |
87 fRelX = SkScalarToFloat(fx) - fCenterX; | 99 SkScalar dfx, SkScalar dfy) |
88 fRelY = SkScalarToFloat(fy) - fCenterY; | 100 : fRec(rec) |
89 fIncX = SkScalarToFloat(dfx); | 101 , fRelX(SkScalarToFloat(fx) - rec.fCenterX) |
90 fIncY = SkScalarToFloat(dfy); | 102 , fRelY(SkScalarToFloat(fy) - rec.fCenterY) |
91 fB = -2 * (fDCenterX * fRelX + fDCenterY * fRelY + fRDR); | 103 , fIncX(SkScalarToFloat(dfx)) |
92 fDB = -2 * (fDCenterX * fIncX + fDCenterY * fIncY); | 104 , fIncY(SkScalarToFloat(dfy)) |
93 } | 105 , fB(-2 * (rec.fDCenterX * fRelX + rec.fDCenterY * fRelY + rec.fRDR)) |
| 106 , fDB(-2 * (rec.fDCenterX * fIncX + rec.fDCenterY * fIncY)) {} |
94 | 107 |
95 SkFixed TwoPtRadial::nextT() { | 108 SkFixed TwoPtRadialContext::nextT() { |
96 float roots[2]; | 109 float roots[2]; |
97 | 110 |
98 float C = sqr(fRelX) + sqr(fRelY) - fRadius2; | 111 float C = sqr(fRelX) + sqr(fRelY) - fRec.fRadius2; |
99 int countRoots = find_quad_roots(fA, fB, C, roots, fFlipped); | 112 int countRoots = find_quad_roots(fRec.fA, fB, C, roots, fRec.fFlipped); |
100 | 113 |
101 fRelX += fIncX; | 114 fRelX += fIncX; |
102 fRelY += fIncY; | 115 fRelY += fIncY; |
103 fB += fDB; | 116 fB += fDB; |
104 | 117 |
105 if (0 == countRoots) { | 118 if (0 == countRoots) { |
106 return kDontDrawT; | 119 return TwoPtRadial::kDontDrawT; |
107 } | 120 } |
108 | 121 |
109 // Prefer the bigger t value if both give a radius(t) > 0 | 122 // Prefer the bigger t value if both give a radius(t) > 0 |
110 // find_quad_roots returns the values sorted, so we start with the last | 123 // find_quad_roots returns the values sorted, so we start with the last |
111 float t = roots[countRoots - 1]; | 124 float t = roots[countRoots - 1]; |
112 float r = lerp(fRadius, fDRadius, t); | 125 float r = lerp(fRec.fRadius, fRec.fDRadius, t); |
113 if (r <= 0) { | 126 if (r <= 0) { |
114 t = roots[0]; // might be the same as roots[countRoots-1] | 127 t = roots[0]; // might be the same as roots[countRoots-1] |
115 r = lerp(fRadius, fDRadius, t); | 128 r = lerp(fRec.fRadius, fRec.fDRadius, t); |
116 if (r <= 0) { | 129 if (r <= 0) { |
117 return kDontDrawT; | 130 return TwoPtRadial::kDontDrawT; |
118 } | 131 } |
119 } | 132 } |
120 return SkFloatToFixed(t); | 133 return SkFloatToFixed(t); |
121 } | 134 } |
122 | 135 |
123 typedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC, | 136 typedef void (*TwoPointConicalProc)(TwoPtRadialContext* rec, SkPMColor* dstC, |
124 const SkPMColor* cache, int toggle, int coun
t); | 137 const SkPMColor* cache, int toggle, int coun
t); |
125 | 138 |
126 static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, | 139 static void twopoint_clamp(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC, |
127 const SkPMColor* SK_RESTRICT cache, int toggle, | 140 const SkPMColor* SK_RESTRICT cache, int toggle, |
128 int count) { | 141 int count) { |
129 for (; count > 0; --count) { | 142 for (; count > 0; --count) { |
130 SkFixed t = rec->nextT(); | 143 SkFixed t = rec->nextT(); |
131 if (TwoPtRadial::DontDrawT(t)) { | 144 if (TwoPtRadial::DontDrawT(t)) { |
132 *dstC++ = 0; | 145 *dstC++ = 0; |
133 } else { | 146 } else { |
134 SkFixed index = SkClampMax(t, 0xFFFF); | 147 SkFixed index = SkClampMax(t, 0xFFFF); |
135 SkASSERT(index <= 0xFFFF); | 148 SkASSERT(index <= 0xFFFF); |
136 *dstC++ = cache[toggle + | 149 *dstC++ = cache[toggle + |
137 (index >> SkGradientShaderBase::kCache32Shift)]; | 150 (index >> SkGradientShaderBase::kCache32Shift)]; |
138 } | 151 } |
139 toggle = next_dither_toggle(toggle); | 152 toggle = next_dither_toggle(toggle); |
140 } | 153 } |
141 } | 154 } |
142 | 155 |
143 static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, | 156 static void twopoint_repeat(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC
, |
144 const SkPMColor* SK_RESTRICT cache, int toggle, | 157 const SkPMColor* SK_RESTRICT cache, int toggle, |
145 int count) { | 158 int count) { |
146 for (; count > 0; --count) { | 159 for (; count > 0; --count) { |
147 SkFixed t = rec->nextT(); | 160 SkFixed t = rec->nextT(); |
148 if (TwoPtRadial::DontDrawT(t)) { | 161 if (TwoPtRadial::DontDrawT(t)) { |
149 *dstC++ = 0; | 162 *dstC++ = 0; |
150 } else { | 163 } else { |
151 SkFixed index = repeat_tileproc(t); | 164 SkFixed index = repeat_tileproc(t); |
152 SkASSERT(index <= 0xFFFF); | 165 SkASSERT(index <= 0xFFFF); |
153 *dstC++ = cache[toggle + | 166 *dstC++ = cache[toggle + |
154 (index >> SkGradientShaderBase::kCache32Shift)]; | 167 (index >> SkGradientShaderBase::kCache32Shift)]; |
155 } | 168 } |
156 toggle = next_dither_toggle(toggle); | 169 toggle = next_dither_toggle(toggle); |
157 } | 170 } |
158 } | 171 } |
159 | 172 |
160 static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC, | 173 static void twopoint_mirror(TwoPtRadialContext* rec, SkPMColor* SK_RESTRICT dstC
, |
161 const SkPMColor* SK_RESTRICT cache, int toggle, | 174 const SkPMColor* SK_RESTRICT cache, int toggle, |
162 int count) { | 175 int count) { |
163 for (; count > 0; --count) { | 176 for (; count > 0; --count) { |
164 SkFixed t = rec->nextT(); | 177 SkFixed t = rec->nextT(); |
165 if (TwoPtRadial::DontDrawT(t)) { | 178 if (TwoPtRadial::DontDrawT(t)) { |
166 *dstC++ = 0; | 179 *dstC++ = 0; |
167 } else { | 180 } else { |
168 SkFixed index = mirror_tileproc(t); | 181 SkFixed index = mirror_tileproc(t); |
169 SkASSERT(index <= 0xFFFF); | 182 SkASSERT(index <= 0xFFFF); |
170 *dstC++ = cache[toggle + | 183 *dstC++ = cache[toggle + |
(...skipping 25 matching lines...) Expand all Loading... |
196 this->init(); | 209 this->init(); |
197 } | 210 } |
198 | 211 |
199 bool SkTwoPointConicalGradient::isOpaque() const { | 212 bool SkTwoPointConicalGradient::isOpaque() const { |
200 // Because areas outside the cone are left untouched, we cannot treat the | 213 // Because areas outside the cone are left untouched, we cannot treat the |
201 // shader as opaque even if the gradient itself is opaque. | 214 // shader as opaque even if the gradient itself is opaque. |
202 // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 | 215 // TODO(junov): Compute whether the cone fills the plane crbug.com/222380 |
203 return false; | 216 return false; |
204 } | 217 } |
205 | 218 |
206 void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam, | 219 size_t SkTwoPointConicalGradient::contextSize() const { |
207 int count) { | 220 return sizeof(TwoPointConicalGradientContext); |
| 221 } |
| 222 |
| 223 SkShader::Context* SkTwoPointConicalGradient::createContext( |
| 224 const SkBitmap& device, const SkPaint& paint, |
| 225 const SkMatrix& matrix, void* storage) const { |
| 226 if (!this->validContext(device, paint, matrix)) { |
| 227 return NULL; |
| 228 } |
| 229 |
| 230 return SkNEW_PLACEMENT_ARGS(storage, TwoPointConicalGradientContext, |
| 231 (*this, device, paint, matrix)); |
| 232 } |
| 233 |
| 234 SkTwoPointConicalGradient::TwoPointConicalGradientContext::TwoPointConicalGradie
ntContext( |
| 235 const SkTwoPointConicalGradient& shader, const SkBitmap& device, |
| 236 const SkPaint& paint, const SkMatrix& matrix) |
| 237 : INHERITED(shader, device, paint, matrix) |
| 238 { |
| 239 // we don't have a span16 proc |
| 240 fFlags &= ~kHasSpan16_Flag; |
| 241 |
| 242 // in general, we might discard based on computed-radius, so clear |
| 243 // this flag (todo: sometimes we can detect that we never discard...) |
| 244 fFlags &= ~kOpaqueAlpha_Flag; |
| 245 } |
| 246 |
| 247 void SkTwoPointConicalGradient::TwoPointConicalGradientContext::shadeSpan( |
| 248 int x, int y, SkPMColor* dstCParam, int count) { |
| 249 const SkTwoPointConicalGradient& twoPointConicalGradient = |
| 250 static_cast<const SkTwoPointConicalGradient&>(fShader); |
| 251 |
208 int toggle = init_dither_toggle(x, y); | 252 int toggle = init_dither_toggle(x, y); |
209 | 253 |
210 SkASSERT(count > 0); | 254 SkASSERT(count > 0); |
211 | 255 |
212 SkPMColor* SK_RESTRICT dstC = dstCParam; | 256 SkPMColor* SK_RESTRICT dstC = dstCParam; |
213 | 257 |
214 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 258 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
215 | 259 |
216 const SkPMColor* SK_RESTRICT cache = this->getCache32(); | 260 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); |
217 | 261 |
218 TwoPointConicalProc shadeProc = twopoint_repeat; | 262 TwoPointConicalProc shadeProc = twopoint_repeat; |
219 if (SkShader::kClamp_TileMode == fTileMode) { | 263 if (SkShader::kClamp_TileMode == twoPointConicalGradient.fTileMode) { |
220 shadeProc = twopoint_clamp; | 264 shadeProc = twopoint_clamp; |
221 } else if (SkShader::kMirror_TileMode == fTileMode) { | 265 } else if (SkShader::kMirror_TileMode == twoPointConicalGradient.fTileMode)
{ |
222 shadeProc = twopoint_mirror; | 266 shadeProc = twopoint_mirror; |
223 } else { | 267 } else { |
224 SkASSERT(SkShader::kRepeat_TileMode == fTileMode); | 268 SkASSERT(SkShader::kRepeat_TileMode == twoPointConicalGradient.fTileMode
); |
225 } | 269 } |
226 | 270 |
227 if (fDstToIndexClass != kPerspective_MatrixClass) { | 271 if (fDstToIndexClass != kPerspective_MatrixClass) { |
228 SkPoint srcPt; | 272 SkPoint srcPt; |
229 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 273 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, |
230 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 274 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
231 SkScalar dx, fx = srcPt.fX; | 275 SkScalar dx, fx = srcPt.fX; |
232 SkScalar dy, fy = srcPt.fY; | 276 SkScalar dy, fy = srcPt.fY; |
233 | 277 |
234 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 278 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
235 SkFixed fixedX, fixedY; | 279 SkFixed fixedX, fixedY; |
236 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY); | 280 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY); |
237 dx = SkFixedToScalar(fixedX); | 281 dx = SkFixedToScalar(fixedX); |
238 dy = SkFixedToScalar(fixedY); | 282 dy = SkFixedToScalar(fixedY); |
239 } else { | 283 } else { |
240 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 284 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
241 dx = fDstToIndex.getScaleX(); | 285 dx = fDstToIndex.getScaleX(); |
242 dy = fDstToIndex.getSkewY(); | 286 dy = fDstToIndex.getSkewY(); |
243 } | 287 } |
244 | 288 |
245 fRec.setup(fx, fy, dx, dy); | 289 TwoPtRadialContext rec(twoPointConicalGradient.fRec, fx, fy, dx, dy); |
246 (*shadeProc)(&fRec, dstC, cache, toggle, count); | 290 (*shadeProc)(&rec, dstC, cache, toggle, count); |
247 } else { // perspective case | 291 } else { // perspective case |
248 SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf; | 292 SkScalar dstX = SkIntToScalar(x) + SK_ScalarHalf; |
249 SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf; | 293 SkScalar dstY = SkIntToScalar(y) + SK_ScalarHalf; |
250 for (; count > 0; --count) { | 294 for (; count > 0; --count) { |
251 SkPoint srcPt; | 295 SkPoint srcPt; |
252 dstProc(fDstToIndex, dstX, dstY, &srcPt); | 296 dstProc(fDstToIndex, dstX, dstY, &srcPt); |
253 fRec.setup(srcPt.fX, srcPt.fY, 0, 0); | 297 TwoPtRadialContext rec(twoPointConicalGradient.fRec, srcPt.fX, srcPt
.fY, 0, 0); |
254 (*shadeProc)(&fRec, dstC, cache, toggle, 1); | 298 (*shadeProc)(&rec, dstC, cache, toggle, 1); |
255 | 299 |
256 dstX += SK_Scalar1; | 300 dstX += SK_Scalar1; |
257 toggle = next_dither_toggle(toggle); | 301 toggle = next_dither_toggle(toggle); |
258 dstC += 1; | 302 dstC += 1; |
259 } | 303 } |
260 } | 304 } |
261 } | 305 } |
262 | 306 |
263 bool SkTwoPointConicalGradient::setContext(const SkBitmap& device, | |
264 const SkPaint& paint, | |
265 const SkMatrix& matrix) { | |
266 if (!this->INHERITED::setContext(device, paint, matrix)) { | |
267 return false; | |
268 } | |
269 | |
270 // we don't have a span16 proc | |
271 fFlags &= ~kHasSpan16_Flag; | |
272 | |
273 // in general, we might discard based on computed-radius, so clear | |
274 // this flag (todo: sometimes we can detect that we never discard...) | |
275 fFlags &= ~kOpaqueAlpha_Flag; | |
276 | |
277 return true; | |
278 } | |
279 | |
280 SkShader::BitmapType SkTwoPointConicalGradient::asABitmap( | 307 SkShader::BitmapType SkTwoPointConicalGradient::asABitmap( |
281 SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const { | 308 SkBitmap* bitmap, SkMatrix* matrix, SkShader::TileMode* xy) const { |
282 SkPoint diff = fCenter2 - fCenter1; | 309 SkPoint diff = fCenter2 - fCenter1; |
283 SkScalar diffLen = 0; | 310 SkScalar diffLen = 0; |
284 | 311 |
285 if (bitmap) { | 312 if (bitmap) { |
286 this->getGradientTableBitmap(bitmap); | 313 this->getGradientTableBitmap(bitmap); |
287 } | 314 } |
288 if (matrix) { | 315 if (matrix) { |
289 diffLen = diff.length(); | 316 diffLen = diff.length(); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 str->appendScalar(fCenter2.fY); | 420 str->appendScalar(fCenter2.fY); |
394 str->append(") radius2: "); | 421 str->append(") radius2: "); |
395 str->appendScalar(fRadius2); | 422 str->appendScalar(fRadius2); |
396 str->append(" "); | 423 str->append(" "); |
397 | 424 |
398 this->INHERITED::toString(str); | 425 this->INHERITED::toString(str); |
399 | 426 |
400 str->append(")"); | 427 str->append(")"); |
401 } | 428 } |
402 #endif | 429 #endif |
OLD | NEW |