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); |