Merge "Use layers for reveal drawable"
diff --git a/graphics/java/android/graphics/drawable/RevealDrawable.java b/graphics/java/android/graphics/drawable/RevealDrawable.java
index ca3543a..c357ae1 100644
--- a/graphics/java/android/graphics/drawable/RevealDrawable.java
+++ b/graphics/java/android/graphics/drawable/RevealDrawable.java
@@ -17,14 +17,11 @@
package android.graphics.drawable;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.Shader.TileMode;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -70,15 +67,11 @@
/** Target density, used to scale density-independent pixels. */
private float mDensity = 1.0f;
- // Masking layer.
- private Bitmap mMaskBitmap;
- private Canvas mMaskCanvas;
- private Paint mMaskPaint;
+ /** Paint used to control appearance of ripples. */
+ private Paint mRipplePaint;
- // Reveal layer.
- private Bitmap mRevealBitmap;
- private Canvas mRevealCanvas;
- private Paint mRevealPaint;
+ /** Paint used to control reveal layer masking. */
+ private Paint mMaskingPaint;
/**
* Create a new reveal drawable with the specified list of layers. At least
@@ -232,61 +225,61 @@
@Override
public void draw(Canvas canvas) {
- final Drawable lower = getDrawable(0);
- lower.draw(canvas);
-
- // No ripples? No problem.
- if (mActiveRipples == null || mActiveRipples.isEmpty()) {
+ final int layerCount = getNumberOfLayers();
+ if (layerCount == 0) {
return;
}
- // Ensure we have a mask buffer.
+ getDrawable(0).draw(canvas);
+
+ final ArrayList<Ripple> activeRipples = mActiveRipples;
+ if (layerCount == 1 || activeRipples == null || activeRipples.isEmpty()) {
+ // Nothing to reveal, we're done here.
+ return;
+ }
+
final Rect bounds = getBounds();
final int width = bounds.width();
final int height = bounds.height();
- if (mMaskBitmap == null) {
- mMaskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
- mMaskCanvas = new Canvas(mMaskBitmap);
- mMaskPaint = new Paint();
- mMaskPaint.setAntiAlias(true);
- } else if (mMaskBitmap.getHeight() < height || mMaskBitmap.getWidth() < width) {
- mMaskBitmap.recycle();
- mMaskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
+
+ if (mRipplePaint == null) {
+ mRipplePaint = new Paint();
+ mRipplePaint.setAntiAlias(true);
}
- // Ensure we have a reveal buffer.
- if (mRevealBitmap == null) {
- mRevealBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- mRevealCanvas = new Canvas(mRevealBitmap);
- mRevealPaint = new Paint();
- mRevealPaint.setAntiAlias(true);
- mRevealPaint.setShader(new BitmapShader(mRevealBitmap, TileMode.CLAMP, TileMode.CLAMP));
- } else if (mRevealBitmap.getHeight() < height || mRevealBitmap.getWidth() < width) {
- mRevealBitmap.recycle();
- mRevealBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- }
-
- // Draw ripples into the mask buffer.
- mMaskCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
- int n = mActiveRipples.size();
+ // Draw ripple mask into a buffer that merges using SRC_OVER.
+ int layerSaveCount = -1;
+ int n = activeRipples.size();
for (int i = 0; i < n; i++) {
- final Ripple ripple = mActiveRipples.get(i);
+ final Ripple ripple = activeRipples.get(i);
if (!ripple.active()) {
- mActiveRipples.remove(i);
+ activeRipples.remove(i);
i--;
n--;
} else {
- ripple.draw(mMaskCanvas, mMaskPaint);
+ if (layerSaveCount < 0) {
+ layerSaveCount = canvas.saveLayer(0, 0, width, height, null, 0);
+ }
+
+ ripple.draw(canvas, mRipplePaint);
}
}
- // Draw upper layer into the reveal buffer.
- mRevealCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
- final Drawable upper = getDrawable(1);
- upper.draw(mRevealCanvas);
+ // If a layer was saved, it contains the ripple mask. Draw the reveal
+ // into another layer and composite using SRC_IN, then composite onto
+ // the original canvas.
+ if (layerSaveCount >= 0) {
+ if (mMaskingPaint == null) {
+ mMaskingPaint = new Paint();
+ mMaskingPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+ }
- // Draw mask buffer onto the canvas using the reveal shader.
- canvas.drawBitmap(mMaskBitmap, 0, 0, mRevealPaint);
+ // TODO: When Drawable.setXfermode() is supported by all drawables,
+ // we won't need an extra layer.
+ canvas.saveLayer(0, 0, width, height, mMaskingPaint, 0);
+ getDrawable(1).draw(canvas);
+ canvas.restoreToCount(layerSaveCount);
+ }
}
private static class RevealState extends LayerState {