LCOV - code coverage report
Current view: directory - gfx/skia/src/effects - SkGradientShader.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1100 4 0.4 %
Date: 2012-06-02 Functions: 94 2 2.1 %

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

Generated by: LCOV version 1.7