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