Add a way to override Xfermode DO NOT MERGE

Add a non-public API to Canvas/GLES20Canvas to provide a way to draw
the touch ripple animation without using a save layer.

Change-Id: I6e2095adffe515194f669fb75bb67abf813bd518
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b86455a..6de06d4 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -994,4 +994,15 @@
             int indexOffset, int indexCount, Paint paint) {
         // TODO: Implement
     }
+
+    @Override
+    public void setOverrideXfermode(PorterDuff.Mode xfermode) {
+        int xfermodeValue = -1;
+        if (xfermode != null) {
+            xfermodeValue = xfermode.nativeInt;
+        }
+        nSetOverrideXfermode(mRenderer, xfermodeValue);
+    }
+
+    private static native void nSetOverrideXfermode(long renderer, int xfermode);
 }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b023ebd..fe64aba 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -172,6 +172,12 @@
     return Caches::getInstance().maxTextureSize;
 }
 
+static void android_view_GLES20Canvas_setOverrideXfermode(JNIEnv* env, jobject clazz,
+        jlong rendererPtr, int xfermode) {
+    DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);
+    renderer->setOverrideXfermode(xfermode);
+}
+
 // ----------------------------------------------------------------------------
 // State
 // ----------------------------------------------------------------------------
@@ -964,6 +970,8 @@
     { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
     { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
 
+    { "nSetOverrideXfermode", "(JI)V",       (void*) android_view_GLES20Canvas_setOverrideXfermode },
+
 #endif
 };
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index f45c0cb..6baf1aa 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -250,6 +250,15 @@
     public void insertInorderBarrier() {}
 
     /**
+     * Set a transfer mode that overrides any transfer modes
+     * in paints used for drawing. Pass null to disable this
+     * override. Only implemented in GLES20Canvas.
+     *
+     * @hide
+     */
+    public void setOverrideXfermode(@Nullable PorterDuff.Mode xfermode) {}
+
+    /**
      * Return true if the device that the current layer draws into is opaque
      * (i.e. does not support per-pixel alpha).
      *
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index c2cb76e..3ec5e40 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -39,6 +39,7 @@
     , mTranslateY(0.0f)
     , mDeferredBarrierType(kBarrier_None)
     , mHighContrastText(false)
+    , mOverrideXfermode(-1)
     , mRestoreSaveCount(-1) {
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2cc2be3..f93a798 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -20,6 +20,7 @@
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkPath.h>
+#include <SkPorterDuff.h>
 #include <cutils/compiler.h>
 
 #include "DisplayListLogBuffer.h"
@@ -161,6 +162,15 @@
     void setHighContrastText(bool highContrastText) {
         mHighContrastText = highContrastText;
     }
+
+    void setOverrideXfermode(int xfermode) {
+        if (xfermode != -1) {
+            SkPorterDuff::Mode porterDuffMode = static_cast<SkPorterDuff::Mode>(xfermode);
+            xfermode = SkPorterDuff::ToXfermodeMode(porterDuffMode);
+        }
+        mOverrideXfermode = xfermode;
+    };
+
 private:
     enum DeferredBarrierType {
         kBarrier_None,
@@ -220,18 +230,26 @@
     inline const SkPaint* refPaint(const SkPaint* paint) {
         if (!paint) return NULL;
 
-        const SkPaint* paintCopy = mPaintMap.valueFor(paint);
-        if (paintCopy == NULL
-                || paintCopy->getGenerationID() != paint->getGenerationID()
-                // We can't compare shader pointers because that will always
-                // change as we do partial copying via wrapping. However, if the
-                // shader changes the paint generationID will have changed and
-                // so we don't hit this comparison anyway
-                || !(paint->getShader() && paintCopy->getShader()
-                        && paint->getShader()->getGenerationID() == paintCopy->getShader()->getGenerationID())) {
-            paintCopy = copyPaint(paint);
-            // replaceValueFor() performs an add if the entry doesn't exist
-            mPaintMap.replaceValueFor(paint, paintCopy);
+        const SkPaint* paintCopy;
+
+        if (mOverrideXfermode != -1) {
+            SkPaint* overriddenPaint = copyPaint(paint);
+            overriddenPaint->setXfermodeMode(static_cast<SkXfermode::Mode>(mOverrideXfermode));
+            paintCopy = overriddenPaint;
+        } else {
+            paintCopy = mPaintMap.valueFor(paint);
+            if (paintCopy == NULL
+                    || paintCopy->getGenerationID() != paint->getGenerationID()
+                    // We can't compare shader pointers because that will always
+                    // change as we do partial copying via wrapping. However, if the
+                    // shader changes the paint generationID will have changed and
+                    // so we don't hit this comparison anyway
+                    || !(paint->getShader() && paintCopy->getShader()
+                            && paint->getShader()->getGenerationID() == paintCopy->getShader()->getGenerationID())) {
+                paintCopy = copyPaint(paint);
+                // replaceValueFor() performs an add if the entry doesn't exist
+                mPaintMap.replaceValueFor(paint, paintCopy);
+            }
         }
 
         return paintCopy;
@@ -304,6 +322,9 @@
     DeferredBarrierType mDeferredBarrierType;
     bool mHighContrastText;
 
+    // -1 if unset, or SkXfermode::Mode value if set
+    int mOverrideXfermode;
+
     int mRestoreSaveCount;
 
     friend class RenderNode;