| Index: src/effects/gradients/SkLinearGradient.cpp
|
| diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
|
| index 15d461960dd8f6b97230d989bbce7d497bc7b660..b36c8f62bcf3c25d0fd15ed64f309f8200531738 100644
|
| --- a/src/effects/gradients/SkLinearGradient.cpp
|
| +++ b/src/effects/gradients/SkLinearGradient.cpp
|
| @@ -5,6 +5,8 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| +#include "math.h"
|
| +
|
| #include "Sk4fLinearGradient.h"
|
| #include "SkLinearGradient.h"
|
|
|
| @@ -13,8 +15,10 @@
|
|
|
| static const float kInv255Float = 1.0f / 255;
|
|
|
| -static inline int repeat_8bits(int x) {
|
| - return x & 0xFF;
|
| +static inline int repeat_8bits(float x) {
|
| + float ignore;
|
| + const float frac = modff(x, &ignore);
|
| + return (int)(frac * 256) & 0xFF;
|
| }
|
|
|
| // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
|
| @@ -23,11 +27,13 @@ static inline int repeat_8bits(int x) {
|
| #pragma optimize("", off)
|
| #endif
|
|
|
| -static inline int mirror_8bits(int x) {
|
| - if (x & 256) {
|
| - x = ~x;
|
| +static inline int mirror_8bits(float x) {
|
| + const float x_mod_2 = fmod(x, 2.0f);
|
| + int x_9bits = (int)(x_mod_2 * 256);
|
| + if (x_9bits & 0x100) {
|
| + x_9bits = ~x_9bits;
|
| }
|
| - return x & 255;
|
| + return x_9bits & 0xFF;
|
| }
|
|
|
| #if defined(_MSC_VER) && (_MSC_VER >= 1600)
|
| @@ -187,21 +193,21 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext(
|
|
|
| namespace {
|
|
|
| -typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| +typedef void (*LinearShadeProc)(TileProc proc, float dx, float fx,
|
| SkPMColor* dstC, const SkPMColor* cache,
|
| int toggle, int count);
|
|
|
| // Linear interpolation (lerp) is unnecessary if there are no sharp
|
| // discontinuities in the gradient - which must be true if there are
|
| // only 2 colors - but it's cheap.
|
| -void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| +void shadeSpan_linear_vertical_lerp(TileProc proc, float dx, float fx,
|
| SkPMColor* SK_RESTRICT dstC,
|
| const SkPMColor* SK_RESTRICT cache,
|
| int toggle, int count) {
|
| // We're a vertical gradient, so no change in a span.
|
| // If colors change sharply across the gradient, dithering is
|
| // insufficient (it subsamples the color space) and we need to lerp.
|
| - unsigned fullIndex = proc(SkGradFixedToFixed(fx));
|
| + unsigned fullIndex = proc(fx);
|
| unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
|
| unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
|
|
|
| @@ -217,12 +223,12 @@ void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed f
|
| sk_memset32_dither(dstC, lerp, dlerp, count);
|
| }
|
|
|
| -void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| +void shadeSpan_linear_clamp(TileProc proc, float float_dx, float float_fx,
|
| SkPMColor* SK_RESTRICT dstC,
|
| const SkPMColor* SK_RESTRICT cache,
|
| int toggle, int count) {
|
| SkClampRange range;
|
| - range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
|
| + range.init(float_fx, float_dx, count, 0, SkGradientShaderBase::kCache32Count - 1);
|
| range.validate(count);
|
|
|
| if ((count = range.fCount0) > 0) {
|
| @@ -234,7 +240,8 @@ void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| }
|
| if ((count = range.fCount1) > 0) {
|
| int unroll = count >> 3;
|
| - fx = range.fFx1;
|
| + SkGradFixed fx = range.fFx1;
|
| + const SkGradFixed dx = SkFloatToGradFixed(float_dx);
|
| for (int i = 0; i < unroll; i++) {
|
| NO_CHECK_ITER; NO_CHECK_ITER;
|
| NO_CHECK_ITER; NO_CHECK_ITER;
|
| @@ -255,12 +262,12 @@ void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| }
|
| }
|
|
|
| -void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| +void shadeSpan_linear_mirror(TileProc proc, float dx, float fx,
|
| SkPMColor* SK_RESTRICT dstC,
|
| const SkPMColor* SK_RESTRICT cache,
|
| int toggle, int count) {
|
| do {
|
| - unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8);
|
| + unsigned fi = mirror_8bits(fx);
|
| SkASSERT(fi <= 0xFF);
|
| fx += dx;
|
| *dstC++ = cache[toggle + fi];
|
| @@ -268,12 +275,12 @@ void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| } while (--count != 0);
|
| }
|
|
|
| -void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
|
| +void shadeSpan_linear_repeat(TileProc proc, float dx, float fx,
|
| SkPMColor* SK_RESTRICT dstC,
|
| const SkPMColor* SK_RESTRICT cache,
|
| int toggle, int count) {
|
| do {
|
| - unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8);
|
| + unsigned fi = repeat_8bits(fx);
|
| SkASSERT(fi <= 0xFF);
|
| fx += dx;
|
| *dstC++ = cache[toggle + fi];
|
| @@ -307,19 +314,18 @@ void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
|
| if (fDstToIndexClass != kPerspective_MatrixClass) {
|
| dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
|
| SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
|
| - SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
|
| + float dx, fx = SkScalarToFloat(srcPt.fX);
|
|
|
| if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
|
| const auto step = fDstToIndex.fixedStepInX(SkIntToScalar(y));
|
| - // todo: do we need a real/high-precision value for dx here?
|
| - dx = SkScalarToGradFixed(step.fX);
|
| + dx = SkScalarToFloat(step.fX);
|
| } else {
|
| SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
|
| - dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
|
| + dx = SkScalarToFloat(fDstToIndex.getScaleX());
|
| }
|
|
|
| LinearShadeProc shadeProc = shadeSpan_linear_repeat;
|
| - if (0 == dx) {
|
| + if (SkScalarNearlyZero(dx)) {
|
| shadeProc = shadeSpan_linear_vertical_lerp;
|
| } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
|
| shadeProc = shadeSpan_linear_clamp;
|
| @@ -334,7 +340,7 @@ void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
|
| SkScalar dstY = SkIntToScalar(y);
|
| do {
|
| dstProc(fDstToIndex, dstX, dstY, &srcPt);
|
| - unsigned fi = proc(SkScalarToFixed(srcPt.fX));
|
| + unsigned fi = proc(SkScalarToFloat(srcPt.fX));
|
| SkASSERT(fi <= 0xFFFF);
|
| *dstC++ = cache[toggle + (fi >> kCache32Shift)];
|
| toggle = next_dither_toggle(toggle);
|
|
|