• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libs/graphics/effects/SkGradientShader.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #include "SkGradientShader.h"
19 #include "SkColorPriv.h"
20 #include "SkUnitMapper.h"
21 #include "SkUtils.h"
22 
23 ///////////////////////////////////////////////////////////////////////////
24 
25 typedef SkFixed (*TileProc)(SkFixed);
26 
clamp_tileproc(SkFixed x)27 static SkFixed clamp_tileproc(SkFixed x) {
28     return SkClampMax(x, 0xFFFF);
29 }
30 
repeat_tileproc(SkFixed x)31 static SkFixed repeat_tileproc(SkFixed x) {
32     return x & 0xFFFF;
33 }
34 
mirror_tileproc(SkFixed x)35 static inline SkFixed mirror_tileproc(SkFixed x) {
36     int s = x << 15 >> 31;
37     return (x ^ s) & 0xFFFF;
38 }
39 
40 static const TileProc gTileProcs[] = {
41     clamp_tileproc,
42     repeat_tileproc,
43     mirror_tileproc
44 };
45 
46 //////////////////////////////////////////////////////////////////////////////
47 
repeat_6bits(int x)48 static inline int repeat_6bits(int x) {
49     return x & 63;
50 }
51 
mirror_6bits(int x)52 static inline int mirror_6bits(int x) {
53 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
54     if (x & 64)
55         x = ~x;
56     return x & 63;
57 #else
58     int s = x << 25 >> 31;
59     return (x ^ s) & 63;
60 #endif
61 }
62 
repeat_8bits(int x)63 static inline int repeat_8bits(int x) {
64     return x & 0xFF;
65 }
66 
mirror_8bits(int x)67 static inline int mirror_8bits(int x) {
68 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
69     if (x & 256) {
70         x = ~x;
71     }
72     return x & 255;
73 #else
74     int s = x << 23 >> 31;
75     return (x ^ s) & 0xFF;
76 #endif
77 }
78 
79 //////////////////////////////////////////////////////////////////////////////
80 
81 class Gradient_Shader : public SkShader {
82 public:
83     Gradient_Shader(const SkColor colors[], const SkScalar pos[],
84                 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
85     virtual ~Gradient_Shader();
86 
87     // overrides
88     virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
getFlags()89     virtual uint32_t getFlags() { return fFlags; }
90 
91 protected:
92     Gradient_Shader(SkFlattenableReadBuffer& );
93     SkUnitMapper* fMapper;
94     SkMatrix    fPtsToUnit;     // set by subclass
95     SkMatrix    fDstToIndex;
96     SkMatrix::MapXYProc fDstToIndexProc;
97     TileMode    fTileMode;
98     TileProc    fTileProc;
99     int         fColorCount;
100     uint8_t     fDstToIndexClass;
101     uint8_t     fFlags;
102 
103     struct Rec {
104         SkFixed     fPos;   // 0...1
105         uint32_t    fScale; // (1 << 24) / range
106     };
107     Rec*        fRecs;
108 
109     enum {
110         kCache16Bits    = 6,    // seems like enough for visual accuracy
111         kCache16Count   = 1 << kCache16Bits,
112         kCache32Bits    = 8,    // pretty much should always be 8
113         kCache32Count   = 1 << kCache32Bits
114     };
115     virtual void flatten(SkFlattenableWriteBuffer& );
116     const uint16_t*     getCache16();
117     const SkPMColor*    getCache32();
118 
119     // called when we kill our cached colors (to be rebuilt later on demand)
120     virtual void onCacheReset()  = 0;
121 
122 private:
123     enum {
124         kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
125 
126         kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
127     };
128     SkColor     fStorage[(kStorageSize + 3) >> 2];
129     SkColor*    fOrigColors;
130 
131     uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
132     SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
133 
134     uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
135     SkPMColor*  fCache32Storage;    // storage for fCache32, allocated on demand
136     unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
137 
138     typedef SkShader INHERITED;
139 };
140 
scalarToU16(SkScalar x)141 static inline unsigned scalarToU16(SkScalar x) {
142     SkASSERT(x >= 0 && x <= SK_Scalar1);
143 
144 #ifdef SK_SCALAR_IS_FLOAT
145     return (unsigned)(x * 0xFFFF);
146 #else
147     return x - (x >> 16);   // probably should be x - (x > 0x7FFF) but that is slower
148 #endif
149 }
150 
Gradient_Shader(const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)151 Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[],
152              int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) {
153     SkASSERT(colorCount > 1);
154 
155     fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
156 
157     fMapper = mapper;
158     mapper->safeRef();
159 
160     SkASSERT((unsigned)mode < SkShader::kTileModeCount);
161     SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
162     fTileMode = mode;
163     fTileProc = gTileProcs[mode];
164 
165     fCache16 = fCache16Storage = NULL;
166     fCache32 = fCache32Storage = NULL;
167 
168     /*  Note: we let the caller skip the first and/or last position.
169         i.e. pos[0] = 0.3, pos[1] = 0.7
170         In these cases, we insert dummy entries to ensure that the final data
171         will be bracketed by [0, 1].
172         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
173 
174         Thus colorCount (the caller's value, and fColorCount (our value) may
175         differ by up to 2. In the above example:
176             colorCount = 2
177             fColorCount = 4
178      */
179     fColorCount = colorCount;
180     // check if we need to add in dummy start and/or end position/colors
181     bool dummyFirst = false;
182     bool dummyLast = false;
183     if (pos) {
184         dummyFirst = pos[0] != 0;
185         dummyLast = pos[colorCount - 1] != SK_Scalar1;
186         fColorCount += dummyFirst + dummyLast;
187     }
188 
189     if (fColorCount > kColorStorageCount) {
190         size_t size = sizeof(SkColor) + sizeof(Rec);
191         fOrigColors = reinterpret_cast<SkColor*>(
192                                         sk_malloc_throw(size * fColorCount));
193     }
194     else {
195         fOrigColors = fStorage;
196     }
197 
198     // Now copy over the colors, adding the dummies as needed
199     {
200         SkColor* origColors = fOrigColors;
201         if (dummyFirst) {
202             *origColors++ = colors[0];
203         }
204         memcpy(origColors, colors, colorCount * sizeof(SkColor));
205         if (dummyLast) {
206             origColors += colorCount;
207             *origColors = colors[colorCount - 1];
208         }
209     }
210 
211     fRecs = (Rec*)(fOrigColors + fColorCount);
212     if (fColorCount > 2) {
213         Rec* recs = fRecs;
214         recs->fPos = 0;
215         //  recs->fScale = 0; // unused;
216         recs += 1;
217         if (pos) {
218             /*  We need to convert the user's array of relative positions into
219                 fixed-point positions and scale factors. We need these results
220                 to be strictly monotonic (no two values equal or out of order).
221                 Hence this complex loop that just jams a zero for the scale
222                 value if it sees a segment out of order, and it assures that
223                 we start at 0 and end at 1.0
224             */
225             SkFixed prev = 0;
226             int startIndex = dummyFirst ? 0 : 1;
227             int count = colorCount + dummyLast;
228             for (int i = startIndex; i < count; i++) {
229                 // force the last value to be 1.0
230                 SkFixed curr;
231                 if (i == colorCount) {  // we're really at the dummyLast
232                     curr = SK_Fixed1;
233                 } else {
234                     curr = SkScalarToFixed(pos[i]);
235                 }
236                 // pin curr withing range
237                 if (curr < 0) {
238                     curr = 0;
239                 } else if (curr > SK_Fixed1) {
240                     curr = SK_Fixed1;
241                 }
242                 recs->fPos = curr;
243                 if (curr > prev) {
244                     recs->fScale = (1 << 24) / (curr - prev);
245                 } else {
246                     recs->fScale = 0; // ignore this segment
247                 }
248                 // get ready for the next value
249                 prev = curr;
250                 recs += 1;
251             }
252         } else {    // assume even distribution
253             SkFixed dp = SK_Fixed1 / (colorCount - 1);
254             SkFixed p = dp;
255             SkFixed scale = (colorCount - 1) << 8;  // (1 << 24) / dp
256             for (int i = 1; i < colorCount; i++) {
257                 recs->fPos   = p;
258                 recs->fScale = scale;
259                 recs += 1;
260                 p += dp;
261             }
262         }
263     }
264     fFlags = 0;
265 }
266 
Gradient_Shader(SkFlattenableReadBuffer & buffer)267 Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
268     INHERITED(buffer) {
269     fCacheAlpha = 256;
270 
271     fMapper = static_cast<SkUnitMapper*>(buffer.readFlattenable());
272 
273     fCache16 = fCache16Storage = NULL;
274     fCache32 = fCache32Storage = NULL;
275 
276     int colorCount = fColorCount = buffer.readU32();
277     if (colorCount > kColorStorageCount) {
278         size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
279         fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount);
280     } else {
281         fOrigColors = fStorage;
282     }
283     buffer.read(fOrigColors, colorCount * sizeof(SkColor));
284 
285     fTileMode = (TileMode)buffer.readU8();
286     fTileProc = gTileProcs[fTileMode];
287     fRecs = (Rec*)(fOrigColors + colorCount);
288     if (colorCount > 2) {
289         Rec* recs = fRecs;
290         recs[0].fPos = 0;
291         for (int i = 1; i < colorCount; i++) {
292             recs[i].fPos = buffer.readS32();
293             recs[i].fScale = buffer.readU32();
294         }
295     }
296     buffer.read(&fPtsToUnit, sizeof(SkMatrix));
297     fFlags = 0;
298 }
299 
~Gradient_Shader()300 Gradient_Shader::~Gradient_Shader() {
301     if (fCache16Storage) {
302         sk_free(fCache16Storage);
303     }
304     if (fCache32Storage) {
305         sk_free(fCache32Storage);
306     }
307     if (fOrigColors != fStorage) {
308         sk_free(fOrigColors);
309     }
310     fMapper->safeUnref();
311 }
312 
flatten(SkFlattenableWriteBuffer & buffer)313 void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
314     this->INHERITED::flatten(buffer);
315     buffer.writeFlattenable(fMapper);
316     buffer.write32(fColorCount);
317     buffer.writeMul4(fOrigColors, fColorCount * sizeof(SkColor));
318     buffer.write8(fTileMode);
319     if (fColorCount > 2) {
320         Rec* recs = fRecs;
321         for (int i = 1; i < fColorCount; i++) {
322             buffer.write32(recs[i].fPos);
323             buffer.write32(recs[i].fScale);
324         }
325     }
326     buffer.writeMul4(&fPtsToUnit, sizeof(SkMatrix));
327 }
328 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)329 bool Gradient_Shader::setContext(const SkBitmap& device,
330                                  const SkPaint& paint,
331                                  const SkMatrix& matrix) {
332     if (!this->INHERITED::setContext(device, paint, matrix)) {
333         return false;
334     }
335 
336     const SkMatrix& inverse = this->getTotalInverse();
337 
338     if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
339         return false;
340     }
341 
342     fDstToIndexProc = fDstToIndex.getMapXYProc();
343     fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
344 
345     // now convert our colors in to PMColors
346     unsigned paintAlpha = this->getPaintAlpha();
347     unsigned colorAlpha = 0xFF;
348 
349     // FIXME: record colorAlpha in constructor, since this is not affected
350     // by setContext()
351     for (int i = 0; i < fColorCount; i++) {
352         SkColor src = fOrigColors[i];
353         unsigned sa = SkColorGetA(src);
354         colorAlpha &= sa;
355     }
356 
357     fFlags = this->INHERITED::getFlags();
358     if ((colorAlpha & paintAlpha) == 0xFF) {
359         fFlags |= kOpaqueAlpha_Flag;
360     }
361     // we can do span16 as long as our individual colors are opaque,
362     // regardless of the paint's alpha
363     if (0xFF == colorAlpha) {
364         fFlags |= kHasSpan16_Flag;
365     }
366 
367     // if the new alpha differs from the previous time we were called, inval our cache
368     // this will trigger the cache to be rebuilt.
369     // we don't care about the first time, since the cache ptrs will already be NULL
370     if (fCacheAlpha != paintAlpha) {
371         fCache16 = NULL;                // inval the cache
372         fCache32 = NULL;                // inval the cache
373         fCacheAlpha = paintAlpha;       // record the new alpha
374         // inform our subclasses
375         this->onCacheReset();
376     }
377     return true;
378 }
379 
blend8(int a,int b,int scale)380 static inline int blend8(int a, int b, int scale) {
381     SkASSERT(a == SkToU8(a));
382     SkASSERT(b == SkToU8(b));
383     SkASSERT(scale >= 0 && scale <= 256);
384     return a + ((b - a) * scale >> 8);
385 }
386 
dot8_blend_packed32(uint32_t s0,uint32_t s1,int blend)387 static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1,
388                                            int blend) {
389 #if 0
390     int a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
391     int r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
392     int g = blend8(SkGetPackedG32(s0), SkGetPackedG32(s1), blend);
393     int b = blend8(SkGetPackedB32(s0), SkGetPackedB32(s1), blend);
394 
395     return SkPackARGB32(a, r, g, b);
396 #else
397     int otherBlend = 256 - blend;
398 
399 #if 0
400     U32 t0 = (((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF;
401     U32 t1 = (((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00;
402     SkASSERT((t0 & t1) == 0);
403     return t0 | t1;
404 #else
405     return  ((((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF) |
406             ((((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00);
407 #endif
408 
409 #endif
410 }
411 
412 #define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
413 
414 /** We take the original colors, not our premultiplied PMColors, since we can
415     build a 16bit table as long as the original colors are opaque, even if the
416     paint specifies a non-opaque alpha.
417 */
build_16bit_cache(uint16_t cache[],SkColor c0,SkColor c1,int count)418 static void build_16bit_cache(uint16_t cache[], SkColor c0, SkColor c1,
419                               int count) {
420     SkASSERT(count > 1);
421     SkASSERT(SkColorGetA(c0) == 0xFF);
422     SkASSERT(SkColorGetA(c1) == 0xFF);
423 
424     SkFixed r = SkColorGetR(c0);
425     SkFixed g = SkColorGetG(c0);
426     SkFixed b = SkColorGetB(c0);
427 
428     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
429     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
430     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
431 
432     r = SkIntToFixed(r) + 0x8000;
433     g = SkIntToFixed(g) + 0x8000;
434     b = SkIntToFixed(b) + 0x8000;
435 
436     do {
437         unsigned rr = r >> 16;
438         unsigned gg = g >> 16;
439         unsigned bb = b >> 16;
440         cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
441         cache[64] = SkDitherPack888ToRGB16(rr, gg, bb);
442         cache += 1;
443         r += dr;
444         g += dg;
445         b += db;
446     } while (--count != 0);
447 }
448 
build_32bit_cache(SkPMColor cache[],SkColor c0,SkColor c1,int count,U8CPU paintAlpha)449 static void build_32bit_cache(SkPMColor cache[], SkColor c0, SkColor c1,
450                               int count, U8CPU paintAlpha) {
451     SkASSERT(count > 1);
452 
453     // need to apply paintAlpha to our two endpoints
454     SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
455     SkFixed da;
456     {
457         int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
458         da = SkIntToFixed(tmp - a) / (count - 1);
459     }
460 
461     SkFixed r = SkColorGetR(c0);
462     SkFixed g = SkColorGetG(c0);
463     SkFixed b = SkColorGetB(c0);
464     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
465     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
466     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
467 
468     a = SkIntToFixed(a) + 0x8000;
469     r = SkIntToFixed(r) + 0x8000;
470     g = SkIntToFixed(g) + 0x8000;
471     b = SkIntToFixed(b) + 0x8000;
472 
473     do {
474         *cache++ = SkPreMultiplyARGB(a >> 16, r >> 16, g >> 16, b >> 16);
475         a += da;
476         r += dr;
477         g += dg;
478         b += db;
479     } while (--count != 0);
480 }
481 
SkFixedToFFFF(SkFixed x)482 static inline int SkFixedToFFFF(SkFixed x) {
483     SkASSERT((unsigned)x <= SK_Fixed1);
484     return x - (x >> 16);
485 }
486 
dot6to16(unsigned x)487 static inline U16CPU dot6to16(unsigned x) {
488     SkASSERT(x < 64);
489     return (x << 10) | (x << 4) | (x >> 2);
490 }
491 
getCache16()492 const uint16_t* Gradient_Shader::getCache16() {
493     if (fCache16 == NULL) {
494         if (fCache16Storage == NULL) { // set the storage and our working ptr
495             fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count * 2);
496         }
497         fCache16 = fCache16Storage;
498         if (fColorCount == 2) {
499             build_16bit_cache(fCache16, fOrigColors[0], fOrigColors[1], kCache16Count);
500         } else {
501             Rec* rec = fRecs;
502             int prevIndex = 0;
503             for (int i = 1; i < fColorCount; i++) {
504                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache16Bits);
505                 SkASSERT(nextIndex < kCache16Count);
506 
507                 if (nextIndex > prevIndex)
508                     build_16bit_cache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
509                 prevIndex = nextIndex;
510             }
511             SkASSERT(prevIndex == kCache16Count - 1);
512         }
513 
514         if (fMapper) {
515             fCache16Storage = (uint16_t*)sk_malloc_throw(sizeof(uint16_t) * kCache16Count * 2);
516             uint16_t* linear = fCache16;         // just computed linear data
517             uint16_t* mapped = fCache16Storage;  // storage for mapped data
518             SkUnitMapper* map = fMapper;
519             for (int i = 0; i < 64; i++) {
520                 int index = map->mapUnit16(dot6to16(i)) >> 10;
521                 mapped[i] = linear[index];
522                 mapped[i + 64] = linear[index + 64];
523             }
524             sk_free(fCache16);
525             fCache16 = fCache16Storage;
526         }
527     }
528     return fCache16;
529 }
530 
getCache32()531 const SkPMColor* Gradient_Shader::getCache32() {
532     if (fCache32 == NULL) {
533         if (fCache32Storage == NULL) // set the storage and our working ptr
534             fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
535 
536         fCache32 = fCache32Storage;
537         if (fColorCount == 2) {
538             build_32bit_cache(fCache32, fOrigColors[0], fOrigColors[1],
539                               kCache32Count, fCacheAlpha);
540         } else {
541             Rec* rec = fRecs;
542             int prevIndex = 0;
543             for (int i = 1; i < fColorCount; i++) {
544                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
545                 SkASSERT(nextIndex < kCache32Count);
546 
547                 if (nextIndex > prevIndex)
548                     build_32bit_cache(fCache32 + prevIndex, fOrigColors[i-1],
549                                       fOrigColors[i],
550                                       nextIndex - prevIndex + 1, fCacheAlpha);
551                 prevIndex = nextIndex;
552             }
553             SkASSERT(prevIndex == kCache32Count - 1);
554         }
555 
556         if (fMapper) {
557             fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
558             SkPMColor* linear = fCache32;           // just computed linear data
559             SkPMColor* mapped = fCache32Storage;    // storage for mapped data
560             SkUnitMapper* map = fMapper;
561             for (int i = 0; i < 256; i++) {
562                 mapped[i] = linear[map->mapUnit16((i << 8) | i) >> 8];
563             }
564             sk_free(fCache32);
565             fCache32 = fCache32Storage;
566         }
567     }
568     return fCache32;
569 }
570 
571 ///////////////////////////////////////////////////////////////////////////
572 
pts_to_unit_matrix(const SkPoint pts[2],SkMatrix * matrix)573 static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
574     SkVector    vec = pts[1] - pts[0];
575     SkScalar    mag = vec.length();
576     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
577 
578     vec.scale(inv);
579     matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
580     matrix->postTranslate(-pts[0].fX, -pts[0].fY);
581     matrix->postScale(inv, inv);
582 }
583 
584 ///////////////////////////////////////////////////////////////////////////////
585 
586 class Linear_Gradient : public Gradient_Shader {
587 public:
Linear_Gradient(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)588     Linear_Gradient(const SkPoint pts[2],
589                     const SkColor colors[], const SkScalar pos[], int colorCount,
590                     SkShader::TileMode mode, SkUnitMapper* mapper)
591         : Gradient_Shader(colors, pos, colorCount, mode, mapper)
592     {
593         fCachedBitmap = NULL;
594         pts_to_unit_matrix(pts, &fPtsToUnit);
595     }
~Linear_Gradient()596     virtual ~Linear_Gradient() {
597         if (fCachedBitmap) {
598             SkDELETE(fCachedBitmap);
599         }
600     }
601 
602     virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
603     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
604     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
605     virtual bool asABitmap(SkBitmap*, SkMatrix*, TileMode*);
onCacheReset()606     virtual void onCacheReset() {
607         if (fCachedBitmap) {
608             SkDELETE(fCachedBitmap);
609             fCachedBitmap = NULL;
610         }
611     }
612 
CreateProc(SkFlattenableReadBuffer & buffer)613     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
614         return SkNEW_ARGS(Linear_Gradient, (buffer));
615     }
616 
617 protected:
Linear_Gradient(SkFlattenableReadBuffer & buffer)618     Linear_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {
619         fCachedBitmap = NULL;
620     }
getFactory()621     virtual Factory getFactory() { return CreateProc; }
622 
623 private:
624     SkBitmap* fCachedBitmap;    // allocated on demand
625 
626     typedef Gradient_Shader INHERITED;
627 };
628 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)629 bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
630                                  const SkMatrix& matrix) {
631     if (!this->INHERITED::setContext(device, paint, matrix)) {
632         return false;
633     }
634 
635     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
636     if ((fDstToIndex.getType() & ~mask) == 0) {
637         fFlags |= SkShader::kConstInY32_Flag;
638         if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
639             // only claim this if we do have a 16bit mode (i.e. none of our
640             // colors have alpha), and if we are not dithering (which obviously
641             // is not const in Y).
642             fFlags |= SkShader::kConstInY16_Flag;
643         }
644     }
645     return true;
646 }
647 
648 //  Return true if fx, fx+dx, fx+2*dx, ... is always in range
no_need_for_clamp(int fx,int dx,int count)649 static inline bool no_need_for_clamp(int fx, int dx, int count)
650 {
651     SkASSERT(count > 0);
652     return (unsigned)((fx | (fx + (count - 1) * dx)) >> 8) <= 0xFF;
653 }
654 
shadeSpan(int x,int y,SkPMColor dstC[],int count)655 void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count)
656 {
657     SkASSERT(count > 0);
658 
659     SkPoint             srcPt;
660     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
661     TileProc            proc = fTileProc;
662     const SkPMColor*    cache = this->getCache32();
663 
664     if (fDstToIndexClass != kPerspective_MatrixClass) {
665         dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
666         SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
667         // preround fx by half the amount we throw away
668         fx += 1 << 7;
669 
670         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
671             SkFixed dxStorage[1];
672             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
673             dx = dxStorage[0];
674         } else {
675             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
676             dx = SkScalarToFixed(fDstToIndex.getScaleX());
677         }
678 
679         if (SkFixedNearlyZero(dx)) {
680             // we're a vertical gradient, so no change in a span
681             unsigned fi = proc(fx);
682             SkASSERT(fi <= 0xFFFF);
683             sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
684         } else if (proc == clamp_tileproc) {
685 #if 0
686             if (no_need_for_clamp(fx, dx, count))
687             {
688                 unsigned fi;
689                 while ((count -= 4) >= 0)
690                 {
691                     fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
692                     fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
693                     fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
694                     fi = fx >> 8; SkASSERT(fi <= 0xFF); fx += dx; *dstC++ = cache[fi];
695                 }
696                 SkASSERT(count <= -1 && count >= -4);
697                 count += 4;
698                 while (--count >= 0)
699                 {
700                     fi = fx >> 8;
701                     SkASSERT(fi <= 0xFF);
702                     fx += dx;
703                     *dstC++ = cache[fi];
704                 }
705             }
706             else
707 #endif
708                 do {
709                     unsigned fi = SkClampMax(fx >> 8, 0xFF);
710                     SkASSERT(fi <= 0xFF);
711                     fx += dx;
712                     *dstC++ = cache[fi];
713                 } while (--count != 0);
714         } else if (proc == mirror_tileproc) {
715             do {
716                 unsigned fi = mirror_8bits(fx >> 8);
717                 SkASSERT(fi <= 0xFF);
718                 fx += dx;
719                 *dstC++ = cache[fi];
720             } while (--count != 0);
721         } else {
722             SkASSERT(proc == repeat_tileproc);
723             do {
724                 unsigned fi = repeat_8bits(fx >> 8);
725                 SkASSERT(fi <= 0xFF);
726                 fx += dx;
727                 *dstC++ = cache[fi];
728             } while (--count != 0);
729         }
730     } else {
731         SkScalar    dstX = SkIntToScalar(x);
732         SkScalar    dstY = SkIntToScalar(y);
733         do {
734             dstProc(fDstToIndex, dstX, dstY, &srcPt);
735             unsigned fi = proc(SkScalarToFixed(srcPt.fX));
736             SkASSERT(fi <= 0xFFFF);
737             *dstC++ = cache[fi >> (16 - kCache32Bits)];
738             dstX += SK_Scalar1;
739         } while (--count != 0);
740     }
741 }
742 
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode xy[])743 bool Linear_Gradient::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
744                                 TileMode xy[]) {
745     // we cache our "bitmap", so it's generationID will be const on subsequent
746     // calls to asABitmap
747     if (NULL == fCachedBitmap) {
748         fCachedBitmap = SkNEW(SkBitmap);
749         fCachedBitmap->setConfig(SkBitmap::kARGB_8888_Config, kCache32Count, 1);
750         fCachedBitmap->setPixels((void*)this->getCache32(), NULL);
751     }
752 
753     if (bitmap) {
754         *bitmap = *fCachedBitmap;
755     }
756     if (matrix) {
757         matrix->setScale(SkIntToScalar(kCache32Count), SK_Scalar1);
758         matrix->preConcat(fPtsToUnit);
759     }
760     if (xy) {
761         xy[0] = fTileMode;
762         xy[1] = kClamp_TileMode;
763     }
764     return true;
765 }
766 
dither_memset16(uint16_t dst[],uint16_t value,uint16_t other,int count)767 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
768                             int count) {
769     if (reinterpret_cast<uintptr_t>(dst) & 2) {
770         *dst++ = value;
771         count -= 1;
772         SkTSwap(value, other);
773     }
774 
775     sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
776 
777     if (count & 1) {
778         dst[count - 1] = value;
779     }
780 }
781 
shadeSpan16(int x,int y,uint16_t dstC[],int count)782 void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count)
783 {
784     SkASSERT(count > 0);
785 
786     SkPoint             srcPt;
787     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
788     TileProc            proc = fTileProc;
789     const uint16_t*     cache = this->getCache16();
790     int                 toggle = ((x ^ y) & 1) << kCache16Bits;
791 
792     if (fDstToIndexClass != kPerspective_MatrixClass) {
793         dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
794         SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
795         // preround fx by half the amount we throw away
796         fx += 1 << 7;
797 
798         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
799             SkFixed dxStorage[1];
800             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
801             dx = dxStorage[0];
802         } else {
803             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
804             dx = SkScalarToFixed(fDstToIndex.getScaleX());
805         }
806 
807         if (SkFixedNearlyZero(dx)) {
808             // we're a vertical gradient, so no change in a span
809             unsigned fi = proc(fx) >> 10;
810             SkASSERT(fi <= 63);
811             dither_memset16(dstC, cache[toggle + fi], cache[(toggle ^ (1 << kCache16Bits)) + fi], count);
812         } else if (proc == clamp_tileproc) {
813             do {
814                 unsigned fi = SkClampMax(fx >> 10, 63);
815                 SkASSERT(fi <= 63);
816                 fx += dx;
817                 *dstC++ = cache[toggle + fi];
818                 toggle ^= (1 << kCache16Bits);
819             } while (--count != 0);
820         } else if (proc == mirror_tileproc) {
821             do {
822                 unsigned fi = mirror_6bits(fx >> 10);
823                 SkASSERT(fi <= 0x3F);
824                 fx += dx;
825                 *dstC++ = cache[toggle + fi];
826                 toggle ^= (1 << kCache16Bits);
827             } while (--count != 0);
828         } else {
829             SkASSERT(proc == repeat_tileproc);
830             do {
831                 unsigned fi = repeat_6bits(fx >> 10);
832                 SkASSERT(fi <= 0x3F);
833                 fx += dx;
834                 *dstC++ = cache[toggle + fi];
835                 toggle ^= (1 << kCache16Bits);
836             } while (--count != 0);
837         }
838     } else {
839         SkScalar    dstX = SkIntToScalar(x);
840         SkScalar    dstY = SkIntToScalar(y);
841         do {
842             dstProc(fDstToIndex, dstX, dstY, &srcPt);
843             unsigned fi = proc(SkScalarToFixed(srcPt.fX));
844             SkASSERT(fi <= 0xFFFF);
845 
846             int index = fi >> (16 - kCache16Bits);
847             *dstC++ = cache[toggle + index];
848             toggle ^= (1 << kCache16Bits);
849 
850             dstX += SK_Scalar1;
851         } while (--count != 0);
852     }
853 }
854 
855 ///////////////////////////////////////////////////////////////////////////////
856 
857 #define kSQRT_TABLE_BITS    11
858 #define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
859 
860 #include "SkRadialGradient_Table.h"
861 
862 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
863 
864 #include <stdio.h>
865 
SkRadialGradient_BuildTable()866 void SkRadialGradient_BuildTable()
867 {
868     // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
869 
870     FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
871     SkASSERT(file);
872     ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
873 
874     for (int i = 0; i < kSQRT_TABLE_SIZE; i++)
875     {
876         if ((i & 15) == 0)
877             ::fprintf(file, "\t");
878 
879         uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
880 
881         ::fprintf(file, "0x%02X", value);
882         if (i < kSQRT_TABLE_SIZE-1)
883             ::fprintf(file, ", ");
884         if ((i & 15) == 15)
885             ::fprintf(file, "\n");
886     }
887     ::fprintf(file, "};\n");
888     ::fclose(file);
889 }
890 
891 #endif
892 
893 
rad_to_unit_matrix(const SkPoint & center,SkScalar radius,SkMatrix * matrix)894 static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, SkMatrix* matrix)
895 {
896     SkScalar    inv = SkScalarInvert(radius);
897 
898     matrix->setTranslate(-center.fX, -center.fY);
899     matrix->postScale(inv, inv);
900 }
901 
902 class Radial_Gradient : public Gradient_Shader {
903 public:
Radial_Gradient(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)904     Radial_Gradient(const SkPoint& center, SkScalar radius,
905                     const SkColor colors[], const SkScalar pos[], int colorCount,
906                     SkShader::TileMode mode, SkUnitMapper* mapper)
907         : Gradient_Shader(colors, pos, colorCount, mode, mapper)
908     {
909         // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
910         SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
911 
912         rad_to_unit_matrix(center, radius, &fPtsToUnit);
913     }
shadeSpan(int x,int y,SkPMColor dstC[],int count)914     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
915     {
916         SkASSERT(count > 0);
917 
918         SkPoint             srcPt;
919         SkMatrix::MapXYProc dstProc = fDstToIndexProc;
920         TileProc            proc = fTileProc;
921         const SkPMColor*    cache = this->getCache32();
922 
923         if (fDstToIndexClass != kPerspective_MatrixClass)
924         {
925             dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
926             SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
927             SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
928 
929             if (fDstToIndexClass == kFixedStepInX_MatrixClass)
930             {
931                 SkFixed storage[2];
932                 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
933                 dx = storage[0];
934                 dy = storage[1];
935             }
936             else
937             {
938                 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
939                 dx = SkScalarToFixed(fDstToIndex.getScaleX());
940                 dy = SkScalarToFixed(fDstToIndex.getSkewY());
941             }
942 
943             if (proc == clamp_tileproc)
944             {
945                 const uint8_t* sqrt_table = gSqrt8Table;
946                 fx >>= 1;
947                 dx >>= 1;
948                 fy >>= 1;
949                 dy >>= 1;
950                 do {
951                     unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
952                     unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
953                     fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
954                     fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
955                     *dstC++ = cache[sqrt_table[fi] >> (8 - kCache32Bits)];
956                     fx += dx;
957                     fy += dy;
958                 } while (--count != 0);
959             }
960             else if (proc == mirror_tileproc)
961             {
962                 do {
963                     SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
964                     unsigned fi = mirror_tileproc(dist);
965                     SkASSERT(fi <= 0xFFFF);
966                     *dstC++ = cache[fi >> (16 - kCache32Bits)];
967                     fx += dx;
968                     fy += dy;
969                 } while (--count != 0);
970             }
971             else
972             {
973                 SkASSERT(proc == repeat_tileproc);
974                 do {
975                     SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
976                     unsigned fi = repeat_tileproc(dist);
977                     SkASSERT(fi <= 0xFFFF);
978                     *dstC++ = cache[fi >> (16 - kCache32Bits)];
979                     fx += dx;
980                     fy += dy;
981                 } while (--count != 0);
982             }
983         }
984         else    // perspective case
985         {
986             SkScalar dstX = SkIntToScalar(x);
987             SkScalar dstY = SkIntToScalar(y);
988             do {
989                 dstProc(fDstToIndex, dstX, dstY, &srcPt);
990                 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
991                 SkASSERT(fi <= 0xFFFF);
992                 *dstC++ = cache[fi >> (16 - kCache32Bits)];
993                 dstX += SK_Scalar1;
994             } while (--count != 0);
995         }
996     }
997 
shadeSpan16(int x,int y,uint16_t dstC[],int count)998     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) {
999         SkASSERT(count > 0);
1000 
1001         SkPoint             srcPt;
1002         SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1003         TileProc            proc = fTileProc;
1004         const uint16_t*     cache = this->getCache16();
1005         int                 toggle = ((x ^ y) & 1) << kCache16Bits;
1006 
1007         if (fDstToIndexClass != kPerspective_MatrixClass) {
1008             dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
1009             SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1010             SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1011 
1012             if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1013                 SkFixed storage[2];
1014                 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
1015                 dx = storage[0];
1016                 dy = storage[1];
1017             } else {
1018                 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1019                 dx = SkScalarToFixed(fDstToIndex.getScaleX());
1020                 dy = SkScalarToFixed(fDstToIndex.getSkewY());
1021             }
1022 
1023             if (proc == clamp_tileproc) {
1024                 const uint8_t* sqrt_table = gSqrt8Table;
1025 
1026                 /* knock these down so we can pin against +- 0x7FFF, which is an immediate load,
1027                     rather than 0xFFFF which is slower. This is a compromise, since it reduces our
1028                     precision, but that appears to be visually OK. If we decide this is OK for
1029                     all of our cases, we could (it seems) put this scale-down into fDstToIndex,
1030                     to avoid having to do these extra shifts each time.
1031                 */
1032                 fx >>= 1;
1033                 dx >>= 1;
1034                 fy >>= 1;
1035                 dy >>= 1;
1036                 if (dy == 0) {    // might perform this check for the other modes, but the win will be a smaller % of the total
1037                     fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1038                     fy *= fy;
1039                     do {
1040                         unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1041                         unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
1042                         fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1043                         fx += dx;
1044                         *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
1045                         toggle ^= (1 << kCache16Bits);
1046                     } while (--count != 0);
1047                 } else {
1048                     do {
1049                         unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1050                         unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1051                         fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
1052                         fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1053                         fx += dx;
1054                         fy += dy;
1055                         *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
1056                         toggle ^= (1 << kCache16Bits);
1057                     } while (--count != 0);
1058                 }
1059             } else if (proc == mirror_tileproc) {
1060                 do {
1061                     SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
1062                     unsigned fi = mirror_tileproc(dist);
1063                     SkASSERT(fi <= 0xFFFF);
1064                     fx += dx;
1065                     fy += dy;
1066                     *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
1067                     toggle ^= (1 << kCache16Bits);
1068                 } while (--count != 0);
1069             } else {
1070                 SkASSERT(proc == repeat_tileproc);
1071                 do {
1072                     SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
1073                     unsigned fi = repeat_tileproc(dist);
1074                     SkASSERT(fi <= 0xFFFF);
1075                     fx += dx;
1076                     fy += dy;
1077                     *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
1078                     toggle ^= (1 << kCache16Bits);
1079                 } while (--count != 0);
1080             }
1081         } else {    // perspective case
1082             SkScalar dstX = SkIntToScalar(x);
1083             SkScalar dstY = SkIntToScalar(y);
1084             do {
1085                 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1086                 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
1087                 SkASSERT(fi <= 0xFFFF);
1088 
1089                 int index = fi >> (16 - kCache16Bits);
1090                 *dstC++ = cache[toggle + index];
1091                 toggle ^= (1 << kCache16Bits);
1092 
1093                 dstX += SK_Scalar1;
1094             } while (--count != 0);
1095         }
1096     }
1097 
CreateProc(SkFlattenableReadBuffer & buffer)1098     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1099         return SkNEW_ARGS(Radial_Gradient, (buffer));
1100     }
1101 
1102 protected:
Radial_Gradient(SkFlattenableReadBuffer & buffer)1103     Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {};
getFactory()1104     virtual Factory getFactory() { return CreateProc; }
onCacheReset()1105     virtual void onCacheReset() {}
1106 
1107 private:
1108     typedef Gradient_Shader INHERITED;
1109 };
1110 
1111 /* Two-point radial gradients are specified by two circles, each with a center
1112    point and radius.  The gradient can be considered to be a series of
1113    concentric circles, with the color interpolated from the start circle
1114    (at t=0) to the end circle (at t=1).
1115 
1116    For each point (x, y) in the span, we want to find the
1117    interpolated circle that intersects that point.  The center
1118    of the desired circle (Cx, Cy) falls at some distance t
1119    along the line segment between the start point (Sx, Sy) and
1120    end point (Ex, Ey):
1121 
1122       Cx = (1 - t) * Sx + t * Ex        (0 <= t <= 1)
1123       Cy = (1 - t) * Sy + t * Ey
1124 
1125    The radius of the desired circle (r) is also a linear interpolation t
1126    between the start and end radii (Sr and Er):
1127 
1128       r = (1 - t) * Sr + t * Er
1129 
1130    But
1131 
1132       (x - Cx)^2 + (y - Cy)^2 = r^2
1133 
1134    so
1135 
1136      (x - ((1 - t) * Sx + t * Ex))^2
1137    + (y - ((1 - t) * Sy + t * Ey))^2
1138    = ((1 - t) * Sr + t * Er)^2
1139 
1140    Solving for t yields
1141 
1142      [(Sx - Ex)^2 + (Sy - Ey)^2 - (Er - Sr)^2)] * t^2
1143    + [2 * (Sx - Ex)(x - Sx) + 2 * (Sy - Ey)(y - Sy) - 2 * (Er - Sr) * Sr] * t
1144    + [(x - Sx)^2 + (y - Sy)^2 - Sr^2] = 0
1145 
1146    To simplify, let Dx = Sx - Ex, Dy = Sy - Ey, Dr = Er - Sr, dx = x - Sx, dy = y - Sy
1147 
1148      [Dx^2 + Dy^2 - Dr^2)] * t^2
1149    + 2 * [Dx * dx + Dy * dy - Dr * Sr] * t
1150    + [dx^2 + dy^2 - Sr^2] = 0
1151 
1152    A quadratic in t.  The two roots of the quadratic reflect the two
1153    possible circles on which the point may fall.  Solving for t yields
1154    the gradient value to use.
1155 
1156    If a<0, the start circle is entirely contained in the
1157    end circle, and one of the roots will be <0 or >1 (off the line
1158    segment).  If a>0, the start circle falls at least partially
1159    outside the end circle (or vice versa), and the gradient
1160    defines a "tube" where a point may be on one circle (on the
1161    inside of the tube) or the other (outside of the tube).  We choose
1162    one arbitrarily.
1163 
1164    In order to keep the math to within the limits of fixed point,
1165    we divide the entire quadratic by Dr^2, and replace
1166    (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
1167 
1168    [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
1169    + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
1170    + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
1171 
1172    (x' and y' are computed by appending the subtract and scale to the
1173    fDstToIndex matrix in the constructor).
1174 
1175    Since the 'A' component of the quadratic is independent of x' and y', it
1176    is precomputed in the constructor.  Since the 'B' component is linear in
1177    x' and y', if x and y are linear in the span, 'B' can be computed
1178    incrementally with a simple delta (db below).  If it is not (e.g.,
1179    a perspective projection), it must be computed in the loop.
1180 
1181 */
1182 
two_point_radial(SkFixed b,SkFixed fx,SkFixed fy,SkFixed sr2d2,SkFixed foura,SkFixed oneOverTwoA,bool posRoot)1183 static inline SkFixed two_point_radial(SkFixed b, SkFixed fx, SkFixed fy, SkFixed sr2d2, SkFixed foura, SkFixed oneOverTwoA, bool posRoot) {
1184     SkFixed c = SkFixedSquare(fx) + SkFixedSquare(fy) - sr2d2;
1185     SkFixed discrim = SkFixedSquare(b) - SkFixedMul(foura, c);
1186     if (discrim < 0) {
1187         discrim = -discrim;
1188     }
1189     SkFixed rootDiscrim = SkFixedSqrt(discrim);
1190     if (posRoot) {
1191         return SkFixedMul(-b + rootDiscrim, oneOverTwoA);
1192     } else {
1193         return SkFixedMul(-b - rootDiscrim, oneOverTwoA);
1194     }
1195 }
1196 
1197 class Two_Point_Radial_Gradient : public Gradient_Shader {
1198 public:
Two_Point_Radial_Gradient(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1199     Two_Point_Radial_Gradient(const SkPoint& start, SkScalar startRadius,
1200                               const SkPoint& end, SkScalar endRadius,
1201                               const SkColor colors[], const SkScalar pos[],
1202                               int colorCount, SkShader::TileMode mode,
1203                               SkUnitMapper* mapper)
1204         : Gradient_Shader(colors, pos, colorCount, mode, mapper)
1205     {
1206         fDiff = start - end;
1207         fDiffRadius = endRadius - startRadius;
1208         SkScalar inv = SkScalarInvert(fDiffRadius);
1209         fDiff.fX = SkScalarMul(fDiff.fX, inv);
1210         fDiff.fY = SkScalarMul(fDiff.fY, inv);
1211         fStartRadius = SkScalarMul(startRadius, inv);
1212         fSr2D2 = SkScalarSquare(fStartRadius);
1213         fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
1214         fOneOverTwoA = SkScalarInvert(fA * 2);
1215 
1216         fPtsToUnit.setTranslate(-start.fX, -start.fY);
1217         fPtsToUnit.postScale(inv, inv);
1218     }
shadeSpan(int x,int y,SkPMColor dstC[],int count)1219     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
1220     {
1221         SkASSERT(count > 0);
1222 
1223         // Zero difference between radii:  fill with transparent black.
1224         if (fDiffRadius == 0) {
1225           sk_bzero(dstC, count * sizeof(*dstC));
1226           return;
1227         }
1228         SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1229         TileProc            proc = fTileProc;
1230         const SkPMColor*    cache = this->getCache32();
1231         SkFixed diffx = SkScalarToFixed(fDiff.fX);
1232         SkFixed diffy = SkScalarToFixed(fDiff.fY);
1233         SkFixed foura = SkScalarToFixed(SkScalarMul(fA, 4));
1234         SkFixed startRadius = SkScalarToFixed(fStartRadius);
1235         SkFixed sr2D2 = SkScalarToFixed(fSr2D2);
1236         SkFixed oneOverTwoA = SkScalarToFixed(fOneOverTwoA);
1237         bool posRoot = fDiffRadius < 0;
1238         if (fDstToIndexClass != kPerspective_MatrixClass)
1239         {
1240             SkPoint srcPt;
1241             dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
1242             SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1243             SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1244 
1245             if (fDstToIndexClass == kFixedStepInX_MatrixClass)
1246             {
1247                 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &dx, &dy);
1248             }
1249             else
1250             {
1251                 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1252                 dx = SkScalarToFixed(fDstToIndex.getScaleX());
1253                 dy = SkScalarToFixed(fDstToIndex.getSkewY());
1254             }
1255             SkFixed b = (SkFixedMul(diffx, fx) +
1256                          SkFixedMul(diffy, fy) - startRadius) << 1;
1257             SkFixed db = (SkFixedMul(diffx, dx) +
1258                           SkFixedMul(diffy, dy)) << 1;
1259             if (proc == clamp_tileproc)
1260             {
1261                 for (; count > 0; --count) {
1262                     SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
1263                     SkFixed index = SkClampMax(t, 0xFFFF);
1264                     SkASSERT(index <= 0xFFFF);
1265                     *dstC++ = cache[index >> (16 - kCache32Bits)];
1266                     fx += dx;
1267                     fy += dy;
1268                     b += db;
1269                 }
1270             }
1271             else if (proc == mirror_tileproc)
1272             {
1273                 for (; count > 0; --count) {
1274                     SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
1275                     SkFixed index = mirror_tileproc(t);
1276                     SkASSERT(index <= 0xFFFF);
1277                     *dstC++ = cache[index >> (16 - kCache32Bits)];
1278                     fx += dx;
1279                     fy += dy;
1280                     b += db;
1281                 }
1282             }
1283             else
1284             {
1285                 SkASSERT(proc == repeat_tileproc);
1286                 for (; count > 0; --count) {
1287                     SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
1288                     SkFixed index = repeat_tileproc(t);
1289                     SkASSERT(index <= 0xFFFF);
1290                     *dstC++ = cache[index >> (16 - kCache32Bits)];
1291                     fx += dx;
1292                     fy += dy;
1293                     b += db;
1294                 }
1295             }
1296         }
1297         else    // perspective case
1298         {
1299             SkScalar dstX = SkIntToScalar(x);
1300             SkScalar dstY = SkIntToScalar(y);
1301             for (; count > 0; --count) {
1302                 SkPoint             srcPt;
1303                 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1304                 SkFixed fx = SkScalarToFixed(srcPt.fX);
1305                 SkFixed fy = SkScalarToFixed(srcPt.fY);
1306                 SkFixed b = (SkFixedMul(diffx, fx) +
1307                              SkFixedMul(diffy, fy) - startRadius) << 1;
1308                 SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
1309                 SkFixed index = proc(t);
1310                 SkASSERT(index <= 0xFFFF);
1311                 *dstC++ = cache[index >> (16 - kCache32Bits)];
1312                 dstX += SK_Scalar1;
1313             }
1314         }
1315     }
1316 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)1317     virtual bool setContext(const SkBitmap& device,
1318                             const SkPaint& paint,
1319                             const SkMatrix& matrix) {
1320         if (!this->INHERITED::setContext(device, paint, matrix)) {
1321             return false;
1322         }
1323 
1324         // we don't have a span16 proc
1325         fFlags &= ~kHasSpan16_Flag;
1326         return true;
1327     }
1328 
CreateProc(SkFlattenableReadBuffer & buffer)1329     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1330         return SkNEW_ARGS(Two_Point_Radial_Gradient, (buffer));
1331     }
1332 
1333 protected:
Two_Point_Radial_Gradient(SkFlattenableReadBuffer & buffer)1334     Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {};
getFactory()1335     virtual Factory getFactory() { return CreateProc; }
onCacheReset()1336     virtual void onCacheReset() {}
1337 
1338 private:
1339     typedef Gradient_Shader INHERITED;
1340     SkPoint fDiff;
1341     SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
1342 };
1343 
1344 ///////////////////////////////////////////////////////////////////////////////
1345 
1346 class Sweep_Gradient : public Gradient_Shader {
1347 public:
Sweep_Gradient(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int count,SkUnitMapper * mapper)1348     Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
1349                    const SkScalar pos[], int count, SkUnitMapper* mapper)
1350     : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper)
1351     {
1352         fPtsToUnit.setTranslate(-cx, -cy);
1353     }
1354     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
1355     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
1356 
CreateProc(SkFlattenableReadBuffer & buffer)1357     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1358         return SkNEW_ARGS(Sweep_Gradient, (buffer));
1359     }
1360 
1361 protected:
Sweep_Gradient(SkFlattenableReadBuffer & buffer)1362     Sweep_Gradient(SkFlattenableReadBuffer& buffer) : Gradient_Shader(buffer) {}
getFactory()1363     virtual Factory getFactory() { return CreateProc; }
onCacheReset()1364     virtual void onCacheReset() {}
1365 
1366 private:
1367     typedef Gradient_Shader INHERITED;
1368 };
1369 
1370 #ifdef COMPUTE_SWEEP_TABLE
1371 #define PI  3.14159265
1372 static bool gSweepTableReady;
1373 static uint8_t gSweepTable[65];
1374 
1375 /*  Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
1376     We scale the results to [0..32]
1377 */
build_sweep_table()1378 static const uint8_t* build_sweep_table()
1379 {
1380     if (!gSweepTableReady)
1381     {
1382         const int N = 65;
1383         const double DENOM = N - 1;
1384 
1385         for (int i = 0; i < N; i++)
1386         {
1387             double arg = i / DENOM;
1388             double v = atan(arg);
1389             int iv = (int)round(v * DENOM * 2 / PI);
1390 //            printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
1391             printf("%d, ", iv);
1392             gSweepTable[i] = iv;
1393         }
1394         gSweepTableReady = true;
1395     }
1396     return gSweepTable;
1397 }
1398 #else
1399 static const uint8_t gSweepTable[] = {
1400     0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
1401     10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
1402     19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
1403     26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
1404     32
1405 };
build_sweep_table()1406 static const uint8_t* build_sweep_table() { return gSweepTable; }
1407 #endif
1408 
1409 // divide numer/denom, with a bias of 6bits. Assumes numer <= denom
1410 // and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
1411 // Same as (but faster than) SkFixedDiv(numer, denom) >> 10
1412 
1413 //unsigned div_64(int numer, int denom);
div_64(int numer,int denom)1414 static unsigned div_64(int numer, int denom)
1415 {
1416     SkASSERT(numer <= denom);
1417     SkASSERT(numer > 0);
1418     SkASSERT(denom > 0);
1419 
1420     int nbits = SkCLZ(numer);
1421     int dbits = SkCLZ(denom);
1422     int bits = 6 - nbits + dbits;
1423     SkASSERT(bits <= 6);
1424 
1425     if (bits < 0)   // detect underflow
1426         return 0;
1427 
1428     denom <<= dbits - 1;
1429     numer <<= nbits - 1;
1430 
1431     unsigned result = 0;
1432 
1433     // do the first one
1434     if ((numer -= denom) >= 0)
1435         result = 1;
1436     else
1437         numer += denom;
1438 
1439     // Now fall into our switch statement if there are more bits to compute
1440     if (bits > 0)
1441     {
1442         // make room for the rest of the answer bits
1443         result <<= bits;
1444         switch (bits) {
1445         case 6:
1446             if ((numer = (numer << 1) - denom) >= 0)
1447                 result |= 32;
1448             else
1449                 numer += denom;
1450         case 5:
1451             if ((numer = (numer << 1) - denom) >= 0)
1452                 result |= 16;
1453             else
1454                 numer += denom;
1455         case 4:
1456             if ((numer = (numer << 1) - denom) >= 0)
1457                 result |= 8;
1458             else
1459                 numer += denom;
1460         case 3:
1461             if ((numer = (numer << 1) - denom) >= 0)
1462                 result |= 4;
1463             else
1464                 numer += denom;
1465         case 2:
1466             if ((numer = (numer << 1) - denom) >= 0)
1467                 result |= 2;
1468             else
1469                 numer += denom;
1470         case 1:
1471         default:    // not strictly need, but makes GCC make better ARM code
1472             if ((numer = (numer << 1) - denom) >= 0)
1473                 result |= 1;
1474             else
1475                 numer += denom;
1476         }
1477     }
1478     return result;
1479 }
1480 
1481 // Given x,y in the first quadrant, return 0..63 for the angle [0..90]
atan_0_90(SkFixed y,SkFixed x)1482 static unsigned atan_0_90(SkFixed y, SkFixed x)
1483 {
1484 #ifdef SK_DEBUG
1485     {
1486         static bool gOnce;
1487         if (!gOnce)
1488         {
1489             gOnce = true;
1490             SkASSERT(div_64(55, 55) == 64);
1491             SkASSERT(div_64(128, 256) == 32);
1492             SkASSERT(div_64(2326528, 4685824) == 31);
1493             SkASSERT(div_64(753664, 5210112) == 9);
1494             SkASSERT(div_64(229376, 4882432) == 3);
1495             SkASSERT(div_64(2, 64) == 2);
1496             SkASSERT(div_64(1, 64) == 1);
1497             // test that we handle underflow correctly
1498             SkASSERT(div_64(12345, 0x54321234) == 0);
1499         }
1500     }
1501 #endif
1502 
1503     SkASSERT(y > 0 && x > 0);
1504     const uint8_t* table = build_sweep_table();
1505 
1506     unsigned result;
1507     bool swap = (x < y);
1508     if (swap)
1509     {
1510         // first part of the atan(v) = PI/2 - atan(1/v) identity
1511         // since our div_64 and table want v <= 1, where v = y/x
1512         SkTSwap<SkFixed>(x, y);
1513     }
1514 
1515     result = div_64(y, x);
1516 
1517 #ifdef SK_DEBUG
1518     {
1519         unsigned result2 = SkDivBits(y, x, 6);
1520         SkASSERT(result2 == result ||
1521                  (result == 1 && result2 == 0));
1522     }
1523 #endif
1524 
1525     SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
1526     result = table[result];
1527 
1528     if (swap)
1529     {
1530         // complete the atan(v) = PI/2 - atan(1/v) identity
1531         result = 64 - result;
1532         // pin to 63
1533         result -= result >> 6;
1534     }
1535 
1536     SkASSERT(result <= 63);
1537     return result;
1538 }
1539 
1540 //  returns angle in a circle [0..2PI) -> [0..255]
SkATan2_255(SkFixed y,SkFixed x)1541 static unsigned SkATan2_255(SkFixed y, SkFixed x)
1542 {
1543     if (x == 0)
1544     {
1545         if (y == 0)
1546             return 0;
1547         return y < 0 ? 192 : 64;
1548     }
1549     if (y == 0)
1550         return x < 0 ? 128 : 0;
1551 
1552     /*  Find the right quadrant for x,y
1553         Since atan_0_90 only handles the first quadrant, we rotate x,y
1554         appropriately before calling it, and then add the right amount
1555         to account for the real quadrant.
1556         quadrant 0 : add 0                  | x > 0 && y > 0
1557         quadrant 1 : add 64 (90 degrees)    | x < 0 && y > 0
1558         quadrant 2 : add 128 (180 degrees)  | x < 0 && y < 0
1559         quadrant 3 : add 192 (270 degrees)  | x > 0 && y < 0
1560 
1561         map x<0 to (1 << 6)
1562         map y<0 to (3 << 6)
1563         add = map_x ^ map_y
1564     */
1565     int xsign = x >> 31;
1566     int ysign = y >> 31;
1567     int add = ((-xsign) ^ (ysign & 3)) << 6;
1568 
1569 #ifdef SK_DEBUG
1570     if (0 == add)
1571         SkASSERT(x > 0 && y > 0);
1572     else if (64 == add)
1573         SkASSERT(x < 0 && y > 0);
1574     else if (128 == add)
1575         SkASSERT(x < 0 && y < 0);
1576     else if (192 == add)
1577         SkASSERT(x > 0 && y < 0);
1578     else
1579         SkASSERT(!"bad value for add");
1580 #endif
1581 
1582     /*  This ^ trick makes x, y positive, and the swap<> handles quadrants
1583         where we need to rotate x,y by 90 or -90
1584     */
1585     x = (x ^ xsign) - xsign;
1586     y = (y ^ ysign) - ysign;
1587     if (add & 64)               // quads 1 or 3 need to swap x,y
1588         SkTSwap<SkFixed>(x, y);
1589 
1590     unsigned result = add + atan_0_90(y, x);
1591     SkASSERT(result < 256);
1592     return result;
1593 }
1594 
shadeSpan(int x,int y,SkPMColor dstC[],int count)1595 void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count)
1596 {
1597     SkMatrix::MapXYProc proc = fDstToIndexProc;
1598     const SkMatrix&     matrix = fDstToIndex;
1599     const SkPMColor*    cache = this->getCache32();
1600     SkPoint             srcPt;
1601 
1602     if (fDstToIndexClass != kPerspective_MatrixClass)
1603     {
1604         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1605                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1606         SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1607         SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1608 
1609         if (fDstToIndexClass == kFixedStepInX_MatrixClass)
1610         {
1611             SkFixed storage[2];
1612             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
1613                                       &storage[0], &storage[1]);
1614             dx = storage[0];
1615             dy = storage[1];
1616         }
1617         else
1618         {
1619             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1620             dx = SkScalarToFixed(matrix.getScaleX());
1621             dy = SkScalarToFixed(matrix.getSkewY());
1622         }
1623 
1624         for (; count > 0; --count)
1625         {
1626             *dstC++ = cache[SkATan2_255(fy, fx)];
1627             fx += dx;
1628             fy += dy;
1629         }
1630     }
1631     else    // perspective case
1632     {
1633         for (int stop = x + count; x < stop; x++)
1634         {
1635             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1636                  SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1637 
1638             int index = SkATan2_255(SkScalarToFixed(srcPt.fY),
1639                                     SkScalarToFixed(srcPt.fX));
1640             *dstC++ = cache[index];
1641         }
1642     }
1643 }
1644 
shadeSpan16(int x,int y,uint16_t dstC[],int count)1645 void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count)
1646 {
1647     SkMatrix::MapXYProc proc = fDstToIndexProc;
1648     const SkMatrix&     matrix = fDstToIndex;
1649     const uint16_t*     cache = this->getCache16();
1650     int                 toggle = ((x ^ y) & 1) << kCache16Bits;
1651     SkPoint             srcPt;
1652 
1653     if (fDstToIndexClass != kPerspective_MatrixClass)
1654     {
1655         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1656                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1657         SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1658         SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
1659 
1660         if (fDstToIndexClass == kFixedStepInX_MatrixClass)
1661         {
1662             SkFixed storage[2];
1663             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
1664                                       &storage[0], &storage[1]);
1665             dx = storage[0];
1666             dy = storage[1];
1667         }
1668         else
1669         {
1670             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1671             dx = SkScalarToFixed(matrix.getScaleX());
1672             dy = SkScalarToFixed(matrix.getSkewY());
1673         }
1674 
1675         for (; count > 0; --count)
1676         {
1677             int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
1678             *dstC++ = cache[toggle + index];
1679             toggle ^= (1 << kCache16Bits);
1680             fx += dx;
1681             fy += dy;
1682         }
1683     }
1684     else    // perspective case
1685     {
1686         for (int stop = x + count; x < stop; x++)
1687         {
1688             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
1689                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1690 
1691             int index = SkATan2_255(SkScalarToFixed(srcPt.fY),
1692                                     SkScalarToFixed(srcPt.fX));
1693             index >>= (8 - kCache16Bits);
1694             *dstC++ = cache[toggle + index];
1695             toggle ^= (1 << kCache16Bits);
1696         }
1697     }
1698 }
1699 
1700 ///////////////////////////////////////////////////////////////////////////
1701 ///////////////////////////////////////////////////////////////////////////
1702 
1703 // assumes colors is SkColor* and pos is SkScalar*
1704 #define EXPAND_1_COLOR(count)               \
1705     SkColor tmp[2];                         \
1706     do {                                    \
1707         if (1 == count) {                   \
1708             tmp[0] = tmp[1] = colors[0];    \
1709             colors = tmp;                   \
1710             pos = NULL;                     \
1711             count = 2;                      \
1712         }                                   \
1713     } while (0)
1714 
CreateLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1715 SkShader* SkGradientShader::CreateLinear(   const SkPoint pts[2],
1716                                             const SkColor colors[], const SkScalar pos[], int colorCount,
1717                                             SkShader::TileMode mode, SkUnitMapper* mapper)
1718 {
1719     if (NULL == pts || NULL == colors || colorCount < 1) {
1720         return NULL;
1721     }
1722     EXPAND_1_COLOR(colorCount);
1723 
1724     return SkNEW_ARGS(Linear_Gradient,
1725                       (pts, colors, pos, colorCount, mode, mapper));
1726 }
1727 
CreateRadial(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1728 SkShader* SkGradientShader::CreateRadial(   const SkPoint& center, SkScalar radius,
1729                                             const SkColor colors[], const SkScalar pos[], int colorCount,
1730                                             SkShader::TileMode mode, SkUnitMapper* mapper)
1731 {
1732     if (radius <= 0 || NULL == colors || colorCount < 1) {
1733         return NULL;
1734     }
1735     EXPAND_1_COLOR(colorCount);
1736 
1737     return SkNEW_ARGS(Radial_Gradient,
1738                       (center, radius, colors, pos, colorCount, mode, mapper));
1739 }
1740 
CreateTwoPointRadial(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1741 SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
1742                                                  SkScalar startRadius,
1743                                                  const SkPoint& end,
1744                                                  SkScalar endRadius,
1745                                                  const SkColor colors[],
1746                                                  const SkScalar pos[],
1747                                                  int colorCount,
1748                                                  SkShader::TileMode mode,
1749                                                  SkUnitMapper* mapper)
1750 {
1751     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
1752         return NULL;
1753     }
1754     EXPAND_1_COLOR(colorCount);
1755 
1756     return SkNEW_ARGS(Two_Point_Radial_Gradient,
1757                       (start, startRadius, end, endRadius, colors, pos, colorCount, mode, mapper));
1758 }
1759 
CreateSweep(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int count,SkUnitMapper * mapper)1760 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
1761                                         const SkColor colors[],
1762                                         const SkScalar pos[],
1763                                         int count, SkUnitMapper* mapper)
1764 {
1765     if (NULL == colors || count < 1) {
1766         return NULL;
1767     }
1768     EXPAND_1_COLOR(count);
1769 
1770     return SkNEW_ARGS(Sweep_Gradient, (cx, cy, colors, pos, count, mapper));
1771 }
1772 
1773 static SkFlattenable::Registrar gLinearGradientReg("Linear_Gradient",
1774                                                    Linear_Gradient::CreateProc);
1775 
1776 static SkFlattenable::Registrar gRadialGradientReg("Radial_Gradient",
1777                                                    Radial_Gradient::CreateProc);
1778 
1779 static SkFlattenable::Registrar gSweepGradientReg("Sweep_Gradient",
1780                                                    Sweep_Gradient::CreateProc);
1781 
1782