Remove unnecessary Rect, better reuse of NinePatch objects
Cloning drawables (which happens a lot) was creating copies of NinePatch
objects, which would cause the hardware renderer to generate more meshes
than necessary. Also avoid keeping a String we don't need (it was interned
but still.) Last but not least, remove 1 RectF per NinePatch in the system.
Change-Id: If4dbfa0c30892c9b00d68875e334fd5c2bde8b94
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index cc7d948..88539f21 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -736,6 +736,21 @@
}
@Override
+ public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+ Bitmap bitmap = patch.getBitmap();
+ if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
+ // Shaders are ignored when drawing patches
+ int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
+ try {
+ final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mChunk,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+ } finally {
+ if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+ }
+ }
+
+ @Override
public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index bbba778..a1c87cb 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1070,9 +1070,23 @@
*
* @hide
*/
+ public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+ }
+
+ /**
+ * Draws the specified bitmap as an N-patch (most often, a 9-patches.)
+ *
+ * Note: Only supported by hardware accelerated canvas at the moment.
+ *
+ * @param patch The ninepatch object to render
+ * @param dst The destination rectangle.
+ * @param paint The paint to draw the bitmap with. may be null
+ *
+ * @hide
+ */
public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
- }
-
+ }
+
/**
* Draw the specified bitmap, with its top/left corner at (x,y), using
* the specified paint, transformed by the current matrix.
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 81e9d84..932e474 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -42,8 +42,18 @@
public final byte[] mChunk;
private Paint mPaint;
private String mSrcName; // Useful for debugging
- private final RectF mRect = new RectF();
-
+
+ /**
+ * Create a drawable projection from a bitmap to nine patches.
+ *
+ * @param bitmap The bitmap describing the patches.
+ * @param chunk The 9-patch data chunk describing how the underlying
+ * bitmap is split apart and drawn.
+ */
+ public NinePatch(Bitmap bitmap, byte[] chunk) {
+ this(bitmap, chunk, null);
+ }
+
/**
* Create a drawable projection from a bitmap to nine patches.
*
@@ -90,13 +100,13 @@
* @param location Where to draw the bitmap.
*/
public void draw(Canvas canvas, RectF location) {
- if (!canvas.isHardwareAccelerated()) {
+ if (canvas.isHardwareAccelerated()) {
+ canvas.drawPatch(this, location, mPaint);
+ } else {
nativeDraw(canvas.mNativeCanvas, location,
mBitmap.ni(), mChunk,
mPaint != null ? mPaint.mNativePaint : 0,
canvas.mDensity, mBitmap.mDensity);
- } else {
- canvas.drawPatch(this, location, mPaint);
}
}
@@ -107,14 +117,13 @@
* @param location Where to draw the bitmap.
*/
public void draw(Canvas canvas, Rect location) {
- if (!canvas.isHardwareAccelerated()) {
+ if (canvas.isHardwareAccelerated()) {
+ canvas.drawPatch(this, location, mPaint);
+ } else {
nativeDraw(canvas.mNativeCanvas, location,
mBitmap.ni(), mChunk,
mPaint != null ? mPaint.mNativePaint : 0,
canvas.mDensity, mBitmap.mDensity);
- } else {
- mRect.set(location);
- canvas.drawPatch(this, mRect, mPaint);
}
}
@@ -126,13 +135,12 @@
* @param paint The Paint to draw through.
*/
public void draw(Canvas canvas, Rect location, Paint paint) {
- if (!canvas.isHardwareAccelerated()) {
+ if (canvas.isHardwareAccelerated()) {
+ canvas.drawPatch(this, location, paint);
+ } else {
nativeDraw(canvas.mNativeCanvas, location,
mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0,
canvas.mDensity, mBitmap.mDensity);
- } else {
- mRect.set(location);
- canvas.drawPatch(this, mRect, paint);
}
}
@@ -170,6 +178,5 @@
private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
byte[] c, int paint_instance_or_null,
int destDensity, int srcDensity);
- private static native int nativeGetTransparentRegion(
- int bitmap, byte[] chunk, Rect location);
+ private static native int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location);
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index b83815b..86e4bad 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -52,7 +52,7 @@
*/
public class NinePatchDrawable extends Drawable {
// dithering helps a lot, and is pretty cheap, so default is true
- private static final boolean DEFAULT_DITHER = true;
+ private static final boolean DEFAULT_DITHER = false;
private NinePatchState mNinePatchState;
private NinePatch mNinePatch;
private Rect mPadding;
@@ -197,10 +197,8 @@
mBitmapHeight = mNinePatch.getHeight();
mOpticalInsets = mNinePatchState.mOpticalInsets;
} else {
- mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(),
- sdensity, tdensity);
- mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(),
- sdensity, tdensity);
+ mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), sdensity, tdensity);
+ mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(), sdensity, tdensity);
if (mNinePatchState.mPadding != null && mPadding != null) {
Rect dest = mPadding;
Rect src = mNinePatchState.mPadding;
@@ -271,6 +269,7 @@
@Override
public void setDither(boolean dither) {
+ //noinspection PointlessBooleanExpression
if (mPaint == null && dither == DEFAULT_DITHER) {
// Fast common case -- leave at default dither.
return;
@@ -299,8 +298,7 @@
}
final boolean dither = a.getBoolean(
- com.android.internal.R.styleable.NinePatchDrawable_dither,
- DEFAULT_DITHER);
+ com.android.internal.R.styleable.NinePatchDrawable_dither, DEFAULT_DITHER);
final BitmapFactory.Options options = new BitmapFactory.Options();
if (dither) {
options.inDither = false;
@@ -330,8 +328,7 @@
": <nine-patch> requires a valid 9-patch source image");
}
- setNinePatchState(new NinePatchState(
- new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
+ setNinePatchState(new NinePatchState(new NinePatch(bitmap, bitmap.getNinePatchChunk()),
padding, opticalInsets, dither), r);
mNinePatchState.mTargetDensity = mTargetDensity;
@@ -429,7 +426,8 @@
// Copy constructor
NinePatchState(NinePatchState state) {
- mNinePatch = new NinePatch(state.mNinePatch);
+ // Note we don't copy the nine patch because it is immutable.
+ mNinePatch = state.mNinePatch;
// Note we don't copy the padding because it is immutable.
mPadding = state.mPadding;
mOpticalInsets = state.mOpticalInsets;