| Index: src/effects/gradients/SkGradientShader.cpp
|
| diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
|
| index d1ab539c076a716279cb888857e75ee4850686ad..6dcbb05f7e1eae0b19dcdb9bfa7dad6d021fc22f 100644
|
| --- a/src/effects/gradients/SkGradientShader.cpp
|
| +++ b/src/effects/gradients/SkGradientShader.cpp
|
| @@ -19,6 +19,7 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
|
|
|
| fMapper = desc.fMapper;
|
| SkSafeRef(fMapper);
|
| + fGradFlags = SkToU8(desc.fFlags);
|
|
|
| SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
|
| SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
|
| @@ -128,8 +129,21 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
|
| this->initCommon();
|
| }
|
|
|
| -SkGradientShaderBase::SkGradientShaderBase(SkFlattenableReadBuffer& buffer) :
|
| - INHERITED(buffer) {
|
| +static uint32_t pack_mode_flags(SkShader::TileMode mode, uint32_t flags) {
|
| + SkASSERT(0 == (flags >> 28));
|
| + SkASSERT(0 == ((uint32_t)mode >> 4));
|
| + return (flags << 4) | mode;
|
| +}
|
| +
|
| +static SkShader::TileMode unpack_mode(uint32_t packed) {
|
| + return (SkShader::TileMode)(packed & 0xF);
|
| +}
|
| +
|
| +static uint32_t unpack_flags(uint32_t packed) {
|
| + return packed >> 4;
|
| +}
|
| +
|
| +SkGradientShaderBase::SkGradientShaderBase(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
| fCacheAlpha = 256;
|
|
|
| fMapper = buffer.readFlattenableT<SkUnitMapper>();
|
| @@ -147,7 +161,11 @@ SkGradientShaderBase::SkGradientShaderBase(SkFlattenableReadBuffer& buffer) :
|
| }
|
| buffer.readColorArray(fOrigColors);
|
|
|
| - fTileMode = (TileMode)buffer.readUInt();
|
| + {
|
| + uint32_t packed = buffer.readUInt();
|
| + fGradFlags = SkToU8(unpack_flags(packed));
|
| + fTileMode = unpack_mode(packed);
|
| + }
|
| fTileProc = gTileProcs[fTileMode];
|
| fRecs = (Rec*)(fOrigColors + colorCount);
|
| if (colorCount > 2) {
|
| @@ -186,7 +204,7 @@ void SkGradientShaderBase::flatten(SkFlattenableWriteBuffer& buffer) const {
|
| this->INHERITED::flatten(buffer);
|
| buffer.writeFlattenable(fMapper);
|
| buffer.writeColorArray(fOrigColors, fColorCount);
|
| - buffer.writeUInt(fTileMode);
|
| + buffer.writeUInt(pack_mode_flags(fTileMode, fGradFlags));
|
| if (fColorCount > 2) {
|
| Rec* recs = fRecs;
|
| for (int i = 1; i < fColorCount; i++) {
|
| @@ -288,39 +306,58 @@ void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor
|
| } while (--count != 0);
|
| }
|
|
|
| +/*
|
| + * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
|
| + * release builds, we saw a compiler error where the 0xFF parameter in
|
| + * SkPackARGB32() was being totally ignored whenever it was called with
|
| + * a non-zero add (e.g. 0x8000).
|
| + *
|
| + * We found two work-arounds:
|
| + * 1. change r,g,b to unsigned (or just one of them)
|
| + * 2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
|
| + * of using |
|
| + *
|
| + * We chose #1 just because it was more localized.
|
| + * See http://code.google.com/p/skia/issues/detail?id=1113
|
| + *
|
| + * The type SkUFixed encapsulate this need for unsigned, but logically Fixed.
|
| + */
|
| +typedef uint32_t SkUFixed;
|
| +
|
| void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
|
| - int count, U8CPU paintAlpha) {
|
| + int count, U8CPU paintAlpha, uint32_t gradFlags) {
|
| SkASSERT(count > 1);
|
|
|
| // need to apply paintAlpha to our two endpoints
|
| - SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
|
| - SkFixed da;
|
| - {
|
| - int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
|
| - da = SkIntToFixed(tmp - a) / (count - 1);
|
| - }
|
| + uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
|
| + uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
|
|
|
| - /*
|
| - * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
|
| - * release builds, we saw a compiler error where the 0xFF parameter in
|
| - * SkPackARGB32() was being totally ignored whenever it was called with
|
| - * a non-zero add (e.g. 0x8000).
|
| - *
|
| - * We found two work-arounds:
|
| - * 1. change r,g,b to unsigned (or just one of them)
|
| - * 2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
|
| - * of using |
|
| - *
|
| - * We chose #1 just because it was more localized.
|
| - * See http://code.google.com/p/skia/issues/detail?id=1113
|
| - */
|
| - uint32_t r = SkColorGetR(c0);
|
| - uint32_t g = SkColorGetG(c0);
|
| - uint32_t b = SkColorGetB(c0);
|
|
|
| - SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
|
| - SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
|
| - SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
|
| + const bool interpInPremul = SkToBool(gradFlags &
|
| + SkGradientShader::kInterpolateColorsInPremul_Flag);
|
| +
|
| + uint32_t r0 = SkColorGetR(c0);
|
| + uint32_t g0 = SkColorGetG(c0);
|
| + uint32_t b0 = SkColorGetB(c0);
|
| +
|
| + uint32_t r1 = SkColorGetR(c1);
|
| + uint32_t g1 = SkColorGetG(c1);
|
| + uint32_t b1 = SkColorGetB(c1);
|
| +
|
| + if (interpInPremul) {
|
| + r0 = SkMulDiv255Round(r0, a0);
|
| + g0 = SkMulDiv255Round(g0, a0);
|
| + b0 = SkMulDiv255Round(b0, a0);
|
| +
|
| + r1 = SkMulDiv255Round(r1, a1);
|
| + g1 = SkMulDiv255Round(g1, a1);
|
| + b1 = SkMulDiv255Round(b1, a1);
|
| + }
|
| +
|
| + SkFixed da = SkIntToFixed(a1 - a0) / (count - 1);
|
| + SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1);
|
| + SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1);
|
| + SkFixed db = SkIntToFixed(b1 - b0) / (count - 1);
|
|
|
| /* We pre-add 1/8 to avoid having to add this to our [0] value each time
|
| in the loop. Without this, the bias for each would be
|
| @@ -328,9 +365,10 @@ void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColo
|
| With this trick, we can add 0 for the first (no-op) and just adjust the
|
| others.
|
| */
|
| - r = SkIntToFixed(r) + 0x2000;
|
| - g = SkIntToFixed(g) + 0x2000;
|
| - b = SkIntToFixed(b) + 0x2000;
|
| + SkUFixed a = SkIntToFixed(a0) + 0x2000;
|
| + SkUFixed r = SkIntToFixed(r0) + 0x2000;
|
| + SkUFixed g = SkIntToFixed(g0) + 0x2000;
|
| + SkUFixed b = SkIntToFixed(b0) + 0x2000;
|
|
|
| /*
|
| * Our dither-cell (spatially) is
|
| @@ -343,7 +381,7 @@ void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColo
|
| * [3] -> [ 5/8 ... 7/8 ) values near 3/4
|
| */
|
|
|
| - if (0xFF == a && 0 == da) {
|
| + if (0xFF == a0 && 0 == da) {
|
| do {
|
| cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0 ) >> 16,
|
| (g + 0 ) >> 16,
|
| @@ -362,8 +400,31 @@ void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColo
|
| g += dg;
|
| b += db;
|
| } while (--count != 0);
|
| - } else {
|
| - a = SkIntToFixed(a) + 0x2000;
|
| + } else if (interpInPremul) {
|
| + do {
|
| + cache[kCache32Count*0] = SkPackARGB32((a + 0 ) >> 16,
|
| + (r + 0 ) >> 16,
|
| + (g + 0 ) >> 16,
|
| + (b + 0 ) >> 16);
|
| + cache[kCache32Count*1] = SkPackARGB32((a + 0x8000) >> 16,
|
| + (r + 0x8000) >> 16,
|
| + (g + 0x8000) >> 16,
|
| + (b + 0x8000) >> 16);
|
| + cache[kCache32Count*2] = SkPackARGB32((a + 0xC000) >> 16,
|
| + (r + 0xC000) >> 16,
|
| + (g + 0xC000) >> 16,
|
| + (b + 0xC000) >> 16);
|
| + cache[kCache32Count*3] = SkPackARGB32((a + 0x4000) >> 16,
|
| + (r + 0x4000) >> 16,
|
| + (g + 0x4000) >> 16,
|
| + (b + 0x4000) >> 16);
|
| + cache += 1;
|
| + a += da;
|
| + r += dr;
|
| + g += dg;
|
| + b += db;
|
| + } while (--count != 0);
|
| + } else { // interpolate in unpreml space
|
| do {
|
| cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0 ) >> 16,
|
| (r + 0 ) >> 16,
|
| @@ -463,7 +524,7 @@ const SkPMColor* SkGradientShaderBase::getCache32() const {
|
| fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
|
| if (fColorCount == 2) {
|
| Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
|
| - kCache32Count, fCacheAlpha);
|
| + kCache32Count, fCacheAlpha, fGradFlags);
|
| } else {
|
| Rec* rec = fRecs;
|
| int prevIndex = 0;
|
| @@ -473,8 +534,8 @@ const SkPMColor* SkGradientShaderBase::getCache32() const {
|
|
|
| if (nextIndex > prevIndex)
|
| Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
|
| - fOrigColors[i],
|
| - nextIndex - prevIndex + 1, fCacheAlpha);
|
| + fOrigColors[i], nextIndex - prevIndex + 1,
|
| + fCacheAlpha, fGradFlags);
|
| prevIndex = nextIndex;
|
| }
|
| }
|
| @@ -522,8 +583,8 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
|
| return;
|
| }
|
|
|
| - // build our key: [numColors + colors[] + {positions[]} ]
|
| - int count = 1 + fColorCount;
|
| + // build our key: [numColors + colors[] + {positions[]} + flags ]
|
| + int count = 1 + fColorCount + 1;
|
| if (fColorCount > 2) {
|
| count += fColorCount - 1; // fRecs[].fPos
|
| }
|
| @@ -539,6 +600,7 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
|
| *buffer++ = fRecs[i].fPos;
|
| }
|
| }
|
| + *buffer++ = fGradFlags;
|
| SkASSERT(buffer - storage.get() == count);
|
|
|
| ///////////////////////////////////
|
| @@ -583,6 +645,7 @@ void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
|
| }
|
| info->fColorCount = fColorCount;
|
| info->fTileMode = fTileMode;
|
| + info->fGradientFlags = fGradFlags;
|
| }
|
| }
|
|
|
| @@ -643,26 +706,28 @@ static void desc_init(SkGradientShaderBase::Descriptor* desc,
|
| const SkColor colors[],
|
| const SkScalar pos[], int colorCount,
|
| SkShader::TileMode mode,
|
| - SkUnitMapper* mapper) {
|
| + SkUnitMapper* mapper, uint32_t flags) {
|
| desc->fColors = colors;
|
| desc->fPos = pos;
|
| desc->fCount = colorCount;
|
| desc->fTileMode = mode;
|
| desc->fMapper = mapper;
|
| + desc->fFlags = flags;
|
| }
|
|
|
| SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
|
| const SkColor colors[],
|
| const SkScalar pos[], int colorCount,
|
| SkShader::TileMode mode,
|
| - SkUnitMapper* mapper) {
|
| + SkUnitMapper* mapper,
|
| + uint32_t flags) {
|
| if (NULL == pts || NULL == colors || colorCount < 1) {
|
| return NULL;
|
| }
|
| EXPAND_1_COLOR(colorCount);
|
|
|
| SkGradientShaderBase::Descriptor desc;
|
| - desc_init(&desc, colors, pos, colorCount, mode, mapper);
|
| + desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
|
| return SkNEW_ARGS(SkLinearGradient, (pts, desc));
|
| }
|
|
|
| @@ -670,14 +735,15 @@ SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
|
| const SkColor colors[],
|
| const SkScalar pos[], int colorCount,
|
| SkShader::TileMode mode,
|
| - SkUnitMapper* mapper) {
|
| + SkUnitMapper* mapper,
|
| + uint32_t flags) {
|
| if (radius <= 0 || NULL == colors || colorCount < 1) {
|
| return NULL;
|
| }
|
| EXPAND_1_COLOR(colorCount);
|
|
|
| SkGradientShaderBase::Descriptor desc;
|
| - desc_init(&desc, colors, pos, colorCount, mode, mapper);
|
| + desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
|
| return SkNEW_ARGS(SkRadialGradient, (center, radius, desc));
|
| }
|
|
|
| @@ -689,27 +755,29 @@ SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
|
| const SkScalar pos[],
|
| int colorCount,
|
| SkShader::TileMode mode,
|
| - SkUnitMapper* mapper) {
|
| + SkUnitMapper* mapper,
|
| + uint32_t flags) {
|
| if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
|
| return NULL;
|
| }
|
| EXPAND_1_COLOR(colorCount);
|
|
|
| SkGradientShaderBase::Descriptor desc;
|
| - desc_init(&desc, colors, pos, colorCount, mode, mapper);
|
| + desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
|
| return SkNEW_ARGS(SkTwoPointRadialGradient,
|
| (start, startRadius, end, endRadius, desc));
|
| }
|
|
|
| SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
|
| - SkScalar startRadius,
|
| - const SkPoint& end,
|
| - SkScalar endRadius,
|
| - const SkColor colors[],
|
| - const SkScalar pos[],
|
| - int colorCount,
|
| - SkShader::TileMode mode,
|
| - SkUnitMapper* mapper) {
|
| + SkScalar startRadius,
|
| + const SkPoint& end,
|
| + SkScalar endRadius,
|
| + const SkColor colors[],
|
| + const SkScalar pos[],
|
| + int colorCount,
|
| + SkShader::TileMode mode,
|
| + SkUnitMapper* mapper,
|
| + uint32_t flags) {
|
| if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
|
| return NULL;
|
| }
|
| @@ -719,7 +787,7 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
|
| EXPAND_1_COLOR(colorCount);
|
|
|
| SkGradientShaderBase::Descriptor desc;
|
| - desc_init(&desc, colors, pos, colorCount, mode, mapper);
|
| + desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
|
| return SkNEW_ARGS(SkTwoPointConicalGradient,
|
| (start, startRadius, end, endRadius, desc));
|
| }
|
| @@ -727,14 +795,15 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
|
| SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
|
| const SkColor colors[],
|
| const SkScalar pos[],
|
| - int colorCount, SkUnitMapper* mapper) {
|
| + int colorCount, SkUnitMapper* mapper,
|
| + uint32_t flags) {
|
| if (NULL == colors || colorCount < 1) {
|
| return NULL;
|
| }
|
| EXPAND_1_COLOR(colorCount);
|
|
|
| SkGradientShaderBase::Descriptor desc;
|
| - desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, mapper);
|
| + desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, mapper, flags);
|
| return SkNEW_ARGS(SkSweepGradient, (cx, cy, desc));
|
| }
|
|
|
|
|