* returns [0..count] for the number of steps (<= count) for which x0 <= edge
* given each step is followed by x0 += dx
*/
-static int chop(int64_t x0, SkFixed edge, int64_t x1, int64_t dx, int count) {
+static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
SkASSERT(dx > 0);
SkASSERT(count >= 0);
return (int)n;
}
-static bool overflows_fixed(int64_t x) {
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
+static bool overflows_gradfixed(int64_t x) {
return x < -SK_FixedMax || x > SK_FixedMax;
}
+#endif
-void SkClampRange::initFor1(SkFixed fx) {
+void SkClampRange::initFor1(SkGradFixed fx) {
fCount0 = fCount1 = fCount2 = 0;
if (fx <= 0) {
fCount0 = 1;
- } else if (fx < 0xFFFF) {
+ } else if (fx < kFracMax_SkGradFixed) {
fCount1 = 1;
fFx1 = fx;
} else {
}
}
-void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
+void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
SkASSERT(count > 0);
fV0 = v0;
int64_t fx = fx0;
int64_t dx = dx0;
+
// start with ex equal to the last computed value
int64_t ex = fx + (count - 1) * dx;
- if ((uint64_t)(fx | ex) <= 0xFFFF) {
+ if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
fCount0 = fCount2 = 0;
fCount1 = count;
fFx1 = fx0;
fCount0 = count;
return;
}
- if (fx >= 0xFFFF && ex >= 0xFFFF) {
+ if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
fCount0 = fCount1 = 0;
fCount2 = count;
return;
// now make ex be 1 past the last computed value
ex += dx;
+
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
// now check for over/under flow
- if (overflows_fixed(ex)) {
+ if (overflows_gradfixed(ex)) {
int originalCount = count;
int64_t ccount;
bool swap = dx < 0;
dx = -dx;
fx = -fx;
}
- ccount = (SK_FixedMax - fx + dx - 1) / dx;
+
+ int shift = 0;
+ if (sizeof(SkGradFixed) == 8) {
+ shift = 16;
+ }
+
+ ccount = ((SK_FixedMax << shift) - fx + dx - 1) / dx;
if (swap) {
dx = -dx;
fx = -fx;
extraCount = originalCount - count;
ex = fx + dx * count;
}
+#endif
bool doSwap = dx < 0;
fx += fCount0 * dx;
SkASSERT(fx >= 0);
SkASSERT(fCount0 == 0 || (fx - dx) < 0);
- fCount1 = chop(fx, 0xFFFF, ex, dx, count);
+ fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
count -= fCount1;
fCount2 = count;
fx += fCount1 * dx;
SkASSERT(fx <= ex);
if (fCount2 > 0) {
- SkASSERT(fx >= 0xFFFF);
+ SkASSERT(fx >= kFracMax_SkGradFixed);
if (fCount1 > 0) {
- SkASSERT(fx - dx < 0xFFFF);
+ SkASSERT(fx - dx < kFracMax_SkGradFixed);
}
}
#endif
-
/*
* Copyright 2011 Google Inc.
*
* found in the LICENSE file.
*/
-
#ifndef SkClampRange_DEFINED
#define SkClampRange_DEFINED
#include "SkFixed.h"
+#include "SkScalar.h"
+
+#define SK_SUPPORT_LEGACY_GRADIENT_PRECISION
+
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
+ #define SkGradFixed SkFixed
+ #define SkScalarToGradFixed SkScalarToFixed
+ #define SkFixedToGradFixed(x) (x)
+ #define SkGradFixedToFixed(x) (x)
+ #define kFracMax_SkGradFixed 0xFFFF
+#else
+ #define SkGradFixed SkFixed3232
+ #define SkScalarToGradFixed SkScalarToFixed3232
+ #define SkFixedToGradFixed SkFixedToFixed3232
+ #define SkGradFixedToFixed(x) (SkFixed)((x) >> 16)
+ #define kFracMax_SkGradFixed 0xFFFFFFFFLL
+#endif
/**
- * Iteration fixed fx by dx, clamping as you go to [0..0xFFFF], this class
+ * Iteration fixed fx by dx, clamping as you go to [0..kFracMax_SkGradFixed], this class
* computes the (up to) 3 spans there are:
*
* range0: use constant value V0
int fCount0; // count for fV0
int fCount1; // count for interpolating (fV0...fV1)
int fCount2; // count for fV1
- SkFixed fFx1; // initial fx value for the fCount1 range.
+ SkGradFixed fFx1; // initial fx value for the fCount1 range.
// only valid if fCount1 > 0
int fV0, fV1;
- void init(SkFixed fx, SkFixed dx, int count, int v0, int v1);
+ void init(SkGradFixed fx, SkGradFixed dx, int count, int v0, int v1);
private:
- void initFor1(SkFixed fx);
+ void initFor1(SkGradFixed fx);
};
#endif
#define NO_CHECK_ITER \
do { \
- unsigned fi = fx >> SkGradientShaderBase::kCache32Shift; \
+ unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \
SkASSERT(fi <= 0xFF); \
fx += dx; \
*dstC++ = cache[toggle + fi]; \
namespace {
-typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
+typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed 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, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed 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(fx);
+ unsigned fullIndex = proc(SkGradFixedToFixed(fx));
unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
sk_memset32_dither(dstC, lerp, dlerp, count);
}
-void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
}
}
-void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = mirror_8bits(fx >> 8);
+ unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8);
SkASSERT(fi <= 0xFF);
fx += dx;
*dstC++ = cache[toggle + fi];
} while (--count != 0);
}
-void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = repeat_8bits(fx >> 8);
+ unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8);
SkASSERT(fi <= 0xFF);
fx += dx;
*dstC++ = cache[toggle + fi];
if (fDstToIndexClass != kPerspective_MatrixClass) {
dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+ SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
SkFixed dxStorage[1];
(void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
- dx = dxStorage[0];
+ // todo: do we need a real/high-precision value for dx here?
+ dx = SkFixedToGradFixed(dxStorage[0]);
} else {
SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(fDstToIndex.getScaleX());
+ dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
}
LinearShadeProc shadeProc = shadeSpan_linear_repeat;
#define NO_CHECK_ITER_16 \
do { \
- unsigned fi = fx >> SkGradientShaderBase::kCache16Shift; \
+ unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift; \
SkASSERT(fi < SkGradientShaderBase::kCache16Count); \
fx += dx; \
*dstC++ = cache[toggle + fi]; \
namespace {
-typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
+typedef void (*LinearShade16Proc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* dstC, const uint16_t* cache,
int toggle, int count);
-void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_vertical(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
// we're a vertical gradient, so no change in a span
- unsigned fi = proc(fx) >> SkGradientShaderBase::kCache16Shift;
+ unsigned fi = proc(SkGradFixedToFixed(fx)) >> SkGradientShaderBase::kCache16Shift;
SkASSERT(fi < SkGradientShaderBase::kCache16Count);
dither_memset16(dstC, cache[toggle + fi],
cache[next_dither_toggle16(toggle) + fi], count);
}
-void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
}
}
-void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = mirror_bits(fx >> SkGradientShaderBase::kCache16Shift,
+ unsigned fi = mirror_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift,
SkGradientShaderBase::kCache16Bits);
SkASSERT(fi < SkGradientShaderBase::kCache16Count);
fx += dx;
} while (--count != 0);
}
-void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = repeat_bits(fx >> SkGradientShaderBase::kCache16Shift,
+ unsigned fi = repeat_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift,
SkGradientShaderBase::kCache16Bits);
SkASSERT(fi < SkGradientShaderBase::kCache16Count);
fx += dx;
if (fDstToIndexClass != kPerspective_MatrixClass) {
dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+ SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
SkFixed dxStorage[1];
(void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
- dx = dxStorage[0];
+ // todo: do we need a real/high-precision value for dx here?
+ dx = SkFixedToGradFixed(dxStorage[0]);
} else {
SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(fDstToIndex.getScaleX());
+ dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
}
LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
- if (fixed_nearly_zero(dx)) {
+ if (fixed_nearly_zero(SkGradFixedToFixed(dx))) {
shadeProc = shadeSpan16_linear_vertical;
} else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
shadeProc = shadeSpan16_linear_clamp;