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