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 "Sk4fLinearGradient.h"
9 #include "SkGradientShaderPriv.h"
10 #include "SkLinearGradient.h"
11 #include "SkRadialGradient.h"
12 #include "SkTwoPointConicalGradient.h"
13 #include "SkSweepGradient.h"
14 
flatten(SkWriteBuffer & buffer) const15 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
16     buffer.writeColorArray(fColors, fCount);
17     if (fPos) {
18         buffer.writeBool(true);
19         buffer.writeScalarArray(fPos, fCount);
20     } else {
21         buffer.writeBool(false);
22     }
23     buffer.write32(fTileMode);
24     buffer.write32(fGradFlags);
25     if (fLocalMatrix) {
26         buffer.writeBool(true);
27         buffer.writeMatrix(*fLocalMatrix);
28     } else {
29         buffer.writeBool(false);
30     }
31 }
32 
unflatten(SkReadBuffer & buffer)33 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
34     fCount = buffer.getArrayCount();
35     if (fCount > kStorageCount) {
36         size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar)) * fCount;
37         fDynamicStorage.reset(allocSize);
38         fColors = (SkColor*)fDynamicStorage.get();
39         fPos = (SkScalar*)(fColors + fCount);
40     } else {
41         fColors = fColorStorage;
42         fPos = fPosStorage;
43     }
44 
45     if (!buffer.readColorArray(const_cast<SkColor*>(fColors), fCount)) {
46         return false;
47     }
48     if (buffer.readBool()) {
49         if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) {
50             return false;
51         }
52     } else {
53         fPos = nullptr;
54     }
55 
56     fTileMode = (SkShader::TileMode)buffer.read32();
57     fGradFlags = buffer.read32();
58 
59     if (buffer.readBool()) {
60         fLocalMatrix = &fLocalMatrixStorage;
61         buffer.readMatrix(&fLocalMatrixStorage);
62     } else {
63         fLocalMatrix = nullptr;
64     }
65     return buffer.isValid();
66 }
67 
68 ////////////////////////////////////////////////////////////////////////////////////////////
69 
SkGradientShaderBase(const Descriptor & desc,const SkMatrix & ptsToUnit)70 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
71     : INHERITED(desc.fLocalMatrix)
72     , fPtsToUnit(ptsToUnit)
73 {
74     fPtsToUnit.getType();  // Precache so reads are threadsafe.
75     SkASSERT(desc.fCount > 1);
76 
77     fGradFlags = SkToU8(desc.fGradFlags);
78 
79     SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
80     SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
81     fTileMode = desc.fTileMode;
82     fTileProc = gTileProcs[desc.fTileMode];
83 
84     /*  Note: we let the caller skip the first and/or last position.
85         i.e. pos[0] = 0.3, pos[1] = 0.7
86         In these cases, we insert dummy entries to ensure that the final data
87         will be bracketed by [0, 1].
88         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
89 
90         Thus colorCount (the caller's value, and fColorCount (our value) may
91         differ by up to 2. In the above example:
92             colorCount = 2
93             fColorCount = 4
94      */
95     fColorCount = desc.fCount;
96     // check if we need to add in dummy start and/or end position/colors
97     bool dummyFirst = false;
98     bool dummyLast = false;
99     if (desc.fPos) {
100         dummyFirst = desc.fPos[0] != 0;
101         dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
102         fColorCount += dummyFirst + dummyLast;
103     }
104 
105     if (fColorCount > kColorStorageCount) {
106         size_t size = sizeof(SkColor) + sizeof(Rec);
107         if (desc.fPos) {
108             size += sizeof(SkScalar);
109         }
110         fOrigColors = reinterpret_cast<SkColor*>(
111                                         sk_malloc_throw(size * fColorCount));
112     }
113     else {
114         fOrigColors = fStorage;
115     }
116 
117     // Now copy over the colors, adding the dummies as needed
118     {
119         SkColor* origColors = fOrigColors;
120         if (dummyFirst) {
121             *origColors++ = desc.fColors[0];
122         }
123         memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor));
124         if (dummyLast) {
125             origColors += desc.fCount;
126             *origColors = desc.fColors[desc.fCount - 1];
127         }
128     }
129 
130     if (desc.fPos && fColorCount) {
131         fOrigPos = (SkScalar*)(fOrigColors + fColorCount);
132         fRecs = (Rec*)(fOrigPos + fColorCount);
133     } else {
134         fOrigPos = nullptr;
135         fRecs = (Rec*)(fOrigColors + fColorCount);
136     }
137 
138     if (fColorCount > 2) {
139         Rec* recs = fRecs;
140         recs->fPos = 0;
141         //  recs->fScale = 0; // unused;
142         recs += 1;
143         if (desc.fPos) {
144             SkScalar* origPosPtr = fOrigPos;
145             *origPosPtr++ = 0;
146 
147             /*  We need to convert the user's array of relative positions into
148                 fixed-point positions and scale factors. We need these results
149                 to be strictly monotonic (no two values equal or out of order).
150                 Hence this complex loop that just jams a zero for the scale
151                 value if it sees a segment out of order, and it assures that
152                 we start at 0 and end at 1.0
153             */
154             SkScalar prev = 0;
155             int startIndex = dummyFirst ? 0 : 1;
156             int count = desc.fCount + dummyLast;
157             for (int i = startIndex; i < count; i++) {
158                 // force the last value to be 1.0
159                 SkScalar curr;
160                 if (i == desc.fCount) {  // we're really at the dummyLast
161                     curr = 1;
162                 } else {
163                     curr = SkScalarPin(desc.fPos[i], 0, 1);
164                 }
165                 *origPosPtr++ = curr;
166 
167                 recs->fPos = SkScalarToFixed(curr);
168                 SkFixed diff = SkScalarToFixed(curr - prev);
169                 if (diff > 0) {
170                     recs->fScale = (1 << 24) / diff;
171                 } else {
172                     recs->fScale = 0; // ignore this segment
173                 }
174                 // get ready for the next value
175                 prev = curr;
176                 recs += 1;
177             }
178         } else {    // assume even distribution
179             fOrigPos = nullptr;
180 
181             SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
182             SkFixed p = dp;
183             SkFixed scale = (desc.fCount - 1) << 8;  // (1 << 24) / dp
184             for (int i = 1; i < desc.fCount - 1; i++) {
185                 recs->fPos   = p;
186                 recs->fScale = scale;
187                 recs += 1;
188                 p += dp;
189             }
190             recs->fPos = SK_Fixed1;
191             recs->fScale = scale;
192         }
193     } else if (desc.fPos) {
194         SkASSERT(2 == fColorCount);
195         fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1);
196         fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1);
197         if (0 == fOrigPos[0] && 1 == fOrigPos[1]) {
198             fOrigPos = nullptr;
199         }
200     }
201     this->initCommon();
202 }
203 
~SkGradientShaderBase()204 SkGradientShaderBase::~SkGradientShaderBase() {
205     if (fOrigColors != fStorage) {
206         sk_free(fOrigColors);
207     }
208 }
209 
initCommon()210 void SkGradientShaderBase::initCommon() {
211     unsigned colorAlpha = 0xFF;
212     for (int i = 0; i < fColorCount; i++) {
213         colorAlpha &= SkColorGetA(fOrigColors[i]);
214     }
215     fColorsAreOpaque = colorAlpha == 0xFF;
216 }
217 
flatten(SkWriteBuffer & buffer) const218 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
219     Descriptor desc;
220     desc.fColors = fOrigColors;
221     desc.fPos = fOrigPos;
222     desc.fCount = fColorCount;
223     desc.fTileMode = fTileMode;
224     desc.fGradFlags = fGradFlags;
225 
226     const SkMatrix& m = this->getLocalMatrix();
227     desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
228     desc.flatten(buffer);
229 }
230 
getGpuColorType(SkColor colors[3]) const231 SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const {
232     if (fColorCount <= 3) {
233         memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor));
234     }
235 
236     if (SkShader::kClamp_TileMode == fTileMode) {
237         if (2 == fColorCount) {
238             return kTwo_GpuColorType;
239         } else if (3 == fColorCount &&
240                    (SkScalarAbs(
241                     SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
242             return kThree_GpuColorType;
243         }
244     }
245     return kTexture_GpuColorType;
246 }
247 
FlipGradientColors(SkColor * colorDst,Rec * recDst,SkColor * colorSrc,Rec * recSrc,int count)248 void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
249                                               SkColor* colorSrc, Rec* recSrc,
250                                               int count) {
251     SkAutoSTArray<8, SkColor> colorsTemp(count);
252     for (int i = 0; i < count; ++i) {
253         int offset = count - i - 1;
254         colorsTemp[i] = colorSrc[offset];
255     }
256     if (count > 2) {
257         SkAutoSTArray<8, Rec> recsTemp(count);
258         for (int i = 0; i < count; ++i) {
259             int offset = count - i - 1;
260             recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos;
261             recsTemp[i].fScale = recSrc[offset].fScale;
262         }
263         memcpy(recDst, recsTemp.get(), count * sizeof(Rec));
264     }
265     memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
266 }
267 
isOpaque() const268 bool SkGradientShaderBase::isOpaque() const {
269     return fColorsAreOpaque;
270 }
271 
rounded_divide(unsigned numer,unsigned denom)272 static unsigned rounded_divide(unsigned numer, unsigned denom) {
273     return (numer + (denom >> 1)) / denom;
274 }
275 
onAsLuminanceColor(SkColor * lum) const276 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
277     // we just compute an average color.
278     // possibly we could weight this based on the proportional width for each color
279     //   assuming they are not evenly distributed in the fPos array.
280     int r = 0;
281     int g = 0;
282     int b = 0;
283     const int n = fColorCount;
284     for (int i = 0; i < n; ++i) {
285         SkColor c = fOrigColors[i];
286         r += SkColorGetR(c);
287         g += SkColorGetG(c);
288         b += SkColorGetB(c);
289     }
290     *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
291     return true;
292 }
293 
GradientShaderBaseContext(const SkGradientShaderBase & shader,const ContextRec & rec)294 SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
295         const SkGradientShaderBase& shader, const ContextRec& rec)
296     : INHERITED(shader, rec)
297 #ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING
298     , fDither(true)
299 #else
300     , fDither(rec.fPaint->isDither())
301 #endif
302     , fCache(shader.refCache(getPaintAlpha(), fDither))
303 {
304     const SkMatrix& inverse = this->getTotalInverse();
305 
306     fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
307 
308     fDstToIndexProc = fDstToIndex.getMapXYProc();
309     fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex);
310 
311     // now convert our colors in to PMColors
312     unsigned paintAlpha = this->getPaintAlpha();
313 
314     fFlags = this->INHERITED::getFlags();
315     if (shader.fColorsAreOpaque && paintAlpha == 0xFF) {
316         fFlags |= kOpaqueAlpha_Flag;
317     }
318 }
319 
GradientShaderCache(U8CPU alpha,bool dither,const SkGradientShaderBase & shader)320 SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
321         U8CPU alpha, bool dither, const SkGradientShaderBase& shader)
322     : fCacheAlpha(alpha)
323     , fCacheDither(dither)
324     , fShader(shader)
325     , fCache16Inited(false)
326     , fCache32Inited(false)
327 {
328     // Only initialize the cache in getCache16/32.
329     fCache16 = nullptr;
330     fCache32 = nullptr;
331     fCache16Storage = nullptr;
332     fCache32PixelRef = nullptr;
333 }
334 
~GradientShaderCache()335 SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {
336     sk_free(fCache16Storage);
337     SkSafeUnref(fCache32PixelRef);
338 }
339 
340 #define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
341 
342 /** We take the original colors, not our premultiplied PMColors, since we can
343     build a 16bit table as long as the original colors are opaque, even if the
344     paint specifies a non-opaque alpha.
345 */
Build16bitCache(uint16_t cache[],SkColor c0,SkColor c1,int count,bool dither)346 void SkGradientShaderBase::GradientShaderCache::Build16bitCache(
347         uint16_t cache[], SkColor c0, SkColor c1, int count, bool dither) {
348     SkASSERT(count > 1);
349     SkASSERT(SkColorGetA(c0) == 0xFF);
350     SkASSERT(SkColorGetA(c1) == 0xFF);
351 
352     SkFixed r = SkColorGetR(c0);
353     SkFixed g = SkColorGetG(c0);
354     SkFixed b = SkColorGetB(c0);
355 
356     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
357     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
358     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
359 
360     r = SkIntToFixed(r) + 0x8000;
361     g = SkIntToFixed(g) + 0x8000;
362     b = SkIntToFixed(b) + 0x8000;
363 
364     if (dither) {
365         do {
366             unsigned rr = r >> 16;
367             unsigned gg = g >> 16;
368             unsigned bb = b >> 16;
369             cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
370             cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
371             cache += 1;
372             r += dr;
373             g += dg;
374             b += db;
375         } while (--count != 0);
376     } else {
377         do {
378             unsigned rr = r >> 16;
379             unsigned gg = g >> 16;
380             unsigned bb = b >> 16;
381             cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
382             cache[kCache16Count] = cache[0];
383             cache += 1;
384             r += dr;
385             g += dg;
386             b += db;
387         } while (--count != 0);
388     }
389 }
390 
391 /*
392  *  r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
393  *  release builds, we saw a compiler error where the 0xFF parameter in
394  *  SkPackARGB32() was being totally ignored whenever it was called with
395  *  a non-zero add (e.g. 0x8000).
396  *
397  *  We found two work-arounds:
398  *      1. change r,g,b to unsigned (or just one of them)
399  *      2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
400  *         of using |
401  *
402  *  We chose #1 just because it was more localized.
403  *  See http://code.google.com/p/skia/issues/detail?id=1113
404  *
405  *  The type SkUFixed encapsulate this need for unsigned, but logically Fixed.
406  */
407 typedef uint32_t SkUFixed;
408 
Build32bitCache(SkPMColor cache[],SkColor c0,SkColor c1,int count,U8CPU paintAlpha,uint32_t gradFlags,bool dither)409 void SkGradientShaderBase::GradientShaderCache::Build32bitCache(
410         SkPMColor cache[], SkColor c0, SkColor c1,
411         int count, U8CPU paintAlpha, uint32_t gradFlags, bool dither) {
412     SkASSERT(count > 1);
413 
414     // need to apply paintAlpha to our two endpoints
415     uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
416     uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
417 
418 
419     const bool interpInPremul = SkToBool(gradFlags &
420                            SkGradientShader::kInterpolateColorsInPremul_Flag);
421 
422     uint32_t r0 = SkColorGetR(c0);
423     uint32_t g0 = SkColorGetG(c0);
424     uint32_t b0 = SkColorGetB(c0);
425 
426     uint32_t r1 = SkColorGetR(c1);
427     uint32_t g1 = SkColorGetG(c1);
428     uint32_t b1 = SkColorGetB(c1);
429 
430     if (interpInPremul) {
431         r0 = SkMulDiv255Round(r0, a0);
432         g0 = SkMulDiv255Round(g0, a0);
433         b0 = SkMulDiv255Round(b0, a0);
434 
435         r1 = SkMulDiv255Round(r1, a1);
436         g1 = SkMulDiv255Round(g1, a1);
437         b1 = SkMulDiv255Round(b1, a1);
438     }
439 
440     SkFixed da = SkIntToFixed(a1 - a0) / (count - 1);
441     SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1);
442     SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1);
443     SkFixed db = SkIntToFixed(b1 - b0) / (count - 1);
444 
445     /*  We pre-add 1/8 to avoid having to add this to our [0] value each time
446         in the loop. Without this, the bias for each would be
447             0x2000  0xA000  0xE000  0x6000
448         With this trick, we can add 0 for the first (no-op) and just adjust the
449         others.
450      */
451     const SkUFixed bias0 = dither ? 0x2000 : 0x8000;
452     const SkUFixed bias1 = dither ? 0x8000 : 0;
453     const SkUFixed bias2 = dither ? 0xC000 : 0;
454     const SkUFixed bias3 = dither ? 0x4000 : 0;
455 
456     SkUFixed a = SkIntToFixed(a0) + bias0;
457     SkUFixed r = SkIntToFixed(r0) + bias0;
458     SkUFixed g = SkIntToFixed(g0) + bias0;
459     SkUFixed b = SkIntToFixed(b0) + bias0;
460 
461     /*
462      *  Our dither-cell (spatially) is
463      *      0 2
464      *      3 1
465      *  Where
466      *      [0] -> [-1/8 ... 1/8 ) values near 0
467      *      [1] -> [ 1/8 ... 3/8 ) values near 1/4
468      *      [2] -> [ 3/8 ... 5/8 ) values near 1/2
469      *      [3] -> [ 5/8 ... 7/8 ) values near 3/4
470      */
471 
472     if (0xFF == a0 && 0 == da) {
473         do {
474             cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0    ) >> 16,
475                                                         (g + 0    ) >> 16,
476                                                         (b + 0    ) >> 16);
477             cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + bias1) >> 16,
478                                                         (g + bias1) >> 16,
479                                                         (b + bias1) >> 16);
480             cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + bias2) >> 16,
481                                                         (g + bias2) >> 16,
482                                                         (b + bias2) >> 16);
483             cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + bias3) >> 16,
484                                                         (g + bias3) >> 16,
485                                                         (b + bias3) >> 16);
486             cache += 1;
487             r += dr;
488             g += dg;
489             b += db;
490         } while (--count != 0);
491     } else if (interpInPremul) {
492         do {
493             cache[kCache32Count*0] = SkPackARGB32((a + 0    ) >> 16,
494                                                   (r + 0    ) >> 16,
495                                                   (g + 0    ) >> 16,
496                                                   (b + 0    ) >> 16);
497             cache[kCache32Count*1] = SkPackARGB32((a + bias1) >> 16,
498                                                   (r + bias1) >> 16,
499                                                   (g + bias1) >> 16,
500                                                   (b + bias1) >> 16);
501             cache[kCache32Count*2] = SkPackARGB32((a + bias2) >> 16,
502                                                   (r + bias2) >> 16,
503                                                   (g + bias2) >> 16,
504                                                   (b + bias2) >> 16);
505             cache[kCache32Count*3] = SkPackARGB32((a + bias3) >> 16,
506                                                   (r + bias3) >> 16,
507                                                   (g + bias3) >> 16,
508                                                   (b + bias3) >> 16);
509             cache += 1;
510             a += da;
511             r += dr;
512             g += dg;
513             b += db;
514         } while (--count != 0);
515     } else {    // interpolate in unpreml space
516         do {
517             cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0     ) >> 16,
518                                                              (r + 0     ) >> 16,
519                                                              (g + 0     ) >> 16,
520                                                              (b + 0     ) >> 16);
521             cache[kCache32Count*1] = SkPremultiplyARGBInline((a + bias1) >> 16,
522                                                              (r + bias1) >> 16,
523                                                              (g + bias1) >> 16,
524                                                              (b + bias1) >> 16);
525             cache[kCache32Count*2] = SkPremultiplyARGBInline((a + bias2) >> 16,
526                                                              (r + bias2) >> 16,
527                                                              (g + bias2) >> 16,
528                                                              (b + bias2) >> 16);
529             cache[kCache32Count*3] = SkPremultiplyARGBInline((a + bias3) >> 16,
530                                                              (r + bias3) >> 16,
531                                                              (g + bias3) >> 16,
532                                                              (b + bias3) >> 16);
533             cache += 1;
534             a += da;
535             r += dr;
536             g += dg;
537             b += db;
538         } while (--count != 0);
539     }
540 }
541 
SkFixedToFFFF(SkFixed x)542 static inline int SkFixedToFFFF(SkFixed x) {
543     SkASSERT((unsigned)x <= SK_Fixed1);
544     return x - (x >> 16);
545 }
546 
getCache16()547 const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() {
548     SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16,
549            this);
550     SkASSERT(fCache16);
551     return fCache16;
552 }
553 
initCache16(GradientShaderCache * cache)554 void SkGradientShaderBase::GradientShaderCache::initCache16(GradientShaderCache* cache) {
555     // double the count for dither entries
556     const int entryCount = kCache16Count * 2;
557     const size_t allocSize = sizeof(uint16_t) * entryCount;
558 
559     SkASSERT(nullptr == cache->fCache16Storage);
560     cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
561     cache->fCache16 = cache->fCache16Storage;
562     if (cache->fShader.fColorCount == 2) {
563         Build16bitCache(cache->fCache16, cache->fShader.fOrigColors[0],
564                         cache->fShader.fOrigColors[1], kCache16Count, cache->fCacheDither);
565     } else {
566         Rec* rec = cache->fShader.fRecs;
567         int prevIndex = 0;
568         for (int i = 1; i < cache->fShader.fColorCount; i++) {
569             int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
570             SkASSERT(nextIndex < kCache16Count);
571 
572             if (nextIndex > prevIndex)
573                 Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1],
574                                 cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
575                                 cache->fCacheDither);
576             prevIndex = nextIndex;
577         }
578     }
579 }
580 
getCache32()581 const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
582     SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32,
583            this);
584     SkASSERT(fCache32);
585     return fCache32;
586 }
587 
initCache32(GradientShaderCache * cache)588 void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) {
589     const int kNumberOfDitherRows = 4;
590     const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows);
591 
592     SkASSERT(nullptr == cache->fCache32PixelRef);
593     cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, nullptr);
594     cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr();
595     if (cache->fShader.fColorCount == 2) {
596         Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0],
597                         cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha,
598                         cache->fShader.fGradFlags, cache->fCacheDither);
599     } else {
600         Rec* rec = cache->fShader.fRecs;
601         int prevIndex = 0;
602         for (int i = 1; i < cache->fShader.fColorCount; i++) {
603             int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
604             SkASSERT(nextIndex < kCache32Count);
605 
606             if (nextIndex > prevIndex)
607                 Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1],
608                                 cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
609                                 cache->fCacheAlpha, cache->fShader.fGradFlags, cache->fCacheDither);
610             prevIndex = nextIndex;
611         }
612     }
613 }
614 
615 /*
616  *  The gradient holds a cache for the most recent value of alpha. Successive
617  *  callers with the same alpha value will share the same cache.
618  */
refCache(U8CPU alpha,bool dither) const619 SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::refCache(U8CPU alpha,
620                                                                           bool dither) const {
621     SkAutoMutexAcquire ama(fCacheMutex);
622     if (!fCache || fCache->getAlpha() != alpha || fCache->getDither() != dither) {
623         fCache.reset(new GradientShaderCache(alpha, dither, *this));
624     }
625     // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
626     // Otherwise, the pointer may have been overwritten on a different thread before the object's
627     // ref count was incremented.
628     fCache.get()->ref();
629     return fCache;
630 }
631 
632 SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
633 /*
634  *  Because our caller might rebuild the same (logically the same) gradient
635  *  over and over, we'd like to return exactly the same "bitmap" if possible,
636  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
637  *  To do that, we maintain a private cache of built-bitmaps, based on our
638  *  colors and positions. Note: we don't try to flatten the fMapper, so if one
639  *  is present, we skip the cache for now.
640  */
getGradientTableBitmap(SkBitmap * bitmap) const641 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
642     // our caller assumes no external alpha, so we ensure that our cache is
643     // built with 0xFF
644     SkAutoTUnref<GradientShaderCache> cache(this->refCache(0xFF, true));
645 
646     // build our key: [numColors + colors[] + {positions[]} + flags ]
647     int count = 1 + fColorCount + 1;
648     if (fColorCount > 2) {
649         count += fColorCount - 1;    // fRecs[].fPos
650     }
651 
652     SkAutoSTMalloc<16, int32_t> storage(count);
653     int32_t* buffer = storage.get();
654 
655     *buffer++ = fColorCount;
656     memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
657     buffer += fColorCount;
658     if (fColorCount > 2) {
659         for (int i = 1; i < fColorCount; i++) {
660             *buffer++ = fRecs[i].fPos;
661         }
662     }
663     *buffer++ = fGradFlags;
664     SkASSERT(buffer - storage.get() == count);
665 
666     ///////////////////////////////////
667 
668     static SkGradientBitmapCache* gCache;
669     // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
670     static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
671     SkAutoMutexAcquire ama(gGradientCacheMutex);
672 
673     if (nullptr == gCache) {
674         gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
675     }
676     size_t size = count * sizeof(int32_t);
677 
678     if (!gCache->find(storage.get(), size, bitmap)) {
679         // force our cahce32pixelref to be built
680         (void)cache->getCache32();
681         bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
682         bitmap->setPixelRef(cache->getCache32PixelRef());
683 
684         gCache->add(storage.get(), size, *bitmap);
685     }
686 }
687 
commonAsAGradient(GradientInfo * info,bool flipGrad) const688 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const {
689     if (info) {
690         if (info->fColorCount >= fColorCount) {
691             SkColor* colorLoc;
692             Rec*     recLoc;
693             if (flipGrad && (info->fColors || info->fColorOffsets)) {
694                 SkAutoSTArray<8, SkColor> colorStorage(fColorCount);
695                 SkAutoSTArray<8, Rec> recStorage(fColorCount);
696                 colorLoc = colorStorage.get();
697                 recLoc = recStorage.get();
698                 FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount);
699             } else {
700                 colorLoc = fOrigColors;
701                 recLoc = fRecs;
702             }
703             if (info->fColors) {
704                 memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor));
705             }
706             if (info->fColorOffsets) {
707                 if (fColorCount == 2) {
708                     info->fColorOffsets[0] = 0;
709                     info->fColorOffsets[1] = SK_Scalar1;
710                 } else if (fColorCount > 2) {
711                     for (int i = 0; i < fColorCount; ++i) {
712                         info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos);
713                     }
714                 }
715             }
716         }
717         info->fColorCount = fColorCount;
718         info->fTileMode = fTileMode;
719         info->fGradientFlags = fGradFlags;
720     }
721 }
722 
723 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const724 void SkGradientShaderBase::toString(SkString* str) const {
725 
726     str->appendf("%d colors: ", fColorCount);
727 
728     for (int i = 0; i < fColorCount; ++i) {
729         str->appendHex(fOrigColors[i], 8);
730         if (i < fColorCount-1) {
731             str->append(", ");
732         }
733     }
734 
735     if (fColorCount > 2) {
736         str->append(" points: (");
737         for (int i = 0; i < fColorCount; ++i) {
738             str->appendScalar(SkFixedToScalar(fRecs[i].fPos));
739             if (i < fColorCount-1) {
740                 str->append(", ");
741             }
742         }
743         str->append(")");
744     }
745 
746     static const char* gTileModeName[SkShader::kTileModeCount] = {
747         "clamp", "repeat", "mirror"
748     };
749 
750     str->append(" ");
751     str->append(gTileModeName[fTileMode]);
752 
753     this->INHERITED::toString(str);
754 }
755 #endif
756 
757 ///////////////////////////////////////////////////////////////////////////////
758 ///////////////////////////////////////////////////////////////////////////////
759 
760 // Return true if these parameters are valid/legal/safe to construct a gradient
761 //
valid_grad(const SkColor colors[],const SkScalar pos[],int count,unsigned tileMode)762 static bool valid_grad(const SkColor colors[], const SkScalar pos[], int count, unsigned tileMode) {
763     return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
764 }
765 
766 // assumes colors is SkColor* and pos is SkScalar*
767 #define EXPAND_1_COLOR(count)               \
768     SkColor tmp[2];                         \
769     do {                                    \
770         if (1 == count) {                   \
771             tmp[0] = tmp[1] = colors[0];    \
772             colors = tmp;                   \
773             pos = nullptr;                     \
774             count = 2;                      \
775         }                                   \
776     } while (0)
777 
desc_init(SkGradientShaderBase::Descriptor * desc,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)778 static void desc_init(SkGradientShaderBase::Descriptor* desc,
779                       const SkColor colors[], const SkScalar pos[], int colorCount,
780                       SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
781     desc->fColors       = colors;
782     desc->fPos          = pos;
783     desc->fCount        = colorCount;
784     desc->fTileMode     = mode;
785     desc->fGradFlags    = flags;
786     desc->fLocalMatrix  = localMatrix;
787 }
788 
CreateLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)789 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
790                                          const SkColor colors[],
791                                          const SkScalar pos[], int colorCount,
792                                          SkShader::TileMode mode,
793                                          uint32_t flags,
794                                          const SkMatrix* localMatrix) {
795     if (!pts) {
796         return nullptr;
797     }
798     if (!valid_grad(colors, pos, colorCount, mode)) {
799         return nullptr;
800     }
801     EXPAND_1_COLOR(colorCount);
802 
803     SkGradientShaderBase::Descriptor desc;
804     desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
805     return new SkLinearGradient(pts, desc);
806 }
807 
CreateRadial(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)808 SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
809                                          const SkColor colors[],
810                                          const SkScalar pos[], int colorCount,
811                                          SkShader::TileMode mode,
812                                          uint32_t flags,
813                                          const SkMatrix* localMatrix) {
814     if (radius <= 0) {
815         return nullptr;
816     }
817     if (!valid_grad(colors, pos, colorCount, mode)) {
818         return nullptr;
819     }
820     EXPAND_1_COLOR(colorCount);
821 
822     SkGradientShaderBase::Descriptor desc;
823     desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
824     return new SkRadialGradient(center, radius, desc);
825 }
826 
CreateTwoPointConical(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)827 SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
828                                                   SkScalar startRadius,
829                                                   const SkPoint& end,
830                                                   SkScalar endRadius,
831                                                   const SkColor colors[],
832                                                   const SkScalar pos[],
833                                                   int colorCount,
834                                                   SkShader::TileMode mode,
835                                                   uint32_t flags,
836                                                   const SkMatrix* localMatrix) {
837     if (startRadius < 0 || endRadius < 0) {
838         return nullptr;
839     }
840     if (!valid_grad(colors, pos, colorCount, mode)) {
841         return nullptr;
842     }
843     if (start == end && startRadius == endRadius) {
844         return SkShader::CreateEmptyShader();
845     }
846 
847     EXPAND_1_COLOR(colorCount);
848 
849     bool flipGradient = startRadius > endRadius;
850 
851     SkGradientShaderBase::Descriptor desc;
852 
853     if (!flipGradient) {
854         desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
855         return new SkTwoPointConicalGradient(start, startRadius, end, endRadius, flipGradient,
856                                              desc);
857     } else {
858         SkAutoSTArray<8, SkColor> colorsNew(colorCount);
859         SkAutoSTArray<8, SkScalar> posNew(colorCount);
860         for (int i = 0; i < colorCount; ++i) {
861             colorsNew[i] = colors[colorCount - i - 1];
862         }
863 
864         if (pos) {
865             for (int i = 0; i < colorCount; ++i) {
866                 posNew[i] = 1 - pos[colorCount - i - 1];
867             }
868             desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, flags, localMatrix);
869         } else {
870             desc_init(&desc, colorsNew.get(), nullptr, colorCount, mode, flags, localMatrix);
871         }
872 
873         return new SkTwoPointConicalGradient(end, endRadius, start, startRadius, flipGradient,
874                                              desc);
875     }
876 }
877 
CreateSweep(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int colorCount,uint32_t flags,const SkMatrix * localMatrix)878 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
879                                         const SkColor colors[],
880                                         const SkScalar pos[],
881                                         int colorCount,
882                                         uint32_t flags,
883                                         const SkMatrix* localMatrix) {
884     if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
885         return nullptr;
886     }
887     EXPAND_1_COLOR(colorCount);
888 
889     SkGradientShaderBase::Descriptor desc;
890     desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, flags, localMatrix);
891     return new SkSweepGradient(cx, cy, desc);
892 }
893 
894 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)895     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
896     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
897     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
898     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
899 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
900 
901 ///////////////////////////////////////////////////////////////////////////////
902 
903 #if SK_SUPPORT_GPU
904 
905 #include "effects/GrTextureStripAtlas.h"
906 #include "GrInvariantOutput.h"
907 #include "gl/GrGLContext.h"
908 #include "glsl/GrGLSLFragmentShaderBuilder.h"
909 #include "glsl/GrGLSLProgramDataManager.h"
910 #include "glsl/GrGLSLUniformHandler.h"
911 #include "SkGr.h"
912 
913 GrGLGradientEffect::GrGLGradientEffect()
914     : fCachedYCoord(SK_ScalarMax) {
915 }
916 
emitUniforms(GrGLSLUniformHandler * uniformHandler,const GrGradientEffect & ge)917 void GrGLGradientEffect::emitUniforms(GrGLSLUniformHandler* uniformHandler,
918                                       const GrGradientEffect& ge) {
919 
920     if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()) { // 2 Color case
921         fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
922                                                     kVec4f_GrSLType, kDefault_GrSLPrecision,
923                                                     "GradientStartColor");
924         fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
925                                                   kVec4f_GrSLType, kDefault_GrSLPrecision,
926                                                   "GradientEndColor");
927 
928     } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { // 3 Color Case
929         fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
930                                                     kVec4f_GrSLType,  kDefault_GrSLPrecision,
931                                                     "GradientStartColor");
932         fColorMidUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
933                                                   kVec4f_GrSLType, kDefault_GrSLPrecision,
934                                                   "GradientMidColor");
935         fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
936                                                   kVec4f_GrSLType, kDefault_GrSLPrecision,
937                                                   "GradientEndColor");
938 
939     } else { // if not a fast case
940         fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
941                                              kFloat_GrSLType, kDefault_GrSLPrecision,
942                                              "GradientYCoordFS");
943     }
944 }
945 
set_color_uni(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkColor * color)946 static inline void set_color_uni(const GrGLSLProgramDataManager& pdman,
947                                  const GrGLSLProgramDataManager::UniformHandle uni,
948                                  const SkColor* color) {
949        pdman.set4f(uni,
950                    SkColorGetR(*color) / 255.f,
951                    SkColorGetG(*color) / 255.f,
952                    SkColorGetB(*color) / 255.f,
953                    SkColorGetA(*color) / 255.f);
954 }
955 
set_mul_color_uni(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkColor * color)956 static inline void set_mul_color_uni(const GrGLSLProgramDataManager& pdman,
957                                      const GrGLSLProgramDataManager::UniformHandle uni,
958                                      const SkColor* color){
959        float a = SkColorGetA(*color) / 255.f;
960        float aDiv255 = a / 255.f;
961        pdman.set4f(uni,
962                    SkColorGetR(*color) * aDiv255,
963                    SkColorGetG(*color) * aDiv255,
964                    SkColorGetB(*color) * aDiv255,
965                    a);
966 }
967 
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)968 void GrGLGradientEffect::onSetData(const GrGLSLProgramDataManager& pdman,
969                                    const GrProcessor& processor) {
970 
971     const GrGradientEffect& e = processor.cast<GrGradientEffect>();
972 
973 
974     if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()){
975 
976         if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
977             set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
978             set_mul_color_uni(pdman, fColorEndUni,   e.getColors(1));
979         } else {
980             set_color_uni(pdman, fColorStartUni, e.getColors(0));
981             set_color_uni(pdman, fColorEndUni,   e.getColors(1));
982         }
983 
984     } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){
985 
986         if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
987             set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
988             set_mul_color_uni(pdman, fColorMidUni,   e.getColors(1));
989             set_mul_color_uni(pdman, fColorEndUni,   e.getColors(2));
990         } else {
991             set_color_uni(pdman, fColorStartUni, e.getColors(0));
992             set_color_uni(pdman, fColorMidUni,   e.getColors(1));
993             set_color_uni(pdman, fColorEndUni,   e.getColors(2));
994         }
995     } else {
996 
997         SkScalar yCoord = e.getYCoord();
998         if (yCoord != fCachedYCoord) {
999             pdman.set1f(fFSYUni, yCoord);
1000             fCachedYCoord = yCoord;
1001         }
1002     }
1003 }
1004 
1005 
GenBaseGradientKey(const GrProcessor & processor)1006 uint32_t GrGLGradientEffect::GenBaseGradientKey(const GrProcessor& processor) {
1007     const GrGradientEffect& e = processor.cast<GrGradientEffect>();
1008 
1009     uint32_t key = 0;
1010 
1011     if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()) {
1012         key |= kTwoColorKey;
1013     } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()) {
1014         key |= kThreeColorKey;
1015     }
1016 
1017     if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
1018         key |= kPremulBeforeInterpKey;
1019     }
1020 
1021     return key;
1022 }
1023 
emitColor(GrGLSLFPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const GrGLSLCaps * glslCaps,const GrGradientEffect & ge,const char * gradientTValue,const char * outputColor,const char * inputColor,const TextureSamplerArray & samplers)1024 void GrGLGradientEffect::emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
1025                                    GrGLSLUniformHandler* uniformHandler,
1026                                    const GrGLSLCaps* glslCaps,
1027                                    const GrGradientEffect& ge,
1028                                    const char* gradientTValue,
1029                                    const char* outputColor,
1030                                    const char* inputColor,
1031                                    const TextureSamplerArray& samplers) {
1032     if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()){
1033         fragBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
1034                                  uniformHandler->getUniformVariable(fColorStartUni).c_str(),
1035                                  uniformHandler->getUniformVariable(fColorEndUni).c_str(),
1036                                  gradientTValue);
1037         // Note that we could skip this step if both colors are known to be opaque. Two
1038         // considerations:
1039         // The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
1040         // case. Make sure the key reflects this optimization (and note that it can use the same
1041         // shader as thekBeforeIterp case). This same optimization applies to the 3 color case
1042         // below.
1043         if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1044             fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
1045         }
1046 
1047         fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
1048                                  (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
1049     } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) {
1050         fragBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
1051                                  gradientTValue);
1052         fragBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
1053                                  uniformHandler->getUniformVariable(fColorStartUni).c_str());
1054         if (!glslCaps->canUseMinAndAbsTogether()) {
1055             // The Tegra3 compiler will sometimes never return if we have
1056             // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
1057             fragBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
1058             fragBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
1059             fragBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
1060                                      uniformHandler->getUniformVariable(fColorMidUni).c_str());
1061         } else {
1062             fragBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
1063                                      uniformHandler->getUniformVariable(fColorMidUni).c_str());
1064         }
1065         fragBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
1066                                  uniformHandler->getUniformVariable(fColorEndUni).c_str());
1067         if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1068             fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
1069         }
1070 
1071         fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
1072                                  (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
1073     } else {
1074         fragBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n",
1075                                  gradientTValue,
1076                                  uniformHandler->getUniformVariable(fFSYUni).c_str());
1077         fragBuilder->codeAppendf("\t%s = ", outputColor);
1078         fragBuilder->appendTextureLookupAndModulate(inputColor,
1079                                                     samplers[0],
1080                                                     "coord");
1081         fragBuilder->codeAppend(";\n");
1082     }
1083 }
1084 
1085 /////////////////////////////////////////////////////////////////////
1086 
GrGradientEffect(GrContext * ctx,const SkGradientShaderBase & shader,const SkMatrix & matrix,SkShader::TileMode tileMode)1087 GrGradientEffect::GrGradientEffect(GrContext* ctx,
1088                                    const SkGradientShaderBase& shader,
1089                                    const SkMatrix& matrix,
1090                                    SkShader::TileMode tileMode) {
1091 
1092     fIsOpaque = shader.isOpaque();
1093 
1094     fColorType = shader.getGpuColorType(&fColors[0]);
1095 
1096     // The two and three color specializations do not currently support tiling.
1097     if (SkGradientShaderBase::kTwo_GpuColorType == fColorType ||
1098         SkGradientShaderBase::kThree_GpuColorType == fColorType) {
1099         fRow = -1;
1100 
1101         if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
1102             fPremulType = kBeforeInterp_PremulType;
1103         } else {
1104             fPremulType = kAfterInterp_PremulType;
1105         }
1106         fCoordTransform.reset(kCoordSet, matrix);
1107     } else {
1108         // doesn't matter how this is set, just be consistent because it is part of the effect key.
1109         fPremulType = kBeforeInterp_PremulType;
1110         SkBitmap bitmap;
1111         shader.getGradientTableBitmap(&bitmap);
1112 
1113         GrTextureStripAtlas::Desc desc;
1114         desc.fWidth  = bitmap.width();
1115         desc.fHeight = 32;
1116         desc.fRowHeight = bitmap.height();
1117         desc.fContext = ctx;
1118         desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
1119         fAtlas = GrTextureStripAtlas::GetAtlas(desc);
1120         SkASSERT(fAtlas);
1121 
1122         // We always filter the gradient table. Each table is one row of a texture, always y-clamp.
1123         GrTextureParams params;
1124         params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
1125         params.setTileModeX(tileMode);
1126 
1127         fRow = fAtlas->lockRow(bitmap);
1128         if (-1 != fRow) {
1129             fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * fAtlas->getNormalizedTexelHeight();
1130             fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode());
1131             fTextureAccess.reset(fAtlas->getTexture(), params);
1132         } else {
1133             SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(ctx, bitmap, params));
1134             if (!texture) {
1135                 return;
1136             }
1137             fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode());
1138             fTextureAccess.reset(texture, params);
1139             fYCoord = SK_ScalarHalf;
1140         }
1141         this->addTextureAccess(&fTextureAccess);
1142     }
1143     this->addCoordTransform(&fCoordTransform);
1144 }
1145 
~GrGradientEffect()1146 GrGradientEffect::~GrGradientEffect() {
1147     if (this->useAtlas()) {
1148         fAtlas->unlockRow(fRow);
1149     }
1150 }
1151 
onIsEqual(const GrFragmentProcessor & processor) const1152 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
1153     const GrGradientEffect& s = processor.cast<GrGradientEffect>();
1154 
1155     if (this->fColorType == s.getColorType()){
1156 
1157         if (SkGradientShaderBase::kTwo_GpuColorType == fColorType) {
1158             if (*this->getColors(0) != *s.getColors(0) ||
1159                 *this->getColors(1) != *s.getColors(1)) {
1160                 return false;
1161             }
1162         } else if (SkGradientShaderBase::kThree_GpuColorType == fColorType) {
1163             if (*this->getColors(0) != *s.getColors(0) ||
1164                 *this->getColors(1) != *s.getColors(1) ||
1165                 *this->getColors(2) != *s.getColors(2)) {
1166                 return false;
1167             }
1168         } else {
1169             if (fYCoord != s.getYCoord()) {
1170                 return false;
1171             }
1172         }
1173 
1174         SkASSERT(this->useAtlas() == s.useAtlas());
1175         return true;
1176     }
1177 
1178     return false;
1179 }
1180 
onComputeInvariantOutput(GrInvariantOutput * inout) const1181 void GrGradientEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
1182     if (fIsOpaque) {
1183         inout->mulByUnknownOpaqueFourComponents();
1184     } else {
1185         inout->mulByUnknownFourComponents();
1186     }
1187 }
1188 
RandomGradientParams(SkRandom * random,SkColor colors[],SkScalar ** stops,SkShader::TileMode * tm)1189 int GrGradientEffect::RandomGradientParams(SkRandom* random,
1190                                            SkColor colors[],
1191                                            SkScalar** stops,
1192                                            SkShader::TileMode* tm) {
1193     int outColors = random->nextRangeU(1, kMaxRandomGradientColors);
1194 
1195     // if one color, omit stops, otherwise randomly decide whether or not to
1196     if (outColors == 1 || (outColors >= 2 && random->nextBool())) {
1197         *stops = nullptr;
1198     }
1199 
1200     SkScalar stop = 0.f;
1201     for (int i = 0; i < outColors; ++i) {
1202         colors[i] = random->nextU();
1203         if (*stops) {
1204             (*stops)[i] = stop;
1205             stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
1206         }
1207     }
1208     *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
1209 
1210     return outColors;
1211 }
1212 
1213 #endif
1214