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