Merge "DO NOT MERGE Inspect SkShader to determine hw shader." into lmp-preview-dev
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index a272296..424d860 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -41,10 +41,6 @@
  * An implementation of Canvas on top of OpenGL ES 2.0.
  */
 class GLES20Canvas extends HardwareCanvas {
-    // Must match modifiers used in the JNI layer
-    private static final int MODIFIER_NONE = 0;
-    private static final int MODIFIER_SHADER = 2;
-
     private final boolean mOpaque;
     protected long mRenderer;
 
@@ -650,13 +646,8 @@
     @Override
     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
-                    startAngle, sweepAngle, useCenter, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+                startAngle, sweepAngle, useCenter, paint.mNativePaint);
     }
 
     private static native void nDrawArc(long renderer, float left, float top,
@@ -672,7 +663,6 @@
     public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
-        // Shaders are ignored when drawing patches
         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@@ -682,7 +672,6 @@
     public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
-        // Shaders are ignored when drawing patches
         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@@ -694,14 +683,8 @@
     @Override
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
         throwIfCannotDraw(bitmap);
-        // Shaders are ignored when drawing bitmaps
-        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
     }
 
     private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -710,15 +693,9 @@
     @Override
     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
         throwIfCannotDraw(bitmap);
-        // Shaders are ignored when drawing bitmaps
-        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
-                    matrix.native_instance, nativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
+                matrix.native_instance, nativePaint);
     }
 
     private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -727,55 +704,43 @@
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
         throwIfCannotDraw(bitmap);
-        // Shaders are ignored when drawing bitmaps
-        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
 
-            int left, top, right, bottom;
-            if (src == null) {
-                left = top = 0;
-                right = bitmap.getWidth();
-                bottom = bitmap.getHeight();
-            } else {
-                left = src.left;
-                right = src.right;
-                top = src.top;
-                bottom = src.bottom;
-            }
-
-            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
-                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        int left, top, right, bottom;
+        if (src == null) {
+            left = top = 0;
+            right = bitmap.getWidth();
+            bottom = bitmap.getHeight();
+        } else {
+            left = src.left;
+            right = src.right;
+            top = src.top;
+            bottom = src.bottom;
         }
+
+        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
         throwIfCannotDraw(bitmap);
-        // Shaders are ignored when drawing bitmaps
-        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-    
-            float left, top, right, bottom;
-            if (src == null) {
-                left = top = 0;
-                right = bitmap.getWidth();
-                bottom = bitmap.getHeight();
-            } else {
-                left = src.left;
-                right = src.right;
-                top = src.top;
-                bottom = src.bottom;
-            }
-    
-            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
-                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+
+        float left, top, right, bottom;
+        if (src == null) {
+            left = top = 0;
+            right = bitmap.getWidth();
+            bottom = bitmap.getHeight();
+        } else {
+            left = src.left;
+            right = src.right;
+            top = src.top;
+            bottom = src.bottom;
         }
+
+        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
     }
 
     private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -805,7 +770,6 @@
             throw new ArrayIndexOutOfBoundsException();
         }
 
-        // Shaders are ignored when drawing bitmaps
         final long nativePaint = paint == null ? 0 : paint.mNativePaint;
         nDrawBitmap(mRenderer, colors, offset, stride, x, y,
                 width, height, hasAlpha, nativePaint);
@@ -817,7 +781,6 @@
     @Override
     public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
             int width, int height, boolean hasAlpha, Paint paint) {
-        // Shaders are ignored when drawing bitmaps
         drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
     }
 
@@ -840,14 +803,9 @@
             checkRange(colors.length, colorOffset, count);
         }
 
-        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        try {
-            final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
-                    verts, vertOffset, colors, colorOffset, nativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
+                verts, vertOffset, colors, colorOffset, nativePaint);
     }
 
     private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer,
@@ -856,12 +814,7 @@
 
     @Override
     public void drawCircle(float cx, float cy, float radius, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
     }
 
     private static native void nDrawCircle(long renderer, float cx, float cy,
@@ -906,12 +859,7 @@
         if ((offset | count) < 0 || offset + count > pts.length) {
             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
         }
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
     }
 
     private static native void nDrawLines(long renderer, float[] points,
@@ -924,12 +872,7 @@
 
     @Override
     public void drawOval(RectF oval, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
     }
 
     private static native void nDrawOval(long renderer, float left, float top,
@@ -944,17 +887,12 @@
 
     @Override
     public void drawPath(Path path, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            if (path.isSimplePath) {
-                if (path.rects != null) {
-                    nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
-                }
-            } else {
-                nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+        if (path.isSimplePath) {
+            if (path.rects != null) {
+                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
             }
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        } else {
+            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
         }
     }
 
@@ -962,12 +900,7 @@
     private static native void nDrawRects(long renderer, long region, long paint);
 
     void drawRects(float[] rects, int count, Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawRects(mRenderer, rects, count, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawRects(mRenderer, rects, count, paint.mNativePaint);
     }
 
     private static native void nDrawRects(long renderer, float[] rects, int count, long paint);
@@ -1029,12 +962,7 @@
     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
         if (count < 2) return;
 
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
     }
 
     private static native void nDrawPoints(long renderer, float[] points,
@@ -1047,12 +975,7 @@
             throw new IndexOutOfBoundsException();
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
     }
 
     private static native void nDrawPosText(long renderer, char[] text, int index, int count,
@@ -1065,12 +988,7 @@
             throw new ArrayIndexOutOfBoundsException();
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
     }
 
     private static native void nDrawPosText(long renderer, String text, int start, int end,
@@ -1079,12 +997,7 @@
     @Override
     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
         if (left == right || top == bottom) return;
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
     }
 
     private static native void nDrawRect(long renderer, float left, float top,
@@ -1108,12 +1021,7 @@
     @Override
     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
             Paint paint) {
-        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
-        try {
-            nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
     }
 
     private static native void nDrawRoundRect(long renderer, float left, float top,
@@ -1125,13 +1033,8 @@
             throw new IndexOutOfBoundsException();
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint,
-                paint.mNativeTypeface);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawText(mRenderer, text, index, count, x, y,
+                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
     
     private static native void nDrawText(long renderer, char[] text, int index, int count,
@@ -1139,24 +1042,18 @@
 
     @Override
     public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
-        int modifiers = setupModifiers(paint);
-        try {
-            if (text instanceof String || text instanceof SpannedString ||
-                    text instanceof SpannableString) {
-                nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
-                        paint.mNativePaint, paint.mNativeTypeface);
-            } else if (text instanceof GraphicsOperations) {
-                ((GraphicsOperations) text).drawText(this, start, end, x, y,
-                                                         paint);
-            } else {
-                char[] buf = TemporaryBuffer.obtain(end - start);
-                TextUtils.getChars(text, start, end, buf, 0);
-                nDrawText(mRenderer, buf, 0, end - start, x, y,
-                        paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
-                TemporaryBuffer.recycle(buf);
-            }
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        if (text instanceof String || text instanceof SpannedString ||
+                text instanceof SpannableString) {
+            nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
+                    paint.mNativePaint, paint.mNativeTypeface);
+        } else if (text instanceof GraphicsOperations) {
+            ((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
+        } else {
+            char[] buf = TemporaryBuffer.obtain(end - start);
+            TextUtils.getChars(text, start, end, buf, 0);
+            nDrawText(mRenderer, buf, 0, end - start, x, y,
+                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+            TemporaryBuffer.recycle(buf);
         }
     }
 
@@ -1166,13 +1063,8 @@
             throw new IndexOutOfBoundsException();
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint,
-                paint.mNativeTypeface);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawText(mRenderer, text, start, end, x, y,
+                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     private static native void nDrawText(long renderer, String text, int start, int end,
@@ -1180,13 +1072,8 @@
 
     @Override
     public void drawText(String text, float x, float y, Paint paint) {
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
-                    paint.mNativePaint, paint.mNativeTypeface);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawText(mRenderer, text, 0, text.length(), x, y,
+                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     @Override
@@ -1196,13 +1083,8 @@
             throw new ArrayIndexOutOfBoundsException();
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
+                paint.mBidiFlags, paint.mNativePaint);
     }
 
     private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
@@ -1212,13 +1094,8 @@
     public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
         if (text.length() == 0) return;
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
-                    paint.mBidiFlags, paint.mNativePaint);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
+                paint.mBidiFlags, paint.mNativePaint);
     }
 
     private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
@@ -1234,13 +1111,8 @@
             throw new IllegalArgumentException("Unknown direction: " + dir);
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
-                    paint.mNativePaint, paint.mNativeTypeface);
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
-        }
+        nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
@@ -1253,27 +1125,22 @@
             throw new IndexOutOfBoundsException();
         }
 
-        int modifiers = setupModifiers(paint);
-        try {
-            int flags = dir == 0 ? 0 : 1;
-            if (text instanceof String || text instanceof SpannedString ||
-                    text instanceof SpannableString) {
-                nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
-                        contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
-            } else if (text instanceof GraphicsOperations) {
-                ((GraphicsOperations) text).drawTextRun(this, start, end,
-                        contextStart, contextEnd, x, y, flags, paint);
-            } else {
-                int contextLen = contextEnd - contextStart;
-                int len = end - start;
-                char[] buf = TemporaryBuffer.obtain(contextLen);
-                TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-                nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
-                        x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
-                TemporaryBuffer.recycle(buf);
-            }
-        } finally {
-            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        int flags = dir == 0 ? 0 : 1;
+        if (text instanceof String || text instanceof SpannedString ||
+                text instanceof SpannableString) {
+            nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
+                    contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+        } else if (text instanceof GraphicsOperations) {
+            ((GraphicsOperations) text).drawTextRun(this, start, end,
+                    contextStart, contextEnd, x, y, flags, paint);
+        } else {
+            int contextLen = contextEnd - contextStart;
+            int len = end - start;
+            char[] buf = TemporaryBuffer.obtain(contextLen);
+            TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
+            nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
+                    x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+            TemporaryBuffer.recycle(buf);
         }
     }
 
@@ -1286,40 +1153,4 @@
             int indexOffset, int indexCount, Paint paint) {
         // TODO: Implement
     }
-
-    private int setupModifiers(Bitmap b, Paint paint) {
-        if (b.getConfig() != Bitmap.Config.ALPHA_8) {
-            return MODIFIER_NONE;
-        } else {
-            return setupModifiers(paint);
-        }
-    }
-
-    private int setupModifiers(Paint paint) {
-        int modifiers = MODIFIER_NONE;
-
-        final Shader shader = paint.getShader();
-        if (shader != null) {
-            nSetupShader(mRenderer, shader.native_shader);
-            modifiers |= MODIFIER_SHADER;
-        }
-
-        return modifiers;
-    }
-
-    private int setupModifiers(Paint paint, int flags) {
-        int modifiers = MODIFIER_NONE;
-
-        final Shader shader = paint.getShader();
-        if (shader != null && (flags & MODIFIER_SHADER) != 0) {
-            nSetupShader(mRenderer, shader.native_shader);
-            modifiers |= MODIFIER_SHADER;
-        }
-
-        return modifiers;
-    }
-
-    private static native void nSetupShader(long renderer, long shader);
-
-    private static native void nResetModifiers(long renderer, int modifiers);
 }
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index b389d9e..0cfcaef 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -50,26 +50,16 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong skiaShaderHandle)
+static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle)
 {
     SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    SkiaShader* skiaShader = reinterpret_cast<SkiaShader*>(skiaShaderHandle);
     SkSafeUnref(shader);
-    // skiaShader == NULL when not !USE_OPENGL_RENDERER, so no need to delete it outside the ifdef
-#ifdef USE_OPENGL_RENDERER
-    if (android::uirenderer::Caches::hasInstance()) {
-        android::uirenderer::Caches::getInstance().resourceCache.destructor(skiaShader);
-    } else {
-        delete skiaShader;
-    }
-#endif
 }
 
 static void Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle,
-        jlong skiaShaderHandle, jlong matrixHandle)
+        jlong matrixHandle)
 {
     SkShader* shader       = reinterpret_cast<SkShader*>(shaderHandle);
-    SkiaShader* skiaShader = reinterpret_cast<SkiaShader*>(skiaShaderHandle);
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     if (shader) {
         if (NULL == matrix) {
@@ -78,9 +68,6 @@
         else {
             shader->setLocalMatrix(*matrix);
         }
-#ifdef USE_OPENGL_RENDERER
-        skiaShader->setMatrix(const_cast<SkMatrix*>(matrix));
-#endif
     }
 }
 
@@ -98,20 +85,6 @@
     return reinterpret_cast<jlong>(s);
 }
 
-static jlong BitmapShader_postConstructor(JNIEnv* env, jobject o, jlong shaderHandle,
-        jlong bitmapHandle, jint tileModeX, jint tileModeY) {
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
-#ifdef USE_OPENGL_RENDERER
-    SkiaShader* skiaShader = new SkiaBitmapShader(bitmap, shader,
-            static_cast<SkShader::TileMode>(tileModeX), static_cast<SkShader::TileMode>(tileModeY),
-            NULL, !shader->isOpaque());
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static jlong LinearGradient_create1(JNIEnv* env, jobject o,
@@ -141,105 +114,6 @@
     return reinterpret_cast<jlong>(shader);
 }
 
-static jlong LinearGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
-        jfloat x0, jfloat y0, jfloat x1, jfloat y1, jintArray colorArray,
-        jfloatArray posArray, jint tileMode) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    size_t count = env->GetArrayLength(colorArray);
-    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
-
-    jfloat* storedBounds = new jfloat[4];
-    storedBounds[0] = x0; storedBounds[1] = y0;
-    storedBounds[2] = x1; storedBounds[3] = y1;
-    
-    bool missFirst = false;
-    bool missLast = false;
-    size_t stopCount = count;
-
-    jfloat* storedPositions = NULL;
-    if (posArray) {
-        AutoJavaFloatArray autoPos(env, posArray, count);
-        const float* posValues = autoPos.ptr();
-
-        missFirst = posValues[0] != 0.0f;
-        missLast = posValues[count - 1] != 1.0f;
-
-        stopCount += missFirst + missLast;
-        storedPositions = new jfloat[stopCount];
-
-        if (missFirst) {
-            storedPositions[0] = 0.0f;
-        }
-
-        for (size_t i = missFirst; i < count + missFirst; i++) {
-            storedPositions[i] = posValues[i - missFirst];
-        }
-
-        if (missLast) {
-            storedPositions[stopCount - 1] = 1.0f;
-        }
-    } else {
-        storedPositions = new jfloat[count];
-        storedPositions[0] = 0.0f;
-        const jfloat step = 1.0f / (count - 1);
-        for (size_t i = 1; i < count - 1; i++) {
-            storedPositions[i] = step * i;
-        }
-        storedPositions[count - 1] = 1.0f;
-    }
-
-    uint32_t* storedColors = new uint32_t[stopCount];
-
-    if (missFirst) {
-        storedColors[0] = static_cast<uint32_t>(colorValues[0]);
-    }
-
-    for (size_t i = missFirst; i < count + missFirst; i++) {
-        storedColors[i] = static_cast<uint32_t>(colorValues[i - missFirst]);
-    }
-
-    if (missLast) {
-        storedColors[stopCount - 1] = static_cast<uint32_t>(colorValues[count - 1]);
-    }
-
-    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
-            storedPositions, stopCount, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
-            !shader->isOpaque());
-
-    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
-static jlong LinearGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
-        jfloat x0, jfloat y0, jfloat x1, jfloat y1, jint color0, jint color1, jint tileMode) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    float* storedBounds = new float[4];
-    storedBounds[0] = x0; storedBounds[1] = y0;
-    storedBounds[2] = x1; storedBounds[3] = y1;
-
-    float* storedPositions = new float[2];
-    storedPositions[0] = 0.0f;
-    storedPositions[1] = 1.0f;
-
-    uint32_t* storedColors = new uint32_t[2];
-    storedColors[0] = static_cast<uint32_t>(color0);
-    storedColors[1] = static_cast<uint32_t>(color1);
-
-    SkiaShader* skiaShader = new SkiaLinearGradientShader(storedBounds, storedColors,
-            storedPositions, 2, shader, static_cast<SkShader::TileMode>(tileMode), NULL,
-            !shader->isOpaque());
-
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
 static jlong LinearGradient_create2(JNIEnv* env, jobject o,
                                     jfloat x0, jfloat y0, jfloat x1, jfloat y1,
                                     jint color0, jint color1, jint tileMode)
@@ -300,67 +174,6 @@
     return reinterpret_cast<jlong>(s);
 }
 
-static jlong RadialGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
-        jfloat x, jfloat y, jfloat radius, jintArray colorArray, jfloatArray posArray, jint tileMode) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    size_t count = env->GetArrayLength(colorArray);
-    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
-
-    jfloat* storedPositions = new jfloat[count];
-    uint32_t* storedColors = new uint32_t[count];
-    for (size_t i = 0; i < count; i++) {
-        storedColors[i] = static_cast<uint32_t>(colorValues[i]);
-    }
-
-    if (posArray) {
-        AutoJavaFloatArray autoPos(env, posArray, count);
-        const float* posValues = autoPos.ptr();
-        for (size_t i = 0; i < count; i++) {
-            storedPositions[i] = posValues[i];
-        }
-    } else {
-        storedPositions[0] = 0.0f;
-        const jfloat step = 1.0f / (count - 1);
-        for (size_t i = 1; i < count - 1; i++) {
-            storedPositions[i] = step * i;
-        }
-        storedPositions[count - 1] = 1.0f;
-    }
-
-    SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
-            storedPositions, count, shader, (SkShader::TileMode) tileMode, NULL,
-            !shader->isOpaque());
-
-    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
-static jlong RadialGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
-        jfloat x, jfloat y, jfloat radius, jint color0, jint color1, jint tileMode) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    float* storedPositions = new float[2];
-    storedPositions[0] = 0.0f;
-    storedPositions[1] = 1.0f;
-
-    uint32_t* storedColors = new uint32_t[2];
-    storedColors[0] = static_cast<uint32_t>(color0);
-    storedColors[1] = static_cast<uint32_t>(color1);
-
-    SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
-            storedPositions, 2, shader, (SkShader::TileMode) tileMode, NULL,
-            !shader->isOpaque());
-
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static jlong SweepGradient_create1(JNIEnv* env, jobject, jfloat x, jfloat y,
@@ -393,65 +206,6 @@
     return reinterpret_cast<jlong>(s);
 }
 
-static jlong SweepGradient_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
-        jfloat x, jfloat y, jintArray colorArray, jfloatArray posArray) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    size_t count = env->GetArrayLength(colorArray);
-    const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
-
-    jfloat* storedPositions = new jfloat[count];
-    uint32_t* storedColors = new uint32_t[count];
-    for (size_t i = 0; i < count; i++) {
-        storedColors[i] = static_cast<uint32_t>(colorValues[i]);
-    }
-
-    if (posArray) {
-        AutoJavaFloatArray autoPos(env, posArray, count);
-        const float* posValues = autoPos.ptr();
-        for (size_t i = 0; i < count; i++) {
-            storedPositions[i] = posValues[i];
-        }
-    } else {
-        storedPositions[0] = 0.0f;
-        const jfloat step = 1.0f / (count - 1);
-        for (size_t i = 1; i < count - 1; i++) {
-            storedPositions[i] = step * i;
-        }
-        storedPositions[count - 1] = 1.0f;
-    }
-
-    SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, count,
-            shader, NULL, !shader->isOpaque());
-
-    env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
-static jlong SweepGradient_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
-        jfloat x, jfloat y, jint color0, jint color1) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
-    float* storedPositions = new float[2];
-    storedPositions[0] = 0.0f;
-    storedPositions[1] = 1.0f;
-
-    uint32_t* storedColors = new uint32_t[2];
-    storedColors[0] = static_cast<uint32_t>(color0);
-    storedColors[1] = static_cast<uint32_t>(color1);
-
-    SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, 2,
-            shader, NULL, !shader->isOpaque());
-
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static jlong ComposeShader_create1(JNIEnv* env, jobject o,
@@ -476,40 +230,6 @@
     return reinterpret_cast<jlong>(shader);
 }
 
-static jlong ComposeShader_postCreate2(JNIEnv* env, jobject o, jlong shaderHandle,
-        jlong shaderAHandle, jlong shaderBHandle, jint porterDuffModeHandle) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader *>(shaderHandle);
-    SkiaShader* shaderA = reinterpret_cast<SkiaShader *>(shaderAHandle);
-    SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle);
-    SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(porterDuffModeHandle);
-    SkXfermode::Mode mode = SkPorterDuff::ToXfermodeMode(porterDuffMode);
-    SkiaShader* skiaShader = new SkiaComposeShader(shaderA, shaderB, mode, shader);
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
-static jlong ComposeShader_postCreate1(JNIEnv* env, jobject o, jlong shaderHandle,
-        jlong shaderAHandle, jlong shaderBHandle, jlong modeHandle) {
-#ifdef USE_OPENGL_RENDERER
-    SkShader* shader = reinterpret_cast<SkShader *>(shaderHandle);
-    SkiaShader* shaderA = reinterpret_cast<SkiaShader *>(shaderAHandle);
-    SkiaShader* shaderB = reinterpret_cast<SkiaShader *>(shaderBHandle);
-    SkXfermode* mode = reinterpret_cast<SkXfermode *>(modeHandle);
-    SkXfermode::Mode skiaMode;
-    if (!SkXfermode::AsMode(mode, &skiaMode)) {
-        // TODO: Support other modes
-        skiaMode = SkXfermode::kSrcOver_Mode;
-    }
-    SkiaShader* skiaShader = new SkiaComposeShader(shaderA, shaderB, skiaMode, shader);
-    return reinterpret_cast<jlong>(skiaShader);
-#else
-    return NULL;
-#endif
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gColorMethods[] = {
@@ -518,41 +238,32 @@
 };
 
 static JNINativeMethod gShaderMethods[] = {
-    { "nativeDestructor",        "(JJ)V",    (void*)Shader_destructor        },
-    { "nativeSetLocalMatrix",    "(JJJ)V",   (void*)Shader_setLocalMatrix    }
+    { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
+    { "nativeSetLocalMatrix",    "(JJ)V",   (void*)Shader_setLocalMatrix    }
 };
 
 static JNINativeMethod gBitmapShaderMethods[] = {
     { "nativeCreate",     "(JII)J",  (void*)BitmapShader_constructor },
-    { "nativePostCreate", "(JJII)J", (void*)BitmapShader_postConstructor }
 };
 
 static JNINativeMethod gLinearGradientMethods[] = {
     { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
     { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
-    { "nativePostCreate1", "(JFFFF[I[FI)J", (void*)LinearGradient_postCreate1 },
-    { "nativePostCreate2", "(JFFFFIII)J",   (void*)LinearGradient_postCreate2 }
 };
 
 static JNINativeMethod gRadialGradientMethods[] = {
     { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
     { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
-    { "nativePostCreate1", "(JFFF[I[FI)J", (void*)RadialGradient_postCreate1 },
-    { "nativePostCreate2", "(JFFFIII)J",   (void*)RadialGradient_postCreate2 }
 };
 
 static JNINativeMethod gSweepGradientMethods[] = {
     { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
     { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
-    { "nativePostCreate1", "(JFF[I[F)J", (void*)SweepGradient_postCreate1 },
-    { "nativePostCreate2", "(JFFII)J",   (void*)SweepGradient_postCreate2 }
 };
 
 static JNINativeMethod gComposeShaderMethods[] = {
     { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
     { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
-    { "nativePostCreate1",  "(JJJJ)J",  (void*)ComposeShader_postCreate1 },
-    { "nativePostCreate2",  "(JJJI)J",  (void*)ComposeShader_postCreate2 }
 };
 
 #include <android_runtime/AndroidRuntime.h>
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 27d3f39..c5dd06f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -45,7 +45,6 @@
 #include <DisplayListRenderer.h>
 #include <LayerRenderer.h>
 #include <OpenGLRenderer.h>
-#include <SkiaShader.h>
 #include <Stencil.h>
 #include <Rect.h>
 #include <RenderNode.h>
@@ -85,8 +84,6 @@
     #define RENDERER_LOGD(...)
 #endif
 
-#define MODIFIER_SHADER 2
-
 // ----------------------------------------------------------------------------
 
 static struct {
@@ -616,24 +613,6 @@
 }
 
 // ----------------------------------------------------------------------------
-// Shaders and color filters
-// ----------------------------------------------------------------------------
-
-static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint modifiers) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    if (modifiers & MODIFIER_SHADER) renderer->resetShader();
-}
-
-static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong shaderPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    SkiaShader* shader = reinterpret_cast<SkiaShader*>(shaderPtr);
-    renderer->setupShader(shader);
-}
-
-
-// ----------------------------------------------------------------------------
 // Draw filters
 // ----------------------------------------------------------------------------
 
@@ -1091,9 +1070,6 @@
     { "nDrawPath",          "(JJJ)V",          (void*) android_view_GLES20Canvas_drawPath },
     { "nDrawLines",         "(J[FIIJ)V",       (void*) android_view_GLES20Canvas_drawLines },
 
-    { "nResetModifiers",    "(JI)V",           (void*) android_view_GLES20Canvas_resetModifiers },
-    { "nSetupShader",       "(JJ)V",           (void*) android_view_GLES20Canvas_setupShader },
-
     { "nSetupPaintFilter",  "(JII)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
     { "nResetPaintFilter",  "(J)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
 
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index b7673d8..3ab57c1 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -44,7 +44,6 @@
         mTileY = tileY;
         final long b = bitmap.ni();
         native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
-        native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt);
     }
 
     /**
@@ -59,6 +58,4 @@
 
     private static native long nativeCreate(long native_bitmap, int shaderTileModeX,
             int shaderTileModeY);
-    private static native long nativePostCreate(long native_shader, long native_bitmap,
-            int shaderTileModeX, int shaderTileModeY);
 }
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 5109ffd..d7b2071 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -55,14 +55,6 @@
         mXferMode = mode;
         native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
                 (mode != null) ? mode.native_instance : 0);
-        if (mode instanceof PorterDuffXfermode) {
-            PorterDuff.Mode pdMode = ((PorterDuffXfermode) mode).mode;
-            native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
-                    shaderB.native_shader, pdMode != null ? pdMode.nativeInt : 0);
-        } else {
-            native_shader = nativePostCreate1(native_instance, shaderA.native_shader,
-                    shaderB.native_shader, mode != null ? mode.native_instance : 0);
-        }
     }
 
     /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
@@ -79,8 +71,6 @@
         mPorterDuffMode = mode;
         native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
                 mode.nativeInt);
-        native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
-                shaderB.native_shader, mode.nativeInt);
     }
 
     /**
@@ -108,8 +98,4 @@
             long native_mode);
     private static native long nativeCreate2(long native_shaderA, long native_shaderB,
             int porterDuffMode);
-    private static native long nativePostCreate1(long native_shader, long native_skiaShaderA,
-            long native_skiaShaderB, long native_mode);
-    private static native long nativePostCreate2(long native_shader, long native_skiaShaderA,
-            long native_skiaShaderB, int porterDuffMode);
 }
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 0eae67c..90cb217 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -66,8 +66,6 @@
         mPositions = positions;
         mTileMode = tile;
         native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
-        native_shader = nativePostCreate1(native_instance, x0, y0, x1, y1, colors, positions,
-                tile.nativeInt);
     }
 
     /** Create a shader that draws a linear gradient along a line.
@@ -90,8 +88,6 @@
         mColor1 = color1;
         mTileMode = tile;
         native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
-        native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
-                tile.nativeInt);
     }
 
     /**
@@ -120,8 +116,4 @@
             int colors[], float positions[], int tileMode);
     private native long nativeCreate2(float x0, float y0, float x1, float y1,
             int color0, int color1, int tileMode);
-    private native long nativePostCreate1(long native_shader, float x0, float y0, float x1, float y1,
-            int colors[], float positions[], int tileMode);
-    private native long nativePostCreate2(long native_shader, float x0, float y0, float x1, float y1,
-            int color0, int color1, int tileMode);
 }
diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java
index c00c612..75c951a 100644
--- a/graphics/java/android/graphics/RadialGradient.java
+++ b/graphics/java/android/graphics/RadialGradient.java
@@ -66,8 +66,6 @@
         mPositions = positions;
         mTileMode = tile;
         native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
-        native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions,
-                tile.nativeInt);
     }
 
     /** Create a shader that draws a radial gradient given the center and radius.
@@ -91,8 +89,6 @@
         mColor1 = color1;
         mTileMode = tile;
         native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
-        native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1,
-                tile.nativeInt);
     }
 
     /**
@@ -121,10 +117,5 @@
             int colors[], float positions[], int tileMode);
     private static native long nativeCreate2(float x, float y, float radius,
             int color0, int color1, int tileMode);
-
-    private static native long nativePostCreate1(long native_shader, float x, float y, float radius,
-            int colors[], float positions[], int tileMode);
-    private static native long nativePostCreate2(long native_shader, float x, float y, float radius,
-            int color0, int color1, int tileMode);
 }
 
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 94b4c4a..6870ab4 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -29,10 +29,6 @@
      * @hide 
      */
     public long native_instance;
-    /**
-     * @hide
-     */
-    public long native_shader;
 
     private Matrix mLocalMatrix;
 
@@ -78,7 +74,7 @@
      */
     public void setLocalMatrix(Matrix localM) {
         mLocalMatrix = localM;
-        nativeSetLocalMatrix(native_instance, native_shader,
+        nativeSetLocalMatrix(native_instance,
                 localM == null ? 0 : localM.native_instance);
     }
 
@@ -86,7 +82,7 @@
         try {
             super.finalize();
         } finally {
-            nativeDestructor(native_instance, native_shader);
+            nativeDestructor(native_instance);
         }
     }
 
@@ -112,7 +108,7 @@
         }
     }
 
-    private static native void nativeDestructor(long native_shader, long native_skiaShader);
+    private static native void nativeDestructor(long native_shader);
     private static native void nativeSetLocalMatrix(long native_shader,
-            long native_skiaShader, long matrix_instance);
+            long matrix_instance);
 }
diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java
index 21239f7..18a748f 100644
--- a/graphics/java/android/graphics/SweepGradient.java
+++ b/graphics/java/android/graphics/SweepGradient.java
@@ -63,7 +63,6 @@
         mColors = colors;
         mPositions = positions;
         native_instance = nativeCreate1(cx, cy, colors, positions);
-        native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions);
     }
 
     /**
@@ -81,7 +80,6 @@
         mColor0 = color0;
         mColor1 = color1;
         native_instance = nativeCreate2(cx, cy, color0, color1);
-        native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1);
     }
 
     /**
@@ -108,10 +106,5 @@
 
     private static native long nativeCreate1(float x, float y, int colors[], float positions[]);
     private static native long nativeCreate2(float x, float y, int color0, int color1);
-
-    private static native long nativePostCreate1(long native_shader, float cx, float cy,
-            int[] colors, float[] positions);    
-    private static native long nativePostCreate2(long native_shader, float cx, float cy,
-            int color0, int color1);
 }
 
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 2e2ee15..5367663 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -33,6 +33,7 @@
 #include "thread/TaskManager.h"
 
 #include "AssetAtlas.h"
+#include "Extensions.h"
 #include "FontRenderer.h"
 #include "GammaFontRenderer.h"
 #include "TextureCache.h"
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 3016814..937bf8d 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -230,6 +230,11 @@
             return false;
         }
 
+        if (op->mPaint && mOps[0].op->mPaint &&
+            op->mPaint->getShader() != mOps[0].op->mPaint->getShader()) {
+            return false;
+        }
+
         /* Draw Modifiers compatibility check
          *
          * Shadows are ignored, as only text uses them, and in that case they are drawn
@@ -244,7 +249,6 @@
          */
         const DrawModifiers& lhsMod = lhs->mDrawModifiers;
         const DrawModifiers& rhsMod = rhs->mDrawModifiers;
-        if (lhsMod.mShader != rhsMod.mShader) return false;
 
         // Draw filter testing expects bit fields to be clear if filter not set.
         if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index dac86cb..96c6292 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -58,11 +58,6 @@
         caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
     }
 
-    for (size_t i = 0; i < shaders.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i));
-        caches.resourceCache.destructorLocked(shaders.itemAt(i));
-    }
-
     for (size_t i = 0; i < sourcePaths.size(); i++) {
         caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
     }
@@ -92,7 +87,6 @@
     bitmapResources.clear();
     ownedBitmapResources.clear();
     patchResources.clear();
-    shaders.clear();
     sourcePaths.clear();
     paints.clear();
     regions.clear();
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index b2ead5b..11e78b0 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -56,7 +56,6 @@
 class OpenGLRenderer;
 class Rect;
 class Layer;
-class SkiaShader;
 
 class ClipRectOp;
 class SaveLayerOp;
@@ -127,7 +126,6 @@
     SortedVector<const SkPath*> sourcePaths;
     Vector<const SkRegion*> regions;
     Vector<const SkMatrix*> matrices;
-    Vector<SkiaShader*> shaders;
     Vector<Layer*> layers;
     uint32_t functorCount;
     bool hasDrawOps;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index e4867220..ea3e7a8 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -208,9 +208,16 @@
         if (!state.mMatrix.isSimple()) return false;
 
         // check state/paint for transparency
-        if (state.mDrawModifiers.mShader ||
-                state.mAlpha != 1.0f ||
-                (mPaint && mPaint->getAlpha() != 0xFF)) return false;
+        if (mPaint) {
+            if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
+                return false;
+            }
+            if (mPaint->getAlpha() != 0xFF) {
+                return false;
+            }
+        }
+
+        if (state.mAlpha != 1.0f) return false;
 
         SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
         return (mode == SkXfermode::kSrcOver_Mode ||
@@ -592,37 +599,6 @@
     const SkRegion* mRegion;
 };
 
-class ResetShaderOp : public StateOp {
-public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.resetShader();
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOGS("ResetShader");
-    }
-
-    virtual const char* name() { return "ResetShader"; }
-};
-
-class SetupShaderOp : public StateOp {
-public:
-    SetupShaderOp(SkiaShader* shader)
-            : mShader(shader) {}
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.setupShader(mShader);
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("SetupShader, shader %p", mShader);
-    }
-
-    virtual const char* name() { return "SetupShader"; }
-
-private:
-    SkiaShader* mShader;
-};
-
 class ResetPaintFilterOp : public StateOp {
 public:
     virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 606c67e..229afdf 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -47,7 +47,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 DisplayListData* DisplayListRenderer::finishRecording() {
-    mShaderMap.clear();
     mPaintMap.clear();
     mRegionMap.clear();
     mPathMap.clear();
@@ -394,15 +393,6 @@
     return DrawGlInfo::kStatusDone;
 }
 
-void DisplayListRenderer::resetShader() {
-    addStateOp(new (alloc()) ResetShaderOp());
-}
-
-void DisplayListRenderer::setupShader(SkiaShader* shader) {
-    shader = refShader(shader);
-    addStateOp(new (alloc()) SetupShaderOp(shader));
-}
-
 void DisplayListRenderer::resetPaintFilter() {
     addStateOp(new (alloc()) ResetPaintFilterOp());
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index d814111..f0ae00f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -95,9 +95,6 @@
     virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
 
     // Misc - should be implemented with SkPaint inspection
-    virtual void resetShader();
-    virtual void setupShader(SkiaShader* shader);
-
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
@@ -269,21 +266,6 @@
         return bitmap;
     }
 
-    inline SkiaShader* refShader(SkiaShader* shader) {
-        if (!shader) return NULL;
-
-        SkiaShader* shaderCopy = mShaderMap.valueFor(shader);
-        // TODO: We also need to handle generation ID changes in compose shaders
-        if (shaderCopy == NULL || shaderCopy->getGenerationId() != shader->getGenerationId()) {
-            shaderCopy = shader->copy();
-            // replaceValueFor() performs an add if the entry doesn't exist
-            mShaderMap.replaceValueFor(shader, shaderCopy);
-            mDisplayListData->shaders.add(shaderCopy);
-            mCaches.resourceCache.incrementRefcount(shaderCopy);
-        }
-        return shaderCopy;
-    }
-
     inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
         mDisplayListData->patchResources.add(patch);
         mCaches.resourceCache.incrementRefcount(patch);
@@ -293,7 +275,6 @@
     DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap;
     DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
     DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
-    DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap;
 
     Caches& mCaches;
     DisplayListData* mDisplayListData;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 647c281..4407ab0 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -73,7 +73,7 @@
         }
     }
     renderer->setupDrawColorFilter(paint->getColorFilter());
-    renderer->setupDrawShader();
+    renderer->setupDrawShader(paint->getShader());
     renderer->setupDrawBlending(paint);
     renderer->setupDrawProgram();
     renderer->setupDrawModelView(kModelViewMode_Translate, false,
@@ -85,7 +85,7 @@
     renderer->setupDrawTexture(0);
     renderer->setupDrawPureColorUniforms();
     renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
-    renderer->setupDrawShaderUniforms(pureTranslate);
+    renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
     renderer->setupDrawTextGammaUniforms();
 
     return NO_ERROR;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 691f1c9..71836dd 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <SkCanvas.h>
+#include <SkShader.h>
 #include <SkTypeface.h>
 
 #include <utils/Log.h>
@@ -37,6 +38,7 @@
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "ShadowTessellator.h"
+#include "SkiaShader.h"
 #include "utils/GLUtils.h"
 #include "Vector.h"
 #include "VertexBuffer.h"
@@ -1053,6 +1055,45 @@
 
 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
 
+// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
+// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
+class LayerShader : public SkShader {
+public:
+    LayerShader(Layer* layer, const SkMatrix* localMatrix)
+    : INHERITED(localMatrix)
+    , mLayer(layer) {
+    }
+
+    virtual bool asACustomShader(void** data) const {
+        if (data) {
+            *data = static_cast<void*>(mLayer);
+        }
+        return true;
+    }
+
+    virtual bool isOpaque() const {
+        return !mLayer->isBlend();
+    }
+
+protected:
+    virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
+        LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
+    }
+
+    virtual void flatten(SkWriteBuffer&) const {
+        LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
+    }
+
+    virtual Factory getFactory() const {
+        LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
+        return NULL;
+    }
+private:
+    // Unowned.
+    Layer* mLayer;
+    typedef SkShader INHERITED;
+};
+
 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
     if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
 
@@ -1066,21 +1107,19 @@
         paint.setAntiAlias(true);
         paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
 
-        SkiaShader* oldShader = mDrawModifiers.mShader;
-
         // create LayerShader to map SaveLayer content into subsequent draw
         SkMatrix shaderMatrix;
         shaderMatrix.setTranslate(rect.left, rect.bottom);
         shaderMatrix.preScale(1, -1);
-        SkiaLayerShader layerShader(layer, &shaderMatrix);
-        mDrawModifiers.mShader = &layerShader;
+        LayerShader layerShader(layer, &shaderMatrix);
+        paint.setShader(&layerShader);
 
         // Since the drawing primitive is defined in local drawing space,
         // we don't need to modify the draw matrix
         const SkPath* maskPath = layer->getConvexMask();
         DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
 
-        mDrawModifiers.mShader = oldShader;
+        paint.setShader(NULL);
         restore();
 
         return;
@@ -1627,9 +1666,9 @@
     mSetShaderColor = mDescription.setColorModulate(a);
 }
 
-void OpenGLRenderer::setupDrawShader() {
-    if (mDrawModifiers.mShader) {
-        mDrawModifiers.mShader->describe(mDescription, mExtensions);
+void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
+    if (shader != NULL) {
+        SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
     }
 }
 
@@ -1655,15 +1694,21 @@
     }
 }
 
+static bool isBlendedColorFilter(const SkColorFilter* filter) {
+    if (filter == NULL) {
+        return false;
+    }
+    return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
+}
+
 void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
     SkXfermode::Mode mode = layer->getMode();
     // When the blending mode is kClear_Mode, we need to use a modulate color
     // argb=1,0,0,0
     accountForClear(mode);
+    // TODO: check shader blending, once we have shader drawing support for layers.
     bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
-            (mColorSet && mColorA < 1.0f) ||
-            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
-            layer->getColorFilter();
+            (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
@@ -1673,8 +1718,8 @@
     // argb=1,0,0,0
     accountForClear(mode);
     blend |= (mColorSet && mColorA < 1.0f) ||
-            (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) ||
-            (paint && paint->getColorFilter());
+            (getShader(paint) && !getShader(paint)->isOpaque()) ||
+            isBlendedColorFilter(getColorFilter(paint));
     chooseBlending(blend, mode, mDescription, swapSrcDst);
 }
 
@@ -1717,8 +1762,8 @@
     }
 }
 
-void OpenGLRenderer::setupDrawColorUniforms() {
-    if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) {
+void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
+    if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
     }
 }
@@ -1729,20 +1774,22 @@
     }
 }
 
-void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
-    if (mDrawModifiers.mShader) {
-        if (ignoreTransform) {
-            // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
-            // because it was built into modelView / the geometry, and the SkiaShader needs to
-            // compensate.
-            mat4 modelViewWithoutTransform;
-            modelViewWithoutTransform.loadInverse(*currentTransform());
-            modelViewWithoutTransform.multiply(mModelViewMatrix);
-            mModelViewMatrix.load(modelViewWithoutTransform);
-        }
-        mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
-                mModelViewMatrix, *mSnapshot, &mTextureUnit);
+void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
+    if (shader == NULL) {
+        return;
     }
+
+    if (ignoreTransform) {
+        // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
+        // because it was built into modelView / the geometry, and the description needs to
+        // compensate.
+        mat4 modelViewWithoutTransform;
+        modelViewWithoutTransform.loadInverse(*currentTransform());
+        modelViewWithoutTransform.multiply(mModelViewMatrix);
+        mModelViewMatrix.load(modelViewWithoutTransform);
+    }
+
+    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
 }
 
 void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
@@ -2201,7 +2248,7 @@
     // Apply a scale transform on the canvas only when a shader is in use
     // Skia handles the ratio between the dst and src rects as a scale factor
     // when a shader is set
-    bool useScaleTransform = mDrawModifiers.mShader && scaled;
+    bool useScaleTransform = getShader(paint) && scaled;
     bool ignoreTransform = false;
 
     if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
@@ -2359,13 +2406,13 @@
     if (isAA) setupDrawAA();
     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
     setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader();
+    setupDrawShader(getShader(paint));
     setupDrawBlending(paint, isAA);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
-    setupDrawColorUniforms();
+    setupDrawColorUniforms(getShader(paint));
     setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms();
+    setupDrawShaderUniforms(getShader(paint));
 
     const void* vertices = vertexBuffer.getBuffer();
     bool force = mCaches.unbindMeshBuffer();
@@ -2670,7 +2717,7 @@
     const float sy = y - shadow->top + textShadow.dy;
 
     const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
-    if (mDrawModifiers.mShader) {
+    if (getShader(paint)) {
         textShadow.color = SK_ColorWHITE;
     }
 
@@ -2678,7 +2725,7 @@
     setupDrawWithTexture(true);
     setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
     setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader();
+    setupDrawShader(getShader(paint));
     setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
@@ -2686,7 +2733,7 @@
     setupDrawTexture(shadow->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms();
+    setupDrawShaderUniforms(getShader(paint));
     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -3008,21 +3055,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Shaders
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetShader() {
-    mDrawModifiers.mShader = NULL;
-}
-
-void OpenGLRenderer::setupShader(SkiaShader* shader) {
-    mDrawModifiers.mShader = shader;
-    if (mDrawModifiers.mShader) {
-        mDrawModifiers.mShader->setCaches(mCaches);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Draw filters
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -3080,7 +3112,7 @@
     setupDrawWithTexture(true);
     setupDrawAlpha8Color(paint->getColor(), alpha);
     setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader();
+    setupDrawShader(getShader(paint));
     setupDrawBlending(paint, true);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
@@ -3088,7 +3120,7 @@
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms();
+    setupDrawShaderUniforms(getShader(paint));
     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
 
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -3254,7 +3286,7 @@
 
     int color = paint->getColor();
     // If a shader is set, preserve only the alpha
-    if (mDrawModifiers.mShader) {
+    if (getShader(paint)) {
         color |= 0x00ffffff;
     }
 
@@ -3290,15 +3322,15 @@
     setupDraw();
     setupDrawNoTexture();
     setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
-    setupDrawShader();
+    setupDrawShader(getShader(paint));
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawBlending(paint);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
     setupDrawModelView(kModelViewMode_Translate, false,
             0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
-    setupDrawColorUniforms();
-    setupDrawShaderUniforms();
+    setupDrawColorUniforms(getShader(paint));
+    setupDrawShaderUniforms(getShader(paint));
     setupDrawColorFilterUniforms(getColorFilter(paint));
 
     if (dirty && hasLayer()) {
@@ -3314,21 +3346,21 @@
         const SkPaint* paint, bool ignoreTransform) {
     int color = paint->getColor();
     // If a shader is set, preserve only the alpha
-    if (mDrawModifiers.mShader) {
+    if (getShader(paint)) {
         color |= 0x00ffffff;
     }
 
     setupDraw();
     setupDrawNoTexture();
     setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
-    setupDrawShader();
+    setupDrawShader(getShader(paint));
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawBlending(paint);
     setupDrawProgram();
     setupDrawModelView(kModelViewMode_TranslateAndScale, false,
             left, top, right, bottom, ignoreTransform);
-    setupDrawColorUniforms();
-    setupDrawShaderUniforms(ignoreTransform);
+    setupDrawColorUniforms(getShader(paint));
+    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawSimpleMesh();
 
@@ -3441,7 +3473,7 @@
         setupDrawAlpha8Color(color, alpha);
     }
     setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader();
+    setupDrawShader(getShader(paint));
     setupDrawBlending(paint, true);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
@@ -3449,7 +3481,7 @@
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms(ignoreTransform);
+    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
     setupDrawMesh(vertices, texCoords);
 
     glDrawArrays(drawMode, 0, elementsCount);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index c6d9071..fc27947 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -26,7 +26,6 @@
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkRegion.h>
-#include <SkShader.h>
 #include <SkXfermode.h>
 
 #include <utils/Blur.h>
@@ -45,13 +44,15 @@
 #include "Program.h"
 #include "Rect.h"
 #include "Renderer.h"
-#include "StatefulBaseRenderer.h"
 #include "Snapshot.h"
+#include "StatefulBaseRenderer.h"
 #include "UvMapper.h"
 #include "Vertex.h"
 #include "Caches.h"
 #include "CanvasProperty.h"
 
+class SkShader;
+
 namespace android {
 namespace uirenderer {
 
@@ -59,7 +60,6 @@
 class RenderNode;
 class TextSetupFunctor;
 class VertexBuffer;
-class SkiaShader;
 
 struct DrawModifiers {
     DrawModifiers() {
@@ -70,7 +70,6 @@
         memset(this, 0, sizeof(DrawModifiers));
     }
 
-    SkiaShader* mShader;
     float mOverrideLayerAlpha;
 
     // Draw filters
@@ -217,9 +216,6 @@
     status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ,
             float casterAlpha, bool casterUnclipped, const SkPath* casterPerimeter);
 
-    virtual void resetShader();
-    virtual void setupShader(SkiaShader* shader);
-
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
@@ -467,6 +463,14 @@
     }
 
     /**
+     * Safely retrieves the Shader from the given Paint. If the paint is
+     * null then null is returned.
+     */
+    static inline const SkShader* getShader(const SkPaint* paint) {
+        return paint ? paint->getShader() : NULL;
+    }
+
+    /**
      * Set to true to suppress error checks at the end of a frame.
      */
     virtual bool suppressErrorChecks() const {
@@ -838,7 +842,7 @@
     void setupDrawColor(float r, float g, float b, float a);
     void setupDrawAlpha8Color(int color, int alpha);
     void setupDrawTextGamma(const SkPaint* paint);
-    void setupDrawShader();
+    void setupDrawShader(const SkShader* shader);
     void setupDrawColorFilter(const SkColorFilter* filter);
     void setupDrawBlending(const Layer* layer, bool swapSrcDst = false);
     void setupDrawBlending(const SkPaint* paint, bool blend = true, bool swapSrcDst = false);
@@ -862,9 +866,17 @@
      */
     void setupDrawModelView(ModelViewMode mode, bool offset,
             float left, float top, float right, float bottom, bool ignoreTransform = false);
-    void setupDrawColorUniforms();
+    void setupDrawColorUniforms(bool hasShader);
     void setupDrawPureColorUniforms();
-    void setupDrawShaderUniforms(bool ignoreTransform = false);
+
+    /**
+     * Setup uniforms for the current shader.
+     *
+     * @param shader SkShader on the current paint.
+     *
+     * @param ignoreTransform Set to true to ignore the transform in shader.
+     */
+    void setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform = false);
     void setupDrawColorFilterUniforms(const SkColorFilter* paint);
     void setupDrawSimpleMesh();
     void setupDrawTexture(GLuint texture);
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index e191a26..23cab0e 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -35,7 +35,6 @@
 class Layer;
 class Matrix4;
 class SkiaColorFilter;
-class SkiaShader;
 class Patch;
 
 enum DrawOpMode {
@@ -183,9 +182,6 @@
     virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
 
     // Misc - should be implemented with SkPaint inspection
-    virtual void resetShader() = 0;
-    virtual void setupShader(SkiaShader* shader) = 0;
-
     virtual void resetPaintFilter() = 0;
     virtual void setupPaintFilter(int clearBits, int setBits) = 0;
 
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 13a3e8e..8b553d1 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -71,11 +71,6 @@
     incrementRefcount((void*) pathResource, kPath);
 }
 
-void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
-    SkSafeRef(shaderResource->getSkShader());
-    incrementRefcount((void*) shaderResource, kShader);
-}
-
 void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
     incrementRefcount((void*) patchResource, kNinePatch);
 }
@@ -104,11 +99,6 @@
     incrementRefcountLocked((void*) pathResource, kPath);
 }
 
-void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) {
-    SkSafeRef(shaderResource->getSkShader());
-    incrementRefcountLocked((void*) shaderResource, kShader);
-}
-
 void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
     incrementRefcountLocked((void*) patchResource, kNinePatch);
 }
@@ -132,11 +122,6 @@
     decrementRefcount((void*) pathResource);
 }
 
-void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
-    SkSafeUnref(shaderResource->getSkShader());
-    decrementRefcount((void*) shaderResource);
-}
-
 void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
     decrementRefcount((void*) patchResource);
 }
@@ -168,11 +153,6 @@
     decrementRefcountLocked((void*) pathResource);
 }
 
-void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) {
-    SkSafeUnref(shaderResource->getSkShader());
-    decrementRefcountLocked((void*) shaderResource);
-}
-
 void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
     decrementRefcountLocked((void*) patchResource);
 }
@@ -227,25 +207,6 @@
     }
 }
 
-void ResourceCache::destructor(SkiaShader* resource) {
-    Mutex::Autolock _l(mLock);
-    destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(SkiaShader* resource) {
-    ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
-        // If we're not tracking this resource, just delete it
-        delete resource;
-        return;
-    }
-    ref->destroyed = true;
-    if (ref->refCount == 0) {
-        deleteResourceReferenceLocked(resource, ref);
-    }
-}
-
 void ResourceCache::destructor(Res_png_9patch* resource) {
     Mutex::Autolock _l(mLock);
     destructorLocked(resource);
@@ -333,11 +294,6 @@
                 }
             }
             break;
-            case kShader: {
-                SkiaShader* shader = (SkiaShader*) resource;
-                delete shader;
-            }
-            break;
             case kNinePatch: {
                 if (Caches::hasInstance()) {
                     Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 4097ba4..3864d4b 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -20,7 +20,6 @@
 #include <cutils/compiler.h>
 
 #include <SkBitmap.h>
-#include <SkiaShader.h>
 
 #include <utils/KeyedVector.h>
 
@@ -36,7 +35,6 @@
  */
 enum ResourceType {
     kBitmap,
-    kShader,
     kNinePatch,
     kPath,
     kLayer
@@ -70,36 +68,30 @@
 
     void incrementRefcount(const SkPath* resource);
     void incrementRefcount(const SkBitmap* resource);
-    void incrementRefcount(SkiaShader* resource);
     void incrementRefcount(const Res_png_9patch* resource);
     void incrementRefcount(Layer* resource);
 
     void incrementRefcountLocked(const SkPath* resource);
     void incrementRefcountLocked(const SkBitmap* resource);
-    void incrementRefcountLocked(SkiaShader* resource);
     void incrementRefcountLocked(const Res_png_9patch* resource);
     void incrementRefcountLocked(Layer* resource);
 
     void decrementRefcount(const SkBitmap* resource);
     void decrementRefcount(const SkPath* resource);
-    void decrementRefcount(SkiaShader* resource);
     void decrementRefcount(const Res_png_9patch* resource);
     void decrementRefcount(Layer* resource);
 
     void decrementRefcountLocked(const SkBitmap* resource);
     void decrementRefcountLocked(const SkPath* resource);
-    void decrementRefcountLocked(SkiaShader* resource);
     void decrementRefcountLocked(const Res_png_9patch* resource);
     void decrementRefcountLocked(Layer* resource);
 
     void destructor(SkPath* resource);
     void destructor(const SkBitmap* resource);
-    void destructor(SkiaShader* resource);
     void destructor(Res_png_9patch* resource);
 
     void destructorLocked(SkPath* resource);
     void destructorLocked(const SkBitmap* resource);
-    void destructorLocked(SkiaShader* resource);
     void destructorLocked(Res_png_9patch* resource);
 
     bool recycle(SkBitmap* resource);
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 6a4a0c8..c672bc4 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -21,9 +21,10 @@
 #include <SkMatrix.h>
 
 #include "Caches.h"
+#include "Layer.h"
+#include "Matrix.h"
 #include "SkiaShader.h"
 #include "Texture.h"
-#include "Matrix.h"
 
 namespace android {
 namespace uirenderer {
@@ -54,89 +55,142 @@
             a);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Base shader
-///////////////////////////////////////////////////////////////////////////////
-
-void SkiaShader::copyFrom(const SkiaShader& shader) {
-    mType = shader.mType;
-    mKey = shader.mKey;
-    mTileX = shader.mTileX;
-    mTileY = shader.mTileY;
-    mBlend = shader.mBlend;
-    mUnitMatrix = shader.mUnitMatrix;
-    mShaderMatrix = shader.mShaderMatrix;
-    mGenerationId = shader.mGenerationId;
-}
-
-SkiaShader::SkiaShader(): mCaches(NULL) {
-}
-
-SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
-        SkShader::TileMode tileY, const SkMatrix* matrix, bool blend):
-        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
-        mCaches(NULL) {
-    setMatrix(matrix);
-    mGenerationId = 0;
-}
-
-SkiaShader::~SkiaShader() {
-}
-
-void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) {
-}
-
-void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-        GLuint* textureUnit) {
-}
-
-void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
-    mCaches->bindTexture(texture->id);
+static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
+    caches->bindTexture(texture->id);
     texture->setWrapST(wrapS, wrapT);
 }
 
-void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
-    screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
-    screenSpace.multiply(modelView);
+/**
+ * Compute the matrix to transform to screen space.
+ * @param screenSpace Output param for the computed matrix.
+ * @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient,
+ *      or identity.
+ * @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix().
+ * @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer.
+ */
+static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix,
+        const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
+    mat4 shaderMatrix;
+    // uses implicit construction
+    shaderMatrix.loadInverse(localMatrix);
+    // again, uses implicit construction
+    screenSpace.loadMultiply(unitMatrix, shaderMatrix);
+    screenSpace.multiply(modelViewMatrix);
+}
+
+// Returns true if one is a bitmap and the other is a gradient
+static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) {
+    return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType)
+            || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType);
+}
+
+SkiaShaderType SkiaShader::getType(const SkShader& shader) {
+    // First check for a gradient shader.
+    switch (shader.asAGradient(NULL)) {
+        case SkShader::kNone_GradientType:
+            // Not a gradient shader. Fall through to check for other types.
+            break;
+        case SkShader::kLinear_GradientType:
+        case SkShader::kRadial_GradientType:
+        case SkShader::kSweep_GradientType:
+            return kGradient_SkiaShaderType;
+        default:
+            // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip.
+            return kNone_SkiaShaderType;
+    }
+
+    // The shader is not a gradient. Check for a bitmap shader.
+    if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
+        return kBitmap_SkiaShaderType;
+    }
+
+    // Check for a ComposeShader.
+    SkShader::ComposeRec rec;
+    if (shader.asACompose(&rec)) {
+        const SkiaShaderType shaderAType = getType(*rec.fShaderA);
+        const SkiaShaderType shaderBType = getType(*rec.fShaderB);
+
+        // Compose is only supported if one is a bitmap and the other is a
+        // gradient. Otherwise, return None to skip.
+        if (!bitmapAndGradient(shaderAType, shaderBType)) {
+            return kNone_SkiaShaderType;
+        }
+        return kCompose_SkiaShaderType;
+    }
+
+    if (shader.asACustomShader(NULL)) {
+        return kLayer_SkiaShaderType;
+    }
+
+    return kNone_SkiaShaderType;
+}
+
+typedef void (*describeProc)(Caches* caches, ProgramDescription& description,
+        const Extensions& extensions, const SkShader& shader);
+
+describeProc gDescribeProc[] = {
+    InvalidSkiaShader::describe,
+    SkiaBitmapShader::describe,
+    SkiaGradientShader::describe,
+    SkiaComposeShader::describe,
+    SkiaLayerShader::describe,
+};
+
+typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix,
+        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
+
+setupProgramProc gSetupProgramProc[] = {
+    InvalidSkiaShader::setupProgram,
+    SkiaBitmapShader::setupProgram,
+    SkiaGradientShader::setupProgram,
+    SkiaComposeShader::setupProgram,
+    SkiaLayerShader::setupProgram,
+};
+
+void SkiaShader::describe(Caches* caches, ProgramDescription& description,
+        const Extensions& extensions, const SkShader& shader) {
+    gDescribeProc[getType(shader)](caches, description, extensions, shader);
+}
+
+void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
+        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
+
+    gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Layer shader
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaLayerShader::SkiaLayerShader(Layer* layer, const SkMatrix* matrix):
-        SkiaShader(kBitmap, NULL, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
-                matrix, layer->isBlend()), mLayer(layer) {
-    updateLocalMatrix(matrix);
-}
-
-SkiaShader* SkiaLayerShader::copy() {
-    SkiaLayerShader* copy = new SkiaLayerShader();
-    copy->copyFrom(*this);
-    copy->mLayer = mLayer;
-    return copy;
-}
-
-void SkiaLayerShader::describe(ProgramDescription& description, const Extensions& extensions) {
+void SkiaLayerShader::describe(Caches*, ProgramDescription& description,
+        const Extensions&, const SkShader& shader) {
     description.hasBitmap = true;
 }
 
-void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView,
-        const Snapshot& snapshot, GLuint* textureUnit) {
-    GLuint textureSlot = (*textureUnit)++;
-    Caches::getInstance().activeTexture(textureSlot);
+void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
+        GLuint* textureUnit, const Extensions&, const SkShader& shader) {
+    Layer* layer;
+    if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) {
+        LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!");
+    }
 
-    const float width = mLayer->getWidth();
-    const float height = mLayer->getHeight();
+    GLuint textureSlot = (*textureUnit)++;
+    caches->activeTexture(textureSlot);
+
+    const float width = layer->getWidth();
+    const float height = layer->getHeight();
 
     mat4 textureTransform;
-    computeScreenSpaceMatrix(textureTransform, modelView);
+    computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
+            modelViewMatrix);
+
 
     // Uniforms
-    mLayer->bindTexture();
-    mLayer->setWrap(GL_CLAMP_TO_EDGE);
-    mLayer->setFilter(GL_LINEAR);
+    layer->bindTexture();
+    layer->setWrap(GL_CLAMP_TO_EDGE);
+    layer->setFilter(GL_LINEAR);
 
+    Program* program = caches->currentProgram;
     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
@@ -147,67 +201,99 @@
 // Bitmap shader
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
-        SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
-        SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
-    updateLocalMatrix(matrix);
-}
+struct BitmapShaderInfo {
+    float width;
+    float height;
+    GLenum wrapS;
+    GLenum wrapT;
+    Texture* texture;
+};
 
-SkiaShader* SkiaBitmapShader::copy() {
-    SkiaBitmapShader* copy = new SkiaBitmapShader();
-    copy->copyFrom(*this);
-    copy->mBitmap = mBitmap;
-    return copy;
-}
-
-void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
-    Texture* texture = mCaches->textureCache.get(mBitmap);
-    if (!texture) return;
-    mTexture = texture;
+static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description,
+        BitmapShaderInfo* shaderInfo,
+        const Extensions& extensions,
+        const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) {
+    Texture* texture = caches->textureCache.get(&bitmap);
+    if (!texture) return false;
 
     const float width = texture->width;
     const float height = texture->height;
+    GLenum wrapS, wrapT;
 
-    description.hasBitmap = true;
+    if (description) {
+        description->hasBitmap = true;
+    }
     // The driver does not support non-power of two mirrored/repeated
     // textures, so do it ourselves
     if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
-            (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
-        description.isBitmapNpot = true;
-        description.bitmapWrapS = gTileModes[mTileX];
-        description.bitmapWrapT = gTileModes[mTileY];
-        mWrapS = GL_CLAMP_TO_EDGE;
-        mWrapT = GL_CLAMP_TO_EDGE;
+            (tileModes[0] != SkShader::kClamp_TileMode ||
+             tileModes[1] != SkShader::kClamp_TileMode)) {
+        if (description) {
+            description->isBitmapNpot = true;
+            description->bitmapWrapS = gTileModes[tileModes[0]];
+            description->bitmapWrapT = gTileModes[tileModes[1]];
+        }
+        wrapS = GL_CLAMP_TO_EDGE;
+        wrapT = GL_CLAMP_TO_EDGE;
     } else {
-        mWrapS = gTileModes[mTileX];
-        mWrapT = gTileModes[mTileY];
+        wrapS = gTileModes[tileModes[0]];
+        wrapT = gTileModes[tileModes[1]];
     }
+
+    if (shaderInfo) {
+        shaderInfo->width = width;
+        shaderInfo->height = height;
+        shaderInfo->wrapS = wrapS;
+        shaderInfo->wrapT = wrapT;
+        shaderInfo->texture = texture;
+    }
+    return true;
 }
 
-void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
-        const Snapshot&, GLuint* textureUnit) {
+void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description,
+        const Extensions& extensions, const SkShader& shader) {
+    SkBitmap bitmap;
+    SkShader::TileMode xy[2];
+    if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
+        LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!");
+    }
+    bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy);
+}
+
+void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
+        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
+    SkBitmap bitmap;
+    SkShader::TileMode xy[2];
+    if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
+        LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!");
+    }
+
     GLuint textureSlot = (*textureUnit)++;
     Caches::getInstance().activeTexture(textureSlot);
 
-    Texture* texture = mTexture;
-    mTexture = NULL;
-    if (!texture) return;
+    BitmapShaderInfo shaderInfo;
+    if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) {
+        return;
+    }
+
+    Program* program = caches->currentProgram;
+    Texture* texture = shaderInfo.texture;
+
     const AutoTexture autoCleanup(texture);
 
-    const float width = texture->width;
-    const float height = texture->height;
-
     mat4 textureTransform;
-    computeScreenSpaceMatrix(textureTransform, modelView);
+    computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
+            modelViewMatrix);
 
     // Uniforms
-    bindTexture(texture, mWrapS, mWrapT);
+    bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
     texture->setFilter(GL_LINEAR);
 
     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
+    glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width,
+            1.0f / shaderInfo.height);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -225,74 +311,6 @@
     matrix->postScale(inv, inv);
 }
 
-SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
-        float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
-        SkMatrix* matrix, bool blend):
-        SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
-        mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
-    SkPoint points[2];
-    points[0].set(bounds[0], bounds[1]);
-    points[1].set(bounds[2], bounds[3]);
-
-    SkMatrix unitMatrix;
-    toUnitMatrix(points, &unitMatrix);
-    mUnitMatrix.load(unitMatrix);
-
-    updateLocalMatrix(matrix);
-
-    mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
-}
-
-SkiaLinearGradientShader::~SkiaLinearGradientShader() {
-    delete[] mBounds;
-    delete[] mColors;
-    delete[] mPositions;
-}
-
-SkiaShader* SkiaLinearGradientShader::copy() {
-    SkiaLinearGradientShader* copy = new SkiaLinearGradientShader();
-    copy->copyFrom(*this);
-    copy->mBounds = new float[4];
-    memcpy(copy->mBounds, mBounds, sizeof(float) * 4);
-    copy->mColors = new uint32_t[mCount];
-    memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
-    copy->mPositions = new float[mCount];
-    memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
-    copy->mCount = mCount;
-    copy->mIsSimple = mIsSimple;
-    return copy;
-}
-
-void SkiaLinearGradientShader::describe(ProgramDescription& description,
-        const Extensions& extensions) {
-    description.hasGradient = true;
-    description.gradientType = ProgramDescription::kGradientLinear;
-    description.isSimpleGradient = mIsSimple;
-}
-
-void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
-        const Snapshot&, GLuint* textureUnit) {
-    if (CC_UNLIKELY(!mIsSimple)) {
-        GLuint textureSlot = (*textureUnit)++;
-        Caches::getInstance().activeTexture(textureSlot);
-
-        Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
-
-        // Uniforms
-        bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
-        glUniform1i(program->getUniform("gradientSampler"), textureSlot);
-    } else {
-        bindUniformColor(program->getUniform("startColor"), mColors[0]);
-        bindUniformColor(program->getUniform("endColor"), mColors[1]);
-    }
-
-    Caches::getInstance().dither.setupProgram(program, textureUnit);
-
-    mat4 screenSpace;
-    computeScreenSpaceMatrix(screenSpace, modelView);
-    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Circular gradient shader
 ///////////////////////////////////////////////////////////////////////////////
@@ -304,37 +322,6 @@
     matrix->postScale(inv, inv);
 }
 
-SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
-        uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
-        SkMatrix* matrix, bool blend):
-        SkiaSweepGradientShader(kCircularGradient, colors, positions, count, key,
-                tileMode, matrix, blend) {
-    SkMatrix unitMatrix;
-    toCircularUnitMatrix(x, y, radius, &unitMatrix);
-    mUnitMatrix.load(unitMatrix);
-
-    updateLocalMatrix(matrix);
-}
-
-SkiaShader* SkiaCircularGradientShader::copy() {
-    SkiaCircularGradientShader* copy = new SkiaCircularGradientShader();
-    copy->copyFrom(*this);
-    copy->mColors = new uint32_t[mCount];
-    memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
-    copy->mPositions = new float[mCount];
-    memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
-    copy->mCount = mCount;
-    copy->mIsSimple = mIsSimple;
-    return copy;
-}
-
-void SkiaCircularGradientShader::describe(ProgramDescription& description,
-        const Extensions& extensions) {
-    description.hasGradient = true;
-    description.gradientType = ProgramDescription::kGradientCircular;
-    description.isSimpleGradient = mIsSimple;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Sweep gradient shader
 ///////////////////////////////////////////////////////////////////////////////
@@ -343,74 +330,103 @@
     matrix->setTranslate(-x, -y);
 }
 
-SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
-        float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
-        SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
-                SkShader::kClamp_TileMode, matrix, blend),
-        mColors(colors), mPositions(positions), mCount(count) {
-    SkMatrix unitMatrix;
-    toSweepUnitMatrix(x, y, &unitMatrix);
-    mUnitMatrix.load(unitMatrix);
+///////////////////////////////////////////////////////////////////////////////
+// Common gradient code
+///////////////////////////////////////////////////////////////////////////////
 
-    updateLocalMatrix(matrix);
-
-    mIsSimple = count == 2;
+static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) {
+    return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode;
 }
 
-SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, uint32_t* colors,
-        float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
-        SkMatrix* matrix, bool blend):
-        SkiaShader(type, key, tileMode, tileMode, matrix, blend),
-        mColors(colors), mPositions(positions), mCount(count) {
-    // protected method, that doesn't setup mUnitMatrix - should be handled by subclass
+void SkiaGradientShader::describe(Caches*, ProgramDescription& description,
+        const Extensions& extensions, const SkShader& shader) {
+    SkShader::GradientInfo gradInfo;
+    gradInfo.fColorCount = 0;
+    gradInfo.fColors = NULL;
+    gradInfo.fColorOffsets = NULL;
 
-    mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
-}
-
-SkiaSweepGradientShader::~SkiaSweepGradientShader() {
-    delete[] mColors;
-    delete[] mPositions;
-}
-
-SkiaShader* SkiaSweepGradientShader::copy() {
-    SkiaSweepGradientShader* copy = new SkiaSweepGradientShader();
-    copy->copyFrom(*this);
-    copy->mColors = new uint32_t[mCount];
-    memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
-    copy->mPositions = new float[mCount];
-    memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
-    copy->mCount = mCount;
-    copy->mIsSimple = mIsSimple;
-    return copy;
-}
-
-void SkiaSweepGradientShader::describe(ProgramDescription& description,
-        const Extensions& extensions) {
+    switch (shader.asAGradient(&gradInfo)) {
+        case SkShader::kLinear_GradientType:
+            description.gradientType = ProgramDescription::kGradientLinear;
+            break;
+        case SkShader::kRadial_GradientType:
+            description.gradientType = ProgramDescription::kGradientCircular;
+            break;
+        case SkShader::kSweep_GradientType:
+            description.gradientType = ProgramDescription::kGradientSweep;
+            break;
+        default:
+            // Do nothing. This shader is unsupported.
+            return;
+    }
     description.hasGradient = true;
-    description.gradientType = ProgramDescription::kGradientSweep;
-    description.isSimpleGradient = mIsSimple;
+    description.isSimpleGradient = isSimpleGradient(gradInfo);
 }
 
-void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
-        const Snapshot& snapshot, GLuint* textureUnit) {
-    if (CC_UNLIKELY(!mIsSimple)) {
-        GLuint textureSlot = (*textureUnit)++;
-        Caches::getInstance().activeTexture(textureSlot);
+void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
+        GLuint* textureUnit, const Extensions&, const SkShader& shader) {
+    // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient
+    // how much space has been allocated for fColors and fColorOffsets.  10 was chosen
+    // arbitrarily, but should be >= 2.
+    // As output, it tells the number of actual colors/offsets in the gradient.
+    const int COLOR_COUNT = 10;
+    SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT);
+    SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT);
 
-        Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
+    SkShader::GradientInfo gradInfo;
+    gradInfo.fColorCount = COLOR_COUNT;
+    gradInfo.fColors = colorStorage.get();
+    gradInfo.fColorOffsets = positionStorage.get();
+
+    SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
+
+    Program* program = caches->currentProgram;
+    if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
+        if (gradInfo.fColorCount > COLOR_COUNT) {
+            // There was not enough room in our arrays for all the colors and offsets. Try again,
+            // now that we know the true number of colors.
+            gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount);
+            gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount);
+
+            shader.asAGradient(&gradInfo);
+        }
+        GLuint textureSlot = (*textureUnit)++;
+        caches->activeTexture(textureSlot);
+
+#ifndef SK_SCALAR_IS_FLOAT
+    #error Need to convert gradInfo.fColorOffsets to float!
+#endif
+        Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets,
+                gradInfo.fColorCount);
 
         // Uniforms
-        bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
+        bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
         glUniform1i(program->getUniform("gradientSampler"), textureSlot);
     } else {
-       bindUniformColor(program->getUniform("startColor"), mColors[0]);
-       bindUniformColor(program->getUniform("endColor"), mColors[1]);
+        bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]);
+        bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]);
     }
 
-    mCaches->dither.setupProgram(program, textureUnit);
+    caches->dither.setupProgram(program, textureUnit);
+
+    SkMatrix unitMatrix;
+    switch (gradType) {
+        case SkShader::kLinear_GradientType:
+            toUnitMatrix(gradInfo.fPoint, &unitMatrix);
+            break;
+        case SkShader::kRadial_GradientType:
+            toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
+                    gradInfo.fRadius[0], &unitMatrix);
+            break;
+        case SkShader::kSweep_GradientType:
+            toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix);
+            break;
+        default:
+            LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType);
+    }
 
     mat4 screenSpace;
-    computeScreenSpaceMatrix(screenSpace, modelView);
+    computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
 
@@ -418,49 +434,39 @@
 // Compose shader
 ///////////////////////////////////////////////////////////////////////////////
 
-SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
-        SkXfermode::Mode mode, SkShader* key):
-        SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
-        NULL, first->blend() || second->blend()),
-        mFirst(first), mSecond(second), mMode(mode), mCleanup(false) {
-}
-
-SkiaComposeShader::~SkiaComposeShader() {
-    if (mCleanup) {
-        delete mFirst;
-        delete mSecond;
+void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description,
+        const Extensions& extensions, const SkShader& shader) {
+    SkShader::ComposeRec rec;
+    if (!shader.asACompose(&rec)) {
+        LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!");
     }
-}
-
-SkiaShader* SkiaComposeShader::copy() {
-    SkiaComposeShader* copy = new SkiaComposeShader();
-    copy->copyFrom(*this);
-    copy->mFirst = mFirst->copy();
-    copy->mSecond = mSecond->copy();
-    copy->mMode = mMode;
-    copy->cleanup();
-    return copy;
-}
-
-void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
-    mFirst->describe(description, extensions);
-    mSecond->describe(description, extensions);
-    if (mFirst->type() == kBitmap) {
+    SkiaShader::describe(caches, description, extensions, *rec.fShaderA);
+    SkiaShader::describe(caches, description, extensions, *rec.fShaderB);
+    if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) {
         description.isBitmapFirst = true;
     }
-    description.shadersMode = mMode;
+    if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) {
+        // TODO: Support other modes.
+        description.shadersMode = SkXfermode::kSrcOver_Mode;
+    }
 }
 
-void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
-        const Snapshot& snapshot, GLuint* textureUnit) {
+void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
+        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
+    SkShader::ComposeRec rec;
+    if (!shader.asACompose(&rec)) {
+        LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!");
+    }
+
     // Apply this compose shader's local transform and pass it down to
     // the child shaders. They will in turn apply their local transform
     // to this matrix.
     mat4 transform;
-    computeScreenSpaceMatrix(transform, modelView);
+    computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(),
+            modelViewMatrix);
 
-    mFirst->setupProgram(program, transform, snapshot, textureUnit);
-    mSecond->setupProgram(program, transform, snapshot, textureUnit);
+    SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA);
+    SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB);
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 9f30257..034c3f6 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -28,249 +28,90 @@
 #include "ProgramCache.h"
 #include "TextureCache.h"
 #include "GradientCache.h"
-#include "Snapshot.h"
 
 namespace android {
 namespace uirenderer {
 
 class Caches;
-
-///////////////////////////////////////////////////////////////////////////////
-// Base shader
-///////////////////////////////////////////////////////////////////////////////
+class Layer;
 
 /**
- * Represents a Skia shader. A shader will modify the GL context and active
- * program to recreate the original effect.
+ * Type of Skia shader in use.
  */
+enum SkiaShaderType {
+    kNone_SkiaShaderType,
+    kBitmap_SkiaShaderType,
+    kGradient_SkiaShaderType,
+    kCompose_SkiaShaderType,
+    kLayer_SkiaShaderType
+};
+
 class SkiaShader {
 public:
-    /**
-     * Type of Skia shader in use.
-     */
-    enum Type {
-        kNone,
-        kBitmap,
-        kLinearGradient,
-        kCircularGradient,
-        kSweepGradient,
-        kCompose
-    };
+    static SkiaShaderType getType(const SkShader& shader);
+    static void describe(Caches* caches, ProgramDescription& description,
+            const Extensions& extensions, const SkShader& shader);
+    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
+            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
+};
 
-    ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
-            SkShader::TileMode tileY, const SkMatrix* matrix, bool blend);
-    virtual ~SkiaShader();
-
-    virtual SkiaShader* copy() = 0;
-    void copyFrom(const SkiaShader& shader);
-
-    virtual void describe(ProgramDescription& description, const Extensions& extensions);
-    virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
-
-    inline SkShader* getSkShader() {
-        return mKey;
+class InvalidSkiaShader {
+public:
+    static void describe(Caches* caches, ProgramDescription& description,
+            const Extensions& extensions, const SkShader& shader) {
+        // This shader is unsupported. Skip it.
+    }
+    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
+            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
+        // This shader is unsupported. Skip it.
     }
 
-    inline bool blend() const {
-        return mBlend;
-    }
-
-    Type type() const {
-        return mType;
-    }
-
-    virtual void setCaches(Caches& caches) {
-        mCaches = &caches;
-    }
-
-    uint32_t getGenerationId() {
-        return mGenerationId;
-    }
-
-    void setMatrix(const SkMatrix* matrix) {
-        updateLocalMatrix(matrix);
-        mGenerationId++;
-    }
-
-    void updateLocalMatrix(const SkMatrix* matrix) {
-        if (matrix) {
-            mat4 localMatrix(*matrix);
-            mShaderMatrix.loadInverse(localMatrix);
-        } else {
-            mShaderMatrix.loadIdentity();
-        }
-    }
-
-    void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
-
-protected:
-    SkiaShader();
-
-    /**
-     * The appropriate texture unit must have been activated prior to invoking
-     * this method.
-     */
-    inline void bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT);
-
-    Type mType;
-    SkShader* mKey;
-    SkShader::TileMode mTileX;
-    SkShader::TileMode mTileY;
-    bool mBlend;
-
-    Caches* mCaches;
-
-    mat4 mUnitMatrix;
-    mat4 mShaderMatrix;
-
-private:
-    uint32_t mGenerationId;
-}; // struct SkiaShader
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Implementations
-///////////////////////////////////////////////////////////////////////////////
-
+};
 /**
  * A shader that draws a layer.
  */
-struct SkiaLayerShader: public SkiaShader {
-    SkiaLayerShader(Layer* layer, const SkMatrix* matrix);
-    SkiaShader* copy();
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
-
-private:
-    SkiaLayerShader() {
-    }
-
-    Layer* mLayer;
-}; // struct SkiaLayerShader
+class SkiaLayerShader {
+public:
+    static void describe(Caches* caches, ProgramDescription& description,
+            const Extensions& extensions, const SkShader& shader);
+    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
+            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
+}; // class SkiaLayerShader
 
 /**
  * A shader that draws a bitmap.
  */
-struct SkiaBitmapShader: public SkiaShader {
-    ANDROID_API SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
-            SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
-    SkiaShader* copy();
+class SkiaBitmapShader {
+public:
+    static void describe(Caches* caches, ProgramDescription& description,
+            const Extensions& extensions, const SkShader& shader);
+    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
+            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
 
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
 
-private:
-    SkiaBitmapShader() : mBitmap(NULL), mTexture(NULL) {
-    }
-
-    SkBitmap* mBitmap;
-    Texture* mTexture;
-    GLenum mWrapS;
-    GLenum mWrapT;
-}; // struct SkiaBitmapShader
+}; // class SkiaBitmapShader
 
 /**
- * A shader that draws a linear gradient.
+ * A shader that draws one of three types of gradient, depending on shader param.
  */
-struct SkiaLinearGradientShader: public SkiaShader {
-    ANDROID_API SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions,
-            int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
-    ~SkiaLinearGradientShader();
-    SkiaShader* copy();
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
-
-private:
-    SkiaLinearGradientShader() {
-    }
-
-    bool mIsSimple;
-    float* mBounds;
-    uint32_t* mColors;
-    float* mPositions;
-    int mCount;
-}; // struct SkiaLinearGradientShader
-
-/**
- * A shader that draws a sweep gradient.
- */
-struct SkiaSweepGradientShader: public SkiaShader {
-    ANDROID_API SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions,
-            int count, SkShader* key, SkMatrix* matrix, bool blend);
-    ~SkiaSweepGradientShader();
-    SkiaShader* copy();
-
-    virtual void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
-
-protected:
-    SkiaSweepGradientShader(Type type, uint32_t* colors, float* positions,
-            int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
-    SkiaSweepGradientShader() {
-    }
-
-    bool mIsSimple;
-    uint32_t* mColors;
-    float* mPositions;
-    int mCount;
-}; // struct SkiaSweepGradientShader
-
-/**
- * A shader that draws a circular gradient.
- */
-struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
-    ANDROID_API SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors,
-            float* positions, int count, SkShader* key,SkShader::TileMode tileMode,
-            SkMatrix* matrix, bool blend);
-    SkiaShader* copy();
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-
-private:
-    SkiaCircularGradientShader() {
-    }
-}; // struct SkiaCircularGradientShader
+class SkiaGradientShader {
+public:
+    static void describe(Caches* caches, ProgramDescription& description,
+            const Extensions& extensions, const SkShader& shader);
+    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
+            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
+};
 
 /**
  * A shader that draws two shaders, composited with an xfermode.
  */
-struct SkiaComposeShader: public SkiaShader {
-    ANDROID_API SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode,
-            SkShader* key);
-    ~SkiaComposeShader();
-    SkiaShader* copy();
-
-    void setCaches(Caches& caches) {
-        SkiaShader::setCaches(caches);
-        mFirst->setCaches(caches);
-        mSecond->setCaches(caches);
-    }
-
-    void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
-
-private:
-    SkiaComposeShader(): mCleanup(false) {
-    }
-
-    void cleanup() {
-        mCleanup = true;
-    }
-
-    SkiaShader* mFirst;
-    SkiaShader* mSecond;
-    SkXfermode::Mode mMode;
-
-    bool mCleanup;
-}; // struct SkiaComposeShader
+class SkiaComposeShader {
+public:
+    static void describe(Caches* caches, ProgramDescription& description,
+            const Extensions& extensions, const SkShader& shader);
+    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
+            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
+}; // class SkiaComposeShader
 
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 34e2265..60b4b96 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -34,7 +34,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 TextureCache::TextureCache():
-        mCache(LruCache<const SkBitmap*, Texture*>::kUnlimitedCapacity),
+        mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity),
         mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
         mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) {
     char property[PROPERTY_VALUE_MAX];
@@ -58,7 +58,7 @@
 }
 
 TextureCache::TextureCache(uint32_t maxByteSize):
-        mCache(LruCache<const SkBitmap*, Texture*>::kUnlimitedCapacity),
+        mCache(LruCache<const SkPixelRef*, Texture*>::kUnlimitedCapacity),
         mSize(0), mMaxSize(maxByteSize) {
     init();
 }
@@ -103,7 +103,7 @@
 // Callbacks
 ///////////////////////////////////////////////////////////////////////////////
 
-void TextureCache::operator()(const SkBitmap*&, Texture*& texture) {
+void TextureCache::operator()(const SkPixelRef*&, Texture*& texture) {
     // This will be called already locked
     if (texture) {
         mSize -= texture->bitmapSize;
@@ -122,7 +122,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void TextureCache::resetMarkInUse() {
-    LruCache<const SkBitmap*, Texture*>::Iterator iter(mCache);
+    LruCache<const SkPixelRef*, Texture*>::Iterator iter(mCache);
     while (iter.next()) {
         iter.value()->isInUse = false;
     }
@@ -140,7 +140,7 @@
 // Returns a prepared Texture* that either is already in the cache or can fit
 // in the cache (and is thus added to the cache)
 Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
-    Texture* texture = mCache.get(bitmap);
+    Texture* texture = mCache.get(bitmap->pixelRef());
 
     if (!texture) {
         if (!canMakeTextureFromBitmap(bitmap)) {
@@ -170,7 +170,7 @@
             if (mDebugEnabled) {
                 ALOGD("Texture created, size = %d", size);
             }
-            mCache.put(bitmap, texture);
+            mCache.put(bitmap->pixelRef(), texture);
         }
     } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
         // Texture was in the cache but is dirty, re-upload
@@ -218,7 +218,7 @@
 }
 
 void TextureCache::remove(const SkBitmap* bitmap) {
-    mCache.remove(bitmap);
+    mCache.remove(bitmap->pixelRef());
 }
 
 void TextureCache::removeDeferred(const SkBitmap* bitmap) {
@@ -231,7 +231,7 @@
     size_t count = mGarbage.size();
     for (size_t i = 0; i < count; i++) {
         const SkBitmap* bitmap = mGarbage.itemAt(i);
-        mCache.remove(bitmap);
+        mCache.remove(bitmap->pixelRef());
         delete bitmap;
     }
     mGarbage.clear();
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 48a10c2..e5b5c1a 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -49,7 +49,7 @@
  * Any texture added to the cache causing the cache to grow beyond the maximum
  * allowed size will also cause the oldest texture to be kicked out.
  */
-class TextureCache: public OnEntryRemoved<const SkBitmap*, Texture*> {
+class TextureCache: public OnEntryRemoved<const SkPixelRef*, Texture*> {
 public:
     TextureCache();
     TextureCache(uint32_t maxByteSize);
@@ -59,7 +59,7 @@
      * Used as a callback when an entry is removed from the cache.
      * Do not invoke directly.
      */
-    void operator()(const SkBitmap*& bitmap, Texture*& texture);
+    void operator()(const SkPixelRef*& pixelRef, Texture*& texture);
 
     /**
      * Resets all Textures to not be marked as in use
@@ -147,7 +147,7 @@
 
     void init();
 
-    LruCache<const SkBitmap*, Texture*> mCache;
+    LruCache<const SkPixelRef*, Texture*> mCache;
 
     uint32_t mSize;
     uint32_t mMaxSize;
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
index 6ad01a0..0f4e122 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java
@@ -302,6 +302,36 @@
                             paint.setShader(ResourceModifiers.instance().mVertGradient);
                         }
                     });
+                    put("radGradient", new DisplayModifier() {
+                        @Override
+                        public void modifyDrawing(Paint paint, Canvas canvas) {
+                            paint.setShader(ResourceModifiers.instance().mRadGradient);
+                        }
+                    });
+                    put("sweepGradient", new DisplayModifier() {
+                        @Override
+                        public void modifyDrawing(Paint paint, Canvas canvas) {
+                            paint.setShader(ResourceModifiers.instance().mSweepGradient);
+                        }
+                    });
+                    put("composeShader", new DisplayModifier() {
+                        @Override
+                        public void modifyDrawing(Paint paint, Canvas canvas) {
+                            paint.setShader(ResourceModifiers.instance().mComposeShader);
+                        }
+                    });
+                    put("bad composeShader", new DisplayModifier() {
+                        @Override
+                        public void modifyDrawing(Paint paint, Canvas canvas) {
+                            paint.setShader(ResourceModifiers.instance().mBadComposeShader);
+                        }
+                    });
+                    put("bad composeShader 2", new DisplayModifier() {
+                        @Override
+                        public void modifyDrawing(Paint paint, Canvas canvas) {
+                            paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader);
+                        }
+                    });
                 }
             });
 
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java
index c705443..d522481 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java
@@ -23,7 +23,11 @@
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapShader;
 import android.graphics.Color;
+import android.graphics.ComposeShader;
 import android.graphics.LinearGradient;
+import android.graphics.PorterDuff;
+import android.graphics.RadialGradient;
+import android.graphics.SweepGradient;
 import android.graphics.Matrix;
 import android.graphics.Shader;
 
@@ -38,6 +42,11 @@
         public final LinearGradient mHorGradient;
         public final LinearGradient mDiagGradient;
         public final LinearGradient mVertGradient;
+        public final RadialGradient mRadGradient;
+        public final SweepGradient mSweepGradient;
+        public final ComposeShader mComposeShader;
+        public final ComposeShader mBadComposeShader;
+        public final ComposeShader mAnotherBadComposeShader;
         public final Bitmap mBitmap;
         private final Matrix mMtx1;
         private final Matrix mMtx2;
@@ -90,6 +99,12 @@
             mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
                     Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
 
+            mSweepGradient = new SweepGradient(mDrawWidth / 2.0f, mDrawHeight / 2.0f,
+                    Color.YELLOW, Color.MAGENTA);
+
+            mComposeShader = new ComposeShader(mRepeatShader, mHorGradient,
+                    PorterDuff.Mode.MULTIPLY);
+
             final float width = mBitmap.getWidth() / 8.0f;
             final float height = mBitmap.getHeight() / 8.0f;
 
@@ -106,6 +121,16 @@
                 0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00,
                 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ff0000,
             };
+
+            // Use a repeating gradient with many colors to test the non simple case.
+            mRadGradient = new RadialGradient(mDrawWidth / 4.0f, mDrawHeight / 4.0f, 4.0f,
+                    mBitmapColors, null, Shader.TileMode.REPEAT);
+
+            mBadComposeShader = new ComposeShader(mRadGradient, mComposeShader,
+                    PorterDuff.Mode.MULTIPLY);
+
+            mAnotherBadComposeShader = new ComposeShader(mRadGradient, mVertGradient,
+                    PorterDuff.Mode.MULTIPLY);
         }
 
 }