• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkGradientShader.h"
11 #include "SkClampRange.h"
12 #include "SkColorPriv.h"
13 #include "SkMallocPixelRef.h"
14 #include "SkUnitMapper.h"
15 #include "SkUtils.h"
16 #include "SkTemplates.h"
17 #include "SkBitmapCache.h"
18 
19 #ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
20     #define USE_DITHER_32BIT_GRADIENT
21 #endif
22 
sk_memset32_dither(uint32_t dst[],uint32_t v0,uint32_t v1,int count)23 static void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
24                                int count) {
25     if (count > 0) {
26         if (v0 == v1) {
27             sk_memset32(dst, v0, count);
28         } else {
29             int pairs = count >> 1;
30             for (int i = 0; i < pairs; i++) {
31                 *dst++ = v0;
32                 *dst++ = v1;
33             }
34             if (count & 1) {
35                 *dst = v0;
36             }
37         }
38     }
39 }
40 
41 ///////////////////////////////////////////////////////////////////////////////
42 // Can't use a two-argument function with side effects like this in a
43 // constructor's initializer's argument list because the order of
44 // evaluations in that context is undefined (and backwards on linux/gcc).
unflatten_point(SkReader32 & buffer)45 static SkPoint unflatten_point(SkReader32& buffer) {
46     SkPoint retval;
47     retval.fX = buffer.readScalar();
48     retval.fY = buffer.readScalar();
49     return retval;
50 }
51 
52 //  Clamp
53 
clamp_tileproc(SkFixed x)54 static SkFixed clamp_tileproc(SkFixed x) {
55     return SkClampMax(x, 0xFFFF);
56 }
57 
58 // Repeat
59 
repeat_tileproc(SkFixed x)60 static SkFixed repeat_tileproc(SkFixed x) {
61     return x & 0xFFFF;
62 }
63 
repeat_bits(int x,const int bits)64 static inline int repeat_bits(int x, const int bits) {
65     return x & ((1 << bits) - 1);
66 }
67 
repeat_8bits(int x)68 static inline int repeat_8bits(int x) {
69     return x & 0xFF;
70 }
71 
72 // Mirror
73 
74 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
75 // See http://code.google.com/p/skia/issues/detail?id=472
76 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
77 #pragma optimize("", off)
78 #endif
79 
mirror_tileproc(SkFixed x)80 static inline SkFixed mirror_tileproc(SkFixed x) {
81     int s = x << 15 >> 31;
82     return (x ^ s) & 0xFFFF;
83 }
84 
mirror_bits(int x,const int bits)85 static inline int mirror_bits(int x, const int bits) {
86 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
87     if (x & (1 << bits))
88         x = ~x;
89     return x & ((1 << bits) - 1);
90 #else
91     int s = x << (31 - bits) >> 31;
92     return (x ^ s) & ((1 << bits) - 1);
93 #endif
94 }
95 
mirror_8bits(int x)96 static inline int mirror_8bits(int x) {
97 #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
98     if (x & 256) {
99         x = ~x;
100     }
101     return x & 255;
102 #else
103     int s = x << 23 >> 31;
104     return (x ^ s) & 0xFF;
105 #endif
106 }
107 
108 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
109 #pragma optimize("", on)
110 #endif
111 
112 ///////////////////////////////////////////////////////////////////////////////
113 
114 typedef SkFixed (*TileProc)(SkFixed);
115 
116 static const TileProc gTileProcs[] = {
117     clamp_tileproc,
118     repeat_tileproc,
119     mirror_tileproc
120 };
121 
122 ///////////////////////////////////////////////////////////////////////////////
123 ///////////////////////////////////////////////////////////////////////////////
124 
125 class Gradient_Shader : public SkShader {
126 public:
127     Gradient_Shader(const SkColor colors[], const SkScalar pos[],
128                 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
129     virtual ~Gradient_Shader();
130 
131     // overrides
132     virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
getFlags()133     virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
134     virtual bool isOpaque() const SK_OVERRIDE;
135 
136     enum {
137         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
138         /// it, use a larger cache.
139         kCache16Bits    = 8,
140         kGradient16Length = (1 << kCache16Bits),
141         /// Each cache gets 1 extra entry at the end so we don't have to
142         /// test for end-of-cache in lerps. This is also the value used
143         /// to stride *writes* into the dither cache; it must not be zero.
144         /// Total space for a cache is 2x kCache16Count entries: one
145         /// regular cache, one for dithering.
146         kCache16Count   = kGradient16Length + 1,
147         kCache16Shift   = 16 - kCache16Bits,
148         kSqrt16Shift    = 8 - kCache16Bits,
149 
150         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
151         /// it, use a larger cache.
152         kCache32Bits    = 8,
153         kGradient32Length = (1 << kCache32Bits),
154         /// Each cache gets 1 extra entry at the end so we don't have to
155         /// test for end-of-cache in lerps. This is also the value used
156         /// to stride *writes* into the dither cache; it must not be zero.
157         /// Total space for a cache is 2x kCache32Count entries: one
158         /// regular cache, one for dithering.
159         kCache32Count   = kGradient32Length + 1,
160         kCache32Shift   = 16 - kCache32Bits,
161         kSqrt32Shift    = 8 - kCache32Bits,
162 
163         /// This value is used to *read* the dither cache; it may be 0
164         /// if dithering is disabled.
165 #ifdef USE_DITHER_32BIT_GRADIENT
166         kDitherStride32 = kCache32Count,
167 #else
168         kDitherStride32 = 0,
169 #endif
170         kDitherStride16 = kCache16Count,
171         kLerpRemainderMask32 = (1 << (16 - kCache32Bits)) - 1
172     };
173 
174 
175 protected:
176     Gradient_Shader(SkFlattenableReadBuffer& );
177     SkUnitMapper* fMapper;
178     SkMatrix    fPtsToUnit;     // set by subclass
179     SkMatrix    fDstToIndex;
180     SkMatrix::MapXYProc fDstToIndexProc;
181     TileMode    fTileMode;
182     TileProc    fTileProc;
183     int         fColorCount;
184     uint8_t     fDstToIndexClass;
185     uint8_t     fFlags;
186 
187     struct Rec {
188         SkFixed     fPos;   // 0...1
189         uint32_t    fScale; // (1 << 24) / range
190     };
191     Rec*        fRecs;
192 
193     virtual void flatten(SkFlattenableWriteBuffer& );
194     const uint16_t*     getCache16() const;
195     const SkPMColor*    getCache32() const;
196 
197     void commonAsABitmap(SkBitmap*) const;
198     void commonAsAGradient(GradientInfo*) const;
199 
200 private:
201     enum {
202         kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
203 
204         kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
205     };
206     SkColor     fStorage[(kStorageSize + 3) >> 2];
207     SkColor*    fOrigColors; // original colors, before modulation by paint in setContext
208     bool        fColorsAreOpaque;
209 
210     mutable uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
211     mutable SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
212 
213     mutable uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
214     mutable SkMallocPixelRef* fCache32PixelRef;
215     mutable unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
216 
217     static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
218     static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
219                                 U8CPU alpha);
220     void setCacheAlpha(U8CPU alpha) const;
221     void initCommon();
222 
223     typedef SkShader INHERITED;
224 };
225 
scalarToU16(SkScalar x)226 static inline unsigned scalarToU16(SkScalar x) {
227     SkASSERT(x >= 0 && x <= SK_Scalar1);
228 
229 #ifdef SK_SCALAR_IS_FLOAT
230     return (unsigned)(x * 0xFFFF);
231 #else
232     return x - (x >> 16);   // probably should be x - (x > 0x7FFF) but that is slower
233 #endif
234 }
235 
Gradient_Shader(const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)236 Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[],
237              int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper) {
238     SkASSERT(colorCount > 1);
239 
240     fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
241 
242     fMapper = mapper;
243     SkSafeRef(mapper);
244 
245     SkASSERT((unsigned)mode < SkShader::kTileModeCount);
246     SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
247     fTileMode = mode;
248     fTileProc = gTileProcs[mode];
249 
250     fCache16 = fCache16Storage = NULL;
251     fCache32 = NULL;
252     fCache32PixelRef = NULL;
253 
254     /*  Note: we let the caller skip the first and/or last position.
255         i.e. pos[0] = 0.3, pos[1] = 0.7
256         In these cases, we insert dummy entries to ensure that the final data
257         will be bracketed by [0, 1].
258         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
259 
260         Thus colorCount (the caller's value, and fColorCount (our value) may
261         differ by up to 2. In the above example:
262             colorCount = 2
263             fColorCount = 4
264      */
265     fColorCount = colorCount;
266     // check if we need to add in dummy start and/or end position/colors
267     bool dummyFirst = false;
268     bool dummyLast = false;
269     if (pos) {
270         dummyFirst = pos[0] != 0;
271         dummyLast = pos[colorCount - 1] != SK_Scalar1;
272         fColorCount += dummyFirst + dummyLast;
273     }
274 
275     if (fColorCount > kColorStorageCount) {
276         size_t size = sizeof(SkColor) + sizeof(Rec);
277         fOrigColors = reinterpret_cast<SkColor*>(
278                                         sk_malloc_throw(size * fColorCount));
279     }
280     else {
281         fOrigColors = fStorage;
282     }
283 
284     // Now copy over the colors, adding the dummies as needed
285     {
286         SkColor* origColors = fOrigColors;
287         if (dummyFirst) {
288             *origColors++ = colors[0];
289         }
290         memcpy(origColors, colors, colorCount * sizeof(SkColor));
291         if (dummyLast) {
292             origColors += colorCount;
293             *origColors = colors[colorCount - 1];
294         }
295     }
296 
297     fRecs = (Rec*)(fOrigColors + fColorCount);
298     if (fColorCount > 2) {
299         Rec* recs = fRecs;
300         recs->fPos = 0;
301         //  recs->fScale = 0; // unused;
302         recs += 1;
303         if (pos) {
304             /*  We need to convert the user's array of relative positions into
305                 fixed-point positions and scale factors. We need these results
306                 to be strictly monotonic (no two values equal or out of order).
307                 Hence this complex loop that just jams a zero for the scale
308                 value if it sees a segment out of order, and it assures that
309                 we start at 0 and end at 1.0
310             */
311             SkFixed prev = 0;
312             int startIndex = dummyFirst ? 0 : 1;
313             int count = colorCount + dummyLast;
314             for (int i = startIndex; i < count; i++) {
315                 // force the last value to be 1.0
316                 SkFixed curr;
317                 if (i == colorCount) {  // we're really at the dummyLast
318                     curr = SK_Fixed1;
319                 } else {
320                     curr = SkScalarToFixed(pos[i]);
321                 }
322                 // pin curr withing range
323                 if (curr < 0) {
324                     curr = 0;
325                 } else if (curr > SK_Fixed1) {
326                     curr = SK_Fixed1;
327                 }
328                 recs->fPos = curr;
329                 if (curr > prev) {
330                     recs->fScale = (1 << 24) / (curr - prev);
331                 } else {
332                     recs->fScale = 0; // ignore this segment
333                 }
334                 // get ready for the next value
335                 prev = curr;
336                 recs += 1;
337             }
338         } else {    // assume even distribution
339             SkFixed dp = SK_Fixed1 / (colorCount - 1);
340             SkFixed p = dp;
341             SkFixed scale = (colorCount - 1) << 8;  // (1 << 24) / dp
342             for (int i = 1; i < colorCount; i++) {
343                 recs->fPos   = p;
344                 recs->fScale = scale;
345                 recs += 1;
346                 p += dp;
347             }
348         }
349     }
350     this->initCommon();
351 }
352 
Gradient_Shader(SkFlattenableReadBuffer & buffer)353 Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
354     INHERITED(buffer) {
355     fCacheAlpha = 256;
356 
357     fMapper = static_cast<SkUnitMapper*>(buffer.readFlattenable());
358 
359     fCache16 = fCache16Storage = NULL;
360     fCache32 = NULL;
361     fCache32PixelRef = NULL;
362 
363     int colorCount = fColorCount = buffer.readU32();
364     if (colorCount > kColorStorageCount) {
365         size_t size = sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec);
366         fOrigColors = (SkColor*)sk_malloc_throw(size * colorCount);
367     } else {
368         fOrigColors = fStorage;
369     }
370     buffer.read(fOrigColors, colorCount * sizeof(SkColor));
371 
372     fTileMode = (TileMode)buffer.readU8();
373     fTileProc = gTileProcs[fTileMode];
374     fRecs = (Rec*)(fOrigColors + colorCount);
375     if (colorCount > 2) {
376         Rec* recs = fRecs;
377         recs[0].fPos = 0;
378         for (int i = 1; i < colorCount; i++) {
379             recs[i].fPos = buffer.readS32();
380             recs[i].fScale = buffer.readU32();
381         }
382     }
383     SkReadMatrix(&buffer, &fPtsToUnit);
384     this->initCommon();
385 }
386 
~Gradient_Shader()387 Gradient_Shader::~Gradient_Shader() {
388     if (fCache16Storage) {
389         sk_free(fCache16Storage);
390     }
391     SkSafeUnref(fCache32PixelRef);
392     if (fOrigColors != fStorage) {
393         sk_free(fOrigColors);
394     }
395     SkSafeUnref(fMapper);
396 }
397 
initCommon()398 void Gradient_Shader::initCommon() {
399     fFlags = 0;
400     unsigned colorAlpha = 0xFF;
401     for (int i = 0; i < fColorCount; i++) {
402         colorAlpha &= SkColorGetA(fOrigColors[i]);
403     }
404     fColorsAreOpaque = colorAlpha == 0xFF;
405 }
406 
flatten(SkFlattenableWriteBuffer & buffer)407 void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
408     this->INHERITED::flatten(buffer);
409     buffer.writeFlattenable(fMapper);
410     buffer.write32(fColorCount);
411     buffer.writeMul4(fOrigColors, fColorCount * sizeof(SkColor));
412     buffer.write8(fTileMode);
413     if (fColorCount > 2) {
414         Rec* recs = fRecs;
415         for (int i = 1; i < fColorCount; i++) {
416             buffer.write32(recs[i].fPos);
417             buffer.write32(recs[i].fScale);
418         }
419     }
420     SkWriteMatrix(&buffer, fPtsToUnit);
421 }
422 
isOpaque() const423 bool Gradient_Shader::isOpaque() const {
424     return fColorsAreOpaque;
425 }
426 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)427 bool Gradient_Shader::setContext(const SkBitmap& device,
428                                  const SkPaint& paint,
429                                  const SkMatrix& matrix) {
430     if (!this->INHERITED::setContext(device, paint, matrix)) {
431         return false;
432     }
433 
434     const SkMatrix& inverse = this->getTotalInverse();
435 
436     if (!fDstToIndex.setConcat(fPtsToUnit, inverse)) {
437         return false;
438     }
439 
440     fDstToIndexProc = fDstToIndex.getMapXYProc();
441     fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
442 
443     // now convert our colors in to PMColors
444     unsigned paintAlpha = this->getPaintAlpha();
445 
446     fFlags = this->INHERITED::getFlags();
447     if (fColorsAreOpaque && paintAlpha == 0xFF) {
448         fFlags |= kOpaqueAlpha_Flag;
449     }
450     // we can do span16 as long as our individual colors are opaque,
451     // regardless of the paint's alpha
452     if (fColorsAreOpaque) {
453         fFlags |= kHasSpan16_Flag;
454     }
455 
456     this->setCacheAlpha(paintAlpha);
457     return true;
458 }
459 
setCacheAlpha(U8CPU alpha) const460 void Gradient_Shader::setCacheAlpha(U8CPU alpha) const {
461     // if the new alpha differs from the previous time we were called, inval our cache
462     // this will trigger the cache to be rebuilt.
463     // we don't care about the first time, since the cache ptrs will already be NULL
464     if (fCacheAlpha != alpha) {
465         fCache16 = NULL;            // inval the cache
466         fCache32 = NULL;            // inval the cache
467         fCacheAlpha = alpha;        // record the new alpha
468         // inform our subclasses
469         if (fCache32PixelRef) {
470             fCache32PixelRef->notifyPixelsChanged();
471         }
472     }
473 }
474 
blend8(int a,int b,int scale)475 static inline int blend8(int a, int b, int scale) {
476     SkASSERT(a == SkToU8(a));
477     SkASSERT(b == SkToU8(b));
478     SkASSERT(scale >= 0 && scale <= 256);
479     return a + ((b - a) * scale >> 8);
480 }
481 
dot8_blend_packed32(uint32_t s0,uint32_t s1,int blend)482 static inline uint32_t dot8_blend_packed32(uint32_t s0, uint32_t s1,
483                                            int blend) {
484 #if 0
485     int a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
486     int r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
487     int g = blend8(SkGetPackedG32(s0), SkGetPackedG32(s1), blend);
488     int b = blend8(SkGetPackedB32(s0), SkGetPackedB32(s1), blend);
489 
490     return SkPackARGB32(a, r, g, b);
491 #else
492     int otherBlend = 256 - blend;
493 
494 #if 0
495     U32 t0 = (((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF;
496     U32 t1 = (((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00;
497     SkASSERT((t0 & t1) == 0);
498     return t0 | t1;
499 #else
500     return  ((((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF) |
501             ((((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00);
502 #endif
503 
504 #endif
505 }
506 
507 #define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
508 
509 /** We take the original colors, not our premultiplied PMColors, since we can
510     build a 16bit table as long as the original colors are opaque, even if the
511     paint specifies a non-opaque alpha.
512 */
Build16bitCache(uint16_t cache[],SkColor c0,SkColor c1,int count)513 void Gradient_Shader::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
514                                       int count) {
515     SkASSERT(count > 1);
516     SkASSERT(SkColorGetA(c0) == 0xFF);
517     SkASSERT(SkColorGetA(c1) == 0xFF);
518 
519     SkFixed r = SkColorGetR(c0);
520     SkFixed g = SkColorGetG(c0);
521     SkFixed b = SkColorGetB(c0);
522 
523     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
524     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
525     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
526 
527     r = SkIntToFixed(r) + 0x8000;
528     g = SkIntToFixed(g) + 0x8000;
529     b = SkIntToFixed(b) + 0x8000;
530 
531     do {
532         unsigned rr = r >> 16;
533         unsigned gg = g >> 16;
534         unsigned bb = b >> 16;
535         cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
536         cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
537         cache += 1;
538         r += dr;
539         g += dg;
540         b += db;
541     } while (--count != 0);
542 }
543 
544 /*
545  *  2x2 dither a fixed-point color component (8.16) down to 8, matching the
546  *  semantics of how we 2x2 dither 32->16
547  */
dither_fixed_to_8(SkFixed n)548 static inline U8CPU dither_fixed_to_8(SkFixed n) {
549     n >>= 8;
550     return ((n << 1) - ((n >> 8 << 8) | (n >> 8))) >> 8;
551 }
552 
553 /*
554  *  For dithering with premultiply, we want to ceiling the alpha component,
555  *  to ensure that it is always >= any color component.
556  */
dither_ceil_fixed_to_8(SkFixed n)557 static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
558     n >>= 8;
559     return ((n << 1) - (n | (n >> 8))) >> 8;
560 }
561 
Build32bitCache(SkPMColor cache[],SkColor c0,SkColor c1,int count,U8CPU paintAlpha)562 void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
563                                       int count, U8CPU paintAlpha) {
564     SkASSERT(count > 1);
565 
566     // need to apply paintAlpha to our two endpoints
567     SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
568     SkFixed da;
569     {
570         int tmp = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
571         da = SkIntToFixed(tmp - a) / (count - 1);
572     }
573 
574     SkFixed r = SkColorGetR(c0);
575     SkFixed g = SkColorGetG(c0);
576     SkFixed b = SkColorGetB(c0);
577     SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
578     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
579     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
580 
581     a = SkIntToFixed(a) + 0x8000;
582     r = SkIntToFixed(r) + 0x8000;
583     g = SkIntToFixed(g) + 0x8000;
584     b = SkIntToFixed(b) + 0x8000;
585 
586     do {
587         cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
588         cache[kCache32Count] =
589             SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
590                                     dither_fixed_to_8(r),
591                                     dither_fixed_to_8(g),
592                                     dither_fixed_to_8(b));
593         cache += 1;
594         a += da;
595         r += dr;
596         g += dg;
597         b += db;
598     } while (--count != 0);
599 }
600 
SkFixedToFFFF(SkFixed x)601 static inline int SkFixedToFFFF(SkFixed x) {
602     SkASSERT((unsigned)x <= SK_Fixed1);
603     return x - (x >> 16);
604 }
605 
bitsTo16(unsigned x,const unsigned bits)606 static inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
607     SkASSERT(x < (1U << bits));
608     if (6 == bits) {
609         return (x << 10) | (x << 4) | (x >> 2);
610     }
611     if (8 == bits) {
612         return (x << 8) | x;
613     }
614     sk_throw();
615     return 0;
616 }
617 
618 /** We duplicate the last value in each half of the cache so that
619     interpolation doesn't have to special-case being at the last point.
620 */
complete_16bit_cache(uint16_t * cache,int stride)621 static void complete_16bit_cache(uint16_t* cache, int stride) {
622     cache[stride - 1] = cache[stride - 2];
623     cache[2 * stride - 1] = cache[2 * stride - 2];
624 }
625 
getCache16() const626 const uint16_t* Gradient_Shader::getCache16() const {
627     if (fCache16 == NULL) {
628         // double the count for dither entries
629         const int entryCount = kCache16Count * 2;
630         const size_t allocSize = sizeof(uint16_t) * entryCount;
631 
632         if (fCache16Storage == NULL) { // set the storage and our working ptr
633             fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
634         }
635         fCache16 = fCache16Storage;
636         if (fColorCount == 2) {
637             Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
638                             kGradient16Length);
639         } else {
640             Rec* rec = fRecs;
641             int prevIndex = 0;
642             for (int i = 1; i < fColorCount; i++) {
643                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
644                 SkASSERT(nextIndex < kCache16Count);
645 
646                 if (nextIndex > prevIndex)
647                     Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
648                 prevIndex = nextIndex;
649             }
650             // one extra space left over at the end for complete_16bit_cache()
651             SkASSERT(prevIndex == kGradient16Length - 1);
652         }
653 
654         if (fMapper) {
655             fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
656             uint16_t* linear = fCache16;         // just computed linear data
657             uint16_t* mapped = fCache16Storage;  // storage for mapped data
658             SkUnitMapper* map = fMapper;
659             for (int i = 0; i < kGradient16Length; i++) {
660                 int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
661                 mapped[i] = linear[index];
662                 mapped[i + kCache16Count] = linear[index + kCache16Count];
663             }
664             sk_free(fCache16);
665             fCache16 = fCache16Storage;
666         }
667         complete_16bit_cache(fCache16, kCache16Count);
668     }
669     return fCache16;
670 }
671 
672 /** We duplicate the last value in each half of the cache so that
673     interpolation doesn't have to special-case being at the last point.
674 */
complete_32bit_cache(SkPMColor * cache,int stride)675 static void complete_32bit_cache(SkPMColor* cache, int stride) {
676     cache[stride - 1] = cache[stride - 2];
677     cache[2 * stride - 1] = cache[2 * stride - 2];
678 }
679 
getCache32() const680 const SkPMColor* Gradient_Shader::getCache32() const {
681     if (fCache32 == NULL) {
682         // double the count for dither entries
683         const int entryCount = kCache32Count * 2;
684         const size_t allocSize = sizeof(SkPMColor) * entryCount;
685 
686         if (NULL == fCache32PixelRef) {
687             fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef,
688                                           (NULL, allocSize, NULL));
689         }
690         fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
691         if (fColorCount == 2) {
692             Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
693                             kGradient32Length, fCacheAlpha);
694         } else {
695             Rec* rec = fRecs;
696             int prevIndex = 0;
697             for (int i = 1; i < fColorCount; i++) {
698                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
699                 SkASSERT(nextIndex < kGradient32Length);
700 
701                 if (nextIndex > prevIndex)
702                     Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
703                                     fOrigColors[i],
704                                     nextIndex - prevIndex + 1, fCacheAlpha);
705                 prevIndex = nextIndex;
706             }
707             SkASSERT(prevIndex == kGradient32Length - 1);
708         }
709 
710         if (fMapper) {
711             SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
712                                                  (NULL, allocSize, NULL));
713             SkPMColor* linear = fCache32;           // just computed linear data
714             SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
715             SkUnitMapper* map = fMapper;
716             for (int i = 0; i < kGradient32Length; i++) {
717                 int index = map->mapUnit16((i << 8) | i) >> 8;
718                 mapped[i] = linear[index];
719                 mapped[i + kCache32Count] = linear[index + kCache32Count];
720             }
721             fCache32PixelRef->unref();
722             fCache32PixelRef = newPR;
723             fCache32 = (SkPMColor*)newPR->getAddr();
724         }
725         complete_32bit_cache(fCache32, kCache32Count);
726     }
727     return fCache32;
728 }
729 
730 /*
731  *  Because our caller might rebuild the same (logically the same) gradient
732  *  over and over, we'd like to return exactly the same "bitmap" if possible,
733  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
734  *  To do that, we maintain a private cache of built-bitmaps, based on our
735  *  colors and positions. Note: we don't try to flatten the fMapper, so if one
736  *  is present, we skip the cache for now.
737  */
commonAsABitmap(SkBitmap * bitmap) const738 void Gradient_Shader::commonAsABitmap(SkBitmap* bitmap) const {
739     // our caller assumes no external alpha, so we ensure that our cache is
740     // built with 0xFF
741     this->setCacheAlpha(0xFF);
742 
743     // don't have a way to put the mapper into our cache-key yet
744     if (fMapper) {
745         // force our cahce32pixelref to be built
746         (void)this->getCache32();
747         bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1);
748         bitmap->setPixelRef(fCache32PixelRef);
749         return;
750     }
751 
752     // build our key: [numColors + colors[] + {positions[]} ]
753     int count = 1 + fColorCount;
754     if (fColorCount > 2) {
755         count += fColorCount - 1;    // fRecs[].fPos
756     }
757 
758     SkAutoSTMalloc<16, int32_t> storage(count);
759     int32_t* buffer = storage.get();
760 
761     *buffer++ = fColorCount;
762     memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
763     buffer += fColorCount;
764     if (fColorCount > 2) {
765         for (int i = 1; i < fColorCount; i++) {
766             *buffer++ = fRecs[i].fPos;
767         }
768     }
769     SkASSERT(buffer - storage.get() == count);
770 
771     ///////////////////////////////////
772 
773     SK_DECLARE_STATIC_MUTEX(gMutex);
774     static SkBitmapCache* gCache;
775     // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
776     static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
777     SkAutoMutexAcquire ama(gMutex);
778 
779     if (NULL == gCache) {
780         gCache = new SkBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
781     }
782     size_t size = count * sizeof(int32_t);
783 
784     if (!gCache->find(storage.get(), size, bitmap)) {
785         // force our cahce32pixelref to be built
786         (void)this->getCache32();
787         // Only expose the linear section of the cache; don't let the caller
788         // know about the padding at the end to make interpolation faster.
789         bitmap->setConfig(SkBitmap::kARGB_8888_Config, kGradient32Length, 1);
790         bitmap->setPixelRef(fCache32PixelRef);
791 
792         gCache->add(storage.get(), size, *bitmap);
793     }
794 }
795 
commonAsAGradient(GradientInfo * info) const796 void Gradient_Shader::commonAsAGradient(GradientInfo* info) const {
797     if (info) {
798         if (info->fColorCount >= fColorCount) {
799             if (info->fColors) {
800                 memcpy(info->fColors, fOrigColors,
801                        fColorCount * sizeof(SkColor));
802             }
803             if (info->fColorOffsets) {
804                 if (fColorCount == 2) {
805                     info->fColorOffsets[0] = 0;
806                     info->fColorOffsets[1] = SK_Scalar1;
807                 } else if (fColorCount > 2) {
808                     for (int i = 0; i < fColorCount; i++)
809                         info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
810                 }
811             }
812         }
813         info->fColorCount = fColorCount;
814         info->fTileMode = fTileMode;
815     }
816 }
817 
818 ///////////////////////////////////////////////////////////////////////////////
819 
pts_to_unit_matrix(const SkPoint pts[2],SkMatrix * matrix)820 static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) {
821     SkVector    vec = pts[1] - pts[0];
822     SkScalar    mag = vec.length();
823     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
824 
825     vec.scale(inv);
826     matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
827     matrix->postTranslate(-pts[0].fX, -pts[0].fY);
828     matrix->postScale(inv, inv);
829 }
830 
831 ///////////////////////////////////////////////////////////////////////////////
832 
833 class Linear_Gradient : public Gradient_Shader {
834 public:
Linear_Gradient(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)835     Linear_Gradient(const SkPoint pts[2],
836                     const SkColor colors[], const SkScalar pos[], int colorCount,
837                     SkShader::TileMode mode, SkUnitMapper* mapper)
838         : Gradient_Shader(colors, pos, colorCount, mode, mapper),
839           fStart(pts[0]),
840           fEnd(pts[1])
841     {
842         pts_to_unit_matrix(pts, &fPtsToUnit);
843     }
844 
845     virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
846     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
847     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
848     virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*,
849                              SkScalar* twoPointRadialParams) const SK_OVERRIDE;
850     virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
851 
CreateProc(SkFlattenableReadBuffer & buffer)852     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
853         return SkNEW_ARGS(Linear_Gradient, (buffer));
854     }
855 
flatten(SkFlattenableWriteBuffer & buffer)856     virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
857         this->INHERITED::flatten(buffer);
858         buffer.writeScalar(fStart.fX);
859         buffer.writeScalar(fStart.fY);
860         buffer.writeScalar(fEnd.fX);
861         buffer.writeScalar(fEnd.fY);
862     }
863 
864     SK_DECLARE_FLATTENABLE_REGISTRAR()
865 
866 protected:
Linear_Gradient(SkFlattenableReadBuffer & buffer)867     Linear_Gradient(SkFlattenableReadBuffer& buffer)
868         : Gradient_Shader(buffer),
869           fStart(unflatten_point(buffer)),
870           fEnd(unflatten_point(buffer)) {
871     }
getFactory()872     virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
873 
874 private:
875     typedef Gradient_Shader INHERITED;
876     const SkPoint fStart;
877     const SkPoint fEnd;
878 };
879 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)880 bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
881                                  const SkMatrix& matrix) {
882     if (!this->INHERITED::setContext(device, paint, matrix)) {
883         return false;
884     }
885 
886     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
887     if ((fDstToIndex.getType() & ~mask) == 0) {
888         fFlags |= SkShader::kConstInY32_Flag;
889         if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
890             // only claim this if we do have a 16bit mode (i.e. none of our
891             // colors have alpha), and if we are not dithering (which obviously
892             // is not const in Y).
893             fFlags |= SkShader::kConstInY16_Flag;
894         }
895     }
896     return true;
897 }
898 
899 #define NO_CHECK_ITER               \
900     do {                            \
901     unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
902     SkASSERT(fi <= 0xFF);           \
903     fx += dx;                       \
904     *dstC++ = cache[toggle + fi];   \
905     toggle ^= Gradient_Shader::kDitherStride32; \
906     } while (0)
907 
908 namespace {
909 
910 typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
911                                 SkPMColor* dstC, const SkPMColor* cache,
912                                 int toggle, int count);
913 
914 // This function is deprecated, and will be replaced by
915 // shadeSpan_linear_vertical_lerp() once Chrome has been weaned off of it.
shadeSpan_linear_vertical(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)916 void shadeSpan_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
917                                SkPMColor* SK_RESTRICT dstC,
918                                const SkPMColor* SK_RESTRICT cache,
919                                int toggle, int count) {
920     // We're a vertical gradient, so no change in a span.
921     // If colors change sharply across the gradient, dithering is
922     // insufficient (it subsamples the color space) and we need to lerp.
923     unsigned fullIndex = proc(fx);
924     unsigned fi = fullIndex >> (16 - Gradient_Shader::kCache32Bits);
925     sk_memset32_dither(dstC,
926             cache[toggle + fi],
927             cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi],
928             count);
929 }
930 
931 // Linear interpolation (lerp) is unnecessary if there are no sharp
932 // discontinuities in the gradient - which must be true if there are
933 // only 2 colors - but it's cheap.
shadeSpan_linear_vertical_lerp(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)934 void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
935                                     SkPMColor* SK_RESTRICT dstC,
936                                     const SkPMColor* SK_RESTRICT cache,
937                                     int toggle, int count) {
938     // We're a vertical gradient, so no change in a span.
939     // If colors change sharply across the gradient, dithering is
940     // insufficient (it subsamples the color space) and we need to lerp.
941     unsigned fullIndex = proc(fx);
942     unsigned fi = fullIndex >> (16 - Gradient_Shader::kCache32Bits);
943     unsigned remainder = fullIndex & Gradient_Shader::kLerpRemainderMask32;
944     SkPMColor lerp =
945         SkFastFourByteInterp(
946             cache[toggle + fi + 1],
947             cache[toggle + fi], remainder);
948     SkPMColor dlerp =
949         SkFastFourByteInterp(
950             cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi + 1],
951             cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi], remainder);
952     sk_memset32_dither(dstC, lerp, dlerp, count);
953 }
954 
shadeSpan_linear_clamp(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)955 void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
956                             SkPMColor* SK_RESTRICT dstC,
957                             const SkPMColor* SK_RESTRICT cache,
958                             int toggle, int count) {
959     SkClampRange range;
960     range.init(fx, dx, count, 0, Gradient_Shader::kGradient32Length);
961 
962     if ((count = range.fCount0) > 0) {
963         sk_memset32_dither(dstC,
964             cache[toggle + range.fV0],
965             cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV0],
966             count);
967         dstC += count;
968     }
969     if ((count = range.fCount1) > 0) {
970         int unroll = count >> 3;
971         fx = range.fFx1;
972         for (int i = 0; i < unroll; i++) {
973             NO_CHECK_ITER;  NO_CHECK_ITER;
974             NO_CHECK_ITER;  NO_CHECK_ITER;
975             NO_CHECK_ITER;  NO_CHECK_ITER;
976             NO_CHECK_ITER;  NO_CHECK_ITER;
977         }
978         if ((count &= 7) > 0) {
979             do {
980                 NO_CHECK_ITER;
981             } while (--count != 0);
982         }
983     }
984     if ((count = range.fCount2) > 0) {
985         sk_memset32_dither(dstC,
986             cache[toggle + range.fV1],
987             cache[(toggle ^ Gradient_Shader::kDitherStride32) + range.fV1],
988             count);
989     }
990 }
991 
shadeSpan_linear_mirror(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)992 void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
993                              SkPMColor* SK_RESTRICT dstC,
994                              const SkPMColor* SK_RESTRICT cache,
995                              int toggle, int count) {
996     do {
997         unsigned fi = mirror_8bits(fx >> 8);
998         SkASSERT(fi <= 0xFF);
999         fx += dx;
1000         *dstC++ = cache[toggle + fi];
1001         toggle ^= Gradient_Shader::kDitherStride32;
1002     } while (--count != 0);
1003 }
1004 
shadeSpan_linear_repeat(TileProc proc,SkFixed dx,SkFixed fx,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int toggle,int count)1005 void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
1006         SkPMColor* SK_RESTRICT dstC,
1007         const SkPMColor* SK_RESTRICT cache,
1008         int toggle, int count) {
1009     do {
1010         unsigned fi = repeat_8bits(fx >> 8);
1011         SkASSERT(fi <= 0xFF);
1012         fx += dx;
1013         *dstC++ = cache[toggle + fi];
1014         toggle ^= Gradient_Shader::kDitherStride32;
1015     } while (--count != 0);
1016 }
1017 
1018 }
1019 
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)1020 void Linear_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
1021                                 int count) {
1022     SkASSERT(count > 0);
1023 
1024     SkPoint             srcPt;
1025     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1026     TileProc            proc = fTileProc;
1027     const SkPMColor* SK_RESTRICT cache = this->getCache32();
1028 #ifdef USE_DITHER_32BIT_GRADIENT
1029     int                 toggle = ((x ^ y) & 1) * kDitherStride32;
1030 #else
1031     int toggle = 0;
1032 #endif
1033 
1034     if (fDstToIndexClass != kPerspective_MatrixClass) {
1035         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1036                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1037         SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1038 
1039         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1040             SkFixed dxStorage[1];
1041             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
1042             dx = dxStorage[0];
1043         } else {
1044             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1045             dx = SkScalarToFixed(fDstToIndex.getScaleX());
1046         }
1047 
1048         LinearShadeProc shadeProc = shadeSpan_linear_repeat;
1049         // We really should check the endpoint colors, but short of that change
1050         // we reduce the tolerance of SkFixedNearlyZero to be more restrictive.
1051         if (SkFixedNearlyZero(dx, (SK_Fixed1 >> 14))) {
1052 #ifdef SK_SIMPLE_TWOCOLOR_VERTICAL_GRADIENTS
1053             if (fColorCount > 2) {
1054                 shadeProc = shadeSpan_linear_vertical_lerp;
1055             } else {
1056                 shadeProc = shadeSpan_linear_vertical;
1057             }
1058 #else
1059             shadeProc = shadeSpan_linear_vertical_lerp;
1060 #endif
1061         } else if (proc == clamp_tileproc) {
1062             shadeProc = shadeSpan_linear_clamp;
1063         } else if (proc == mirror_tileproc) {
1064             shadeProc = shadeSpan_linear_mirror;
1065         } else {
1066             SkASSERT(proc == repeat_tileproc);
1067         }
1068         (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
1069     } else {
1070         SkScalar    dstX = SkIntToScalar(x);
1071         SkScalar    dstY = SkIntToScalar(y);
1072         do {
1073             dstProc(fDstToIndex, dstX, dstY, &srcPt);
1074             unsigned fi = proc(SkScalarToFixed(srcPt.fX));
1075             SkASSERT(fi <= 0xFFFF);
1076             *dstC++ = cache[toggle + (fi >> kCache32Shift)];
1077             toggle ^= Gradient_Shader::kDitherStride32;
1078             dstX += SK_Scalar1;
1079         } while (--count != 0);
1080     }
1081 }
1082 
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode xy[],SkScalar * twoPointRadialParams) const1083 SkShader::BitmapType Linear_Gradient::asABitmap(SkBitmap* bitmap,
1084                                                 SkMatrix* matrix,
1085                                                 TileMode xy[],
1086                                         SkScalar* twoPointRadialParams) const {
1087     if (bitmap) {
1088         this->commonAsABitmap(bitmap);
1089     }
1090     if (matrix) {
1091         matrix->setScale(SkIntToScalar(kGradient32Length), SK_Scalar1);
1092         matrix->preConcat(fPtsToUnit);
1093     }
1094     if (xy) {
1095         xy[0] = fTileMode;
1096         xy[1] = kClamp_TileMode;
1097     }
1098     return kDefault_BitmapType;
1099 }
1100 
asAGradient(GradientInfo * info) const1101 SkShader::GradientType Linear_Gradient::asAGradient(GradientInfo* info) const {
1102     if (info) {
1103         commonAsAGradient(info);
1104         info->fPoint[0] = fStart;
1105         info->fPoint[1] = fEnd;
1106     }
1107     return kLinear_GradientType;
1108 }
1109 
dither_memset16(uint16_t dst[],uint16_t value,uint16_t other,int count)1110 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
1111                             int count) {
1112     if (reinterpret_cast<uintptr_t>(dst) & 2) {
1113         *dst++ = value;
1114         count -= 1;
1115         SkTSwap(value, other);
1116     }
1117 
1118     sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
1119 
1120     if (count & 1) {
1121         dst[count - 1] = value;
1122     }
1123 }
1124 
1125 #define NO_CHECK_ITER_16                \
1126     do {                                \
1127     unsigned fi = fx >> Gradient_Shader::kCache16Shift;  \
1128     SkASSERT(fi < Gradient_Shader::kCache16Count);       \
1129     fx += dx;                           \
1130     *dstC++ = cache[toggle + fi];       \
1131     toggle ^= Gradient_Shader::kDitherStride16;            \
1132     } while (0)
1133 
1134 namespace {
1135 
1136 typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
1137                                   uint16_t* dstC, const uint16_t* cache,
1138                                   int toggle, int count);
1139 
shadeSpan16_linear_vertical(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1140 void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
1141                                  uint16_t* SK_RESTRICT dstC,
1142                                  const uint16_t* SK_RESTRICT cache,
1143                                  int toggle, int count) {
1144     // we're a vertical gradient, so no change in a span
1145     unsigned fi = proc(fx) >> Gradient_Shader::kCache16Shift;
1146     SkASSERT(fi < Gradient_Shader::kCache16Count);
1147     dither_memset16(dstC, cache[toggle + fi],
1148         cache[(toggle ^ Gradient_Shader::kDitherStride16) + fi], count);
1149 
1150 }
1151 
shadeSpan16_linear_clamp(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1152 void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
1153                               uint16_t* SK_RESTRICT dstC,
1154                               const uint16_t* SK_RESTRICT cache,
1155                               int toggle, int count) {
1156     SkClampRange range;
1157     range.init(fx, dx, count, 0, Gradient_Shader::kGradient16Length);
1158 
1159     if ((count = range.fCount0) > 0) {
1160         dither_memset16(dstC,
1161             cache[toggle + range.fV0],
1162             cache[(toggle ^ Gradient_Shader::kDitherStride16) + range.fV0],
1163             count);
1164         dstC += count;
1165     }
1166     if ((count = range.fCount1) > 0) {
1167         int unroll = count >> 3;
1168         fx = range.fFx1;
1169         for (int i = 0; i < unroll; i++) {
1170             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
1171             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
1172             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
1173             NO_CHECK_ITER_16;  NO_CHECK_ITER_16;
1174         }
1175         if ((count &= 7) > 0) {
1176             do {
1177                 NO_CHECK_ITER_16;
1178             } while (--count != 0);
1179         }
1180     }
1181     if ((count = range.fCount2) > 0) {
1182         dither_memset16(dstC,
1183             cache[toggle + range.fV1],
1184             cache[(toggle ^ Gradient_Shader::kDitherStride16) + range.fV1],
1185             count);
1186     }
1187 }
1188 
shadeSpan16_linear_mirror(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1189 void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
1190                                uint16_t* SK_RESTRICT dstC,
1191                                const uint16_t* SK_RESTRICT cache,
1192                                int toggle, int count) {
1193     do {
1194         unsigned fi = mirror_bits(fx >> Gradient_Shader::kCache16Shift,
1195                                         Gradient_Shader::kCache16Bits);
1196         SkASSERT(fi < Gradient_Shader::kCache16Count);
1197         fx += dx;
1198         *dstC++ = cache[toggle + fi];
1199         toggle ^= Gradient_Shader::kDitherStride16;
1200     } while (--count != 0);
1201 }
1202 
shadeSpan16_linear_repeat(TileProc proc,SkFixed dx,SkFixed fx,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1203 void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
1204                                uint16_t* SK_RESTRICT dstC,
1205                                const uint16_t* SK_RESTRICT cache,
1206                                int toggle, int count) {
1207     SkASSERT(proc == repeat_tileproc);
1208     do {
1209         unsigned fi = repeat_bits(fx >> Gradient_Shader::kCache16Shift,
1210                                   Gradient_Shader::kCache16Bits);
1211         SkASSERT(fi < Gradient_Shader::kCache16Count);
1212         fx += dx;
1213         *dstC++ = cache[toggle + fi];
1214         toggle ^= Gradient_Shader::kDitherStride16;
1215     } while (--count != 0);
1216 }
1217 }
1218 
shadeSpan16(int x,int y,uint16_t * SK_RESTRICT dstC,int count)1219 void Linear_Gradient::shadeSpan16(int x, int y,
1220                                   uint16_t* SK_RESTRICT dstC, int count) {
1221     SkASSERT(count > 0);
1222 
1223     SkPoint             srcPt;
1224     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1225     TileProc            proc = fTileProc;
1226     const uint16_t* SK_RESTRICT cache = this->getCache16();
1227     int                 toggle = ((x ^ y) & 1) * kDitherStride16;
1228 
1229     if (fDstToIndexClass != kPerspective_MatrixClass) {
1230         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1231                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1232         SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
1233 
1234         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1235             SkFixed dxStorage[1];
1236             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
1237             dx = dxStorage[0];
1238         } else {
1239             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1240             dx = SkScalarToFixed(fDstToIndex.getScaleX());
1241         }
1242 
1243         LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
1244         if (SkFixedNearlyZero(dx)) {
1245             shadeProc = shadeSpan16_linear_vertical;
1246         } else if (proc == clamp_tileproc) {
1247             shadeProc = shadeSpan16_linear_clamp;
1248         } else if (proc == mirror_tileproc) {
1249             shadeProc = shadeSpan16_linear_mirror;
1250         } else {
1251             SkASSERT(proc == repeat_tileproc);
1252         }
1253         (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
1254     } else {
1255         SkScalar    dstX = SkIntToScalar(x);
1256         SkScalar    dstY = SkIntToScalar(y);
1257         do {
1258             dstProc(fDstToIndex, dstX, dstY, &srcPt);
1259             unsigned fi = proc(SkScalarToFixed(srcPt.fX));
1260             SkASSERT(fi <= 0xFFFF);
1261 
1262             int index = fi >> kCache16Shift;
1263             *dstC++ = cache[toggle + index];
1264             toggle ^= Gradient_Shader::kDitherStride16;
1265 
1266             dstX += SK_Scalar1;
1267         } while (--count != 0);
1268     }
1269 }
1270 
1271 ///////////////////////////////////////////////////////////////////////////////
1272 
1273 #define kSQRT_TABLE_BITS    11
1274 #define kSQRT_TABLE_SIZE    (1 << kSQRT_TABLE_BITS)
1275 
1276 #include "SkRadialGradient_Table.h"
1277 
1278 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
1279 
1280 #include <stdio.h>
1281 
SkRadialGradient_BuildTable()1282 void SkRadialGradient_BuildTable() {
1283     // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
1284 
1285     FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
1286     SkASSERT(file);
1287     ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n");
1288 
1289     for (int i = 0; i < kSQRT_TABLE_SIZE; i++) {
1290         if ((i & 15) == 0) {
1291             ::fprintf(file, "\t");
1292         }
1293 
1294         uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
1295 
1296         ::fprintf(file, "0x%02X", value);
1297         if (i < kSQRT_TABLE_SIZE-1) {
1298             ::fprintf(file, ", ");
1299         }
1300         if ((i & 15) == 15) {
1301             ::fprintf(file, "\n");
1302         }
1303     }
1304     ::fprintf(file, "};\n");
1305     ::fclose(file);
1306 }
1307 
1308 #endif
1309 
1310 
rad_to_unit_matrix(const SkPoint & center,SkScalar radius,SkMatrix * matrix)1311 static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
1312                                SkMatrix* matrix) {
1313     SkScalar    inv = SkScalarInvert(radius);
1314 
1315     matrix->setTranslate(-center.fX, -center.fY);
1316     matrix->postScale(inv, inv);
1317 }
1318 
1319 
1320 namespace {
1321 
1322 typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx,
1323         SkScalar sfy, SkScalar sdy,
1324         uint16_t* dstC, const uint16_t* cache,
1325         int toggle, int count);
1326 
shadeSpan16_radial_clamp(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1327 void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx,
1328         SkScalar sfy, SkScalar sdy,
1329         uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
1330         int toggle, int count) {
1331     const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
1332 
1333     /* knock these down so we can pin against +- 0x7FFF, which is an
1334        immediate load, rather than 0xFFFF which is slower. This is a
1335        compromise, since it reduces our precision, but that appears
1336        to be visually OK. If we decide this is OK for all of our cases,
1337        we could (it seems) put this scale-down into fDstToIndex,
1338        to avoid having to do these extra shifts each time.
1339     */
1340     SkFixed fx = SkScalarToFixed(sfx) >> 1;
1341     SkFixed dx = SkScalarToFixed(sdx) >> 1;
1342     SkFixed fy = SkScalarToFixed(sfy) >> 1;
1343     SkFixed dy = SkScalarToFixed(sdy) >> 1;
1344     // might perform this check for the other modes,
1345     // but the win will be a smaller % of the total
1346     if (dy == 0) {
1347         fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1348         fy *= fy;
1349         do {
1350             unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1351             unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
1352             fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1353             fx += dx;
1354             *dstC++ = cache[toggle +
1355                             (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
1356             toggle ^= Gradient_Shader::kDitherStride16;
1357         } while (--count != 0);
1358     } else {
1359         do {
1360             unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1361             unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1362             fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
1363             fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1364             fx += dx;
1365             fy += dy;
1366             *dstC++ = cache[toggle +
1367                             (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
1368             toggle ^= Gradient_Shader::kDitherStride16;
1369         } while (--count != 0);
1370     }
1371 }
1372 
shadeSpan16_radial_mirror(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1373 void shadeSpan16_radial_mirror(SkScalar sfx, SkScalar sdx,
1374         SkScalar sfy, SkScalar sdy,
1375         uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
1376         int toggle, int count) {
1377     do {
1378 #ifdef SK_SCALAR_IS_FLOAT
1379         float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
1380         SkFixed dist = SkFloatToFixed(fdist);
1381 #else
1382         SkFixed magnitudeSquared = SkFixedSquare(sfx) +
1383             SkFixedSquare(sfy);
1384         if (magnitudeSquared < 0) // Overflow.
1385             magnitudeSquared = SK_FixedMax;
1386         SkFixed dist = SkFixedSqrt(magnitudeSquared);
1387 #endif
1388         unsigned fi = mirror_tileproc(dist);
1389         SkASSERT(fi <= 0xFFFF);
1390         *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
1391         toggle ^= Gradient_Shader::kDitherStride16;
1392         sfx += sdx;
1393         sfy += sdy;
1394     } while (--count != 0);
1395 }
1396 
shadeSpan16_radial_repeat(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,uint16_t * SK_RESTRICT dstC,const uint16_t * SK_RESTRICT cache,int toggle,int count)1397 void shadeSpan16_radial_repeat(SkScalar sfx, SkScalar sdx,
1398         SkScalar sfy, SkScalar sdy,
1399         uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache,
1400         int toggle, int count) {
1401     SkFixed fx = SkScalarToFixed(sfx);
1402     SkFixed dx = SkScalarToFixed(sdx);
1403     SkFixed fy = SkScalarToFixed(sfy);
1404     SkFixed dy = SkScalarToFixed(sdy);
1405     do {
1406         SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
1407         unsigned fi = repeat_tileproc(dist);
1408         SkASSERT(fi <= 0xFFFF);
1409         fx += dx;
1410         fy += dy;
1411         *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
1412         toggle ^= Gradient_Shader::kDitherStride16;
1413     } while (--count != 0);
1414 }
1415 
1416 }
1417 
1418 class Radial_Gradient : public Gradient_Shader {
1419 public:
Radial_Gradient(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)1420     Radial_Gradient(const SkPoint& center, SkScalar radius,
1421                     const SkColor colors[], const SkScalar pos[], int colorCount,
1422                     SkShader::TileMode mode, SkUnitMapper* mapper)
1423         : Gradient_Shader(colors, pos, colorCount, mode, mapper),
1424           fCenter(center),
1425           fRadius(radius)
1426     {
1427         // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
1428         SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
1429 
1430         rad_to_unit_matrix(center, radius, &fPtsToUnit);
1431     }
1432 
1433     virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count)
1434         SK_OVERRIDE;
shadeSpan16(int x,int y,uint16_t * SK_RESTRICT dstC,int count)1435     virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
1436                              int count) SK_OVERRIDE {
1437         SkASSERT(count > 0);
1438 
1439         SkPoint             srcPt;
1440         SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1441         TileProc            proc = fTileProc;
1442         const uint16_t* SK_RESTRICT cache = this->getCache16();
1443         int                 toggle = ((x ^ y) & 1) * kDitherStride16;
1444 
1445         if (fDstToIndexClass != kPerspective_MatrixClass) {
1446             dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1447                                  SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1448 
1449             SkScalar sdx = fDstToIndex.getScaleX();
1450             SkScalar sdy = fDstToIndex.getSkewY();
1451 
1452             if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1453                 SkFixed storage[2];
1454                 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
1455                                                &storage[0], &storage[1]);
1456                 sdx = SkFixedToScalar(storage[0]);
1457                 sdy = SkFixedToScalar(storage[1]);
1458             } else {
1459                 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1460             }
1461 
1462             RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
1463             if (proc == clamp_tileproc) {
1464                 shadeProc = shadeSpan16_radial_clamp;
1465             } else if (proc == mirror_tileproc) {
1466                 shadeProc = shadeSpan16_radial_mirror;
1467             } else {
1468                 SkASSERT(proc == repeat_tileproc);
1469             }
1470             (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC,
1471                          cache, toggle, count);
1472         } else {    // perspective case
1473             SkScalar dstX = SkIntToScalar(x);
1474             SkScalar dstY = SkIntToScalar(y);
1475             do {
1476                 dstProc(fDstToIndex, dstX, dstY, &srcPt);
1477                 unsigned fi = proc(SkScalarToFixed(srcPt.length()));
1478                 SkASSERT(fi <= 0xFFFF);
1479 
1480                 int index = fi >> (16 - kCache16Bits);
1481                 *dstC++ = cache[toggle + index];
1482                 toggle ^= kDitherStride16;
1483 
1484                 dstX += SK_Scalar1;
1485             } while (--count != 0);
1486         }
1487     }
1488 
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode * xy,SkScalar * twoPointRadialParams) const1489     virtual BitmapType asABitmap(SkBitmap* bitmap,
1490                                  SkMatrix* matrix,
1491                                  TileMode* xy,
1492                                  SkScalar* twoPointRadialParams)
1493             const SK_OVERRIDE {
1494         if (bitmap) {
1495             this->commonAsABitmap(bitmap);
1496         }
1497         if (matrix) {
1498             matrix->setScale(SkIntToScalar(kGradient32Length),
1499                              SkIntToScalar(kGradient32Length));
1500             matrix->preConcat(fPtsToUnit);
1501         }
1502         if (xy) {
1503             xy[0] = fTileMode;
1504             xy[1] = kClamp_TileMode;
1505         }
1506         return kRadial_BitmapType;
1507     }
asAGradient(GradientInfo * info) const1508     virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
1509         if (info) {
1510             commonAsAGradient(info);
1511             info->fPoint[0] = fCenter;
1512             info->fRadius[0] = fRadius;
1513         }
1514         return kRadial_GradientType;
1515     }
1516 
CreateProc(SkFlattenableReadBuffer & buffer)1517     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
1518         return SkNEW_ARGS(Radial_Gradient, (buffer));
1519     }
1520 
flatten(SkFlattenableWriteBuffer & buffer)1521     virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
1522         this->INHERITED::flatten(buffer);
1523         buffer.writeScalar(fCenter.fX);
1524         buffer.writeScalar(fCenter.fY);
1525         buffer.writeScalar(fRadius);
1526     }
1527 
1528 protected:
Radial_Gradient(SkFlattenableReadBuffer & buffer)1529     Radial_Gradient(SkFlattenableReadBuffer& buffer)
1530         : Gradient_Shader(buffer),
1531           fCenter(unflatten_point(buffer)),
1532           fRadius(buffer.readScalar()) {
1533     }
getFactory()1534     virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
1535 
1536 private:
1537     typedef Gradient_Shader INHERITED;
1538     const SkPoint fCenter;
1539     const SkScalar fRadius;
1540 };
1541 
1542 namespace {
1543 
radial_completely_pinned(int fx,int dx,int fy,int dy)1544 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
1545     // fast, overly-conservative test: checks unit square instead
1546     // of unit circle
1547     bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
1548                     (fx <= -SK_FixedHalf && dx <= 0);
1549     bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
1550                     (fy <= -SK_FixedHalf && dy <= 0);
1551 
1552     return xClamped || yClamped;
1553 }
1554 
1555 // Return true if (fx * fy) is always inside the unit circle
1556 // SkPin32 is expensive, but so are all the SkFixedMul in this test,
1557 // so it shouldn't be run if count is small.
no_need_for_radial_pin(int fx,int dx,int fy,int dy,int count)1558 inline bool no_need_for_radial_pin(int fx, int dx,
1559                                           int fy, int dy, int count) {
1560     SkASSERT(count > 0);
1561     if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
1562         return false;
1563     }
1564     if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
1565         return false;
1566     }
1567     fx += (count - 1) * dx;
1568     fy += (count - 1) * dy;
1569     if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
1570         return false;
1571     }
1572     return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
1573 }
1574 
1575 #define UNPINNED_RADIAL_STEP \
1576     fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
1577     *dstC++ = cache[toggle + \
1578                     (sqrt_table[fi] >> Gradient_Shader::kSqrt32Shift)]; \
1579     toggle ^= Gradient_Shader::kDitherStride32; \
1580     fx += dx; \
1581     fy += dy;
1582 
1583 typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx,
1584         SkScalar sfy, SkScalar sdy,
1585         SkPMColor* dstC, const SkPMColor* cache,
1586         int count, int toggle);
1587 
1588 // On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
shadeSpan_radial_clamp(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count,int toggle)1589 void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
1590         SkScalar sfy, SkScalar sdy,
1591         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1592         int count, int toggle) {
1593     // Floating point seems to be slower than fixed point,
1594     // even when we have float hardware.
1595     const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
1596     SkFixed fx = SkScalarToFixed(sfx) >> 1;
1597     SkFixed dx = SkScalarToFixed(sdx) >> 1;
1598     SkFixed fy = SkScalarToFixed(sfy) >> 1;
1599     SkFixed dy = SkScalarToFixed(sdy) >> 1;
1600     if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
1601         unsigned fi = Gradient_Shader::kGradient32Length;
1602         sk_memset32_dither(dstC,
1603             cache[toggle + fi],
1604             cache[(toggle ^ Gradient_Shader::kDitherStride32) + fi],
1605             count);
1606     } else if ((count > 4) &&
1607                no_need_for_radial_pin(fx, dx, fy, dy, count)) {
1608         unsigned fi;
1609         // 4x unroll appears to be no faster than 2x unroll on Linux
1610         while (count > 1) {
1611             UNPINNED_RADIAL_STEP;
1612             UNPINNED_RADIAL_STEP;
1613             count -= 2;
1614         }
1615         if (count) {
1616             UNPINNED_RADIAL_STEP;
1617         }
1618     }
1619     else  {
1620         // Specializing for dy == 0 gains us 25% on Skia benchmarks
1621         if (dy == 0) {
1622             unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1623             yy *= yy;
1624             do {
1625                 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1626                 unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS);
1627                 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1628                 *dstC++ = cache[toggle + (sqrt_table[fi] >>
1629                     Gradient_Shader::kSqrt32Shift)];
1630                 toggle ^= Gradient_Shader::kDitherStride32;
1631                 fx += dx;
1632             } while (--count != 0);
1633         } else {
1634             do {
1635                 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
1636                 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
1637                 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
1638                 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
1639                 *dstC++ = cache[toggle + (sqrt_table[fi] >>
1640                     Gradient_Shader::kSqrt32Shift)];
1641                 toggle ^= Gradient_Shader::kDitherStride32;
1642                 fx += dx;
1643                 fy += dy;
1644             } while (--count != 0);
1645         }
1646     }
1647 }
1648 
1649 // Unrolling this loop doesn't seem to help (when float); we're stalling to
1650 // get the results of the sqrt (?), and don't have enough extra registers to
1651 // have many in flight.
shadeSpan_radial_mirror(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count,int toggle)1652 void shadeSpan_radial_mirror(SkScalar sfx, SkScalar sdx,
1653         SkScalar sfy, SkScalar sdy,
1654         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1655         int count, int toggle) {
1656     do {
1657 #ifdef SK_SCALAR_IS_FLOAT
1658         float fdist = sk_float_sqrt(sfx*sfx + sfy*sfy);
1659         SkFixed dist = SkFloatToFixed(fdist);
1660 #else
1661         SkFixed magnitudeSquared = SkFixedSquare(sfx) +
1662             SkFixedSquare(sfy);
1663         if (magnitudeSquared < 0) // Overflow.
1664             magnitudeSquared = SK_FixedMax;
1665         SkFixed dist = SkFixedSqrt(magnitudeSquared);
1666 #endif
1667         unsigned fi = mirror_tileproc(dist);
1668         SkASSERT(fi <= 0xFFFF);
1669         *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache32Shift)];
1670         toggle ^= Gradient_Shader::kDitherStride32;
1671         sfx += sdx;
1672         sfy += sdy;
1673     } while (--count != 0);
1674 }
1675 
shadeSpan_radial_repeat(SkScalar sfx,SkScalar sdx,SkScalar sfy,SkScalar sdy,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count,int toggle)1676 void shadeSpan_radial_repeat(SkScalar sfx, SkScalar sdx,
1677         SkScalar sfy, SkScalar sdy,
1678         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1679         int count, int toggle) {
1680     SkFixed fx = SkScalarToFixed(sfx);
1681     SkFixed dx = SkScalarToFixed(sdx);
1682     SkFixed fy = SkScalarToFixed(sfy);
1683     SkFixed dy = SkScalarToFixed(sdy);
1684     do {
1685         SkFixed magnitudeSquared = SkFixedSquare(fx) +
1686             SkFixedSquare(fy);
1687         if (magnitudeSquared < 0) // Overflow.
1688             magnitudeSquared = SK_FixedMax;
1689         SkFixed dist = SkFixedSqrt(magnitudeSquared);
1690         unsigned fi = repeat_tileproc(dist);
1691         SkASSERT(fi <= 0xFFFF);
1692         *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache32Shift)];
1693         toggle ^= Gradient_Shader::kDitherStride32;
1694         fx += dx;
1695         fy += dy;
1696     } while (--count != 0);
1697 }
1698 }
1699 
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)1700 void Radial_Gradient::shadeSpan(int x, int y,
1701                                 SkPMColor* SK_RESTRICT dstC, int count) {
1702     SkASSERT(count > 0);
1703 
1704     SkPoint             srcPt;
1705     SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1706     TileProc            proc = fTileProc;
1707     const SkPMColor* SK_RESTRICT cache = this->getCache32();
1708 #ifdef USE_DITHER_32BIT_GRADIENT
1709     int toggle = ((x ^ y) & 1) * Gradient_Shader::kDitherStride32;
1710 #else
1711     int toggle = 0;
1712 #endif
1713 
1714     if (fDstToIndexClass != kPerspective_MatrixClass) {
1715         dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1716                              SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1717         SkScalar sdx = fDstToIndex.getScaleX();
1718         SkScalar sdy = fDstToIndex.getSkewY();
1719 
1720         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1721             SkFixed storage[2];
1722             (void)fDstToIndex.fixedStepInX(SkIntToScalar(y),
1723                                            &storage[0], &storage[1]);
1724             sdx = SkFixedToScalar(storage[0]);
1725             sdy = SkFixedToScalar(storage[1]);
1726         } else {
1727             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
1728         }
1729 
1730         RadialShadeProc shadeProc = shadeSpan_radial_repeat;
1731         if (proc == clamp_tileproc) {
1732             shadeProc = shadeSpan_radial_clamp;
1733         } else if (proc == mirror_tileproc) {
1734             shadeProc = shadeSpan_radial_mirror;
1735         } else {
1736             SkASSERT(proc == repeat_tileproc);
1737         }
1738         (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle);
1739     } else {    // perspective case
1740         SkScalar dstX = SkIntToScalar(x);
1741         SkScalar dstY = SkIntToScalar(y);
1742         do {
1743             dstProc(fDstToIndex, dstX, dstY, &srcPt);
1744             unsigned fi = proc(SkScalarToFixed(srcPt.length()));
1745             SkASSERT(fi <= 0xFFFF);
1746             *dstC++ = cache[fi >> Gradient_Shader::kCache32Shift];
1747             dstX += SK_Scalar1;
1748         } while (--count != 0);
1749     }
1750 }
1751 
1752 /* Two-point radial gradients are specified by two circles, each with a center
1753    point and radius.  The gradient can be considered to be a series of
1754    concentric circles, with the color interpolated from the start circle
1755    (at t=0) to the end circle (at t=1).
1756 
1757    For each point (x, y) in the span, we want to find the
1758    interpolated circle that intersects that point.  The center
1759    of the desired circle (Cx, Cy) falls at some distance t
1760    along the line segment between the start point (Sx, Sy) and
1761    end point (Ex, Ey):
1762 
1763       Cx = (1 - t) * Sx + t * Ex        (0 <= t <= 1)
1764       Cy = (1 - t) * Sy + t * Ey
1765 
1766    The radius of the desired circle (r) is also a linear interpolation t
1767    between the start and end radii (Sr and Er):
1768 
1769       r = (1 - t) * Sr + t * Er
1770 
1771    But
1772 
1773       (x - Cx)^2 + (y - Cy)^2 = r^2
1774 
1775    so
1776 
1777      (x - ((1 - t) * Sx + t * Ex))^2
1778    + (y - ((1 - t) * Sy + t * Ey))^2
1779    = ((1 - t) * Sr + t * Er)^2
1780 
1781    Solving for t yields
1782 
1783      [(Sx - Ex)^2 + (Sy - Ey)^2 - (Er - Sr)^2)] * t^2
1784    + [2 * (Sx - Ex)(x - Sx) + 2 * (Sy - Ey)(y - Sy) - 2 * (Er - Sr) * Sr] * t
1785    + [(x - Sx)^2 + (y - Sy)^2 - Sr^2] = 0
1786 
1787    To simplify, let Dx = Sx - Ex, Dy = Sy - Ey, Dr = Er - Sr, dx = x - Sx, dy = y - Sy
1788 
1789      [Dx^2 + Dy^2 - Dr^2)] * t^2
1790    + 2 * [Dx * dx + Dy * dy - Dr * Sr] * t
1791    + [dx^2 + dy^2 - Sr^2] = 0
1792 
1793    A quadratic in t.  The two roots of the quadratic reflect the two
1794    possible circles on which the point may fall.  Solving for t yields
1795    the gradient value to use.
1796 
1797    If a<0, the start circle is entirely contained in the
1798    end circle, and one of the roots will be <0 or >1 (off the line
1799    segment).  If a>0, the start circle falls at least partially
1800    outside the end circle (or vice versa), and the gradient
1801    defines a "tube" where a point may be on one circle (on the
1802    inside of the tube) or the other (outside of the tube).  We choose
1803    one arbitrarily.
1804 
1805    In order to keep the math to within the limits of fixed point,
1806    we divide the entire quadratic by Dr^2, and replace
1807    (x - Sx)/Dr with x' and (y - Sy)/Dr with y', giving
1808 
1809    [Dx^2 / Dr^2 + Dy^2 / Dr^2 - 1)] * t^2
1810    + 2 * [x' * Dx / Dr + y' * Dy / Dr - Sr / Dr] * t
1811    + [x'^2 + y'^2 - Sr^2/Dr^2] = 0
1812 
1813    (x' and y' are computed by appending the subtract and scale to the
1814    fDstToIndex matrix in the constructor).
1815 
1816    Since the 'A' component of the quadratic is independent of x' and y', it
1817    is precomputed in the constructor.  Since the 'B' component is linear in
1818    x' and y', if x and y are linear in the span, 'B' can be computed
1819    incrementally with a simple delta (db below).  If it is not (e.g.,
1820    a perspective projection), it must be computed in the loop.
1821 
1822 */
1823 
1824 namespace {
1825 
two_point_radial(SkScalar b,SkScalar fx,SkScalar fy,SkScalar sr2d2,SkScalar foura,SkScalar oneOverTwoA,bool posRoot)1826 inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
1827                                 SkScalar sr2d2, SkScalar foura,
1828                                 SkScalar oneOverTwoA, bool posRoot) {
1829     SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
1830     if (0 == foura) {
1831         return SkScalarToFixed(SkScalarDiv(-c, b));
1832     }
1833 
1834     SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
1835     if (discrim < 0) {
1836         discrim = -discrim;
1837     }
1838     SkScalar rootDiscrim = SkScalarSqrt(discrim);
1839     SkScalar result;
1840     if (posRoot) {
1841         result = SkScalarMul(-b + rootDiscrim, oneOverTwoA);
1842     } else {
1843         result = SkScalarMul(-b - rootDiscrim, oneOverTwoA);
1844     }
1845     return SkScalarToFixed(result);
1846 }
1847 
1848 typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
1849         SkScalar fy, SkScalar dy,
1850         SkScalar b, SkScalar db,
1851         SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1852         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1853         int count);
1854 
shadeSpan_twopoint_clamp(SkScalar fx,SkScalar dx,SkScalar fy,SkScalar dy,SkScalar b,SkScalar db,SkScalar fSr2D2,SkScalar foura,SkScalar fOneOverTwoA,bool posRoot,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count)1855 void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
1856         SkScalar fy, SkScalar dy,
1857         SkScalar b, SkScalar db,
1858         SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1859         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1860         int count) {
1861     for (; count > 0; --count) {
1862         SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
1863                                      fOneOverTwoA, posRoot);
1864         SkFixed index = SkClampMax(t, 0xFFFF);
1865         SkASSERT(index <= 0xFFFF);
1866         *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
1867         fx += dx;
1868         fy += dy;
1869         b += db;
1870     }
1871 }
shadeSpan_twopoint_mirror(SkScalar fx,SkScalar dx,SkScalar fy,SkScalar dy,SkScalar b,SkScalar db,SkScalar fSr2D2,SkScalar foura,SkScalar fOneOverTwoA,bool posRoot,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count)1872 void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
1873         SkScalar fy, SkScalar dy,
1874         SkScalar b, SkScalar db,
1875         SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1876         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1877         int count) {
1878     for (; count > 0; --count) {
1879         SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
1880                                      fOneOverTwoA, posRoot);
1881         SkFixed index = mirror_tileproc(t);
1882         SkASSERT(index <= 0xFFFF);
1883         *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
1884         fx += dx;
1885         fy += dy;
1886         b += db;
1887     }
1888 }
1889 
shadeSpan_twopoint_repeat(SkScalar fx,SkScalar dx,SkScalar fy,SkScalar dy,SkScalar b,SkScalar db,SkScalar fSr2D2,SkScalar foura,SkScalar fOneOverTwoA,bool posRoot,SkPMColor * SK_RESTRICT dstC,const SkPMColor * SK_RESTRICT cache,int count)1890 void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
1891         SkScalar fy, SkScalar dy,
1892         SkScalar b, SkScalar db,
1893         SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
1894         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
1895         int count) {
1896     for (; count > 0; --count) {
1897         SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
1898                                      fOneOverTwoA, posRoot);
1899         SkFixed index = repeat_tileproc(t);
1900         SkASSERT(index <= 0xFFFF);
1901         *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
1902         fx += dx;
1903         fy += dy;
1904         b += db;
1905     }
1906 }
1907 
1908 
1909 
1910 }
1911 
1912 class Two_Point_Radial_Gradient : public Gradient_Shader {
1913 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)1914     Two_Point_Radial_Gradient(const SkPoint& start, SkScalar startRadius,
1915                               const SkPoint& end, SkScalar endRadius,
1916                               const SkColor colors[], const SkScalar pos[],
1917                               int colorCount, SkShader::TileMode mode,
1918                               SkUnitMapper* mapper)
1919             : Gradient_Shader(colors, pos, colorCount, mode, mapper),
1920               fCenter1(start),
1921               fCenter2(end),
1922               fRadius1(startRadius),
1923               fRadius2(endRadius) {
1924         init();
1925     }
1926 
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode * xy,SkScalar * twoPointRadialParams) const1927     virtual BitmapType asABitmap(SkBitmap* bitmap,
1928                                  SkMatrix* matrix,
1929                                  TileMode* xy,
1930                                  SkScalar* twoPointRadialParams) const {
1931         if (bitmap) {
1932             this->commonAsABitmap(bitmap);
1933         }
1934         SkScalar diffL = 0; // just to avoid gcc warning
1935         if (matrix || twoPointRadialParams) {
1936             diffL = SkScalarSqrt(SkScalarSquare(fDiff.fX) +
1937                                  SkScalarSquare(fDiff.fY));
1938         }
1939         if (matrix) {
1940             if (diffL) {
1941                 SkScalar invDiffL = SkScalarInvert(diffL);
1942                 matrix->setSinCos(-SkScalarMul(invDiffL, fDiff.fY),
1943                                   SkScalarMul(invDiffL, fDiff.fX));
1944             } else {
1945                 matrix->reset();
1946             }
1947             matrix->preConcat(fPtsToUnit);
1948         }
1949         if (xy) {
1950             xy[0] = fTileMode;
1951             xy[1] = kClamp_TileMode;
1952         }
1953         if (NULL != twoPointRadialParams) {
1954             twoPointRadialParams[0] = diffL;
1955             twoPointRadialParams[1] = fStartRadius;
1956             twoPointRadialParams[2] = fDiffRadius;
1957         }
1958         return kTwoPointRadial_BitmapType;
1959     }
1960 
asAGradient(GradientInfo * info) const1961     virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
1962         if (info) {
1963             commonAsAGradient(info);
1964             info->fPoint[0] = fCenter1;
1965             info->fPoint[1] = fCenter2;
1966             info->fRadius[0] = fRadius1;
1967             info->fRadius[1] = fRadius2;
1968         }
1969         return kRadial2_GradientType;
1970     }
1971 
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)1972     virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
1973                            int count) SK_OVERRIDE {
1974         SkASSERT(count > 0);
1975 
1976         // Zero difference between radii:  fill with transparent black.
1977         if (fDiffRadius == 0) {
1978           sk_bzero(dstC, count * sizeof(*dstC));
1979           return;
1980         }
1981         SkMatrix::MapXYProc dstProc = fDstToIndexProc;
1982         TileProc            proc = fTileProc;
1983         const SkPMColor* SK_RESTRICT cache = this->getCache32();
1984 
1985         SkScalar foura = fA * 4;
1986         bool posRoot = fDiffRadius < 0;
1987         if (fDstToIndexClass != kPerspective_MatrixClass) {
1988             SkPoint srcPt;
1989             dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
1990                                  SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
1991             SkScalar dx, fx = srcPt.fX;
1992             SkScalar dy, fy = srcPt.fY;
1993 
1994             if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
1995                 SkFixed fixedX, fixedY;
1996                 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
1997                 dx = SkFixedToScalar(fixedX);
1998                 dy = SkFixedToScalar(fixedY);
1999             } else {
2000                 SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2001                 dx = fDstToIndex.getScaleX();
2002                 dy = fDstToIndex.getSkewY();
2003             }
2004             SkScalar b = (SkScalarMul(fDiff.fX, fx) +
2005                          SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
2006             SkScalar db = (SkScalarMul(fDiff.fX, dx) +
2007                           SkScalarMul(fDiff.fY, dy)) * 2;
2008 
2009             TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
2010             if (proc == clamp_tileproc) {
2011                 shadeProc = shadeSpan_twopoint_clamp;
2012             } else if (proc == mirror_tileproc) {
2013                 shadeProc = shadeSpan_twopoint_mirror;
2014             } else {
2015                 SkASSERT(proc == repeat_tileproc);
2016             }
2017             (*shadeProc)(fx, dx, fy, dy, b, db,
2018                          fSr2D2, foura, fOneOverTwoA, posRoot,
2019                          dstC, cache, count);
2020         } else {    // perspective case
2021             SkScalar dstX = SkIntToScalar(x);
2022             SkScalar dstY = SkIntToScalar(y);
2023             for (; count > 0; --count) {
2024                 SkPoint             srcPt;
2025                 dstProc(fDstToIndex, dstX, dstY, &srcPt);
2026                 SkScalar fx = srcPt.fX;
2027                 SkScalar fy = srcPt.fY;
2028                 SkScalar b = (SkScalarMul(fDiff.fX, fx) +
2029                              SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
2030                 SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
2031                                              fOneOverTwoA, posRoot);
2032                 SkFixed index = proc(t);
2033                 SkASSERT(index <= 0xFFFF);
2034                 *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
2035                 dstX += SK_Scalar1;
2036             }
2037         }
2038     }
2039 
setContext(const SkBitmap & device,const SkPaint & paint,const SkMatrix & matrix)2040     virtual bool setContext(const SkBitmap& device,
2041                             const SkPaint& paint,
2042                             const SkMatrix& matrix) SK_OVERRIDE {
2043         if (!this->INHERITED::setContext(device, paint, matrix)) {
2044             return false;
2045         }
2046 
2047         // we don't have a span16 proc
2048         fFlags &= ~kHasSpan16_Flag;
2049         return true;
2050     }
2051 
CreateProc(SkFlattenableReadBuffer & buffer)2052     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2053         return SkNEW_ARGS(Two_Point_Radial_Gradient, (buffer));
2054     }
2055 
flatten(SkFlattenableWriteBuffer & buffer)2056     virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
2057         this->INHERITED::flatten(buffer);
2058         buffer.writeScalar(fCenter1.fX);
2059         buffer.writeScalar(fCenter1.fY);
2060         buffer.writeScalar(fCenter2.fX);
2061         buffer.writeScalar(fCenter2.fY);
2062         buffer.writeScalar(fRadius1);
2063         buffer.writeScalar(fRadius2);
2064     }
2065 
2066 protected:
Two_Point_Radial_Gradient(SkFlattenableReadBuffer & buffer)2067     Two_Point_Radial_Gradient(SkFlattenableReadBuffer& buffer)
2068             : Gradient_Shader(buffer),
2069               fCenter1(unflatten_point(buffer)),
2070               fCenter2(unflatten_point(buffer)),
2071               fRadius1(buffer.readScalar()),
2072               fRadius2(buffer.readScalar()) {
2073         init();
2074     };
getFactory()2075     virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
2076 
2077 private:
2078     typedef Gradient_Shader INHERITED;
2079     const SkPoint fCenter1;
2080     const SkPoint fCenter2;
2081     const SkScalar fRadius1;
2082     const SkScalar fRadius2;
2083     SkPoint fDiff;
2084     SkScalar fStartRadius, fDiffRadius, fSr2D2, fA, fOneOverTwoA;
2085 
init()2086     void init() {
2087         fDiff = fCenter1 - fCenter2;
2088         fDiffRadius = fRadius2 - fRadius1;
2089         SkScalar inv = SkScalarInvert(fDiffRadius);
2090         fDiff.fX = SkScalarMul(fDiff.fX, inv);
2091         fDiff.fY = SkScalarMul(fDiff.fY, inv);
2092         fStartRadius = SkScalarMul(fRadius1, inv);
2093         fSr2D2 = SkScalarSquare(fStartRadius);
2094         fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
2095         fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
2096 
2097         fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
2098         fPtsToUnit.postScale(inv, inv);
2099     }
2100 };
2101 
2102 ///////////////////////////////////////////////////////////////////////////////
2103 
2104 class Sweep_Gradient : public Gradient_Shader {
2105 public:
Sweep_Gradient(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int count,SkUnitMapper * mapper)2106     Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
2107                    const SkScalar pos[], int count, SkUnitMapper* mapper)
2108     : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper),
2109       fCenter(SkPoint::Make(cx, cy))
2110     {
2111         fPtsToUnit.setTranslate(-cx, -cy);
2112     }
2113     virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
2114     virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
2115 
asABitmap(SkBitmap * bitmap,SkMatrix * matrix,TileMode * xy,SkScalar * twoPointRadialParams) const2116     virtual BitmapType asABitmap(SkBitmap* bitmap,
2117                                  SkMatrix* matrix,
2118                                  TileMode* xy,
2119                                  SkScalar* twoPointRadialParams) const SK_OVERRIDE {
2120         if (bitmap) {
2121             this->commonAsABitmap(bitmap);
2122         }
2123         if (matrix) {
2124             *matrix = fPtsToUnit;
2125         }
2126         if (xy) {
2127             xy[0] = fTileMode;
2128             xy[1] = kClamp_TileMode;
2129         }
2130         return kSweep_BitmapType;
2131     }
2132 
asAGradient(GradientInfo * info) const2133     virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
2134         if (info) {
2135             commonAsAGradient(info);
2136             info->fPoint[0] = fCenter;
2137         }
2138         return kSweep_GradientType;
2139     }
2140 
CreateProc(SkFlattenableReadBuffer & buffer)2141     static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2142         return SkNEW_ARGS(Sweep_Gradient, (buffer));
2143     }
2144 
flatten(SkFlattenableWriteBuffer & buffer)2145     virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
2146         this->INHERITED::flatten(buffer);
2147         buffer.writeScalar(fCenter.fX);
2148         buffer.writeScalar(fCenter.fY);
2149     }
2150 
2151 protected:
Sweep_Gradient(SkFlattenableReadBuffer & buffer)2152     Sweep_Gradient(SkFlattenableReadBuffer& buffer)
2153         : Gradient_Shader(buffer),
2154           fCenter(unflatten_point(buffer)) {
2155     }
2156 
getFactory()2157     virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
2158 
2159 private:
2160     typedef Gradient_Shader INHERITED;
2161     const SkPoint fCenter;
2162 };
2163 
2164 #ifdef COMPUTE_SWEEP_TABLE
2165 #define PI  3.14159265
2166 static bool gSweepTableReady;
2167 static uint8_t gSweepTable[65];
2168 
2169 /*  Our table stores precomputed values for atan: [0...1] -> [0..PI/4]
2170     We scale the results to [0..32]
2171 */
build_sweep_table()2172 static const uint8_t* build_sweep_table() {
2173     if (!gSweepTableReady) {
2174         const int N = 65;
2175         const double DENOM = N - 1;
2176 
2177         for (int i = 0; i < N; i++)
2178         {
2179             double arg = i / DENOM;
2180             double v = atan(arg);
2181             int iv = (int)round(v * DENOM * 2 / PI);
2182 //            printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv);
2183             printf("%d, ", iv);
2184             gSweepTable[i] = iv;
2185         }
2186         gSweepTableReady = true;
2187     }
2188     return gSweepTable;
2189 }
2190 #else
2191 static const uint8_t gSweepTable[] = {
2192     0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9,
2193     10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18,
2194     19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26,
2195     26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32,
2196     32
2197 };
build_sweep_table()2198 static const uint8_t* build_sweep_table() { return gSweepTable; }
2199 #endif
2200 
2201 // divide numer/denom, with a bias of 6bits. Assumes numer <= denom
2202 // and denom != 0. Since our table is 6bits big (+1), this is a nice fit.
2203 // Same as (but faster than) SkFixedDiv(numer, denom) >> 10
2204 
2205 //unsigned div_64(int numer, int denom);
div_64(int numer,int denom)2206 static unsigned div_64(int numer, int denom) {
2207     SkASSERT(numer <= denom);
2208     SkASSERT(numer > 0);
2209     SkASSERT(denom > 0);
2210 
2211     int nbits = SkCLZ(numer);
2212     int dbits = SkCLZ(denom);
2213     int bits = 6 - nbits + dbits;
2214     SkASSERT(bits <= 6);
2215 
2216     if (bits < 0) {  // detect underflow
2217         return 0;
2218     }
2219 
2220     denom <<= dbits - 1;
2221     numer <<= nbits - 1;
2222 
2223     unsigned result = 0;
2224 
2225     // do the first one
2226     if ((numer -= denom) >= 0) {
2227         result = 1;
2228     } else {
2229         numer += denom;
2230     }
2231 
2232     // Now fall into our switch statement if there are more bits to compute
2233     if (bits > 0) {
2234         // make room for the rest of the answer bits
2235         result <<= bits;
2236         switch (bits) {
2237         case 6:
2238             if ((numer = (numer << 1) - denom) >= 0)
2239                 result |= 32;
2240             else
2241                 numer += denom;
2242         case 5:
2243             if ((numer = (numer << 1) - denom) >= 0)
2244                 result |= 16;
2245             else
2246                 numer += denom;
2247         case 4:
2248             if ((numer = (numer << 1) - denom) >= 0)
2249                 result |= 8;
2250             else
2251                 numer += denom;
2252         case 3:
2253             if ((numer = (numer << 1) - denom) >= 0)
2254                 result |= 4;
2255             else
2256                 numer += denom;
2257         case 2:
2258             if ((numer = (numer << 1) - denom) >= 0)
2259                 result |= 2;
2260             else
2261                 numer += denom;
2262         case 1:
2263         default:    // not strictly need, but makes GCC make better ARM code
2264             if ((numer = (numer << 1) - denom) >= 0)
2265                 result |= 1;
2266             else
2267                 numer += denom;
2268         }
2269     }
2270     return result;
2271 }
2272 
2273 // Given x,y in the first quadrant, return 0..63 for the angle [0..90]
atan_0_90(SkFixed y,SkFixed x)2274 static unsigned atan_0_90(SkFixed y, SkFixed x) {
2275 #ifdef SK_DEBUG
2276     {
2277         static bool gOnce;
2278         if (!gOnce) {
2279             gOnce = true;
2280             SkASSERT(div_64(55, 55) == 64);
2281             SkASSERT(div_64(128, 256) == 32);
2282             SkASSERT(div_64(2326528, 4685824) == 31);
2283             SkASSERT(div_64(753664, 5210112) == 9);
2284             SkASSERT(div_64(229376, 4882432) == 3);
2285             SkASSERT(div_64(2, 64) == 2);
2286             SkASSERT(div_64(1, 64) == 1);
2287             // test that we handle underflow correctly
2288             SkASSERT(div_64(12345, 0x54321234) == 0);
2289         }
2290     }
2291 #endif
2292 
2293     SkASSERT(y > 0 && x > 0);
2294     const uint8_t* table = build_sweep_table();
2295 
2296     unsigned result;
2297     bool swap = (x < y);
2298     if (swap) {
2299         // first part of the atan(v) = PI/2 - atan(1/v) identity
2300         // since our div_64 and table want v <= 1, where v = y/x
2301         SkTSwap<SkFixed>(x, y);
2302     }
2303 
2304     result = div_64(y, x);
2305 
2306 #ifdef SK_DEBUG
2307     {
2308         unsigned result2 = SkDivBits(y, x, 6);
2309         SkASSERT(result2 == result ||
2310                  (result == 1 && result2 == 0));
2311     }
2312 #endif
2313 
2314     SkASSERT(result < SK_ARRAY_COUNT(gSweepTable));
2315     result = table[result];
2316 
2317     if (swap) {
2318         // complete the atan(v) = PI/2 - atan(1/v) identity
2319         result = 64 - result;
2320         // pin to 63
2321         result -= result >> 6;
2322     }
2323 
2324     SkASSERT(result <= 63);
2325     return result;
2326 }
2327 
2328 //  returns angle in a circle [0..2PI) -> [0..255]
2329 #ifdef SK_SCALAR_IS_FLOAT
SkATan2_255(float y,float x)2330 static unsigned SkATan2_255(float y, float x) {
2331     //    static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
2332     static const float g255Over2PI = 40.584510488433314f;
2333 
2334     float result = sk_float_atan2(y, x);
2335     if (result < 0) {
2336         result += 2 * SK_ScalarPI;
2337     }
2338     SkASSERT(result >= 0);
2339     // since our value is always >= 0, we can cast to int, which is faster than
2340     // calling floorf()
2341     int ir = (int)(result * g255Over2PI);
2342     SkASSERT(ir >= 0 && ir <= 255);
2343     return ir;
2344 }
2345 #else
SkATan2_255(SkFixed y,SkFixed x)2346 static unsigned SkATan2_255(SkFixed y, SkFixed x) {
2347     if (x == 0) {
2348         if (y == 0) {
2349             return 0;
2350         }
2351         return y < 0 ? 192 : 64;
2352     }
2353     if (y == 0) {
2354         return x < 0 ? 128 : 0;
2355     }
2356 
2357     /*  Find the right quadrant for x,y
2358         Since atan_0_90 only handles the first quadrant, we rotate x,y
2359         appropriately before calling it, and then add the right amount
2360         to account for the real quadrant.
2361         quadrant 0 : add 0                  | x > 0 && y > 0
2362         quadrant 1 : add 64 (90 degrees)    | x < 0 && y > 0
2363         quadrant 2 : add 128 (180 degrees)  | x < 0 && y < 0
2364         quadrant 3 : add 192 (270 degrees)  | x > 0 && y < 0
2365 
2366         map x<0 to (1 << 6)
2367         map y<0 to (3 << 6)
2368         add = map_x ^ map_y
2369     */
2370     int xsign = x >> 31;
2371     int ysign = y >> 31;
2372     int add = ((-xsign) ^ (ysign & 3)) << 6;
2373 
2374 #ifdef SK_DEBUG
2375     if (0 == add)
2376         SkASSERT(x > 0 && y > 0);
2377     else if (64 == add)
2378         SkASSERT(x < 0 && y > 0);
2379     else if (128 == add)
2380         SkASSERT(x < 0 && y < 0);
2381     else if (192 == add)
2382         SkASSERT(x > 0 && y < 0);
2383     else
2384         SkDEBUGFAIL("bad value for add");
2385 #endif
2386 
2387     /*  This ^ trick makes x, y positive, and the swap<> handles quadrants
2388         where we need to rotate x,y by 90 or -90
2389     */
2390     x = (x ^ xsign) - xsign;
2391     y = (y ^ ysign) - ysign;
2392     if (add & 64) {             // quads 1 or 3 need to swap x,y
2393         SkTSwap<SkFixed>(x, y);
2394     }
2395 
2396     unsigned result = add + atan_0_90(y, x);
2397     SkASSERT(result < 256);
2398     return result;
2399 }
2400 #endif
2401 
shadeSpan(int x,int y,SkPMColor * SK_RESTRICT dstC,int count)2402 void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
2403                                int count) {
2404     SkMatrix::MapXYProc proc = fDstToIndexProc;
2405     const SkMatrix&     matrix = fDstToIndex;
2406     const SkPMColor* SK_RESTRICT cache = this->getCache32();
2407     SkPoint             srcPt;
2408 
2409     if (fDstToIndexClass != kPerspective_MatrixClass) {
2410         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2411                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2412         SkScalar dx, fx = srcPt.fX;
2413         SkScalar dy, fy = srcPt.fY;
2414 
2415         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
2416             SkFixed storage[2];
2417             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
2418                                       &storage[0], &storage[1]);
2419             dx = SkFixedToScalar(storage[0]);
2420             dy = SkFixedToScalar(storage[1]);
2421         } else {
2422             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2423             dx = matrix.getScaleX();
2424             dy = matrix.getSkewY();
2425         }
2426 
2427         for (; count > 0; --count) {
2428             *dstC++ = cache[SkATan2_255(fy, fx)];
2429             fx += dx;
2430             fy += dy;
2431         }
2432     } else {  // perspective case
2433         for (int stop = x + count; x < stop; x++) {
2434             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2435                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2436             *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
2437         }
2438     }
2439 }
2440 
shadeSpan16(int x,int y,uint16_t * SK_RESTRICT dstC,int count)2441 void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC,
2442                                  int count) {
2443     SkMatrix::MapXYProc proc = fDstToIndexProc;
2444     const SkMatrix&     matrix = fDstToIndex;
2445     const uint16_t* SK_RESTRICT cache = this->getCache16();
2446     int                 toggle = ((x ^ y) & 1) * kDitherStride16;
2447     SkPoint             srcPt;
2448 
2449     if (fDstToIndexClass != kPerspective_MatrixClass) {
2450         proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2451                      SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2452         SkScalar dx, fx = srcPt.fX;
2453         SkScalar dy, fy = srcPt.fY;
2454 
2455         if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
2456             SkFixed storage[2];
2457             (void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
2458                                       &storage[0], &storage[1]);
2459             dx = SkFixedToScalar(storage[0]);
2460             dy = SkFixedToScalar(storage[1]);
2461         } else {
2462             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
2463             dx = matrix.getScaleX();
2464             dy = matrix.getSkewY();
2465         }
2466 
2467         for (; count > 0; --count) {
2468             int index = SkATan2_255(fy, fx) >> (8 - kCache16Bits);
2469             *dstC++ = cache[toggle + index];
2470             toggle ^= kDitherStride16;
2471             fx += dx;
2472             fy += dy;
2473         }
2474     } else {  // perspective case
2475         for (int stop = x + count; x < stop; x++) {
2476             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
2477                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
2478 
2479             int index = SkATan2_255(srcPt.fY, srcPt.fX);
2480             index >>= (8 - kCache16Bits);
2481             *dstC++ = cache[toggle + index];
2482             toggle ^= kDitherStride16;
2483         }
2484     }
2485 }
2486 
2487 ///////////////////////////////////////////////////////////////////////////////
2488 ///////////////////////////////////////////////////////////////////////////////
2489 
2490 // assumes colors is SkColor* and pos is SkScalar*
2491 #define EXPAND_1_COLOR(count)               \
2492     SkColor tmp[2];                         \
2493     do {                                    \
2494         if (1 == count) {                   \
2495             tmp[0] = tmp[1] = colors[0];    \
2496             colors = tmp;                   \
2497             pos = NULL;                     \
2498             count = 2;                      \
2499         }                                   \
2500     } while (0)
2501 
CreateLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)2502 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
2503                                          const SkColor colors[],
2504                                          const SkScalar pos[], int colorCount,
2505                                          SkShader::TileMode mode,
2506                                          SkUnitMapper* mapper) {
2507     if (NULL == pts || NULL == colors || colorCount < 1) {
2508         return NULL;
2509     }
2510     EXPAND_1_COLOR(colorCount);
2511 
2512     return SkNEW_ARGS(Linear_Gradient,
2513                       (pts, colors, pos, colorCount, mode, mapper));
2514 }
2515 
CreateRadial(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)2516 SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
2517                                          const SkColor colors[],
2518                                          const SkScalar pos[], int colorCount,
2519                                          SkShader::TileMode mode,
2520                                          SkUnitMapper* mapper) {
2521     if (radius <= 0 || NULL == colors || colorCount < 1) {
2522         return NULL;
2523     }
2524     EXPAND_1_COLOR(colorCount);
2525 
2526     return SkNEW_ARGS(Radial_Gradient,
2527                       (center, radius, colors, pos, colorCount, mode, mapper));
2528 }
2529 
CreateTwoPointRadial(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,SkUnitMapper * mapper)2530 SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
2531                                                  SkScalar startRadius,
2532                                                  const SkPoint& end,
2533                                                  SkScalar endRadius,
2534                                                  const SkColor colors[],
2535                                                  const SkScalar pos[],
2536                                                  int colorCount,
2537                                                  SkShader::TileMode mode,
2538                                                  SkUnitMapper* mapper) {
2539     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
2540         return NULL;
2541     }
2542     EXPAND_1_COLOR(colorCount);
2543 
2544     return SkNEW_ARGS(Two_Point_Radial_Gradient,
2545                       (start, startRadius, end, endRadius, colors, pos,
2546                        colorCount, mode, mapper));
2547 }
2548 
CreateSweep(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int count,SkUnitMapper * mapper)2549 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
2550                                         const SkColor colors[],
2551                                         const SkScalar pos[],
2552                                         int count, SkUnitMapper* mapper) {
2553     if (NULL == colors || count < 1) {
2554         return NULL;
2555     }
2556     EXPAND_1_COLOR(count);
2557 
2558     return SkNEW_ARGS(Sweep_Gradient, (cx, cy, colors, pos, count, mapper));
2559 }
2560 
2561 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
2562     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Linear_Gradient)
2563     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Radial_Gradient)
2564 
2565     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Sweep_Gradient)
2566 
2567     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Two_Point_Radial_Gradient)
2568 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
2569