Chromium Code Reviews| Index: src/effects/gradients/SkLinearGradient.cpp |
| diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp |
| index 11c79f0956248e0a56f891aacdab56c7f4186847..404207e7190268d17c7ecd0d59ad58c6a3c38911 100644 |
| --- a/src/effects/gradients/SkLinearGradient.cpp |
| +++ b/src/effects/gradients/SkLinearGradient.cpp |
| @@ -100,6 +100,40 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext( |
| fFlags |= SkShader::kConstInY16_Flag; |
| } |
| } |
| + |
| + // setup for Sk4f |
| + int count = shader.fColorCount; |
| + fColorCount = count; |
| + fColors4 = new Sk4f[count]; |
| + fPos = new float[count * 2]; |
| + fPosScale = fPos + count; |
| + if (shader.fOrigPos) { |
| + fPos[0] = 0; |
| + fPosScale[0] = 0; // should never get used |
| + for (int i = 1; i < count; ++i) { |
| + fPos[i] = SkTMin(SkTMax(fPos[i - 1], shader.fOrigPos[i]), 1.0f); |
| + fPosScale[i] = 1.0f / (fPos[i] - fPos[i - 1]); |
| + } |
| + fPos[count - 1] = 1; // overwrite the last value just to be sure we end at 1.0 |
| + } else { |
| + float invScale = 1.0f / (count - 1); |
| + for (int i = 0; i < count; ++i) { |
| + fPos[i] = i * invScale; |
| + fPosScale[i] = count - 1; |
| + } |
| + } |
| + for (int i = 0; i < count; ++i) { |
| + SkPMColor pmc = SkPreMultiplyColor(shader.fOrigColors[i]); |
| + fColors4[i] = Sk4f::FromBytes((const uint8_t*)&pmc); |
| + if (i > 0) { |
| + SkASSERT(fPos[i - 1] <= fPos[i]); |
| + } |
| + } |
| +} |
| + |
| +SkLinearGradient::LinearGradientContext::~LinearGradientContext() { |
| + delete[] fPos; |
| + delete[] fColors4; |
| } |
| #define NO_CHECK_ITER \ |
| @@ -211,6 +245,11 @@ void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx, |
| void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, |
| int count) { |
| + if (true) { |
| + this->shadeSpan4(x, y, dstC, count); |
| + return; |
| + } |
| + |
| SkASSERT(count > 0); |
| const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&>(fShader); |
| @@ -576,3 +615,111 @@ void SkLinearGradient::toString(SkString* str) const { |
| str->append(")"); |
| } |
| #endif |
| + |
| +/////////////////////////////////////////////////////////////////////////////////////////////////// |
| + |
| +#include "SkNx.h" |
| + |
| +#if 0 |
| +static Sk4f premul(const Sk4f& x) { |
| + return x * scale_rgb(x.kth<SK_A32_SHIFT/8>()); |
| +} |
| + |
| +static Sk4f unpremul(const Sk4f& x) { |
| + return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>()); // TODO: fast/approx invert? |
| +} |
| + |
| +static Sk4f clamp_0_1(const Sk4f& x) { |
| + return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0)); |
| +} |
| +#endif |
| + |
| +static SkPMColor round_from_255(const Sk4f& x) { |
| + SkPMColor c; |
| + (x + Sk4f(0.5f)).toBytes((uint8_t*)&c); |
| + return c; |
| +} |
| + |
| +static Sk4f lerp(Sk4f a, Sk4f b, float t) { |
| + return a + Sk4f(t) * (b - a); |
| +} |
| + |
| +static int find(float tiledX, const float pos[], int count) { |
| + SkASSERT(count > 1); |
| + SkASSERT(0 == pos[0]); |
| + SkASSERT(1 == pos[count - 1]); |
| + SkASSERT(tiledX >= 0 && tiledX <= 1); |
| + |
| + int i = 1; |
| + while (pos[i] < tiledX) { |
| + i += 1; |
| + } |
| + return i - 1; |
| +} |
| + |
| +/* |
| + * TODOs |
| + * |
| + * - tilemodes |
| + * - interp before or after premul |
| + * - apply paint's alpha (available when we create the context |
| + * - perspective |
| + * - dithering |
| + * - optimizations |
| + * - even spacing (how common is that?) |
| + * - use fixed (32bit or 16bit) instead of floats? |
| + */ |
| +void SkLinearGradient::LinearGradientContext::shadeSpan4(int x, int y, SkPMColor* SK_RESTRICT dstC, |
| + int count) { |
| + SkASSERT(count > 0); |
| + |
| + const Sk4f* colors4 = fColors4; |
| + const float* pos = fPos; |
| + const float* posScale = fPosScale; |
| + |
| + SkPoint srcPt; |
| + SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
| +// int toggle = init_dither_toggle(x, y); |
| + |
| + float dx, fx; |
| + if (fDstToIndexClass != kPerspective_MatrixClass || true) { |
| + dstProc(fDstToIndex, x + SK_ScalarHalf, y + SK_ScalarHalf, &srcPt); |
| + fx = srcPt.x(); |
| + |
| + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
| + SkFixed dxStorage[1]; |
| + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr); |
| + // todo: do we need a real/high-precision value for dx here? |
| + dx = SkFixedToFloat(dxStorage[0]); |
| + } else { |
| + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
| + dx = fDstToIndex.getScaleX(); |
| + } |
| + } |
| + |
| + int prevIndex = 0; |
| + for (int i = 0; i < count; ++i) { |
| + float tiledX = fx; |
| + |
| + // Apply the TileMode |
| + if (tiledX < 0) { |
| + tiledX = 0; |
| + } |
| + if (tiledX > 1) { |
| + tiledX = 1; |
| + } |
| + |
| + // Are we in the same relative interval, or do we need to search |
| + if (pos[prevIndex] > tiledX || tiledX > pos[prevIndex + 1]) { |
|
f(malita)
2015/11/11 05:14:16
What if instead of projecting the span pixels onto
|
| + prevIndex = find(tiledX, pos, fColorCount); |
| + } |
| + |
| + // Compute the color |
| + float t = (fx - pos[prevIndex]) * posScale[prevIndex + 1]; |
| + Sk4f c = lerp(colors4[prevIndex], colors4[prevIndex + 1], t); |
| + dstC[i] = round_from_255(c); |
| + |
| + fx += dx; |
| + } |
| +} |
| + |