Home | History | Annotate | Download | only in gradients
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "SkGradientShaderPriv.h"
     10 #include "SkLinearGradient.h"
     11 #include "SkRadialGradient.h"
     12 #include "SkTwoPointRadialGradient.h"
     13 #include "SkTwoPointConicalGradient.h"
     14 #include "SkSweepGradient.h"
     15 
     16 SkGradientShaderBase::SkGradientShaderBase(const SkColor colors[], const SkScalar pos[],
     17              int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) {
     18     SkASSERT(colorCount > 1);
     19 
     20     fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
     21 
     22     fMapper = mapper;
     23     SkSafeRef(mapper);
     24 
     25     SkASSERT((unsigned)mode < SkShader::kTileModeCount);
     26     SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
     27     fTileMode = mode;
     28     fTileProc = gTileProcs[mode];
     29 
     30     fCache16 = fCache16Storage = NULL;
     31     fCache32 = NULL;
     32     fCache32PixelRef = NULL;
     33 
     34     /*  Note: we let the caller skip the first and/or last position.
     35         i.e. pos[0] = 0.3, pos[1] = 0.7
     36         In these cases, we insert dummy entries to ensure that the final data
     37         will be bracketed by [0, 1].
     38         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
     39 
     40         Thus colorCount (the caller's value, and fColorCount (our value) may
     41         differ by up to 2. In the above example:
     42             colorCount = 2
     43             fColorCount = 4
     44      */
     45     fColorCount = colorCount;
     46     // check if we need to add in dummy start and/or end position/colors
     47     bool dummyFirst = false;
     48     bool dummyLast = false;
     49     if (pos) {
     50         dummyFirst = pos[0] != 0;
     51         dummyLast = pos[colorCount - 1] != SK_Scalar1;
     52         fColorCount += dummyFirst + dummyLast;
     53     }
     54 
     55     if (fColorCount > kColorStorageCount) {
     56         size_t size = sizeof(SkColor) + sizeof(Rec);
     57         fOrigColors = reinterpret_cast<SkColor*>(
     58                                         sk_malloc_throw(size * fColorCount));
     59     }
     60     else {
     61         fOrigColors = fStorage;
     62     }
     63 
     64     // Now copy over the colors, adding the dummies as needed
     65     {
     66         SkColor* origColors = fOrigColors;
     67         if (dummyFirst) {
     68             *origColors++ = colors[0];
     69         }
     70         memcpy(origColors, colors, colorCount * sizeof(SkColor));
     71         if (dummyLast) {
     72             origColors += colorCount;
     73             *origColors = colors[colorCount - 1];
     74         }
     75     }
     76 
     77     fRecs = (Rec*)(fOrigColors + fColorCount);
     78     if (fColorCount > 2) {
     79         Rec* recs = fRecs;
     80         recs->fPos = 0;
     81         //  recs->fScale = 0; // unused;
     82         recs += 1;
     83         if (pos) {
     84             /*  We need to convert the user's array of relative positions into
     85                 fixed-point positions and scale factors. We need these results
     86                 to be strictly monotonic (no two values equal or out of order).
     87                 Hence this complex loop that just jams a zero for the scale
     88                 value if it sees a segment out of order, and it assures that
     89                 we start at 0 and end at 1.0
     90             */
     91             SkFixed prev = 0;
     92             int startIndex = dummyFirst ? 0 : 1;
     93             int count = colorCount + dummyLast;
     94             for (int i = startIndex; i < count; i++) {
     95                 // force the last value to be 1.0
     96                 SkFixed curr;
     97                 if (i == colorCount) {  // we're really at the dummyLast
     98                     curr = SK_Fixed1;
     99                 } else {
    100                     curr = SkScalarToFixed(pos[i]);
    101                 }
    102                 // pin curr withing range
    103                 if (curr < 0) {
    104                     curr = 0;
    105                 } else if (curr > SK_Fixed1) {
    106                     curr = SK_Fixed1;
    107                 }
    108                 recs->fPos = curr;
    109                 if (curr > prev) {
    110                     recs->fScale = (1 << 24) / (curr - prev);
    111                 } else {
    112                     recs->fScale = 0; // ignore this segment
    113                 }
    114                 // get ready for the next value
    115                 prev = curr;
    116                 recs += 1;
    117             }
    118         } else {    // assume even distribution
    119             SkFixed dp = SK_Fixed1 / (colorCount - 1);
    120             SkFixed p = dp;
    121             SkFixed scale = (colorCount - 1) << 8;  // (1 << 24) / dp
    122             for (int i = 1; i < colorCount; i++) {
    123                 recs->fPos   = p;
    124                 recs->fScale = scale;
    125                 recs += 1;
    126                 p += dp;
    127             }
    128         }
    129     }
    130     this->initCommon();
    131 }
    132 
    133 SkGradientShaderBase::SkGradientShaderBase(SkFlattenableReadBuffer& buffer) :
    134     INHERITED(buffer) {
    135     fCacheAlpha = 256;
    136 
    137     fMapper = buffer.readFlattenableT<SkUnitMapper>();
    138 
    139     fCache16 = fCache16Storage = NULL;
    140     fCache32 = NULL;
    141     fCache32PixelRef = NULL;
    142 
    143     int colorCount = fColorCount = buffer.getArrayCount();
    144     if (colorCount > kColorStorageCount) {
    145         size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
    146         fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount);
    147     } else {
    148         fOrigColors = fStorage;
    149     }
    150     buffer.readColorArray(fOrigColors);
    151 
    152     fTileMode = (TileMode)buffer.readUInt();
    153     fTileProc = gTileProcs[fTileMode];
    154     fRecs = (Rec*)(fOrigColors + colorCount);
    155     if (colorCount > 2) {
    156         Rec* recs = fRecs;
    157         recs[0].fPos = 0;
    158         for (int i = 1; i < colorCount; i++) {
    159             recs[i].fPos = buffer.readInt();
    160             recs[i].fScale = buffer.readUInt();
    161         }
    162     }
    163     buffer.readMatrix(&fPtsToUnit);
    164     this->initCommon();
    165 }
    166 
    167 SkGradientShaderBase::~SkGradientShaderBase() {
    168     if (fCache16Storage) {
    169         sk_free(fCache16Storage);
    170     }
    171     SkSafeUnref(fCache32PixelRef);
    172     if (fOrigColors != fStorage) {
    173         sk_free(fOrigColors);
    174     }
    175     SkSafeUnref(fMapper);
    176 }
    177 
    178 void SkGradientShaderBase::initCommon() {
    179     fFlags = 0;
    180     unsigned colorAlpha = 0xFF;
    181     for (int i = 0; i < fColorCount; i++) {
    182         colorAlpha &= SkColorGetA(fOrigColors[i]);
    183     }
    184     fColorsAreOpaque = colorAlpha == 0xFF;
    185 }
    186 
    187 void SkGradientShaderBase::flatten(SkFlattenableWriteBuffer& buffer) const {
    188     this->INHERITED::flatten(buffer);
    189     buffer.writeFlattenable(fMapper);
    190     buffer.writeColorArray(fOrigColors, fColorCount);
    191     buffer.writeUInt(fTileMode);
    192     if (fColorCount > 2) {
    193         Rec* recs = fRecs;
    194         for (int i = 1; i < fColorCount; i++) {
    195             buffer.writeInt(recs[i].fPos);
    196             buffer.writeUInt(recs[i].fScale);
    197         }
    198     }
    199     buffer.writeMatrix(fPtsToUnit);
    200 }
    201 
    202 bool SkGradientShaderBase::isOpaque() const {
    203     return fColorsAreOpaque;
    204 }
    205 
    206 bool SkGradientShaderBase::setContext(const SkBitmap& device,
    207                                  const SkPaint& paint,
    208                                  const SkMatrix& matrix) {
    209     if (!this->INHERITED::setContext(device, paint, matrix)) {
    210         return false;
    211     }
    212 
    213     const SkMatrix& inverse = this->getTotalInverse();
    214 
    215     if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
    216         // need to keep our set/end context calls balanced.
    217         this->INHERITED::endContext();
    218         return false;
    219     }
    220 
    221     fDstToIndexProc = fDstToIndex.getMapXYProc();
    222     fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
    223 
    224     // now convert our colors in to PMColors
    225     unsigned paintAlpha = this->getPaintAlpha();
    226 
    227     fFlags = this->INHERITED::getFlags();
    228     if (fColorsAreOpaque && paintAlpha == 0xFF) {
    229         fFlags |= kOpaqueAlpha_Flag;
    230     }
    231     // we can do span16 as long as our individual colors are opaque,
    232     // regardless of the paint's alpha
    233     if (fColorsAreOpaque) {
    234         fFlags |= kHasSpan16_Flag;
    235     }
    236 
    237     this->setCacheAlpha(paintAlpha);
    238     return true;
    239 }
    240 
    241 void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const {
    242     // if the new alpha differs from the previous time we were called, inval our cache
    243     // this will trigger the cache to be rebuilt.
    244     // we don't care about the first time, since the cache ptrs will already be NULL
    245     if (fCacheAlpha != alpha) {
    246         fCache16 = NULL;            // inval the cache
    247         fCache32 = NULL;            // inval the cache
    248         fCacheAlpha = alpha;        // record the new alpha
    249         // inform our subclasses
    250         if (fCache32PixelRef) {
    251             fCache32PixelRef->notifyPixelsChanged();
    252         }
    253     }
    254 }
    255 
    256 #define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
    257 
    258 /** We take the original colors, not our premultiplied PMColors, since we can
    259     build a 16bit table as long as the original colors are opaque, even if the
    260     paint specifies a non-opaque alpha.
    261 */
    262 void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
    263                                       int count) {
    264     SkASSERT(count > 1);
    265     SkASSERT(SkColorGetA(c0) == 0xFF);
    266     SkASSERT(SkColorGetA(c1) == 0xFF);
    267 
    268     SkFixed r = SkColorGetR(c0);
    269     SkFixed g = SkColorGetG(c0);
    270     SkFixed b = SkColorGetB(c0);
    271 
    272     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
    273     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
    274     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
    275 
    276     r = SkIntToFixed(r) + 0x8000;
    277     g = SkIntToFixed(g) + 0x8000;
    278     b = SkIntToFixed(b) + 0x8000;
    279 
    280     do {
    281         unsigned rr = r >> 16;
    282         unsigned gg = g >> 16;
    283         unsigned bb = b >> 16;
    284         cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
    285         cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
    286         cache += 1;
    287         r += dr;
    288         g += dg;
    289         b += db;
    290     } while (--count != 0);
    291 }
    292 
    293 /*
    294  *  2x2 dither a fixed-point color component (8.16) down to 8, matching the
    295  *  semantics of how we 2x2 dither 32->16
    296  */
    297 static inline U8CPU dither_fixed_to_8(SkFixed n) {
    298     n >>= 8;
    299     return ((n << 1) - ((n >> 8 << 8) | (n >> 8))) >> 8;
    300 }
    301 
    302 /*
    303  *  For dithering with premultiply, we want to ceiling the alpha component,
    304  *  to ensure that it is always >= any color component.
    305  */
    306 static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
    307     n >>= 8;
    308     return ((n << 1) - (n | (n >> 8))) >> 8;
    309 }
    310 
    311 void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
    312                                       int count, U8CPU paintAlpha) {
    313     SkASSERT(count > 1);
    314 
    315     // need to apply paintAlpha to our two endpoints
    316     SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
    317     SkFixed da;
    318     {
    319         int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
    320         da = SkIntToFixed(tmp - a) / (count - 1);
    321     }
    322 
    323     SkFixed r = SkColorGetR(c0);
    324     SkFixed g = SkColorGetG(c0);
    325     SkFixed b = SkColorGetB(c0);
    326     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
    327     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
    328     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
    329 
    330     a = SkIntToFixed(a) + 0x8000;
    331     r = SkIntToFixed(r) + 0x8000;
    332     g = SkIntToFixed(g) + 0x8000;
    333     b = SkIntToFixed(b) + 0x8000;
    334 
    335     do {
    336         cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
    337         cache[kCache32Count] =
    338             SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
    339                                     dither_fixed_to_8(r),
    340                                     dither_fixed_to_8(g),
    341                                     dither_fixed_to_8(b));
    342         cache += 1;
    343         a += da;
    344         r += dr;
    345         g += dg;
    346         b += db;
    347     } while (--count != 0);
    348 }
    349 
    350 static inline int SkFixedToFFFF(SkFixed x) {
    351     SkASSERT((unsigned)x <= SK_Fixed1);
    352     return x - (x >> 16);
    353 }
    354 
    355 static inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
    356     SkASSERT(x < (1U << bits));
    357     if (6 == bits) {
    358         return (x << 10) | (x << 4) | (x >> 2);
    359     }
    360     if (8 == bits) {
    361         return (x << 8) | x;
    362     }
    363     sk_throw();
    364     return 0;
    365 }
    366 
    367 const uint16_t* SkGradientShaderBase::getCache16() const {
    368     if (fCache16 == NULL) {
    369         // double the count for dither entries
    370         const int entryCount = kCache16Count * 2;
    371         const size_t allocSize = sizeof(uint16_t) * entryCount;
    372 
    373         if (fCache16Storage == NULL) { // set the storage and our working ptr
    374             fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
    375         }
    376         fCache16 = fCache16Storage;
    377         if (fColorCount == 2) {
    378             Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
    379                             kCache16Count);
    380         } else {
    381             Rec* rec = fRecs;
    382             int prevIndex = 0;
    383             for (int i = 1; i < fColorCount; i++) {
    384                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
    385                 SkASSERT(nextIndex < kCache16Count);
    386 
    387                 if (nextIndex > prevIndex)
    388                     Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
    389                 prevIndex = nextIndex;
    390             }
    391         }
    392 
    393         if (fMapper) {
    394             fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
    395             uint16_t* linear = fCache16;         // just computed linear data
    396             uint16_t* mapped = fCache16Storage;  // storage for mapped data
    397             SkUnitMapper* map = fMapper;
    398             for (int i = 0; i < kCache16Count; i++) {
    399                 int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
    400                 mapped[i] = linear[index];
    401                 mapped[i + kCache16Count] = linear[index + kCache16Count];
    402             }
    403             sk_free(fCache16);
    404             fCache16 = fCache16Storage;
    405         }
    406     }
    407     return fCache16;
    408 }
    409 
    410 const SkPMColor* SkGradientShaderBase::getCache32() const {
    411     if (fCache32 == NULL) {
    412         // double the count for dither entries
    413         const int entryCount = kCache32Count * 2;
    414         const size_t allocSize = sizeof(SkPMColor) * entryCount;
    415 
    416         if (NULL == fCache32PixelRef) {
    417             fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef,
    418                                           (NULL, allocSize, NULL));
    419         }
    420         fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
    421         if (fColorCount == 2) {
    422             Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
    423                             kCache32Count, fCacheAlpha);
    424         } else {
    425             Rec* rec = fRecs;
    426             int prevIndex = 0;
    427             for (int i = 1; i < fColorCount; i++) {
    428                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
    429                 SkASSERT(nextIndex < kCache32Count);
    430 
    431                 if (nextIndex > prevIndex)
    432                     Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
    433                                     fOrigColors[i],
    434                                     nextIndex - prevIndex + 1, fCacheAlpha);
    435                 prevIndex = nextIndex;
    436             }
    437         }
    438 
    439         if (fMapper) {
    440             SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
    441                                                  (NULL, allocSize, NULL));
    442             SkPMColor* linear = fCache32;           // just computed linear data
    443             SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
    444             SkUnitMapper* map = fMapper;
    445             for (int i = 0; i < kCache32Count; i++) {
    446                 int index = map->mapUnit16((i << 8) | i) >> 8;
    447                 mapped[i] = linear[index];
    448                 mapped[i + kCache32Count] = linear[index + kCache32Count];
    449             }
    450             fCache32PixelRef->unref();
    451             fCache32PixelRef = newPR;
    452             fCache32 = (SkPMColor*)newPR->getAddr();
    453         }
    454     }
    455     return fCache32;
    456 }
    457 
    458 /*
    459  *  Because our caller might rebuild the same (logically the same) gradient
    460  *  over and over, we'd like to return exactly the same "bitmap" if possible,
    461  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
    462  *  To do that, we maintain a private cache of built-bitmaps, based on our
    463  *  colors and positions. Note: we don't try to flatten the fMapper, so if one
    464  *  is present, we skip the cache for now.
    465  */
    466 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
    467     // our caller assumes no external alpha, so we ensure that our cache is
    468     // built with 0xFF
    469     this->setCacheAlpha(0xFF);
    470 
    471     // don't have a way to put the mapper into our cache-key yet
    472     if (fMapper) {
    473         // force our cahce32pixelref to be built
    474         (void)this->getCache32();
    475         bitmap->setConfig(SkBitmap::kARGB_8888_Config, kCache32Count, 1);
    476         bitmap->setPixelRef(fCache32PixelRef);
    477         return;
    478     }
    479 
    480     // build our key: [numColors + colors[] + {positions[]} ]
    481     int count = 1 + fColorCount;
    482     if (fColorCount > 2) {
    483         count += fColorCount - 1;    // fRecs[].fPos
    484     }
    485 
    486     SkAutoSTMalloc<16, int32_t> storage(count);
    487     int32_t* buffer = storage.get();
    488 
    489     *buffer++ = fColorCount;
    490     memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
    491     buffer += fColorCount;
    492     if (fColorCount > 2) {
    493         for (int i = 1; i < fColorCount; i++) {
    494             *buffer++ = fRecs[i].fPos;
    495         }
    496     }
    497     SkASSERT(buffer - storage.get() == count);
    498 
    499     ///////////////////////////////////
    500 
    501     SK_DECLARE_STATIC_MUTEX(gMutex);
    502     static SkBitmapCache* gCache;
    503     // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
    504     static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
    505     SkAutoMutexAcquire ama(gMutex);
    506 
    507     if (NULL == gCache) {
    508         gCache = SkNEW_ARGS(SkBitmapCache, (MAX_NUM_CACHED_GRADIENT_BITMAPS));
    509     }
    510     size_t size = count * sizeof(int32_t);
    511 
    512     if (!gCache->find(storage.get(), size, bitmap)) {
    513         // force our cahce32pixelref to be built
    514         (void)this->getCache32();
    515         bitmap->setConfig(SkBitmap::kARGB_8888_Config, kCache32Count, 1);
    516         bitmap->setPixelRef(fCache32PixelRef);
    517 
    518         gCache->add(storage.get(), size, *bitmap);
    519     }
    520 }
    521 
    522 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
    523     if (info) {
    524         if (info->fColorCount >= fColorCount) {
    525             if (info->fColors) {
    526                 memcpy(info->fColors, fOrigColors, fColorCount * sizeof(SkColor));
    527             }
    528             if (info->fColorOffsets) {
    529                 if (fColorCount == 2) {
    530                     info->fColorOffsets[0] = 0;
    531                     info->fColorOffsets[1] = SK_Scalar1;
    532                 } else if (fColorCount > 2) {
    533                     for (int i = 0; i < fColorCount; ++i) {
    534                         info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
    535                     }
    536                 }
    537             }
    538         }
    539         info->fColorCount = fColorCount;
    540         info->fTileMode = fTileMode;
    541     }
    542 }
    543 
    544 #ifdef SK_DEVELOPER
    545 void SkGradientShaderBase::toString(SkString* str) const {
    546 
    547     str->appendf("%d colors: ", fColorCount);
    548 
    549     for (int i = 0; i < fColorCount; ++i) {
    550         str->appendHex(fOrigColors[i]);
    551         if (i < fColorCount-1) {
    552             str->append(", ");
    553         }
    554     }
    555 
    556     if (fColorCount > 2) {
    557         str->append(" points: (");
    558         for (int i = 0; i < fColorCount; ++i) {
    559             str->appendScalar(SkFixedToScalar(fRecs[i].fPos));
    560             if (i < fColorCount-1) {
    561                 str->append(", ");
    562             }
    563         }
    564         str->append(")");
    565     }
    566 
    567     static const char* gTileModeName[SkShader::kTileModeCount] = {
    568         "clamp", "repeat", "mirror"
    569     };
    570 
    571     str->append(" ");
    572     str->append(gTileModeName[fTileMode]);
    573 
    574     // TODO: add "fMapper->toString(str);" when SkUnitMapper::toString is added
    575 
    576     this->INHERITED::toString(str);
    577 }
    578 #endif
    579 
    580 ///////////////////////////////////////////////////////////////////////////////
    581 ///////////////////////////////////////////////////////////////////////////////
    582 
    583 #include "SkEmptyShader.h"
    584 
    585 // assumes colors is SkColor* and pos is SkScalar*
    586 #define EXPAND_1_COLOR(count)               \
    587     SkColor tmp[2];                         \
    588     do {                                    \
    589         if (1 == count) {                   \
    590             tmp[0] = tmp[1] = colors[0];    \
    591             colors = tmp;                   \
    592             pos = NULL;                     \
    593             count = 2;                      \
    594         }                                   \
    595     } while (0)
    596 
    597 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
    598                                          const SkColor colors[],
    599                                          const SkScalar pos[], int colorCount,
    600                                          SkShader::TileMode mode,
    601                                          SkUnitMapper* mapper) {
    602     if (NULL == pts || NULL == colors || colorCount < 1) {
    603         return NULL;
    604     }
    605     EXPAND_1_COLOR(colorCount);
    606 
    607     return SkNEW_ARGS(SkLinearGradient,
    608                       (pts, colors, pos, colorCount, mode, mapper));
    609 }
    610 
    611 SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
    612                                          const SkColor colors[],
    613                                          const SkScalar pos[], int colorCount,
    614                                          SkShader::TileMode mode,
    615                                          SkUnitMapper* mapper) {
    616     if (radius <= 0 || NULL == colors || colorCount < 1) {
    617         return NULL;
    618     }
    619     EXPAND_1_COLOR(colorCount);
    620 
    621     return SkNEW_ARGS(SkRadialGradient,
    622                       (center, radius, colors, pos, colorCount, mode, mapper));
    623 }
    624 
    625 SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
    626                                                  SkScalar startRadius,
    627                                                  const SkPoint& end,
    628                                                  SkScalar endRadius,
    629                                                  const SkColor colors[],
    630                                                  const SkScalar pos[],
    631                                                  int colorCount,
    632                                                  SkShader::TileMode mode,
    633                                                  SkUnitMapper* mapper) {
    634     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
    635         return NULL;
    636     }
    637     EXPAND_1_COLOR(colorCount);
    638 
    639     return SkNEW_ARGS(SkTwoPointRadialGradient,
    640                       (start, startRadius, end, endRadius, colors, pos,
    641                        colorCount, mode, mapper));
    642 }
    643 
    644 SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
    645                                                  SkScalar startRadius,
    646                                                  const SkPoint& end,
    647                                                  SkScalar endRadius,
    648                                                  const SkColor colors[],
    649                                                  const SkScalar pos[],
    650                                                  int colorCount,
    651                                                  SkShader::TileMode mode,
    652                                                  SkUnitMapper* mapper) {
    653     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
    654         return NULL;
    655     }
    656     if (start == end && startRadius == endRadius) {
    657         return SkNEW(SkEmptyShader);
    658     }
    659     EXPAND_1_COLOR(colorCount);
    660 
    661     return SkNEW_ARGS(SkTwoPointConicalGradient,
    662                       (start, startRadius, end, endRadius, colors, pos,
    663                        colorCount, mode, mapper));
    664 }
    665 
    666 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
    667                                         const SkColor colors[],
    668                                         const SkScalar pos[],
    669                                         int count, SkUnitMapper* mapper) {
    670     if (NULL == colors || count < 1) {
    671         return NULL;
    672     }
    673     EXPAND_1_COLOR(count);
    674 
    675     return SkNEW_ARGS(SkSweepGradient, (cx, cy, colors, pos, count, mapper));
    676 }
    677 
    678 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
    679     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
    680     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
    681     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
    682     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointRadialGradient)
    683     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
    684 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    685 
    686 ///////////////////////////////////////////////////////////////////////////////
    687 
    688 #if SK_SUPPORT_GPU
    689 
    690 #include "effects/GrTextureStripAtlas.h"
    691 #include "SkGr.h"
    692 
    693 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
    694     : INHERITED(factory)
    695     , fCachedYCoord(SK_ScalarMax)
    696     , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) {
    697 }
    698 
    699 GrGLGradientEffect::~GrGLGradientEffect() { }
    700 
    701 void GrGLGradientEffect::emitYCoordUniform(GrGLShaderBuilder* builder) {
    702     fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
    703                                   kFloat_GrSLType, "GradientYCoordFS");
    704 }
    705 
    706 void GrGLGradientEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
    707     const GrGradientEffect& e = GetEffectFromStage<GrGradientEffect>(stage);
    708     const GrTexture* texture = e.texture(0);
    709     fEffectMatrix.setData(uman, e.getMatrix(), stage.getCoordChangeMatrix(), texture);
    710 
    711     SkScalar yCoord = e.getYCoord();
    712     if (yCoord != fCachedYCoord) {
    713         uman.set1f(fFSYUni, yCoord);
    714         fCachedYCoord = yCoord;
    715     }
    716 }
    717 
    718 GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrEffectStage& s) {
    719     const GrGradientEffect& e = GetEffectFromStage<GrGradientEffect>(s);
    720     const GrTexture* texture = e.texture(0);
    721     return GrGLEffectMatrix::GenKey(e.getMatrix(), s.getCoordChangeMatrix(), texture);
    722 }
    723 
    724 void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder,
    725                                      EffectKey key,
    726                                      const char* vertexCoords,
    727                                      const char** fsCoordName,
    728                                      const char** vsVaryingName,
    729                                      GrSLType* vsVaryingType) {
    730     fEffectMatrix.emitCodeMakeFSCoords2D(builder,
    731                                          key & kMatrixKeyMask,
    732                                          vertexCoords,
    733                                          fsCoordName,
    734                                          vsVaryingName,
    735                                          vsVaryingType);
    736 }
    737 
    738 void GrGLGradientEffect::emitColorLookup(GrGLShaderBuilder* builder,
    739                                          const char* gradientTValue,
    740                                          const char* outputColor,
    741                                          const char* inputColor,
    742                                          const GrGLShaderBuilder::TextureSampler& sampler) {
    743 
    744     SkString* code = &builder->fFSCode;
    745     code->appendf("\tvec2 coord = vec2(%s, %s);\n",
    746                   gradientTValue,
    747                   builder->getUniformVariable(fFSYUni).c_str());
    748     code->appendf("\t%s = ", outputColor);
    749     builder->appendTextureLookupAndModulate(code, inputColor, sampler, "coord");
    750     code->append(";\n");
    751 }
    752 
    753 /////////////////////////////////////////////////////////////////////
    754 
    755 GrGradientEffect::GrGradientEffect(GrContext* ctx,
    756                                    const SkGradientShaderBase& shader,
    757                                    const SkMatrix& matrix,
    758                                    SkShader::TileMode tileMode) {
    759     // TODO: check for simple cases where we don't need a texture:
    760     //GradientInfo info;
    761     //shader.asAGradient(&info);
    762     //if (info.fColorCount == 2) { ...
    763 
    764     fMatrix = matrix;
    765 
    766     SkBitmap bitmap;
    767     shader.getGradientTableBitmap(&bitmap);
    768 
    769     fIsOpaque = shader.isOpaque();
    770 
    771     GrTextureStripAtlas::Desc desc;
    772     desc.fWidth  = bitmap.width();
    773     desc.fHeight = 32;
    774     desc.fRowHeight = bitmap.height();
    775     desc.fContext = ctx;
    776     desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
    777     fAtlas = GrTextureStripAtlas::GetAtlas(desc);
    778     GrAssert(NULL != fAtlas);
    779 
    780     // We always filter the gradient table. Each table is one row of a texture, so always y-clamp.
    781     GrTextureParams params;
    782     params.setBilerp(true);
    783     params.setTileModeX(tileMode);
    784 
    785     fRow = fAtlas->lockRow(bitmap);
    786     if (-1 != fRow) {
    787         fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf *
    788                   fAtlas->getVerticalScaleFactor();
    789         fTextureAccess.reset(fAtlas->getTexture(), params);
    790     } else {
    791         GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, &params);
    792         fTextureAccess.reset(texture, params);
    793         fYCoord = SK_ScalarHalf;
    794 
    795         // Unlock immediately, this is not great, but we don't have a way of
    796         // knowing when else to unlock it currently, so it may get purged from
    797         // the cache, but it'll still be ref'd until it's no longer being used.
    798         GrUnlockAndUnrefCachedBitmapTexture(texture);
    799     }
    800     this->addTextureAccess(&fTextureAccess);
    801 }
    802 
    803 GrGradientEffect::~GrGradientEffect() {
    804     if (this->useAtlas()) {
    805         fAtlas->unlockRow(fRow);
    806     }
    807 }
    808 
    809 bool GrGradientEffect::onIsEqual(const GrEffect& effect) const {
    810     const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect);
    811     return fTextureAccess.getTexture() == s.fTextureAccess.getTexture()  &&
    812            fTextureAccess.getParams().getTileModeX() ==
    813                 s.fTextureAccess.getParams().getTileModeX() &&
    814            this->useAtlas() == s.useAtlas() &&
    815            fYCoord == s.getYCoord() &&
    816            fMatrix.cheapEqualTo(s.getMatrix());
    817 }
    818 
    819 void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
    820     if (fIsOpaque && (kA_ValidComponentFlag & *validFlags) && 0xff == GrColorUnpackA(*color)) {
    821         *validFlags = kA_ValidComponentFlag;
    822     } else {
    823         *validFlags = 0;
    824     }
    825 }
    826 
    827 int GrGradientEffect::RandomGradientParams(SkRandom* random,
    828                                            SkColor colors[],
    829                                            SkScalar** stops,
    830                                            SkShader::TileMode* tm) {
    831     int outColors = random->nextRangeU(1, kMaxRandomGradientColors);
    832 
    833     // if one color, omit stops, otherwise randomly decide whether or not to
    834     if (outColors == 1 || (outColors >= 2 && random->nextBool())) {
    835         *stops = NULL;
    836     }
    837 
    838     SkScalar stop = 0.f;
    839     for (int i = 0; i < outColors; ++i) {
    840         colors[i] = random->nextU();
    841         if (NULL != *stops) {
    842             (*stops)[i] = stop;
    843             stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
    844         }
    845     }
    846     *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
    847 
    848     return outColors;
    849 }
    850 
    851 #endif
    852