Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / effects / gradients / SkGradientShader.cpp
index b1fa560..0d17308 100644 (file)
 #include "SkTwoPointConicalGradient.h"
 #include "SkSweepGradient.h"
 
-SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
-    SkASSERT(desc.fCount > 1);
+void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
+    buffer.writeColorArray(fColors, fCount);
+    if (fPos) {
+        buffer.writeBool(true);
+        buffer.writeScalarArray(fPos, fCount);
+    } else {
+        buffer.writeBool(false);
+    }
+    buffer.write32(fTileMode);
+    buffer.write32(fGradFlags);
+    if (fLocalMatrix) {
+        buffer.writeBool(true);
+        buffer.writeMatrix(*fLocalMatrix);
+    } else {
+        buffer.writeBool(false);
+    }
+}
+
+bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
+    fCount = buffer.getArrayCount();
+    if (fCount > kStorageCount) {
+        size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar)) * fCount;
+        fDynamicStorage.reset(allocSize);
+        fColors = (SkColor*)fDynamicStorage.get();
+        fPos = (SkScalar*)(fColors + fCount);
+    } else {
+        fColors = fColorStorage;
+        fPos = fPosStorage;
+    }
 
-    fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
+    if (!buffer.readColorArray(const_cast<SkColor*>(fColors), fCount)) {
+        return false;
+    }
+    if (buffer.readBool()) {
+        if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) {
+            return false;
+        }
+    } else {
+        fPos = NULL;
+    }
 
-    fMapper = desc.fMapper;
-    SkSafeRef(fMapper);
-    fGradFlags = SkToU8(desc.fFlags);
+    fTileMode = (SkShader::TileMode)buffer.read32();
+    fGradFlags = buffer.read32();
+
+    if (buffer.readBool()) {
+        fLocalMatrix = &fLocalMatrixStorage;
+        buffer.readMatrix(&fLocalMatrixStorage);
+    } else {
+        fLocalMatrix = NULL;
+    }
+    return buffer.isValid();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc)
+    : INHERITED(desc.fLocalMatrix)
+{
+    SkASSERT(desc.fCount > 1);
+
+    fGradFlags = SkToU8(desc.fGradFlags);
 
     SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
     SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
     fTileMode = desc.fTileMode;
     fTileProc = gTileProcs[desc.fTileMode];
 
-    fCache16 = fCache16Storage = NULL;
-    fCache32 = NULL;
-    fCache32PixelRef = NULL;
-
     /*  Note: we let the caller skip the first and/or last position.
         i.e. pos[0] = 0.3, pos[1] = 0.7
         In these cases, we insert dummy entries to ensure that the final data
@@ -53,6 +102,9 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
 
     if (fColorCount > kColorStorageCount) {
         size_t size = sizeof(SkColor) + sizeof(Rec);
+        if (desc.fPos) {
+            size += sizeof(SkScalar);
+        }
         fOrigColors = reinterpret_cast<SkColor*>(
                                         sk_malloc_throw(size * fColorCount));
     }
@@ -73,13 +125,23 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
         }
     }
 
-    fRecs = (Rec*)(fOrigColors + fColorCount);
+    if (desc.fPos && fColorCount) {
+        fOrigPos = (SkScalar*)(fOrigColors + fColorCount);
+        fRecs = (Rec*)(fOrigPos + fColorCount);
+    } else {
+        fOrigPos = NULL;
+        fRecs = (Rec*)(fOrigColors + fColorCount);
+    }
+
     if (fColorCount > 2) {
         Rec* recs = fRecs;
         recs->fPos = 0;
         //  recs->fScale = 0; // unused;
         recs += 1;
         if (desc.fPos) {
+            SkScalar* origPosPtr = fOrigPos;
+            *origPosPtr++ = 0;
+
             /*  We need to convert the user's array of relative positions into
                 fixed-point positions and scale factors. We need these results
                 to be strictly monotonic (no two values equal or out of order).
@@ -87,26 +149,23 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
                 value if it sees a segment out of order, and it assures that
                 we start at 0 and end at 1.0
             */
-            SkFixed prev = 0;
+            SkScalar prev = 0;
             int startIndex = dummyFirst ? 0 : 1;
             int count = desc.fCount + dummyLast;
             for (int i = startIndex; i < count; i++) {
                 // force the last value to be 1.0
-                SkFixed curr;
+                SkScalar curr;
                 if (i == desc.fCount) {  // we're really at the dummyLast
-                    curr = SK_Fixed1;
+                    curr = 1;
                 } else {
-                    curr = SkScalarToFixed(desc.fPos[i]);
+                    curr = SkScalarPin(desc.fPos[i], 0, 1);
                 }
-                // pin curr withing range
-                if (curr < 0) {
-                    curr = 0;
-                } else if (curr > SK_Fixed1) {
-                    curr = SK_Fixed1;
-                }
-                recs->fPos = curr;
-                if (curr > prev) {
-                    recs->fScale = (1 << 24) / (curr - prev);
+                *origPosPtr++ = curr;
+
+                recs->fPos = SkScalarToFixed(curr);
+                SkFixed diff = SkScalarToFixed(curr - prev);
+                if (diff > 0) {
+                    recs->fScale = (1 << 24) / diff;
                 } else {
                     recs->fScale = 0; // ignore this segment
                 }
@@ -115,26 +174,32 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) {
                 recs += 1;
             }
         } else {    // assume even distribution
+            fOrigPos = NULL;
+
             SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
             SkFixed p = dp;
             SkFixed scale = (desc.fCount - 1) << 8;  // (1 << 24) / dp
-            for (int i = 1; i < desc.fCount; i++) {
+            for (int i = 1; i < desc.fCount - 1; i++) {
                 recs->fPos   = p;
                 recs->fScale = scale;
                 recs += 1;
                 p += dp;
             }
+            recs->fPos = SK_Fixed1;
+            recs->fScale = scale;
+        }
+    } else if (desc.fPos) {
+        SkASSERT(2 == fColorCount);
+        fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1);
+        fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1);
+        if (0 == fOrigPos[0] && 1 == fOrigPos[1]) {
+            fOrigPos = NULL;
         }
     }
     this->initCommon();
 }
 
-static uint32_t pack_mode_flags(SkShader::TileMode mode, uint32_t flags) {
-    SkASSERT(0 == (flags >> 28));
-    SkASSERT(0 == ((uint32_t)mode >> 4));
-    return (flags << 4) | mode;
-}
-
+#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
 static SkShader::TileMode unpack_mode(uint32_t packed) {
     return (SkShader::TileMode)(packed & 0xF);
 }
@@ -144,17 +209,14 @@ static uint32_t unpack_flags(uint32_t packed) {
 }
 
 SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) {
-    fCacheAlpha = 256;
-
-    fMapper = buffer.readUnitMapper();
-
-    fCache16 = fCache16Storage = NULL;
-    fCache32 = NULL;
-    fCache32PixelRef = NULL;
+    if (buffer.isVersionLT(SkReadBuffer::kNoUnitMappers_Version)) {
+        // skip the old SkUnitMapper slot
+        buffer.skipFlattenable();
+    }
 
     int colorCount = fColorCount = buffer.getArrayCount();
     if (colorCount > kColorStorageCount) {
-        size_t allocSize = (sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount;
+        size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec)) * colorCount;
         if (buffer.validateAvailable(allocSize)) {
             fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(allocSize));
         } else {
@@ -166,38 +228,39 @@ SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buf
     }
     buffer.readColorArray(fOrigColors, colorCount);
 
+    fOrigPos = (SkScalar*)(fOrigColors + colorCount);
+
     {
         uint32_t packed = buffer.readUInt();
         fGradFlags = SkToU8(unpack_flags(packed));
         fTileMode = unpack_mode(packed);
     }
     fTileProc = gTileProcs[fTileMode];
-    fRecs = (Rec*)(fOrigColors + colorCount);
+    fRecs = (Rec*)(fOrigPos + colorCount);
     if (colorCount > 2) {
         Rec* recs = fRecs;
         recs[0].fPos = 0;
+        fOrigPos[0] = 0;
         for (int i = 1; i < colorCount; i++) {
             recs[i].fPos = buffer.readInt();
             recs[i].fScale = buffer.readUInt();
+            fOrigPos[i] = SkFixedToScalar(recs[i].fPos);
         }
+    } else {
+        fOrigPos = NULL;
     }
     buffer.readMatrix(&fPtsToUnit);
     this->initCommon();
 }
+#endif
 
 SkGradientShaderBase::~SkGradientShaderBase() {
-    if (fCache16Storage) {
-        sk_free(fCache16Storage);
-    }
-    SkSafeUnref(fCache32PixelRef);
     if (fOrigColors != fStorage) {
         sk_free(fOrigColors);
     }
-    SkSafeUnref(fMapper);
 }
 
 void SkGradientShaderBase::initCommon() {
-    fFlags = 0;
     unsigned colorAlpha = 0xFF;
     for (int i = 0; i < fColorCount; i++) {
         colorAlpha &= SkColorGetA(fOrigColors[i]);
@@ -206,67 +269,128 @@ void SkGradientShaderBase::initCommon() {
 }
 
 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
-    this->INHERITED::flatten(buffer);
-    buffer.writeFlattenable(fMapper);
-    buffer.writeColorArray(fOrigColors, fColorCount);
-    buffer.writeUInt(pack_mode_flags(fTileMode, fGradFlags));
-    if (fColorCount > 2) {
-        Rec* recs = fRecs;
-        for (int i = 1; i < fColorCount; i++) {
-            buffer.writeInt(recs[i].fPos);
-            buffer.writeUInt(recs[i].fScale);
+    Descriptor desc;
+    desc.fColors = fOrigColors;
+    desc.fPos = fOrigPos;
+    desc.fCount = fColorCount;
+    desc.fTileMode = fTileMode;
+    desc.fGradFlags = fGradFlags;
+
+    const SkMatrix& m = this->getLocalMatrix();
+    desc.fLocalMatrix = m.isIdentity() ? NULL : &m;
+    desc.flatten(buffer);
+}
+
+SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const {
+    if (fColorCount <= 3) {
+        memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor));
+    }
+
+    if (SkShader::kClamp_TileMode == fTileMode) {
+        if (2 == fColorCount) {
+            return kTwo_GpuColorType;
+        } else if (3 == fColorCount &&
+                   (SkScalarAbs(
+                    SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
+            return kThree_GpuColorType;
         }
     }
-    buffer.writeMatrix(fPtsToUnit);
+    return kTexture_GpuColorType;
+}
+
+void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
+                                              SkColor* colorSrc, Rec* recSrc,
+                                              int count) {
+    SkAutoSTArray<8, SkColor> colorsTemp(count);
+    for (int i = 0; i < count; ++i) {
+        int offset = count - i - 1;
+        colorsTemp[i] = colorSrc[offset];
+    }
+    if (count > 2) {
+        SkAutoSTArray<8, Rec> recsTemp(count);
+        for (int i = 0; i < count; ++i) {
+            int offset = count - i - 1;
+            recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos;
+            recsTemp[i].fScale = recSrc[offset].fScale;
+        }
+        memcpy(recDst, recsTemp.get(), count * sizeof(Rec));
+    }
+    memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
+}
+
+void SkGradientShaderBase::flipGradientColors() {
+    FlipGradientColors(fOrigColors, fRecs, fOrigColors, fRecs, fColorCount);
 }
 
 bool SkGradientShaderBase::isOpaque() const {
     return fColorsAreOpaque;
 }
 
-bool SkGradientShaderBase::setContext(const SkBitmap& device,
-                                 const SkPaint& paint,
-                                 const SkMatrix& matrix) {
-    if (!this->INHERITED::setContext(device, paint, matrix)) {
-        return false;
+static unsigned rounded_divide(unsigned numer, unsigned denom) {
+    return (numer + (denom >> 1)) / denom;
+}
+
+bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
+    // we just compute an average color.
+    // possibly we could weight this based on the proportional width for each color
+    //   assuming they are not evenly distributed in the fPos array.
+    int r = 0;
+    int g = 0;
+    int b = 0;
+    const int n = fColorCount;
+    for (int i = 0; i < n; ++i) {
+        SkColor c = fOrigColors[i];
+        r += SkColorGetR(c);
+        g += SkColorGetG(c);
+        b += SkColorGetB(c);
     }
+    *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
+    return true;
+}
 
+SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
+        const SkGradientShaderBase& shader, const ContextRec& rec)
+    : INHERITED(shader, rec)
+    , fCache(shader.refCache(getPaintAlpha()))
+{
     const SkMatrix& inverse = this->getTotalInverse();
 
-    fDstToIndex.setConcat(fPtsToUnit, inverse);
+    fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
+
     fDstToIndexProc = fDstToIndex.getMapXYProc();
-    fDstToIndexClass = (uint8_t)SkShader::ComputeMatrixClass(fDstToIndex);
+    fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex);
 
     // now convert our colors in to PMColors
     unsigned paintAlpha = this->getPaintAlpha();
 
     fFlags = this->INHERITED::getFlags();
-    if (fColorsAreOpaque && paintAlpha == 0xFF) {
+    if (shader.fColorsAreOpaque && paintAlpha == 0xFF) {
         fFlags |= kOpaqueAlpha_Flag;
     }
     // we can do span16 as long as our individual colors are opaque,
     // regardless of the paint's alpha
-    if (fColorsAreOpaque) {
+    if (shader.fColorsAreOpaque) {
         fFlags |= kHasSpan16_Flag;
     }
+}
 
-    this->setCacheAlpha(paintAlpha);
-    return true;
+SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
+        U8CPU alpha, const SkGradientShaderBase& shader)
+    : fCacheAlpha(alpha)
+    , fShader(shader)
+    , fCache16Inited(false)
+    , fCache32Inited(false)
+{
+    // Only initialize the cache in getCache16/32.
+    fCache16 = NULL;
+    fCache32 = NULL;
+    fCache16Storage = NULL;
+    fCache32PixelRef = NULL;
 }
 
-void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const {
-    // if the new alpha differs from the previous time we were called, inval our cache
-    // this will trigger the cache to be rebuilt.
-    // we don't care about the first time, since the cache ptrs will already be NULL
-    if (fCacheAlpha != alpha) {
-        fCache16 = NULL;            // inval the cache
-        fCache32 = NULL;            // inval the cache
-        fCacheAlpha = alpha;        // record the new alpha
-        // inform our subclasses
-        if (fCache32PixelRef) {
-            fCache32PixelRef->notifyPixelsChanged();
-        }
-    }
+SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {
+    sk_free(fCache16Storage);
+    SkSafeUnref(fCache32PixelRef);
 }
 
 #define Fixed_To_Dot8(x)        (((x) + 0x80) >> 8)
@@ -275,8 +399,8 @@ void SkGradientShaderBase::setCacheAlpha(U8CPU alpha) const {
     build a 16bit table as long as the original colors are opaque, even if the
     paint specifies a non-opaque alpha.
 */
-void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor c1,
-                                      int count) {
+void SkGradientShaderBase::GradientShaderCache::Build16bitCache(
+        uint16_t cache[], SkColor c0, SkColor c1, int count) {
     SkASSERT(count > 1);
     SkASSERT(SkColorGetA(c0) == 0xFF);
     SkASSERT(SkColorGetA(c1) == 0xFF);
@@ -324,8 +448,9 @@ void SkGradientShaderBase::Build16bitCache(uint16_t cache[], SkColor c0, SkColor
  */
 typedef uint32_t SkUFixed;
 
-void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
-                                      int count, U8CPU paintAlpha, uint32_t gradFlags) {
+void SkGradientShaderBase::GradientShaderCache::Build32bitCache(
+        SkPMColor cache[], SkColor c0, SkColor c1,
+        int count, U8CPU paintAlpha, uint32_t gradFlags) {
     SkASSERT(count > 1);
 
     // need to apply paintAlpha to our two endpoints
@@ -456,111 +581,90 @@ static inline int SkFixedToFFFF(SkFixed x) {
     return x - (x >> 16);
 }
 
-static inline U16CPU bitsTo16(unsigned x, const unsigned bits) {
-    SkASSERT(x < (1U << bits));
-    if (6 == bits) {
-        return (x << 10) | (x << 4) | (x >> 2);
-    }
-    if (8 == bits) {
-        return (x << 8) | x;
-    }
-    sk_throw();
-    return 0;
+const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() {
+    SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16,
+           this);
+    SkASSERT(fCache16);
+    return fCache16;
 }
 
-const uint16_t* SkGradientShaderBase::getCache16() const {
-    if (fCache16 == NULL) {
-        // double the count for dither entries
-        const int entryCount = kCache16Count * 2;
-        const size_t allocSize = sizeof(uint16_t) * entryCount;
-
-        if (fCache16Storage == NULL) { // set the storage and our working ptr
-            fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
-        }
-        fCache16 = fCache16Storage;
-        if (fColorCount == 2) {
-            Build16bitCache(fCache16, fOrigColors[0], fOrigColors[1],
-                            kCache16Count);
-        } else {
-            Rec* rec = fRecs;
-            int prevIndex = 0;
-            for (int i = 1; i < fColorCount; i++) {
-                int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
-                SkASSERT(nextIndex < kCache16Count);
-
-                if (nextIndex > prevIndex)
-                    Build16bitCache(fCache16 + prevIndex, fOrigColors[i-1], fOrigColors[i], nextIndex - prevIndex + 1);
-                prevIndex = nextIndex;
-            }
-        }
-
-        if (fMapper) {
-            fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
-            uint16_t* linear = fCache16;         // just computed linear data
-            uint16_t* mapped = fCache16Storage;  // storage for mapped data
-            SkUnitMapper* map = fMapper;
-            for (int i = 0; i < kCache16Count; i++) {
-                int index = map->mapUnit16(bitsTo16(i, kCache16Bits)) >> kCache16Shift;
-                mapped[i] = linear[index];
-                mapped[i + kCache16Count] = linear[index + kCache16Count];
-            }
-            sk_free(fCache16);
-            fCache16 = fCache16Storage;
+void SkGradientShaderBase::GradientShaderCache::initCache16(GradientShaderCache* cache) {
+    // double the count for dither entries
+    const int entryCount = kCache16Count * 2;
+    const size_t allocSize = sizeof(uint16_t) * entryCount;
+
+    SkASSERT(NULL == cache->fCache16Storage);
+    cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
+    cache->fCache16 = cache->fCache16Storage;
+    if (cache->fShader.fColorCount == 2) {
+        Build16bitCache(cache->fCache16, cache->fShader.fOrigColors[0],
+                        cache->fShader.fOrigColors[1], kCache16Count);
+    } else {
+        Rec* rec = cache->fShader.fRecs;
+        int prevIndex = 0;
+        for (int i = 1; i < cache->fShader.fColorCount; i++) {
+            int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
+            SkASSERT(nextIndex < kCache16Count);
+
+            if (nextIndex > prevIndex)
+                Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1],
+                                cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1);
+            prevIndex = nextIndex;
         }
     }
-    return fCache16;
 }
 
-const SkPMColor* SkGradientShaderBase::getCache32() const {
-    if (fCache32 == NULL) {
-        SkImageInfo info;
-        info.fWidth = kCache32Count;
-        info.fHeight = 4;   // for our 4 dither rows
-        info.fAlphaType = kPremul_SkAlphaType;
-        info.fColorType = kPMColor_SkColorType;
+const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
+    SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32,
+           this);
+    SkASSERT(fCache32);
+    return fCache32;
+}
 
-        if (NULL == fCache32PixelRef) {
-            fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL);
-        }
-        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
-        if (fColorCount == 2) {
-            Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
-                            kCache32Count, fCacheAlpha, fGradFlags);
-        } else {
-            Rec* rec = fRecs;
-            int prevIndex = 0;
-            for (int i = 1; i < fColorCount; i++) {
-                int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
-                SkASSERT(nextIndex < kCache32Count);
-
-                if (nextIndex > prevIndex)
-                    Build32bitCache(fCache32 + prevIndex, fOrigColors[i-1],
-                                    fOrigColors[i], nextIndex - prevIndex + 1,
-                                    fCacheAlpha, fGradFlags);
-                prevIndex = nextIndex;
-            }
+void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) {
+    const int kNumberOfDitherRows = 4;
+    const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows);
+
+    SkASSERT(NULL == cache->fCache32PixelRef);
+    cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL);
+    cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr();
+    if (cache->fShader.fColorCount == 2) {
+        Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0],
+                        cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha,
+                        cache->fShader.fGradFlags);
+    } else {
+        Rec* rec = cache->fShader.fRecs;
+        int prevIndex = 0;
+        for (int i = 1; i < cache->fShader.fColorCount; i++) {
+            int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
+            SkASSERT(nextIndex < kCache32Count);
+
+            if (nextIndex > prevIndex)
+                Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1],
+                                cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
+                                cache->fCacheAlpha, cache->fShader.fGradFlags);
+            prevIndex = nextIndex;
         }
+    }
+}
 
-        if (fMapper) {
-            SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL);
-            SkPMColor* linear = fCache32;           // just computed linear data
-            SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
-            SkUnitMapper* map = fMapper;
-            for (int i = 0; i < kCache32Count; i++) {
-                int index = map->mapUnit16((i << 8) | i) >> 8;
-                mapped[i + kCache32Count*0] = linear[index + kCache32Count*0];
-                mapped[i + kCache32Count*1] = linear[index + kCache32Count*1];
-                mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
-                mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
-            }
-            fCache32PixelRef->unref();
-            fCache32PixelRef = newPR;
-            fCache32 = (SkPMColor*)newPR->getAddr();
-        }
+/*
+ *  The gradient holds a cache for the most recent value of alpha. Successive
+ *  callers with the same alpha value will share the same cache.
+ */
+SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::refCache(U8CPU alpha) const {
+    SkAutoMutexAcquire ama(fCacheMutex);
+    if (!fCache || fCache->getAlpha() != alpha) {
+        fCache.reset(SkNEW_ARGS(GradientShaderCache, (alpha, *this)));
     }
-    return fCache32;
+    // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
+    // Otherwise, the pointer may have been overwritten on a different thread before the object's
+    // ref count was incremented.
+    fCache.get()->ref();
+    return fCache;
 }
 
+SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
 /*
  *  Because our caller might rebuild the same (logically the same) gradient
  *  over and over, we'd like to return exactly the same "bitmap" if possible,
@@ -572,16 +676,7 @@ const SkPMColor* SkGradientShaderBase::getCache32() const {
 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
     // our caller assumes no external alpha, so we ensure that our cache is
     // built with 0xFF
-    this->setCacheAlpha(0xFF);
-
-    // don't have a way to put the mapper into our cache-key yet
-    if (fMapper) {
-        // force our cahce32pixelref to be built
-        (void)this->getCache32();
-        bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
-        bitmap->setPixelRef(fCache32PixelRef);
-        return;
-    }
+    SkAutoTUnref<GradientShaderCache> cache(this->refCache(0xFF));
 
     // build our key: [numColors + colors[] + {positions[]} + flags ]
     int count = 1 + fColorCount + 1;
@@ -605,32 +700,43 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
 
     ///////////////////////////////////
 
-    SK_DECLARE_STATIC_MUTEX(gMutex);
-    static SkBitmapCache* gCache;
+    static SkGradientBitmapCache* gCache;
     // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
     static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
-    SkAutoMutexAcquire ama(gMutex);
+    SkAutoMutexAcquire ama(gGradientCacheMutex);
 
     if (NULL == gCache) {
-        gCache = SkNEW_ARGS(SkBitmapCache, (MAX_NUM_CACHED_GRADIENT_BITMAPS));
+        gCache = SkNEW_ARGS(SkGradientBitmapCache, (MAX_NUM_CACHED_GRADIENT_BITMAPS));
     }
     size_t size = count * sizeof(int32_t);
 
     if (!gCache->find(storage.get(), size, bitmap)) {
         // force our cahce32pixelref to be built
-        (void)this->getCache32();
-        bitmap->setConfig(SkImageInfo::MakeN32Premul(kCache32Count, 1));
-        bitmap->setPixelRef(fCache32PixelRef);
+        (void)cache->getCache32();
+        bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
+        bitmap->setPixelRef(cache->getCache32PixelRef());
 
         gCache->add(storage.get(), size, *bitmap);
     }
 }
 
-void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
+void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const {
     if (info) {
         if (info->fColorCount >= fColorCount) {
+            SkColor* colorLoc;
+            Rec*     recLoc;
+            if (flipGrad && (info->fColors || info->fColorOffsets)) {
+                SkAutoSTArray<8, SkColor> colorStorage(fColorCount);
+                SkAutoSTArray<8, Rec> recStorage(fColorCount);
+                colorLoc = colorStorage.get();
+                recLoc = recStorage.get();
+                FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount);
+            } else {
+                colorLoc = fOrigColors;
+                recLoc = fRecs;
+            }
             if (info->fColors) {
-                memcpy(info->fColors, fOrigColors, fColorCount * sizeof(SkColor));
+                memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor));
             }
             if (info->fColorOffsets) {
                 if (fColorCount == 2) {
@@ -638,7 +744,7 @@ void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
                     info->fColorOffsets[1] = SK_Scalar1;
                 } else if (fColorCount > 2) {
                     for (int i = 0; i < fColorCount; ++i) {
-                        info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
+                        info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos);
                     }
                 }
             }
@@ -679,8 +785,6 @@ void SkGradientShaderBase::toString(SkString* str) const {
     str->append(" ");
     str->append(gTileModeName[fTileMode]);
 
-    // TODO: add "fMapper->toString(str);" when SkUnitMapper::toString is added
-
     this->INHERITED::toString(str);
 }
 #endif
@@ -688,8 +792,6 @@ void SkGradientShaderBase::toString(SkString* str) const {
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "SkEmptyShader.h"
-
 // assumes colors is SkColor* and pos is SkScalar*
 #define EXPAND_1_COLOR(count)               \
     SkColor tmp[2];                         \
@@ -703,31 +805,29 @@ void SkGradientShaderBase::toString(SkString* str) const {
     } while (0)
 
 static void desc_init(SkGradientShaderBase::Descriptor* desc,
-                      const SkColor colors[],
-                      const SkScalar pos[], int colorCount,
-                      SkShader::TileMode mode,
-                      SkUnitMapper* mapper, uint32_t flags) {
-    desc->fColors   = colors;
-    desc->fPos      = pos;
-    desc->fCount    = colorCount;
-    desc->fTileMode = mode;
-    desc->fMapper   = mapper;
-    desc->fFlags    = flags;
+                      const SkColor colors[], const SkScalar pos[], int colorCount,
+                      SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
+    desc->fColors       = colors;
+    desc->fPos          = pos;
+    desc->fCount        = colorCount;
+    desc->fTileMode     = mode;
+    desc->fGradFlags    = flags;
+    desc->fLocalMatrix  = localMatrix;
 }
 
 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
                                          const SkColor colors[],
                                          const SkScalar pos[], int colorCount,
                                          SkShader::TileMode mode,
-                                         SkUnitMapper* mapper,
-                                         uint32_t flags) {
+                                         uint32_t flags,
+                                         const SkMatrix* localMatrix) {
     if (NULL == pts || NULL == colors || colorCount < 1) {
         return NULL;
     }
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
+    desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
     return SkNEW_ARGS(SkLinearGradient, (pts, desc));
 }
 
@@ -735,15 +835,15 @@ SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
                                          const SkColor colors[],
                                          const SkScalar pos[], int colorCount,
                                          SkShader::TileMode mode,
-                                         SkUnitMapper* mapper,
-                                         uint32_t flags) {
+                                         uint32_t flags,
+                                         const SkMatrix* localMatrix) {
     if (radius <= 0 || NULL == colors || colorCount < 1) {
         return NULL;
     }
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
+    desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
     return SkNEW_ARGS(SkRadialGradient, (center, radius, desc));
 }
 
@@ -755,15 +855,15 @@ SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start,
                                                  const SkScalar pos[],
                                                  int colorCount,
                                                  SkShader::TileMode mode,
-                                                 SkUnitMapper* mapper,
-                                                 uint32_t flags) {
+                                                 uint32_t flags,
+                                                 const SkMatrix* localMatrix) {
     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
         return NULL;
     }
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
+    desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
     return SkNEW_ARGS(SkTwoPointRadialGradient,
                       (start, startRadius, end, endRadius, desc));
 }
@@ -776,34 +876,59 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
                                                   const SkScalar pos[],
                                                   int colorCount,
                                                   SkShader::TileMode mode,
-                                                  SkUnitMapper* mapper,
-                                                  uint32_t flags) {
+                                                  uint32_t flags,
+                                                  const SkMatrix* localMatrix) {
     if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) {
         return NULL;
     }
     if (start == end && startRadius == endRadius) {
-        return SkNEW(SkEmptyShader);
+        return SkShader::CreateEmptyShader();
     }
+
     EXPAND_1_COLOR(colorCount);
 
+    bool flipGradient = startRadius > endRadius;
+
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
-    return SkNEW_ARGS(SkTwoPointConicalGradient,
-                      (start, startRadius, end, endRadius, desc));
+
+    if (!flipGradient) {
+        desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
+        return SkNEW_ARGS(SkTwoPointConicalGradient,
+                          (start, startRadius, end, endRadius, flipGradient, desc));
+    } else {
+        SkAutoSTArray<8, SkColor> colorsNew(colorCount);
+        SkAutoSTArray<8, SkScalar> posNew(colorCount);
+        for (int i = 0; i < colorCount; ++i) {
+            colorsNew[i] = colors[colorCount - i - 1];
+        }
+
+        if (pos) {
+            for (int i = 0; i < colorCount; ++i) {
+                posNew[i] = 1 - pos[colorCount - i - 1];
+            }
+            desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, flags, localMatrix);
+        } else {
+            desc_init(&desc, colorsNew.get(), NULL, colorCount, mode, flags, localMatrix);
+        }
+
+        return SkNEW_ARGS(SkTwoPointConicalGradient,
+                          (end, endRadius, start, startRadius, flipGradient, desc));
+    }
 }
 
 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
                                         const SkColor colors[],
                                         const SkScalar pos[],
-                                        int colorCount, SkUnitMapper* mapper,
-                                        uint32_t flags) {
+                                        int colorCount,
+                                        uint32_t flags,
+                                        const SkMatrix* localMatrix) {
     if (NULL == colors || colorCount < 1) {
         return NULL;
     }
     EXPAND_1_COLOR(colorCount);
 
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, mapper, flags);
+    desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, flags, localMatrix);
     return SkNEW_ARGS(SkSweepGradient, (cx, cy, desc));
 }
 
@@ -820,106 +945,107 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
 #if SK_SUPPORT_GPU
 
 #include "effects/GrTextureStripAtlas.h"
-#include "GrTBackendEffectFactory.h"
+#include "GrTBackendProcessorFactory.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
-GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
+GrGLGradientEffect::GrGLGradientEffect(const GrBackendProcessorFactory& factory)
     : INHERITED(factory)
     , fCachedYCoord(SK_ScalarMax) {
 }
 
 GrGLGradientEffect::~GrGLGradientEffect() { }
 
-void GrGLGradientEffect::emitUniforms(GrGLShaderBuilder* builder, EffectKey key) {
+void GrGLGradientEffect::emitUniforms(GrGLFPBuilder* builder, uint32_t baseKey) {
 
-    if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)) { // 2 Color case
-        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    if (SkGradientShaderBase::kTwo_GpuColorType == ColorTypeFromKey(baseKey)) { // 2 Color case
+        fColorStartUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec4f_GrSLType, "GradientStartColor");
-        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorEndUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kVec4f_GrSLType, "GradientEndColor");
 
-    } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){ // 3 Color Case
-        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    } else if (SkGradientShaderBase::kThree_GpuColorType == ColorTypeFromKey(baseKey)){ // 3 Color Case
+        fColorStartUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec4f_GrSLType, "GradientStartColor");
-        fColorMidUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorMidUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kVec4f_GrSLType, "GradientMidColor");
-        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorEndUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec4f_GrSLType, "GradientEndColor");
 
     } else { // if not a fast case
-        fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fFSYUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                       kFloat_GrSLType, "GradientYCoordFS");
     }
 }
 
-static inline void set_color_uni(const GrGLUniformManager& uman,
-                                 const GrGLUniformManager::UniformHandle uni,
+static inline void set_color_uni(const GrGLProgramDataManager& pdman,
+                                 const GrGLProgramDataManager::UniformHandle uni,
                                  const SkColor* color) {
-       uman.set4f(uni,
-                  SkColorGetR(*color) / 255.f,
-                  SkColorGetG(*color) / 255.f,
-                  SkColorGetB(*color) / 255.f,
-                  SkColorGetA(*color) / 255.f);
+       pdman.set4f(uni,
+                   SkColorGetR(*color) / 255.f,
+                   SkColorGetG(*color) / 255.f,
+                   SkColorGetB(*color) / 255.f,
+                   SkColorGetA(*color) / 255.f);
 }
 
-static inline void set_mul_color_uni(const GrGLUniformManager& uman,
-                                     const GrGLUniformManager::UniformHandle uni,
+static inline void set_mul_color_uni(const GrGLProgramDataManager& pdman,
+                                     const GrGLProgramDataManager::UniformHandle uni,
                                      const SkColor* color){
        float a = SkColorGetA(*color) / 255.f;
        float aDiv255 = a / 255.f;
-       uman.set4f(uni,
-                  SkColorGetR(*color) * aDiv255,
-                  SkColorGetG(*color) * aDiv255,
-                  SkColorGetB(*color) * aDiv255,
-                  a);
+       pdman.set4f(uni,
+                   SkColorGetR(*color) * aDiv255,
+                   SkColorGetG(*color) * aDiv255,
+                   SkColorGetB(*color) * aDiv255,
+                   a);
 }
 
-void GrGLGradientEffect::setData(const GrGLUniformManager& uman,
-                                 const GrDrawEffect& drawEffect) {
+void GrGLGradientEffect::setData(const GrGLProgramDataManager& pdman,
+                                 const GrProcessor& processor) {
 
-    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
+    const GrGradientEffect& e = processor.cast<GrGradientEffect>();
 
 
-    if (GrGradientEffect::kTwo_ColorType == e.getColorType()){
+    if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()){
 
         if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
-            set_mul_color_uni(uman, fColorStartUni, e.getColors(0));
-            set_mul_color_uni(uman, fColorEndUni,   e.getColors(1));
+            set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
+            set_mul_color_uni(pdman, fColorEndUni,   e.getColors(1));
         } else {
-            set_color_uni(uman, fColorStartUni, e.getColors(0));
-            set_color_uni(uman, fColorEndUni,   e.getColors(1));
+            set_color_uni(pdman, fColorStartUni, e.getColors(0));
+            set_color_uni(pdman, fColorEndUni,   e.getColors(1));
         }
 
-    } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){
+    } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){
 
         if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
-            set_mul_color_uni(uman, fColorStartUni, e.getColors(0));
-            set_mul_color_uni(uman, fColorMidUni,   e.getColors(1));
-            set_mul_color_uni(uman, fColorEndUni,   e.getColors(2));
+            set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
+            set_mul_color_uni(pdman, fColorMidUni,   e.getColors(1));
+            set_mul_color_uni(pdman, fColorEndUni,   e.getColors(2));
         } else {
-            set_color_uni(uman, fColorStartUni, e.getColors(0));
-            set_color_uni(uman, fColorMidUni,   e.getColors(1));
-            set_color_uni(uman, fColorEndUni,   e.getColors(2));
+            set_color_uni(pdman, fColorStartUni, e.getColors(0));
+            set_color_uni(pdman, fColorMidUni,   e.getColors(1));
+            set_color_uni(pdman, fColorEndUni,   e.getColors(2));
         }
     } else {
 
         SkScalar yCoord = e.getYCoord();
         if (yCoord != fCachedYCoord) {
-            uman.set1f(fFSYUni, yCoord);
+            pdman.set1f(fFSYUni, yCoord);
             fCachedYCoord = yCoord;
         }
     }
 }
 
 
-GrGLEffect::EffectKey GrGLGradientEffect::GenBaseGradientKey(const GrDrawEffect& drawEffect) {
-    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
+uint32_t GrGLGradientEffect::GenBaseGradientKey(const GrProcessor& processor) {
+    const GrGradientEffect& e = processor.cast<GrGradientEffect>();
 
-    EffectKey key = 0;
+    uint32_t key = 0;
 
-    if (GrGradientEffect::kTwo_ColorType == e.getColorType()) {
+    if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()) {
         key |= kTwoColorKey;
-    } else if (GrGradientEffect::kThree_ColorType == e.getColorType()){
+    } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){
         key |= kThreeColorKey;
     }
 
@@ -930,14 +1056,15 @@ GrGLEffect::EffectKey GrGLGradientEffect::GenBaseGradientKey(const GrDrawEffect&
     return key;
 }
 
-void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder,
+void GrGLGradientEffect::emitColor(GrGLFPBuilder* builder,
                                    const char* gradientTValue,
-                                   EffectKey key,
+                                   uint32_t baseKey,
                                    const char* outputColor,
                                    const char* inputColor,
                                    const TextureSamplerArray& samplers) {
-    if (GrGradientEffect::kTwo_ColorType == ColorTypeFromKey(key)){
-        builder->fsCodeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
+    GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    if (SkGradientShaderBase::kTwo_GpuColorType == ColorTypeFromKey(baseKey)){
+        fsBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
                                builder->getUniformVariable(fColorStartUni).c_str(),
                                builder->getUniformVariable(fColorEndUni).c_str(),
                                gradientTValue);
@@ -946,45 +1073,45 @@ void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder,
         // The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
         // case. Make sure the key reflects this optimization (and note that it can use the same
         // shader as thekBeforeIterp case). This same optimization applies to the 3 color case below.
-        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) {
-            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
+        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(baseKey)) {
+            fsBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
         }
 
-        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+        fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
-    } else if (GrGradientEffect::kThree_ColorType == ColorTypeFromKey(key)){
-        builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
+    } else if (SkGradientShaderBase::kThree_GpuColorType == ColorTypeFromKey(baseKey)){
+        fsBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
                                gradientTValue);
-        builder->fsCodeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
+        fsBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
                                builder->getUniformVariable(fColorStartUni).c_str());
         if (kTegra3_GrGLRenderer == builder->ctxInfo().renderer()) {
             // The Tegra3 compiler will sometimes never return if we have
             // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
-            builder->fsCodeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
-            builder->fsCodeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
-            builder->fsCodeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
+            fsBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
+            fsBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
+            fsBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
                                    builder->getUniformVariable(fColorMidUni).c_str());
         } else {
-            builder->fsCodeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
+            fsBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
                                    builder->getUniformVariable(fColorMidUni).c_str());
         }
-        builder->fsCodeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
+        fsBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
                                builder->getUniformVariable(fColorEndUni).c_str());
-        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(key)) {
-            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
+        if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(baseKey)) {
+            fsBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
         }
 
-        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+        fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
     } else {
-        builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
+        fsBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n",
                                gradientTValue,
                                builder->getUniformVariable(fFSYUni).c_str());
-        builder->fsCodeAppendf("\t%s = ", outputColor);
-        builder->fsAppendTextureLookupAndModulate(inputColor,
+        fsBuilder->codeAppendf("\t%s = ", outputColor);
+        fsBuilder->appendTextureLookupAndModulate(inputColor,
                                                   samplers[0],
                                                   "coord");
-        builder->fsCodeAppend(";\n");
+        fsBuilder->codeAppend(";\n");
     }
 }
 
@@ -997,30 +1124,14 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx,
 
     fIsOpaque = shader.isOpaque();
 
-    SkShader::GradientInfo info;
-    SkScalar pos[3] = {0};
-
-    info.fColorCount = 3;
-    info.fColors = &fColors[0];
-    info.fColorOffsets = &pos[0];
-    shader.asAGradient(&info);
+    fColorType = shader.getGpuColorType(&fColors[0]);
 
     // The two and three color specializations do not currently support tiling.
-    bool foundSpecialCase = false;
-    if (SkShader::kClamp_TileMode == info.fTileMode) {
-        if (2 == info.fColorCount) {
-            fRow = -1; // flag for no atlas
-            fColorType = kTwo_ColorType;
-            foundSpecialCase = true;
-        } else if (3 == info.fColorCount &&
-                   (SkScalarAbs(pos[1] - SK_ScalarHalf) < SK_Scalar1 / 1000)) { // 3 color symmetric
-            fRow = -1; // flag for no atlas
-            fColorType = kThree_ColorType;
-            foundSpecialCase = true;
-        }
-    }
-    if (foundSpecialCase) {
-        if (SkGradientShader::kInterpolateColorsInPremul_Flag & info.fGradientFlags) {
+    if (SkGradientShaderBase::kTwo_GpuColorType == fColorType ||
+        SkGradientShaderBase::kThree_GpuColorType == fColorType) {
+        fRow = -1;
+
+        if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
             fPremulType = kBeforeInterp_PremulType;
         } else {
             fPremulType = kAfterInterp_PremulType;
@@ -1031,16 +1142,15 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx,
         fPremulType = kBeforeInterp_PremulType;
         SkBitmap bitmap;
         shader.getGradientTableBitmap(&bitmap);
-        fColorType = kTexture_ColorType;
 
         GrTextureStripAtlas::Desc desc;
         desc.fWidth  = bitmap.width();
         desc.fHeight = 32;
         desc.fRowHeight = bitmap.height();
         desc.fContext = ctx;
-        desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.colorType(), bitmap.alphaType());
+        desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
         fAtlas = GrTextureStripAtlas::GetAtlas(desc);
-        SkASSERT(NULL != fAtlas);
+        SkASSERT(fAtlas);
 
         // We always filter the gradient table. Each table is one row of a texture, always y-clamp.
         GrTextureParams params;
@@ -1049,20 +1159,14 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx,
 
         fRow = fAtlas->lockRow(bitmap);
         if (-1 != fRow) {
-            fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf *
-            fAtlas->getVerticalScaleFactor();
+            fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * fAtlas->getNormalizedTexelHeight();
             fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture());
             fTextureAccess.reset(fAtlas->getTexture(), params);
         } else {
-            GrTexture* texture = GrLockAndRefCachedBitmapTexture(ctx, bitmap, &params);
+            SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(ctx, bitmap, &params));
             fCoordTransform.reset(kCoordSet, matrix, texture);
             fTextureAccess.reset(texture, params);
             fYCoord = SK_ScalarHalf;
-
-            // Unlock immediately, this is not great, but we don't have a way of
-            // knowing when else to unlock it currently, so it may get purged from
-            // the cache, but it'll still be ref'd until it's no longer being used.
-            GrUnlockAndUnrefCachedBitmapTexture(texture);
         }
         this->addTextureAccess(&fTextureAccess);
     }
@@ -1075,17 +1179,17 @@ GrGradientEffect::~GrGradientEffect() {
     }
 }
 
-bool GrGradientEffect::onIsEqual(const GrEffect& effect) const {
-    const GrGradientEffect& s = CastEffect<GrGradientEffect>(effect);
+bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
+    const GrGradientEffect& s = processor.cast<GrGradientEffect>();
 
     if (this->fColorType == s.getColorType()){
 
-        if (kTwo_ColorType == fColorType) {
+        if (SkGradientShaderBase::kTwo_GpuColorType == fColorType) {
             if (*this->getColors(0) != *s.getColors(0) ||
                 *this->getColors(1) != *s.getColors(1)) {
                 return false;
             }
-        } else if (kThree_ColorType == fColorType) {
+        } else if (SkGradientShaderBase::kThree_GpuColorType == fColorType) {
             if (*this->getColors(0) != *s.getColors(0) ||
                 *this->getColors(1) != *s.getColors(1) ||
                 *this->getColors(2) != *s.getColors(2)) {
@@ -1097,21 +1201,18 @@ bool GrGradientEffect::onIsEqual(const GrEffect& effect) const {
             }
         }
 
-        return fTextureAccess.getTexture() == s.fTextureAccess.getTexture()  &&
-            fTextureAccess.getParams().getTileModeX() ==
-                s.fTextureAccess.getParams().getTileModeX() &&
-            this->useAtlas() == s.useAtlas() &&
-            fCoordTransform.getMatrix().cheapEqualTo(s.fCoordTransform.getMatrix());
+        SkASSERT(this->useAtlas() == s.useAtlas());
+        return true;
     }
 
     return false;
 }
 
-void GrGradientEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
-    if (fIsOpaque && (kA_GrColorComponentFlag & *validFlags) && 0xff == GrColorUnpackA(*color)) {
-        *validFlags = kA_GrColorComponentFlag;
+void GrGradientEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
+    if (fIsOpaque) {
+        inout->mulByUnknownOpaqueColor();
     } else {
-        *validFlags = 0;
+        inout->mulByUnknownColor();
     }
 }
 
@@ -1129,7 +1230,7 @@ int GrGradientEffect::RandomGradientParams(SkRandom* random,
     SkScalar stop = 0.f;
     for (int i = 0; i < outColors; ++i) {
         colors[i] = random->nextU();
-        if (NULL != *stops) {
+        if (*stops) {
             (*stops)[i] = stop;
             stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
         }