michael@0: From f941ea32e44a2436d235e83ef1a434289a9d9c1e Mon Sep 17 00:00:00 2001 michael@0: From: George Wright michael@0: Date: Wed, 23 May 2012 11:40:25 -0400 michael@0: Subject: [PATCH 08/10] Bug 755869 - [11] Re-apply bug 687188 - Skia michael@0: radial gradients should use the 0/1 color stop values michael@0: for clamping. r=mattwoodrow michael@0: michael@0: --- michael@0: gfx/skia/src/effects/SkGradientShader.cpp | 76 +++++++++++++++++++++++------ michael@0: 1 files changed, 61 insertions(+), 15 deletions(-) michael@0: michael@0: diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp michael@0: index 59ba48c..ea05a39 100644 michael@0: --- a/gfx/skia/src/effects/SkGradientShader.cpp michael@0: +++ b/gfx/skia/src/effects/SkGradientShader.cpp michael@0: @@ -204,6 +204,7 @@ private: michael@0: mutable SkMallocPixelRef* fCache32PixelRef; michael@0: mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value michael@0: michael@0: + static SkPMColor PremultiplyColor(SkColor c0, U8CPU alpha); michael@0: static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count); michael@0: static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count, michael@0: U8CPU alpha); michael@0: @@ -507,6 +508,21 @@ static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) { michael@0: return ((n << 1) - (n | (n >> 8))) >> 8; michael@0: } michael@0: michael@0: +SkPMColor Gradient_Shader::PremultiplyColor(SkColor c0, U8CPU paintAlpha) michael@0: +{ michael@0: + SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha); michael@0: + SkFixed r = SkColorGetR(c0); michael@0: + SkFixed g = SkColorGetG(c0); michael@0: + SkFixed b = SkColorGetB(c0); michael@0: + michael@0: + a = SkIntToFixed(a) + 0x8000; michael@0: + r = SkIntToFixed(r) + 0x8000; michael@0: + g = SkIntToFixed(g) + 0x8000; michael@0: + b = SkIntToFixed(b) + 0x8000; michael@0: + michael@0: + return SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16); michael@0: +} michael@0: + michael@0: void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1, michael@0: int count, U8CPU paintAlpha) { michael@0: SkASSERT(count > 1); michael@0: @@ -628,14 +644,14 @@ static void complete_32bit_cache(SkPMColor* cache, int stride) { michael@0: const SkPMColor* Gradient_Shader::getCache32() const { michael@0: if (fCache32 == NULL) { michael@0: // double the count for dither entries michael@0: - const int entryCount = kCache32Count * 2; michael@0: + const int entryCount = kCache32Count * 2 + 2; michael@0: const size_t allocSize = sizeof(SkPMColor) * entryCount; michael@0: michael@0: if (NULL == fCache32PixelRef) { michael@0: fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef, michael@0: (NULL, allocSize, NULL)); michael@0: } michael@0: - fCache32 = (SkPMColor*)fCache32PixelRef->getAddr(); michael@0: + fCache32 = (SkPMColor*)fCache32PixelRef->getAddr() + 1; michael@0: if (fColorCount == 2) { michael@0: Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1], michael@0: kGradient32Length, fCacheAlpha); michael@0: @@ -659,7 +675,7 @@ const SkPMColor* Gradient_Shader::getCache32() const { michael@0: SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef, michael@0: (NULL, allocSize, NULL)); michael@0: SkPMColor* linear = fCache32; // just computed linear data michael@0: - SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data michael@0: + SkPMColor* mapped = (SkPMColor*)newPR->getAddr() + 1; // storage for mapped data michael@0: SkUnitMapper* map = fMapper; michael@0: for (int i = 0; i < kGradient32Length; i++) { michael@0: int index = map->mapUnit16((i << 8) | i) >> 8; michael@0: @@ -668,10 +684,13 @@ const SkPMColor* Gradient_Shader::getCache32() const { michael@0: } michael@0: fCache32PixelRef->unref(); michael@0: fCache32PixelRef = newPR; michael@0: - fCache32 = (SkPMColor*)newPR->getAddr(); michael@0: + fCache32 = (SkPMColor*)newPR->getAddr() + 1; michael@0: } michael@0: complete_32bit_cache(fCache32, kCache32Count); michael@0: } michael@0: + //Write the clamp colours into the first and last entries of fCache32 michael@0: + fCache32[-1] = PremultiplyColor(fOrigColors[0], fCacheAlpha); michael@0: + fCache32[kCache32Count * 2] = PremultiplyColor(fOrigColors[fColorCount - 1], fCacheAlpha); michael@0: return fCache32; michael@0: } michael@0: michael@0: @@ -857,6 +876,18 @@ void shadeSpan_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx, michael@0: SkPMColor* SK_RESTRICT dstC, michael@0: const SkPMColor* SK_RESTRICT cache, michael@0: int toggle, int count) { michael@0: + if (proc == clamp_tileproc) { michael@0: + // Read out clamp values from beginning/end of the cache. No need to lerp michael@0: + // or dither michael@0: + if (fx < 0) { michael@0: + sk_memset32(dstC, cache[-1], count); michael@0: + return; michael@0: + } else if (fx > 0xFFFF) { michael@0: + sk_memset32(dstC, cache[Gradient_Shader::kCache32Count * 2], count); michael@0: + return; michael@0: + } michael@0: + } michael@0: + michael@0: // We're a vertical gradient, so no change in a span. michael@0: // If colors change sharply across the gradient, dithering is michael@0: // insufficient (it subsamples the color space) and we need to lerp. michael@0: @@ -875,6 +906,18 @@ void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx, michael@0: SkPMColor* SK_RESTRICT dstC, michael@0: const SkPMColor* SK_RESTRICT cache, michael@0: int toggle, int count) { michael@0: + if (proc == clamp_tileproc) { michael@0: + // Read out clamp values from beginning/end of the cache. No need to lerp michael@0: + // or dither michael@0: + if (fx < 0) { michael@0: + sk_memset32(dstC, cache[-1], count); michael@0: + return; michael@0: + } else if (fx > 0xFFFF) { michael@0: + sk_memset32(dstC, cache[Gradient_Shader::kCache32Count * 2], count); michael@0: + return; michael@0: + } michael@0: + } michael@0: + michael@0: // We're a vertical gradient, so no change in a span. michael@0: // If colors change sharply across the gradient, dithering is michael@0: // insufficient (it subsamples the color space) and we need to lerp. michael@0: @@ -900,10 +943,8 @@ void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx, michael@0: range.init(fx, dx, count, 0, Gradient_Shader::kGradient32Length); michael@0: michael@0: if ((count = range.fCount0) > 0) { michael@0: - sk_memset32_dither(dstC, michael@0: - cache[toggle + range.fV0], michael@0: - cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV0], michael@0: - count); michael@0: + // Shouldn't be any need to dither for clamping? michael@0: + sk_memset32(dstC, cache[-1], count); michael@0: dstC += count; michael@0: } michael@0: if ((count = range.fCount1) > 0) { michael@0: @@ -922,10 +963,8 @@ void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx, michael@0: } michael@0: } michael@0: if ((count = range.fCount2) > 0) { michael@0: - sk_memset32_dither(dstC, michael@0: - cache[toggle + range.fV1], michael@0: - cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV1], michael@0: - count); michael@0: + // Shouldn't be any need to dither for clamping? michael@0: + sk_memset32(dstC, cache[Gradient_Shader::kCache32Count * 2], count); michael@0: } michael@0: } michael@0: michael@0: @@ -1796,9 +1835,16 @@ void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx, michael@0: for (; count > 0; --count) { michael@0: SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, michael@0: fOneOverTwoA, posRoot); michael@0: - SkFixed index = SkClampMax(t, 0xFFFF); michael@0: - SkASSERT(index <= 0xFFFF); michael@0: - *dstC++ = cache[index >> Gradient_Shader::kCache32Shift]; michael@0: + michael@0: + if (t < 0) { michael@0: + *dstC++ = cache[-1]; michael@0: + } else if (t > 0xFFFF) { michael@0: + *dstC++ = cache[Gradient_Shader::kCache32Count * 2]; michael@0: + } else { michael@0: + SkASSERT(t <= 0xFFFF); michael@0: + *dstC++ = cache[t >> Gradient_Shader::kCache32Shift]; michael@0: + } michael@0: + michael@0: fx += dx; michael@0: fy += dy; michael@0: b += db; michael@0: -- michael@0: 1.7.5.4 michael@0: