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;