gfx/skia/trunk/src/effects/gradients/SkGradientShader.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/effects/gradients/SkGradientShader.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1147 @@
     1.4 +/*
     1.5 + * Copyright 2006 The Android Open Source Project
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkGradientShaderPriv.h"
    1.12 +#include "SkLinearGradient.h"
    1.13 +#include "SkRadialGradient.h"
    1.14 +#include "SkTwoPointRadialGradient.h"
    1.15 +#include "SkTwoPointConicalGradient.h"
    1.16 +#include "SkSweepGradient.h"
    1.17 +
    1.18 +SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
    1.19 +    SkASSERT(desc.fCount > 1);
    1.20 +
    1.21 +    fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
    1.22 +
    1.23 +    fMapper = desc.fMapper;
    1.24 +    SkSafeRef(fMapper);
    1.25 +    fGradFlags = SkToU8(desc.fFlags);
    1.26 +
    1.27 +    SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
    1.28 +    SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
    1.29 +    fTileMode = desc.fTileMode;
    1.30 +    fTileProc = gTileProcs[desc.fTileMode];
    1.31 +
    1.32 +    fCache16 = fCache16Storage = NULL;
    1.33 +    fCache32 = NULL;
    1.34 +    fCache32PixelRef = NULL;
    1.35 +
    1.36 +    /*  Note: we let the caller skip the first and/or last position.
    1.37 +        i.e. pos[0] = 0.3, pos[1] = 0.7
    1.38 +        In these cases, we insert dummy entries to ensure that the final data
    1.39 +        will be bracketed by [0, 1].
    1.40 +        i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
    1.41 +
    1.42 +        Thus colorCount (the caller's value, and fColorCount (our value) may
    1.43 +        differ by up to 2. In the above example:
    1.44 +            colorCount = 2
    1.45 +            fColorCount = 4
    1.46 +     */
    1.47 +    fColorCount = desc.fCount;
    1.48 +    // check if we need to add in dummy start and/or end position/colors
    1.49 +    bool dummyFirst = false;
    1.50 +    bool dummyLast = false;
    1.51 +    if (desc.fPos) {
    1.52 +        dummyFirst = desc.fPos[0] != 0;
    1.53 +        dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
    1.54 +        fColorCount += dummyFirst + dummyLast;
    1.55 +    }
    1.56 +
    1.57 +    if (fColorCount > kColorStorageCount) {
    1.58 +        size_t size = sizeof(SkColor) + sizeof(Rec);
    1.59 +        fOrigColors = reinterpret_cast<SkColor*>(
    1.60 +                                        sk_malloc_throw(size * fColorCount));
    1.61 +    }
    1.62 +    else {
    1.63 +        fOrigColors = fStorage;
    1.64 +    }
    1.65 +
    1.66 +    // Now copy over the colors, adding the dummies as needed
    1.67 +    {
    1.68 +        SkColor* origColors = fOrigColors;
    1.69 +        if (dummyFirst) {
    1.70 +            *origColors++ = desc.fColors[0];
    1.71 +        }
    1.72 +        memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor));
    1.73 +        if (dummyLast) {
    1.74 +            origColors += desc.fCount;
    1.75 +            *origColors = desc.fColors[desc.fCount - 1];
    1.76 +        }
    1.77 +    }
    1.78 +
    1.79 +    fRecs = (Rec*)(fOrigColors + fColorCount);
    1.80 +    if (fColorCount > 2) {
    1.81 +        Rec* recs = fRecs;
    1.82 +        recs->fPos = 0;
    1.83 +        //  recs->fScale = 0; // unused;
    1.84 +        recs += 1;
    1.85 +        if (desc.fPos) {
    1.86 +            /*  We need to convert the user's array of relative positions into
    1.87 +                fixed-point positions and scale factors. We need these results
    1.88 +                to be strictly monotonic (no two values equal or out of order).
    1.89 +                Hence this complex loop that just jams a zero for the scale
    1.90 +                value if it sees a segment out of order, and it assures that
    1.91 +                we start at 0 and end at 1.0
    1.92 +            */
    1.93 +            SkFixed prev = 0;
    1.94 +            int startIndex = dummyFirst ? 0 : 1;
    1.95 +            int count = desc.fCount + dummyLast;
    1.96 +            for (int i = startIndex; i < count; i++) {
    1.97 +                // force the last value to be 1.0
    1.98 +                SkFixed curr;
    1.99 +                if (i == desc.fCount) {  // we're really at the dummyLast
   1.100 +                    curr = SK_Fixed1;
   1.101 +                } else {
   1.102 +                    curr = SkScalarToFixed(desc.fPos[i]);
   1.103 +                }
   1.104 +                // pin curr withing range
   1.105 +                if (curr < 0) {
   1.106 +                    curr = 0;
   1.107 +                } else if (curr > SK_Fixed1) {
   1.108 +                    curr = SK_Fixed1;
   1.109 +                }
   1.110 +                recs->fPos = curr;
   1.111 +                if (curr > prev) {
   1.112 +                    recs->fScale = (1 << 24) / (curr - prev);
   1.113 +                } else {
   1.114 +                    recs->fScale = 0; // ignore this segment
   1.115 +                }
   1.116 +                // get ready for the next value
   1.117 +                prev = curr;
   1.118 +                recs += 1;
   1.119 +            }
   1.120 +        } else {    // assume even distribution
   1.121 +            SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
   1.122 +            SkFixed p = dp;
   1.123 +            SkFixed scale = (desc.fCount - 1) << 8;  // (1 << 24) / dp
   1.124 +            for (int i = 1; i < desc.fCount; i++) {
   1.125 +                recs->fPos   = p;
   1.126 +                recs->fScale = scale;
   1.127 +                recs += 1;
   1.128 +                p += dp;
   1.129 +            }
   1.130 +        }
   1.131 +    }
   1.132 +    this->initCommon();
   1.133 +}
   1.134 +
   1.135 +static uint32_t pack_mode_flags(SkShader::TileMode mode, uint32_t flags) {
   1.136 +    SkASSERT(0 == (flags >> 28));
   1.137 +    SkASSERT(0 == ((uint32_t)mode >> 4));
   1.138 +    return (flags << 4) | mode;
   1.139 +}
   1.140 +
   1.141 +static SkShader::TileMode unpack_mode(uint32_t packed) {
   1.142 +    return (SkShader::TileMode)(packed & 0xF);
   1.143 +}
   1.144 +
   1.145 +static uint32_t unpack_flags(uint32_t packed) {
   1.146 +    return packed >> 4;
   1.147 +}
   1.148 +
   1.149 +SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) {
   1.150 +    fCacheAlpha = 256;
   1.151 +
   1.152 +    fMapper = buffer.readUnitMapper();
   1.153 +
   1.154 +    fCache16 = fCache16Storage = NULL;
   1.155 +    fCache32 = NULL;
   1.156 +    fCache32PixelRef = NULL;
   1.157 +
   1.158 +    int colorCount = fColorCount = buffer.getArrayCount();
   1.159 +    if (colorCount > kColorStorageCount) {
   1.160 +        size_t allocSize = (sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount;
   1.161 +        if (buffer.validateAvailable(allocSize)) {
   1.162 +            fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(allocSize));
   1.163 +        } else {
   1.164 +            fOrigColors =  NULL;
   1.165 +            colorCount = fColorCount = 0;
   1.166 +        }
   1.167 +    } else {
   1.168 +        fOrigColors = fStorage;
   1.169 +    }
   1.170 +    buffer.readColorArray(fOrigColors, colorCount);
   1.171 +
   1.172 +    {
   1.173 +        uint32_t packed = buffer.readUInt();
   1.174 +        fGradFlags = SkToU8(unpack_flags(packed));
   1.175 +        fTileMode = unpack_mode(packed);
   1.176 +    }
   1.177 +    fTileProc = gTileProcs[fTileMode];
   1.178 +    fRecs = (Rec*)(fOrigColors + colorCount);
   1.179 +    if (colorCount > 2) {
   1.180 +        Rec* recs = fRecs;
   1.181 +        recs[0].fPos = 0;
   1.182 +        for (int i = 1; i < colorCount; i++) {
   1.183 +            recs[i].fPos = buffer.readInt();
   1.184 +            recs[i].fScale = buffer.readUInt();
   1.185 +        }
   1.186 +    }
   1.187 +    buffer.readMatrix(&fPtsToUnit);
   1.188 +    this->initCommon();
   1.189 +}
   1.190 +
   1.191 +SkGradientShaderBase::~SkGradientShaderBase() {
   1.192 +    if (fCache16Storage) {
   1.193 +        sk_free(fCache16Storage);
   1.194 +    }
   1.195 +    SkSafeUnref(fCache32PixelRef);
   1.196 +    if (fOrigColors != fStorage) {
   1.197 +        sk_free(fOrigColors);
   1.198 +    }
   1.199 +    SkSafeUnref(fMapper);
   1.200 +}
   1.201 +
   1.202 +void SkGradientShaderBase::initCommon() {
   1.203 +    fFlags = 0;
   1.204 +    unsigned colorAlpha = 0xFF;
   1.205 +    for (int i = 0; i < fColorCount; i++) {
   1.206 +        colorAlpha &= SkColorGetA(fOrigColors[i]);
   1.207 +    }
   1.208 +    fColorsAreOpaque = colorAlpha == 0xFF;
   1.209 +}
   1.210 +
   1.211 +void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
   1.212 +    this->INHERITED::flatten(buffer);
   1.213 +    buffer.writeFlattenable(fMapper);
   1.214 +    buffer.writeColorArray(fOrigColors, fColorCount);
   1.215 +    buffer.writeUInt(pack_mode_flags(fTileMode, fGradFlags));
   1.216 +    if (fColorCount > 2) {
   1.217 +        Rec* recs = fRecs;
   1.218 +        for (int i = 1; i < fColorCount; i++) {
   1.219 +            buffer.writeInt(recs[i].fPos);
   1.220 +            buffer.writeUInt(recs[i].fScale);
   1.221 +        }
   1.222 +    }
   1.223 +    buffer.writeMatrix(fPtsToUnit);
   1.224 +}
   1.225 +
   1.226 +bool SkGradientShaderBase::isOpaque() const {
   1.227 +    return fColorsAreOpaque;
   1.228 +}
   1.229 +
   1.230 +bool SkGradientShaderBase::setContext(const SkBitmap& device,
   1.231 +                                 const SkPaint& paint,
   1.232 +                                 const SkMatrix& matrix) {
   1.233 +    if (!this->INHERITED::setContext(device, paint, matrix)) {
   1.234 +        return false;
   1.235 +    }
   1.236 +
   1.237 +    const SkMatrix& inverse = this->getTotalInverse();
   1.238 +
   1.239 +    if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
   1.240 +        // need to keep our set/end context calls balanced.
   1.241 +        this->INHERITED::endContext();
   1.242 +        return false;
   1.243 +    }
   1.244 +
   1.245 +    fDstToIndexProc = fDstToIndex.getMapXYProc();
   1.246 +    fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
   1.247 +
   1.248 +    // now convert our colors in to PMColors
   1.249 +    unsigned paintAlpha = this->getPaintAlpha();
   1.250 +
   1.251 +    fFlags = this->INHERITED::getFlags();
   1.252 +    if (fColorsAreOpaque && paintAlpha == 0xFF) {
   1.253 +        fFlags |= kOpaqueAlpha_Flag;
   1.254 +    }
   1.255 +    // we can do span16 as long as our individual colors are opaque,
   1.256 +    // regardless of the paint's alpha
   1.257 +    if (fColorsAreOpaque) {
   1.258 +        fFlags |= kHasSpan16_Flag;
   1.259 +    }
   1.260 +
   1.261 +    this->setCacheAlpha(paintAlpha);
   1.262 +    return true;
   1.263 +}
   1.264 +
   1.265 +void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const {
   1.266 +    // if the new alpha differs from the previous time we were called, inval our cache
   1.267 +    // this will trigger the cache to be rebuilt.
   1.268 +    // we don't care about the first time, since the cache ptrs will already be NULL
   1.269 +    if (fCacheAlpha != alpha) {
   1.270 +        fCache16 = NULL;            // inval the cache
   1.271 +        fCache32 = NULL;            // inval the cache
   1.272 +        fCacheAlpha = alpha;        // record the new alpha
   1.273 +        // inform our subclasses
   1.274 +        if (fCache32PixelRef) {
   1.275 +            fCache32PixelRef->notifyPixelsChanged();
   1.276 +        }
   1.277 +    }
   1.278 +}
   1.279 +
   1.280 +#define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
   1.281 +
   1.282 +/** We take the original colors, not our premultiplied PMColors, since we can
   1.283 +    build a 16bit table as long as the original colors are opaque, even if the
   1.284 +    paint specifies a non-opaque alpha.
   1.285 +*/
   1.286 +void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
   1.287 +                                      int count) {
   1.288 +    SkASSERT(count > 1);
   1.289 +    SkASSERT(SkColorGetA(c0) == 0xFF);
   1.290 +    SkASSERT(SkColorGetA(c1) == 0xFF);
   1.291 +
   1.292 +    SkFixed r = SkColorGetR(c0);
   1.293 +    SkFixed g = SkColorGetG(c0);
   1.294 +    SkFixed b = SkColorGetB(c0);
   1.295 +
   1.296 +    SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
   1.297 +    SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
   1.298 +    SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
   1.299 +
   1.300 +    r = SkIntToFixed(r) + 0x8000;
   1.301 +    g = SkIntToFixed(g) + 0x8000;
   1.302 +    b = SkIntToFixed(b) + 0x8000;
   1.303 +
   1.304 +    do {
   1.305 +        unsigned rr = r >> 16;
   1.306 +        unsigned gg = g >> 16;
   1.307 +        unsigned bb = b >> 16;
   1.308 +        cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
   1.309 +        cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
   1.310 +        cache += 1;
   1.311 +        r += dr;
   1.312 +        g += dg;
   1.313 +        b += db;
   1.314 +    } while (--count != 0);
   1.315 +}
   1.316 +
   1.317 +/*
   1.318 + *  r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
   1.319 + *  release builds, we saw a compiler error where the 0xFF parameter in
   1.320 + *  SkPackARGB32() was being totally ignored whenever it was called with
   1.321 + *  a non-zero add (e.g. 0x8000).
   1.322 + *
   1.323 + *  We found two work-arounds:
   1.324 + *      1. change r,g,b to unsigned (or just one of them)
   1.325 + *      2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
   1.326 + *         of using |
   1.327 + *
   1.328 + *  We chose #1 just because it was more localized.
   1.329 + *  See http://code.google.com/p/skia/issues/detail?id=1113
   1.330 + *
   1.331 + *  The type SkUFixed encapsulate this need for unsigned, but logically Fixed.
   1.332 + */
   1.333 +typedef uint32_t SkUFixed;
   1.334 +
   1.335 +void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
   1.336 +                                      int count, U8CPU paintAlpha, uint32_t gradFlags) {
   1.337 +    SkASSERT(count > 1);
   1.338 +
   1.339 +    // need to apply paintAlpha to our two endpoints
   1.340 +    uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
   1.341 +    uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
   1.342 +
   1.343 +
   1.344 +    const bool interpInPremul = SkToBool(gradFlags &
   1.345 +                           SkGradientShader::kInterpolateColorsInPremul_Flag);
   1.346 +
   1.347 +    uint32_t r0 = SkColorGetR(c0);
   1.348 +    uint32_t g0 = SkColorGetG(c0);
   1.349 +    uint32_t b0 = SkColorGetB(c0);
   1.350 +
   1.351 +    uint32_t r1 = SkColorGetR(c1);
   1.352 +    uint32_t g1 = SkColorGetG(c1);
   1.353 +    uint32_t b1 = SkColorGetB(c1);
   1.354 +
   1.355 +    if (interpInPremul) {
   1.356 +        r0 = SkMulDiv255Round(r0, a0);
   1.357 +        g0 = SkMulDiv255Round(g0, a0);
   1.358 +        b0 = SkMulDiv255Round(b0, a0);
   1.359 +
   1.360 +        r1 = SkMulDiv255Round(r1, a1);
   1.361 +        g1 = SkMulDiv255Round(g1, a1);
   1.362 +        b1 = SkMulDiv255Round(b1, a1);
   1.363 +    }
   1.364 +
   1.365 +    SkFixed da = SkIntToFixed(a1 - a0) / (count - 1);
   1.366 +    SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1);
   1.367 +    SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1);
   1.368 +    SkFixed db = SkIntToFixed(b1 - b0) / (count - 1);
   1.369 +
   1.370 +    /*  We pre-add 1/8 to avoid having to add this to our [0] value each time
   1.371 +        in the loop. Without this, the bias for each would be
   1.372 +            0x2000  0xA000  0xE000  0x6000
   1.373 +        With this trick, we can add 0 for the first (no-op) and just adjust the
   1.374 +        others.
   1.375 +     */
   1.376 +    SkUFixed a = SkIntToFixed(a0) + 0x2000;
   1.377 +    SkUFixed r = SkIntToFixed(r0) + 0x2000;
   1.378 +    SkUFixed g = SkIntToFixed(g0) + 0x2000;
   1.379 +    SkUFixed b = SkIntToFixed(b0) + 0x2000;
   1.380 +
   1.381 +    /*
   1.382 +     *  Our dither-cell (spatially) is
   1.383 +     *      0 2
   1.384 +     *      3 1
   1.385 +     *  Where
   1.386 +     *      [0] -> [-1/8 ... 1/8 ) values near 0
   1.387 +     *      [1] -> [ 1/8 ... 3/8 ) values near 1/4
   1.388 +     *      [2] -> [ 3/8 ... 5/8 ) values near 1/2
   1.389 +     *      [3] -> [ 5/8 ... 7/8 ) values near 3/4
   1.390 +     */
   1.391 +
   1.392 +    if (0xFF == a0 && 0 == da) {
   1.393 +        do {
   1.394 +            cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0     ) >> 16,
   1.395 +                                                        (g + 0     ) >> 16,
   1.396 +                                                        (b + 0     ) >> 16);
   1.397 +            cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + 0x8000) >> 16,
   1.398 +                                                        (g + 0x8000) >> 16,
   1.399 +                                                        (b + 0x8000) >> 16);
   1.400 +            cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + 0xC000) >> 16,
   1.401 +                                                        (g + 0xC000) >> 16,
   1.402 +                                                        (b + 0xC000) >> 16);
   1.403 +            cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + 0x4000) >> 16,
   1.404 +                                                        (g + 0x4000) >> 16,
   1.405 +                                                        (b + 0x4000) >> 16);
   1.406 +            cache += 1;
   1.407 +            r += dr;
   1.408 +            g += dg;
   1.409 +            b += db;
   1.410 +        } while (--count != 0);
   1.411 +    } else if (interpInPremul) {
   1.412 +        do {
   1.413 +            cache[kCache32Count*0] = SkPackARGB32((a + 0     ) >> 16,
   1.414 +                                                  (r + 0     ) >> 16,
   1.415 +                                                  (g + 0     ) >> 16,
   1.416 +                                                  (b + 0     ) >> 16);
   1.417 +            cache[kCache32Count*1] = SkPackARGB32((a + 0x8000) >> 16,
   1.418 +                                                  (r + 0x8000) >> 16,
   1.419 +                                                  (g + 0x8000) >> 16,
   1.420 +                                                  (b + 0x8000) >> 16);
   1.421 +            cache[kCache32Count*2] = SkPackARGB32((a + 0xC000) >> 16,
   1.422 +                                                  (r + 0xC000) >> 16,
   1.423 +                                                  (g + 0xC000) >> 16,
   1.424 +                                                  (b + 0xC000) >> 16);
   1.425 +            cache[kCache32Count*3] = SkPackARGB32((a + 0x4000) >> 16,
   1.426 +                                                  (r + 0x4000) >> 16,
   1.427 +                                                  (g + 0x4000) >> 16,
   1.428 +                                                  (b + 0x4000) >> 16);
   1.429 +            cache += 1;
   1.430 +            a += da;
   1.431 +            r += dr;
   1.432 +            g += dg;
   1.433 +            b += db;
   1.434 +        } while (--count != 0);
   1.435 +    } else {    // interpolate in unpreml space
   1.436 +        do {
   1.437 +            cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0     ) >> 16,
   1.438 +                                                             (r + 0     ) >> 16,
   1.439 +                                                             (g + 0     ) >> 16,
   1.440 +                                                             (b + 0     ) >> 16);
   1.441 +            cache[kCache32Count*1] = SkPremultiplyARGBInline((a + 0x8000) >> 16,
   1.442 +                                                             (r + 0x8000) >> 16,
   1.443 +                                                             (g + 0x8000) >> 16,
   1.444 +                                                             (b + 0x8000) >> 16);
   1.445 +            cache[kCache32Count*2] = SkPremultiplyARGBInline((a + 0xC000) >> 16,
   1.446 +                                                             (r + 0xC000) >> 16,
   1.447 +                                                             (g + 0xC000) >> 16,
   1.448 +                                                             (b + 0xC000) >> 16);
   1.449 +            cache[kCache32Count*3] = SkPremultiplyARGBInline((a + 0x4000) >> 16,
   1.450 +                                                             (r + 0x4000) >> 16,
   1.451 +                                                             (g + 0x4000) >> 16,
   1.452 +                                                             (b + 0x4000) >> 16);
   1.453 +            cache += 1;
   1.454 +            a += da;
   1.455 +            r += dr;
   1.456 +            g += dg;
   1.457 +            b += db;
   1.458 +        } while (--count != 0);
   1.459 +    }
   1.460 +}
   1.461 +
   1.462 +static inline int SkFixedToFFFF(SkFixed x) {
   1.463 +    SkASSERT((unsigned)x <= SK_Fixed1);
   1.464 +    return x - (x >> 16);
   1.465 +}
   1.466 +
   1.467 +static inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
   1.468 +    SkASSERT(x < (1U << bits));
   1.469 +    if (6 == bits) {
   1.470 +        return (x << 10) | (x << 4) | (x >> 2);
   1.471 +    }
   1.472 +    if (8 == bits) {
   1.473 +        return (x << 8) | x;
   1.474 +    }
   1.475 +    sk_throw();
   1.476 +    return 0;
   1.477 +}
   1.478 +
   1.479 +const uint16_t* SkGradientShaderBase::getCache16() const {
   1.480 +    if (fCache16 == NULL) {
   1.481 +        // double the count for dither entries
   1.482 +        const int entryCount = kCache16Count * 2;
   1.483 +        const size_t allocSize = sizeof(uint16_t) * entryCount;
   1.484 +
   1.485 +        if (fCache16Storage == NULL) { // set the storage and our working ptr
   1.486 +            fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
   1.487 +        }
   1.488 +        fCache16 = fCache16Storage;
   1.489 +        if (fColorCount == 2) {
   1.490 +            Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
   1.491 +                            kCache16Count);
   1.492 +        } else {
   1.493 +            Rec* rec = fRecs;
   1.494 +            int prevIndex = 0;
   1.495 +            for (int i = 1; i < fColorCount; i++) {
   1.496 +                int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
   1.497 +                SkASSERT(nextIndex < kCache16Count);
   1.498 +
   1.499 +                if (nextIndex > prevIndex)
   1.500 +                    Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
   1.501 +                prevIndex = nextIndex;
   1.502 +            }
   1.503 +        }
   1.504 +
   1.505 +        if (fMapper) {
   1.506 +            fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
   1.507 +            uint16_t* linear = fCache16;         // just computed linear data
   1.508 +            uint16_t* mapped = fCache16Storage;  // storage for mapped data
   1.509 +            SkUnitMapper* map = fMapper;
   1.510 +            for (int i = 0; i < kCache16Count; i++) {
   1.511 +                int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
   1.512 +                mapped[i] = linear[index];
   1.513 +                mapped[i + kCache16Count] = linear[index + kCache16Count];
   1.514 +            }
   1.515 +            sk_free(fCache16);
   1.516 +            fCache16 = fCache16Storage;
   1.517 +        }
   1.518 +    }
   1.519 +    return fCache16;
   1.520 +}
   1.521 +
   1.522 +const SkPMColor* SkGradientShaderBase::getCache32() const {
   1.523 +    if (fCache32 == NULL) {
   1.524 +        SkImageInfo info;
   1.525 +        info.fWidth = kCache32Count;
   1.526 +        info.fHeight = 4;   // for our 4 dither rows
   1.527 +        info.fAlphaType = kPremul_SkAlphaType;
   1.528 +        info.fColorType = kPMColor_SkColorType;
   1.529 +
   1.530 +        if (NULL == fCache32PixelRef) {
   1.531 +            fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL);
   1.532 +        }
   1.533 +        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
   1.534 +        if (fColorCount == 2) {
   1.535 +            Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
   1.536 +                            kCache32Count, fCacheAlpha, fGradFlags);
   1.537 +        } else {
   1.538 +            Rec* rec = fRecs;
   1.539 +            int prevIndex = 0;
   1.540 +            for (int i = 1; i < fColorCount; i++) {
   1.541 +                int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
   1.542 +                SkASSERT(nextIndex < kCache32Count);
   1.543 +
   1.544 +                if (nextIndex > prevIndex)
   1.545 +                    Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
   1.546 +                                    fOrigColors[i], nextIndex - prevIndex + 1,
   1.547 +                                    fCacheAlpha, fGradFlags);
   1.548 +                prevIndex = nextIndex;
   1.549 +            }
   1.550 +        }
   1.551 +
   1.552 +        if (fMapper) {
   1.553 +            SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL);
   1.554 +            SkPMColor* linear = fCache32;           // just computed linear data
   1.555 +            SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
   1.556 +            SkUnitMapper* map = fMapper;
   1.557 +            for (int i = 0; i < kCache32Count; i++) {
   1.558 +                int index = map->mapUnit16((i << 8) | i) >> 8;
   1.559 +                mapped[i + kCache32Count*0] = linear[index + kCache32Count*0];
   1.560 +                mapped[i + kCache32Count*1] = linear[index + kCache32Count*1];
   1.561 +                mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
   1.562 +                mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
   1.563 +            }
   1.564 +            fCache32PixelRef->unref();
   1.565 +            fCache32PixelRef = newPR;
   1.566 +            fCache32 = (SkPMColor*)newPR->getAddr();
   1.567 +        }
   1.568 +    }
   1.569 +    return fCache32;
   1.570 +}
   1.571 +
   1.572 +/*
   1.573 + *  Because our caller might rebuild the same (logically the same) gradient
   1.574 + *  over and over, we'd like to return exactly the same "bitmap" if possible,
   1.575 + *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
   1.576 + *  To do that, we maintain a private cache of built-bitmaps, based on our
   1.577 + *  colors and positions. Note: we don't try to flatten the fMapper, so if one
   1.578 + *  is present, we skip the cache for now.
   1.579 + */
   1.580 +void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
   1.581 +    // our caller assumes no external alpha, so we ensure that our cache is
   1.582 +    // built with 0xFF
   1.583 +    this->setCacheAlpha(0xFF);
   1.584 +
   1.585 +    // don't have a way to put the mapper into our cache-key yet
   1.586 +    if (fMapper) {
   1.587 +        // force our cahce32pixelref to be built
   1.588 +        (void)this->getCache32();
   1.589 +        bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
   1.590 +        bitmap->setPixelRef(fCache32PixelRef);
   1.591 +        return;
   1.592 +    }
   1.593 +
   1.594 +    // build our key: [numColors + colors[] + {positions[]} + flags ]
   1.595 +    int count = 1 + fColorCount + 1;
   1.596 +    if (fColorCount > 2) {
   1.597 +        count += fColorCount - 1;    // fRecs[].fPos
   1.598 +    }
   1.599 +
   1.600 +    SkAutoSTMalloc<16, int32_t> storage(count);
   1.601 +    int32_t* buffer = storage.get();
   1.602 +
   1.603 +    *buffer++ = fColorCount;
   1.604 +    memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
   1.605 +    buffer += fColorCount;
   1.606 +    if (fColorCount > 2) {
   1.607 +        for (int i = 1; i < fColorCount; i++) {
   1.608 +            *buffer++ = fRecs[i].fPos;
   1.609 +        }
   1.610 +    }
   1.611 +    *buffer++ = fGradFlags;
   1.612 +    SkASSERT(buffer - storage.get() == count);
   1.613 +
   1.614 +    ///////////////////////////////////
   1.615 +
   1.616 +    SK_DECLARE_STATIC_MUTEX(gMutex);
   1.617 +    static SkBitmapCache* gCache;
   1.618 +    // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
   1.619 +    static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
   1.620 +    SkAutoMutexAcquire ama(gMutex);
   1.621 +
   1.622 +    if (NULL == gCache) {
   1.623 +        gCache = SkNEW_ARGS(SkBitmapCache, (MAX_NUM_CACHED_GRADIENT_BITMAPS));
   1.624 +    }
   1.625 +    size_t size = count * sizeof(int32_t);
   1.626 +
   1.627 +    if (!gCache->find(storage.get(), size, bitmap)) {
   1.628 +        // force our cahce32pixelref to be built
   1.629 +        (void)this->getCache32();
   1.630 +        bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
   1.631 +        bitmap->setPixelRef(fCache32PixelRef);
   1.632 +
   1.633 +        gCache->add(storage.get(), size, *bitmap);
   1.634 +    }
   1.635 +}
   1.636 +
   1.637 +void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
   1.638 +    if (info) {
   1.639 +        if (info->fColorCount >= fColorCount) {
   1.640 +            if (info->fColors) {
   1.641 +                memcpy(info->fColors, fOrigColors, fColorCount * sizeof(SkColor));
   1.642 +            }
   1.643 +            if (info->fColorOffsets) {
   1.644 +                if (fColorCount == 2) {
   1.645 +                    info->fColorOffsets[0] = 0;
   1.646 +                    info->fColorOffsets[1] = SK_Scalar1;
   1.647 +                } else if (fColorCount > 2) {
   1.648 +                    for (int i = 0; i < fColorCount; ++i) {
   1.649 +                        info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
   1.650 +                    }
   1.651 +                }
   1.652 +            }
   1.653 +        }
   1.654 +        info->fColorCount = fColorCount;
   1.655 +        info->fTileMode = fTileMode;
   1.656 +        info->fGradientFlags = fGradFlags;
   1.657 +    }
   1.658 +}
   1.659 +
   1.660 +#ifndef SK_IGNORE_TO_STRING
   1.661 +void SkGradientShaderBase::toString(SkString* str) const {
   1.662 +
   1.663 +    str->appendf("%d colors: ", fColorCount);
   1.664 +
   1.665 +    for (int i = 0; i < fColorCount; ++i) {
   1.666 +        str->appendHex(fOrigColors[i]);
   1.667 +        if (i < fColorCount-1) {
   1.668 +            str->append(", ");
   1.669 +        }
   1.670 +    }
   1.671 +
   1.672 +    if (fColorCount > 2) {
   1.673 +        str->append(" points: (");
   1.674 +        for (int i = 0; i < fColorCount; ++i) {
   1.675 +            str->appendScalar(SkFixedToScalar(fRecs[i].fPos));
   1.676 +            if (i < fColorCount-1) {
   1.677 +                str->append(", ");
   1.678 +            }
   1.679 +        }
   1.680 +        str->append(")");
   1.681 +    }
   1.682 +
   1.683 +    static const char* gTileModeName[SkShader::kTileModeCount] = {
   1.684 +        "clamp", "repeat", "mirror"
   1.685 +    };
   1.686 +
   1.687 +    str->append(" ");
   1.688 +    str->append(gTileModeName[fTileMode]);
   1.689 +
   1.690 +    // TODO: add "fMapper->toString(str);" when SkUnitMapper::toString is added
   1.691 +
   1.692 +    this->INHERITED::toString(str);
   1.693 +}
   1.694 +#endif
   1.695 +
   1.696 +///////////////////////////////////////////////////////////////////////////////
   1.697 +///////////////////////////////////////////////////////////////////////////////
   1.698 +
   1.699 +#include "SkEmptyShader.h"
   1.700 +
   1.701 +// assumes colors is SkColor* and pos is SkScalar*
   1.702 +#define EXPAND_1_COLOR(count)               \
   1.703 +    SkColor tmp[2];                         \
   1.704 +    do {                                    \
   1.705 +        if (1 == count) {                   \
   1.706 +            tmp[0] = tmp[1] = colors[0];    \
   1.707 +            colors = tmp;                   \
   1.708 +            pos = NULL;                     \
   1.709 +            count = 2;                      \
   1.710 +        }                                   \
   1.711 +    } while (0)
   1.712 +
   1.713 +static void desc_init(SkGradientShaderBase::Descriptor* desc,
   1.714 +                      const SkColor colors[],
   1.715 +                      const SkScalar pos[], int colorCount,
   1.716 +                      SkShader::TileMode mode,
   1.717 +                      SkUnitMapper* mapper, uint32_t flags) {
   1.718 +    desc->fColors   = colors;
   1.719 +    desc->fPos      = pos;
   1.720 +    desc->fCount    = colorCount;
   1.721 +    desc->fTileMode = mode;
   1.722 +    desc->fMapper   = mapper;
   1.723 +    desc->fFlags    = flags;
   1.724 +}
   1.725 +
   1.726 +SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
   1.727 +                                         const SkColor colors[],
   1.728 +                                         const SkScalar pos[], int colorCount,
   1.729 +                                         SkShader::TileMode mode,
   1.730 +                                         SkUnitMapper* mapper,
   1.731 +                                         uint32_t flags) {
   1.732 +    if (NULL == pts || NULL == colors || colorCount < 1) {
   1.733 +        return NULL;
   1.734 +    }
   1.735 +    EXPAND_1_COLOR(colorCount);
   1.736 +
   1.737 +    SkGradientShaderBase::Descriptor desc;
   1.738 +    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
   1.739 +    return SkNEW_ARGS(SkLinearGradient, (pts, desc));
   1.740 +}
   1.741 +
   1.742 +SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
   1.743 +                                         const SkColor colors[],
   1.744 +                                         const SkScalar pos[], int colorCount,
   1.745 +                                         SkShader::TileMode mode,
   1.746 +                                         SkUnitMapper* mapper,
   1.747 +                                         uint32_t flags) {
   1.748 +    if (radius <= 0 || NULL == colors || colorCount < 1) {
   1.749 +        return NULL;
   1.750 +    }
   1.751 +    EXPAND_1_COLOR(colorCount);
   1.752 +
   1.753 +    SkGradientShaderBase::Descriptor desc;
   1.754 +    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
   1.755 +    return SkNEW_ARGS(SkRadialGradient, (center, radius, desc));
   1.756 +}
   1.757 +
   1.758 +SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
   1.759 +                                                 SkScalar startRadius,
   1.760 +                                                 const SkPoint& end,
   1.761 +                                                 SkScalar endRadius,
   1.762 +                                                 const SkColor colors[],
   1.763 +                                                 const SkScalar pos[],
   1.764 +                                                 int colorCount,
   1.765 +                                                 SkShader::TileMode mode,
   1.766 +                                                 SkUnitMapper* mapper,
   1.767 +                                                 uint32_t flags) {
   1.768 +    if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
   1.769 +        return NULL;
   1.770 +    }
   1.771 +    EXPAND_1_COLOR(colorCount);
   1.772 +
   1.773 +    SkGradientShaderBase::Descriptor desc;
   1.774 +    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
   1.775 +    return SkNEW_ARGS(SkTwoPointRadialGradient,
   1.776 +                      (start, startRadius, end, endRadius, desc));
   1.777 +}
   1.778 +
   1.779 +SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
   1.780 +                                                  SkScalar startRadius,
   1.781 +                                                  const SkPoint& end,
   1.782 +                                                  SkScalar endRadius,
   1.783 +                                                  const SkColor colors[],
   1.784 +                                                  const SkScalar pos[],
   1.785 +                                                  int colorCount,
   1.786 +                                                  SkShader::TileMode mode,
   1.787 +                                                  SkUnitMapper* mapper,
   1.788 +                                                  uint32_t flags) {
   1.789 +    if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
   1.790 +        return NULL;
   1.791 +    }
   1.792 +    if (start == end && startRadius == endRadius) {
   1.793 +        return SkNEW(SkEmptyShader);
   1.794 +    }
   1.795 +    EXPAND_1_COLOR(colorCount);
   1.796 +
   1.797 +    SkGradientShaderBase::Descriptor desc;
   1.798 +    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
   1.799 +    return SkNEW_ARGS(SkTwoPointConicalGradient,
   1.800 +                      (start, startRadius, end, endRadius, desc));
   1.801 +}
   1.802 +
   1.803 +SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
   1.804 +                                        const SkColor colors[],
   1.805 +                                        const SkScalar pos[],
   1.806 +                                        int colorCount, SkUnitMapper* mapper,
   1.807 +                                        uint32_t flags) {
   1.808 +    if (NULL == colors || colorCount < 1) {
   1.809 +        return NULL;
   1.810 +    }
   1.811 +    EXPAND_1_COLOR(colorCount);
   1.812 +
   1.813 +    SkGradientShaderBase::Descriptor desc;
   1.814 +    desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, mapper, flags);
   1.815 +    return SkNEW_ARGS(SkSweepGradient, (cx, cy, desc));
   1.816 +}
   1.817 +
   1.818 +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
   1.819 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
   1.820 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
   1.821 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
   1.822 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointRadialGradient)
   1.823 +    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
   1.824 +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
   1.825 +
   1.826 +///////////////////////////////////////////////////////////////////////////////
   1.827 +
   1.828 +#if SK_SUPPORT_GPU
   1.829 +
   1.830 +#include "effects/GrTextureStripAtlas.h"
   1.831 +#include "GrTBackendEffectFactory.h"
   1.832 +#include "SkGr.h"
   1.833 +
   1.834 +GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
   1.835 +    : INHERITED(factory)
   1.836 +    , fCachedYCoord(SK_ScalarMax) {
   1.837 +}
   1.838 +
   1.839 +GrGLGradientEffect::~GrGLGradientEffect() { }
   1.840 +
   1.841 +void GrGLGradientEffect::emitUniforms(GrGLShaderBuilder* builder, EffectKey key) {
   1.842 +
   1.843 +    if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)) { // 2 Color case
   1.844 +        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   1.845 +                                             kVec4f_GrSLType, "GradientStartColor");
   1.846 +        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   1.847 +                                           kVec4f_GrSLType, "GradientEndColor");
   1.848 +
   1.849 +    } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ // 3 Color Case
   1.850 +        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   1.851 +                                             kVec4f_GrSLType, "GradientStartColor");
   1.852 +        fColorMidUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   1.853 +                                           kVec4f_GrSLType, "GradientMidColor");
   1.854 +        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   1.855 +                                             kVec4f_GrSLType, "GradientEndColor");
   1.856 +
   1.857 +    } else { // if not a fast case
   1.858 +        fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
   1.859 +                                      kFloat_GrSLType, "GradientYCoordFS");
   1.860 +    }
   1.861 +}
   1.862 +
   1.863 +static inline void set_color_uni(const GrGLUniformManager& uman,
   1.864 +                                 const GrGLUniformManager::UniformHandle uni,
   1.865 +                                 const SkColor* color) {
   1.866 +       uman.set4f(uni,
   1.867 +                  SkColorGetR(*color) / 255.f,
   1.868 +                  SkColorGetG(*color) / 255.f,
   1.869 +                  SkColorGetB(*color) / 255.f,
   1.870 +                  SkColorGetA(*color) / 255.f);
   1.871 +}
   1.872 +
   1.873 +static inline void set_mul_color_uni(const GrGLUniformManager& uman,
   1.874 +                                     const GrGLUniformManager::UniformHandle uni,
   1.875 +                                     const SkColor* color){
   1.876 +       float a = SkColorGetA(*color) / 255.f;
   1.877 +       float aDiv255 = a / 255.f;
   1.878 +       uman.set4f(uni,
   1.879 +                  SkColorGetR(*color) * aDiv255,
   1.880 +                  SkColorGetG(*color) * aDiv255,
   1.881 +                  SkColorGetB(*color) * aDiv255,
   1.882 +                  a);
   1.883 +}
   1.884 +
   1.885 +void GrGLGradientEffect::setData(const GrGLUniformManager& uman,
   1.886 +                                 const GrDrawEffect& drawEffect) {
   1.887 +
   1.888 +    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
   1.889 +
   1.890 +
   1.891 +    if (GrGradientEffect::kTwo_ColorType == e.getColorType()){
   1.892 +
   1.893 +        if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
   1.894 +            set_mul_color_uni(uman, fColorStartUni, e.getColors(0));
   1.895 +            set_mul_color_uni(uman, fColorEndUni,   e.getColors(1));
   1.896 +        } else {
   1.897 +            set_color_uni(uman, fColorStartUni, e.getColors(0));
   1.898 +            set_color_uni(uman, fColorEndUni,   e.getColors(1));
   1.899 +        }
   1.900 +
   1.901 +    } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){
   1.902 +
   1.903 +        if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
   1.904 +            set_mul_color_uni(uman, fColorStartUni, e.getColors(0));
   1.905 +            set_mul_color_uni(uman, fColorMidUni,   e.getColors(1));
   1.906 +            set_mul_color_uni(uman, fColorEndUni,   e.getColors(2));
   1.907 +        } else {
   1.908 +            set_color_uni(uman, fColorStartUni, e.getColors(0));
   1.909 +            set_color_uni(uman, fColorMidUni,   e.getColors(1));
   1.910 +            set_color_uni(uman, fColorEndUni,   e.getColors(2));
   1.911 +        }
   1.912 +    } else {
   1.913 +
   1.914 +        SkScalar yCoord = e.getYCoord();
   1.915 +        if (yCoord != fCachedYCoord) {
   1.916 +            uman.set1f(fFSYUni, yCoord);
   1.917 +            fCachedYCoord = yCoord;
   1.918 +        }
   1.919 +    }
   1.920 +}
   1.921 +
   1.922 +
   1.923 +GrGLEffect::EffectKey GrGLGradientEffect::GenBaseGradientKey(const GrDrawEffect& drawEffect) {
   1.924 +    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
   1.925 +
   1.926 +    EffectKey key = 0;
   1.927 +
   1.928 +    if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
   1.929 +        key |= kTwoColorKey;
   1.930 +    } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){
   1.931 +        key |= kThreeColorKey;
   1.932 +    }
   1.933 +
   1.934 +    if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
   1.935 +        key |= kPremulBeforeInterpKey;
   1.936 +    }
   1.937 +
   1.938 +    return key;
   1.939 +}
   1.940 +
   1.941 +void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder,
   1.942 +                                   const char* gradientTValue,
   1.943 +                                   EffectKey key,
   1.944 +                                   const char* outputColor,
   1.945 +                                   const char* inputColor,
   1.946 +                                   const TextureSamplerArray& samplers) {
   1.947 +    if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)){
   1.948 +        builder->fsCodeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
   1.949 +                               builder->getUniformVariable(fColorStartUni).c_str(),
   1.950 +                               builder->getUniformVariable(fColorEndUni).c_str(),
   1.951 +                               gradientTValue);
   1.952 +        // Note that we could skip this step if both colors are known to be opaque. Two
   1.953 +        // considerations:
   1.954 +        // The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
   1.955 +        // case. Make sure the key reflects this optimization (and note that it can use the same
   1.956 +        // shader as thekBeforeIterp case). This same optimization applies to the 3 color case below.
   1.957 +        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) {
   1.958 +            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
   1.959 +        }
   1.960 +
   1.961 +        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
   1.962 +                               (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
   1.963 +    } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){
   1.964 +        builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
   1.965 +                               gradientTValue);
   1.966 +        builder->fsCodeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
   1.967 +                               builder->getUniformVariable(fColorStartUni).c_str());
   1.968 +        if (kTegra3_GrGLRenderer == builder->ctxInfo().renderer()) {
   1.969 +            // The Tegra3 compiler will sometimes never return if we have
   1.970 +            // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
   1.971 +            builder->fsCodeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
   1.972 +            builder->fsCodeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
   1.973 +            builder->fsCodeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
   1.974 +                                   builder->getUniformVariable(fColorMidUni).c_str());
   1.975 +        } else {
   1.976 +            builder->fsCodeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
   1.977 +                                   builder->getUniformVariable(fColorMidUni).c_str());
   1.978 +        }
   1.979 +        builder->fsCodeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
   1.980 +                               builder->getUniformVariable(fColorEndUni).c_str());
   1.981 +        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) {
   1.982 +            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
   1.983 +        }
   1.984 +
   1.985 +        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
   1.986 +                               (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
   1.987 +    } else {
   1.988 +        builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
   1.989 +                               gradientTValue,
   1.990 +                               builder->getUniformVariable(fFSYUni).c_str());
   1.991 +        builder->fsCodeAppendf("\t%s = ", outputColor);
   1.992 +        builder->fsAppendTextureLookupAndModulate(inputColor,
   1.993 +                                                  samplers[0],
   1.994 +                                                  "coord");
   1.995 +        builder->fsCodeAppend(";\n");
   1.996 +    }
   1.997 +}
   1.998 +
   1.999 +/////////////////////////////////////////////////////////////////////
  1.1000 +
  1.1001 +GrGradientEffect::GrGradientEffect(GrContext* ctx,
  1.1002 +                                   const SkGradientShaderBase& shader,
  1.1003 +                                   const SkMatrix& matrix,
  1.1004 +                                   SkShader::TileMode tileMode) {
  1.1005 +
  1.1006 +    fIsOpaque = shader.isOpaque();
  1.1007 +
  1.1008 +    SkShader::GradientInfo info;
  1.1009 +    SkScalar pos[3] = {0};
  1.1010 +
  1.1011 +    info.fColorCount = 3;
  1.1012 +    info.fColors = &fColors[0];
  1.1013 +    info.fColorOffsets = &pos[0];
  1.1014 +    shader.asAGradient(&info);
  1.1015 +
  1.1016 +    // The two and three color specializations do not currently support tiling.
  1.1017 +    bool foundSpecialCase = false;
  1.1018 +    if (SkShader::kClamp_TileMode == info.fTileMode) {
  1.1019 +        if (2 == info.fColorCount) {
  1.1020 +            fRow = -1; // flag for no atlas
  1.1021 +            fColorType = kTwo_ColorType;
  1.1022 +            foundSpecialCase = true;
  1.1023 +        } else if (3 == info.fColorCount &&
  1.1024 +                   (SkScalarAbs(pos[1] - SK_ScalarHalf) < SK_Scalar1 / 1000)) { // 3 color symmetric
  1.1025 +            fRow = -1; // flag for no atlas
  1.1026 +            fColorType = kThree_ColorType;
  1.1027 +            foundSpecialCase = true;
  1.1028 +        }
  1.1029 +    }
  1.1030 +    if (foundSpecialCase) {
  1.1031 +        if (SkGradientShader::kInterpolateColorsInPremul_Flag & info.fGradientFlags) {
  1.1032 +            fPremulType = kBeforeInterp_PremulType;
  1.1033 +        } else {
  1.1034 +            fPremulType = kAfterInterp_PremulType;
  1.1035 +        }
  1.1036 +        fCoordTransform.reset(kCoordSet, matrix);
  1.1037 +    } else {
  1.1038 +        // doesn't matter how this is set, just be consistent because it is part of the effect key.
  1.1039 +        fPremulType = kBeforeInterp_PremulType;
  1.1040 +        SkBitmap bitmap;
  1.1041 +        shader.getGradientTableBitmap(&bitmap);
  1.1042 +        fColorType = kTexture_ColorType;
  1.1043 +
  1.1044 +        GrTextureStripAtlas::Desc desc;
  1.1045 +        desc.fWidth  = bitmap.width();
  1.1046 +        desc.fHeight = 32;
  1.1047 +        desc.fRowHeight = bitmap.height();
  1.1048 +        desc.fContext = ctx;
  1.1049 +        desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.colorType(), bitmap.alphaType());
  1.1050 +        fAtlas = GrTextureStripAtlas::GetAtlas(desc);
  1.1051 +        SkASSERT(NULL != fAtlas);
  1.1052 +
  1.1053 +        // We always filter the gradient table. Each table is one row of a texture, always y-clamp.
  1.1054 +        GrTextureParams params;
  1.1055 +        params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
  1.1056 +        params.setTileModeX(tileMode);
  1.1057 +
  1.1058 +        fRow = fAtlas->lockRow(bitmap);
  1.1059 +        if (-1 != fRow) {
  1.1060 +            fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf *
  1.1061 +            fAtlas->getVerticalScaleFactor();
  1.1062 +            fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture());
  1.1063 +            fTextureAccess.reset(fAtlas->getTexture(), params);
  1.1064 +        } else {
  1.1065 +            GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, &params);
  1.1066 +            fCoordTransform.reset(kCoordSet, matrix, texture);
  1.1067 +            fTextureAccess.reset(texture, params);
  1.1068 +            fYCoord = SK_ScalarHalf;
  1.1069 +
  1.1070 +            // Unlock immediately, this is not great, but we don't have a way of
  1.1071 +            // knowing when else to unlock it currently, so it may get purged from
  1.1072 +            // the cache, but it'll still be ref'd until it's no longer being used.
  1.1073 +            GrUnlockAndUnrefCachedBitmapTexture(texture);
  1.1074 +        }
  1.1075 +        this->addTextureAccess(&fTextureAccess);
  1.1076 +    }
  1.1077 +    this->addCoordTransform(&fCoordTransform);
  1.1078 +}
  1.1079 +
  1.1080 +GrGradientEffect::~GrGradientEffect() {
  1.1081 +    if (this->useAtlas()) {
  1.1082 +        fAtlas->unlockRow(fRow);
  1.1083 +    }
  1.1084 +}
  1.1085 +
  1.1086 +bool GrGradientEffect::onIsEqual(const GrEffect& effect) const {
  1.1087 +    const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect);
  1.1088 +
  1.1089 +    if (this->fColorType == s.getColorType()){
  1.1090 +
  1.1091 +        if (kTwo_ColorType == fColorType) {
  1.1092 +            if (*this->getColors(0) != *s.getColors(0) ||
  1.1093 +                *this->getColors(1) != *s.getColors(1)) {
  1.1094 +                return false;
  1.1095 +            }
  1.1096 +        } else if (kThree_ColorType == fColorType) {
  1.1097 +            if (*this->getColors(0) != *s.getColors(0) ||
  1.1098 +                *this->getColors(1) != *s.getColors(1) ||
  1.1099 +                *this->getColors(2) != *s.getColors(2)) {
  1.1100 +                return false;
  1.1101 +            }
  1.1102 +        } else {
  1.1103 +            if (fYCoord != s.getYCoord()) {
  1.1104 +                return false;
  1.1105 +            }
  1.1106 +        }
  1.1107 +
  1.1108 +        return fTextureAccess.getTexture() == s.fTextureAccess.getTexture()  &&
  1.1109 +            fTextureAccess.getParams().getTileModeX() ==
  1.1110 +                s.fTextureAccess.getParams().getTileModeX() &&
  1.1111 +            this->useAtlas() == s.useAtlas() &&
  1.1112 +            fCoordTransform.getMatrix().cheapEqualTo(s.fCoordTransform.getMatrix());
  1.1113 +    }
  1.1114 +
  1.1115 +    return false;
  1.1116 +}
  1.1117 +
  1.1118 +void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
  1.1119 +    if (fIsOpaque && (kA_GrColorComponentFlag & *validFlags) && 0xff == GrColorUnpackA(*color)) {
  1.1120 +        *validFlags = kA_GrColorComponentFlag;
  1.1121 +    } else {
  1.1122 +        *validFlags = 0;
  1.1123 +    }
  1.1124 +}
  1.1125 +
  1.1126 +int GrGradientEffect::RandomGradientParams(SkRandom* random,
  1.1127 +                                           SkColor colors[],
  1.1128 +                                           SkScalar** stops,
  1.1129 +                                           SkShader::TileMode* tm) {
  1.1130 +    int outColors = random->nextRangeU(1, kMaxRandomGradientColors);
  1.1131 +
  1.1132 +    // if one color, omit stops, otherwise randomly decide whether or not to
  1.1133 +    if (outColors == 1 || (outColors >= 2 && random->nextBool())) {
  1.1134 +        *stops = NULL;
  1.1135 +    }
  1.1136 +
  1.1137 +    SkScalar stop = 0.f;
  1.1138 +    for (int i = 0; i < outColors; ++i) {
  1.1139 +        colors[i] = random->nextU();
  1.1140 +        if (NULL != *stops) {
  1.1141 +            (*stops)[i] = stop;
  1.1142 +            stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
  1.1143 +        }
  1.1144 +    }
  1.1145 +    *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
  1.1146 +
  1.1147 +    return outColors;
  1.1148 +}
  1.1149 +
  1.1150 +#endif

mercurial