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