| 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 "math.h" | 
|  | 9 | 
| 8 #include "Sk4fLinearGradient.h" | 10 #include "Sk4fLinearGradient.h" | 
| 9 #include "SkLinearGradient.h" | 11 #include "SkLinearGradient.h" | 
| 10 | 12 | 
| 11 // define to test the 4f gradient path | 13 // define to test the 4f gradient path | 
| 12 // #define FORCE_4F_CONTEXT | 14 // #define FORCE_4F_CONTEXT | 
| 13 | 15 | 
| 14 static const float kInv255Float = 1.0f / 255; | 16 static const float kInv255Float = 1.0f / 255; | 
| 15 | 17 | 
| 16 static inline int repeat_8bits(int x) { | 18 static inline int repeat_8bits(float x) { | 
| 17     return x & 0xFF; | 19     float ignore; | 
|  | 20     const float frac = modff(x, &ignore); | 
|  | 21     return (int)(frac * 256) & 0xFF; | 
| 18 } | 22 } | 
| 19 | 23 | 
| 20 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. | 24 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. | 
| 21 // See http://code.google.com/p/skia/issues/detail?id=472 | 25 // See http://code.google.com/p/skia/issues/detail?id=472 | 
| 22 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 26 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 
| 23 #pragma optimize("", off) | 27 #pragma optimize("", off) | 
| 24 #endif | 28 #endif | 
| 25 | 29 | 
| 26 static inline int mirror_8bits(int x) { | 30 static inline int mirror_8bits(float x) { | 
| 27     if (x & 256) { | 31     const float x_mod_2 = fmod(x, 2.0f); | 
| 28         x = ~x; | 32     int x_9bits = (int)(x_mod_2 * 256); | 
|  | 33     if (x_9bits & 0x100) { | 
|  | 34         x_9bits = ~x_9bits; | 
| 29     } | 35     } | 
| 30     return x & 255; | 36     return x_9bits & 0xFF; | 
| 31 } | 37 } | 
| 32 | 38 | 
| 33 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 39 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 
| 34 #pragma optimize("", on) | 40 #pragma optimize("", on) | 
| 35 #endif | 41 #endif | 
| 36 | 42 | 
| 37 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) { | 43 static SkMatrix pts_to_unit_matrix(const SkPoint pts[2]) { | 
| 38     SkVector    vec = pts[1] - pts[0]; | 44     SkVector    vec = pts[1] - pts[0]; | 
| 39     SkScalar    mag = vec.length(); | 45     SkScalar    mag = vec.length(); | 
| 40     SkScalar    inv = mag ? SkScalarInvert(mag) : 0; | 46     SkScalar    inv = mag ? SkScalarInvert(mag) : 0; | 
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 180     do {                            \ | 186     do {                            \ | 
| 181     unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift;
      \ | 187     unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift;
      \ | 
| 182     SkASSERT(fi <= 0xFF);           \ | 188     SkASSERT(fi <= 0xFF);           \ | 
| 183     fx += dx;                       \ | 189     fx += dx;                       \ | 
| 184     *dstC++ = cache[toggle + fi];   \ | 190     *dstC++ = cache[toggle + fi];   \ | 
| 185     toggle = next_dither_toggle(toggle); \ | 191     toggle = next_dither_toggle(toggle); \ | 
| 186     } while (0) | 192     } while (0) | 
| 187 | 193 | 
| 188 namespace { | 194 namespace { | 
| 189 | 195 | 
| 190 typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 196 typedef void (*LinearShadeProc)(TileProc proc, float dx, float fx, | 
| 191                                 SkPMColor* dstC, const SkPMColor* cache, | 197                                 SkPMColor* dstC, const SkPMColor* cache, | 
| 192                                 int toggle, int count); | 198                                 int toggle, int count); | 
| 193 | 199 | 
| 194 // Linear interpolation (lerp) is unnecessary if there are no sharp | 200 // Linear interpolation (lerp) is unnecessary if there are no sharp | 
| 195 // discontinuities in the gradient - which must be true if there are | 201 // discontinuities in the gradient - which must be true if there are | 
| 196 // only 2 colors - but it's cheap. | 202 // only 2 colors - but it's cheap. | 
| 197 void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed f
     x, | 203 void shadeSpan_linear_vertical_lerp(TileProc proc, float dx, float fx, | 
| 198                                     SkPMColor* SK_RESTRICT dstC, | 204                                     SkPMColor* SK_RESTRICT dstC, | 
| 199                                     const SkPMColor* SK_RESTRICT cache, | 205                                     const SkPMColor* SK_RESTRICT cache, | 
| 200                                     int toggle, int count) { | 206                                     int toggle, int count) { | 
| 201     // We're a vertical gradient, so no change in a span. | 207     // We're a vertical gradient, so no change in a span. | 
| 202     // If colors change sharply across the gradient, dithering is | 208     // If colors change sharply across the gradient, dithering is | 
| 203     // insufficient (it subsamples the color space) and we need to lerp. | 209     // insufficient (it subsamples the color space) and we need to lerp. | 
| 204     unsigned fullIndex = proc(SkGradFixedToFixed(fx)); | 210     unsigned fullIndex = proc(fx); | 
| 205     unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; | 211     unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift; | 
| 206     unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift)
      - 1); | 212     unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift)
      - 1); | 
| 207 | 213 | 
| 208     int index0 = fi + toggle; | 214     int index0 = fi + toggle; | 
| 209     int index1 = index0; | 215     int index1 = index0; | 
| 210     if (fi < SkGradientShaderBase::kCache32Count - 1) { | 216     if (fi < SkGradientShaderBase::kCache32Count - 1) { | 
| 211         index1 += 1; | 217         index1 += 1; | 
| 212     } | 218     } | 
| 213     SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainde
     r); | 219     SkPMColor lerp = SkFastFourByteInterp(cache[index1], cache[index0], remainde
     r); | 
| 214     index0 ^= SkGradientShaderBase::kDitherStride32; | 220     index0 ^= SkGradientShaderBase::kDitherStride32; | 
| 215     index1 ^= SkGradientShaderBase::kDitherStride32; | 221     index1 ^= SkGradientShaderBase::kDitherStride32; | 
| 216     SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remaind
     er); | 222     SkPMColor dlerp = SkFastFourByteInterp(cache[index1], cache[index0], remaind
     er); | 
| 217     sk_memset32_dither(dstC, lerp, dlerp, count); | 223     sk_memset32_dither(dstC, lerp, dlerp, count); | 
| 218 } | 224 } | 
| 219 | 225 | 
| 220 void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 226 void shadeSpan_linear_clamp(TileProc proc, float float_dx, float float_fx, | 
| 221                             SkPMColor* SK_RESTRICT dstC, | 227                             SkPMColor* SK_RESTRICT dstC, | 
| 222                             const SkPMColor* SK_RESTRICT cache, | 228                             const SkPMColor* SK_RESTRICT cache, | 
| 223                             int toggle, int count) { | 229                             int toggle, int count) { | 
| 224     SkClampRange range; | 230     SkClampRange range; | 
| 225     range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); | 231     range.init(float_fx, float_dx, count, 0, SkGradientShaderBase::kCache32Count
      - 1); | 
| 226     range.validate(count); | 232     range.validate(count); | 
| 227 | 233 | 
| 228     if ((count = range.fCount0) > 0) { | 234     if ((count = range.fCount0) > 0) { | 
| 229         sk_memset32_dither(dstC, | 235         sk_memset32_dither(dstC, | 
| 230             cache[toggle + range.fV0], | 236             cache[toggle + range.fV0], | 
| 231             cache[next_dither_toggle(toggle) + range.fV0], | 237             cache[next_dither_toggle(toggle) + range.fV0], | 
| 232             count); | 238             count); | 
| 233         dstC += count; | 239         dstC += count; | 
| 234     } | 240     } | 
| 235     if ((count = range.fCount1) > 0) { | 241     if ((count = range.fCount1) > 0) { | 
| 236         int unroll = count >> 3; | 242         int unroll = count >> 3; | 
| 237         fx = range.fFx1; | 243         SkGradFixed fx = range.fFx1; | 
|  | 244         const SkGradFixed dx = SkFloatToGradFixed(float_dx); | 
| 238         for (int i = 0; i < unroll; i++) { | 245         for (int i = 0; i < unroll; i++) { | 
| 239             NO_CHECK_ITER;  NO_CHECK_ITER; | 246             NO_CHECK_ITER;  NO_CHECK_ITER; | 
| 240             NO_CHECK_ITER;  NO_CHECK_ITER; | 247             NO_CHECK_ITER;  NO_CHECK_ITER; | 
| 241             NO_CHECK_ITER;  NO_CHECK_ITER; | 248             NO_CHECK_ITER;  NO_CHECK_ITER; | 
| 242             NO_CHECK_ITER;  NO_CHECK_ITER; | 249             NO_CHECK_ITER;  NO_CHECK_ITER; | 
| 243         } | 250         } | 
| 244         if ((count &= 7) > 0) { | 251         if ((count &= 7) > 0) { | 
| 245             do { | 252             do { | 
| 246                 NO_CHECK_ITER; | 253                 NO_CHECK_ITER; | 
| 247             } while (--count != 0); | 254             } while (--count != 0); | 
| 248         } | 255         } | 
| 249     } | 256     } | 
| 250     if ((count = range.fCount2) > 0) { | 257     if ((count = range.fCount2) > 0) { | 
| 251         sk_memset32_dither(dstC, | 258         sk_memset32_dither(dstC, | 
| 252             cache[toggle + range.fV1], | 259             cache[toggle + range.fV1], | 
| 253             cache[next_dither_toggle(toggle) + range.fV1], | 260             cache[next_dither_toggle(toggle) + range.fV1], | 
| 254             count); | 261             count); | 
| 255     } | 262     } | 
| 256 } | 263 } | 
| 257 | 264 | 
| 258 void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 265 void shadeSpan_linear_mirror(TileProc proc, float dx, float fx, | 
| 259                              SkPMColor* SK_RESTRICT dstC, | 266                              SkPMColor* SK_RESTRICT dstC, | 
| 260                              const SkPMColor* SK_RESTRICT cache, | 267                              const SkPMColor* SK_RESTRICT cache, | 
| 261                              int toggle, int count) { | 268                              int toggle, int count) { | 
| 262     do { | 269     do { | 
| 263         unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8); | 270         unsigned fi = mirror_8bits(fx); | 
| 264         SkASSERT(fi <= 0xFF); | 271         SkASSERT(fi <= 0xFF); | 
| 265         fx += dx; | 272         fx += dx; | 
| 266         *dstC++ = cache[toggle + fi]; | 273         *dstC++ = cache[toggle + fi]; | 
| 267         toggle = next_dither_toggle(toggle); | 274         toggle = next_dither_toggle(toggle); | 
| 268     } while (--count != 0); | 275     } while (--count != 0); | 
| 269 } | 276 } | 
| 270 | 277 | 
| 271 void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx, | 278 void shadeSpan_linear_repeat(TileProc proc, float dx, float fx, | 
| 272         SkPMColor* SK_RESTRICT dstC, | 279         SkPMColor* SK_RESTRICT dstC, | 
| 273         const SkPMColor* SK_RESTRICT cache, | 280         const SkPMColor* SK_RESTRICT cache, | 
| 274         int toggle, int count) { | 281         int toggle, int count) { | 
| 275     do { | 282     do { | 
| 276         unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8); | 283         unsigned fi = repeat_8bits(fx); | 
| 277         SkASSERT(fi <= 0xFF); | 284         SkASSERT(fi <= 0xFF); | 
| 278         fx += dx; | 285         fx += dx; | 
| 279         *dstC++ = cache[toggle + fi]; | 286         *dstC++ = cache[toggle + fi]; | 
| 280         toggle = next_dither_toggle(toggle); | 287         toggle = next_dither_toggle(toggle); | 
| 281     } while (--count != 0); | 288     } while (--count != 0); | 
| 282 } | 289 } | 
| 283 | 290 | 
| 284 } | 291 } | 
| 285 | 292 | 
| 286 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
      SK_RESTRICT dstC, | 293 void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
      SK_RESTRICT dstC, | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 300 | 307 | 
| 301     SkPoint             srcPt; | 308     SkPoint             srcPt; | 
| 302     SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 309     SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 
| 303     TileProc            proc = linearGradient.fTileProc; | 310     TileProc            proc = linearGradient.fTileProc; | 
| 304     const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 311     const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 
| 305     int                 toggle = init_dither_toggle(x, y); | 312     int                 toggle = init_dither_toggle(x, y); | 
| 306 | 313 | 
| 307     if (fDstToIndexClass != kPerspective_MatrixClass) { | 314     if (fDstToIndexClass != kPerspective_MatrixClass) { | 
| 308         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 315         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 
| 309                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 316                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 
| 310         SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX); | 317         float dx, fx = SkScalarToFloat(srcPt.fX); | 
| 311 | 318 | 
| 312         if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 319         if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 
| 313             const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y)); | 320             const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y)); | 
| 314             // todo: do we need a real/high-precision value for dx here? | 321             dx = SkScalarToFloat(step.fX); | 
| 315             dx = SkScalarToGradFixed(step.fX); |  | 
| 316         } else { | 322         } else { | 
| 317             SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 323             SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 
| 318             dx = SkScalarToGradFixed(fDstToIndex.getScaleX()); | 324             dx = SkScalarToFloat(fDstToIndex.getScaleX()); | 
| 319         } | 325         } | 
| 320 | 326 | 
| 321         LinearShadeProc shadeProc = shadeSpan_linear_repeat; | 327         LinearShadeProc shadeProc = shadeSpan_linear_repeat; | 
| 322         if (0 == dx) { | 328         if (SkScalarNearlyZero(dx)) { | 
| 323             shadeProc = shadeSpan_linear_vertical_lerp; | 329             shadeProc = shadeSpan_linear_vertical_lerp; | 
| 324         } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { | 330         } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { | 
| 325             shadeProc = shadeSpan_linear_clamp; | 331             shadeProc = shadeSpan_linear_clamp; | 
| 326         } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { | 332         } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { | 
| 327             shadeProc = shadeSpan_linear_mirror; | 333             shadeProc = shadeSpan_linear_mirror; | 
| 328         } else { | 334         } else { | 
| 329             SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); | 335             SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); | 
| 330         } | 336         } | 
| 331         (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); | 337         (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); | 
| 332     } else { | 338     } else { | 
| 333         SkScalar    dstX = SkIntToScalar(x); | 339         SkScalar    dstX = SkIntToScalar(x); | 
| 334         SkScalar    dstY = SkIntToScalar(y); | 340         SkScalar    dstY = SkIntToScalar(y); | 
| 335         do { | 341         do { | 
| 336             dstProc(fDstToIndex, dstX, dstY, &srcPt); | 342             dstProc(fDstToIndex, dstX, dstY, &srcPt); | 
| 337             unsigned fi = proc(SkScalarToFixed(srcPt.fX)); | 343             unsigned fi = proc(SkScalarToFloat(srcPt.fX)); | 
| 338             SkASSERT(fi <= 0xFFFF); | 344             SkASSERT(fi <= 0xFFFF); | 
| 339             *dstC++ = cache[toggle + (fi >> kCache32Shift)]; | 345             *dstC++ = cache[toggle + (fi >> kCache32Shift)]; | 
| 340             toggle = next_dither_toggle(toggle); | 346             toggle = next_dither_toggle(toggle); | 
| 341             dstX += SK_Scalar1; | 347             dstX += SK_Scalar1; | 
| 342         } while (--count != 0); | 348         } while (--count != 0); | 
| 343     } | 349     } | 
| 344 } | 350 } | 
| 345 | 351 | 
| 346 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { | 352 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { | 
| 347     if (info) { | 353     if (info) { | 
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 762             this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dithe
     r); | 768             this->shade4_dx_clamp<false, true>(dstC, count, fx, dx, invDx, dithe
     r); | 
| 763         } | 769         } | 
| 764     } else { | 770     } else { | 
| 765         if (fApplyAlphaAfterInterp) { | 771         if (fApplyAlphaAfterInterp) { | 
| 766             this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dithe
     r); | 772             this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dithe
     r); | 
| 767         } else { | 773         } else { | 
| 768             this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dith
     er); | 774             this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dith
     er); | 
| 769         } | 775         } | 
| 770     } | 776     } | 
| 771 } | 777 } | 
| OLD | NEW | 
|---|