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