NinePatch.java revision ffa84e008c712ceffa09d6b89a49882c88b3cca5
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics; 18 19/** 20 * The NinePatch class permits drawing a bitmap in nine or more sections. 21 * Essentially, it allows the creation of custom graphics that will scale the 22 * way that you define, when content added within the image exceeds the normal 23 * bounds of the graphic. For a thorough explanation of a NinePatch image, 24 * read the discussion in the 25 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D 26 * Graphics</a> document. 27 * <p> 28 * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a> 29 * tool offers an extremely handy way to create your NinePatch images, 30 * using a WYSIWYG graphics editor. 31 * </p> 32 */ 33public class NinePatch { 34 /** 35 * Struct of inset information attached to a 9 patch bitmap. 36 * 37 * Present on a 9 patch bitmap if it optical insets were manually included, 38 * or if outline insets were automatically included by aapt. 39 * 40 * @hide 41 */ 42 public static class InsetStruct { 43 @SuppressWarnings({"UnusedDeclaration"}) // called from JNI 44 InsetStruct(int opticalLeft, int opticalTop, int opticalRight, int opticalBottom, 45 int outlineLeft, int outlineTop, int outlineRight, int outlineBottom, 46 float outlineRadius, int outlineAlpha, float decodeScale) { 47 opticalRect = new Rect(opticalLeft, opticalTop, opticalRight, opticalBottom); 48 outlineRect = new Rect(outlineLeft, outlineTop, outlineRight, outlineBottom); 49 50 if (decodeScale != 1.0f) { 51 // if bitmap was scaled when decoded, scale the insets from the metadata values 52 opticalRect.scale(decodeScale); 53 54 // round inward while scaling outline, as the outline should always be conservative 55 outlineRect.scaleRoundIn(decodeScale); 56 } 57 this.outlineRadius = outlineRadius * decodeScale; 58 this.outlineAlpha = outlineAlpha / 255.0f; 59 } 60 61 public final Rect opticalRect; 62 public final Rect outlineRect; 63 public final float outlineRadius; 64 public final float outlineAlpha; 65 } 66 67 private final Bitmap mBitmap; 68 69 /** 70 * Used by native code. This pointer is an instance of Res_png_9patch*. 71 * 72 * @hide 73 */ 74 public long mNativeChunk; 75 76 private Paint mPaint; 77 private String mSrcName; 78 79 /** 80 * Create a drawable projection from a bitmap to nine patches. 81 * 82 * @param bitmap The bitmap describing the patches. 83 * @param chunk The 9-patch data chunk describing how the underlying bitmap 84 * is split apart and drawn. 85 */ 86 public NinePatch(Bitmap bitmap, byte[] chunk) { 87 this(bitmap, chunk, null); 88 } 89 90 /** 91 * Create a drawable projection from a bitmap to nine patches. 92 * 93 * @param bitmap The bitmap describing the patches. 94 * @param chunk The 9-patch data chunk describing how the underlying 95 * bitmap is split apart and drawn. 96 * @param srcName The name of the source for the bitmap. Might be null. 97 */ 98 public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) { 99 mBitmap = bitmap; 100 mSrcName = srcName; 101 mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk); 102 } 103 104 /** 105 * @hide 106 */ 107 public NinePatch(NinePatch patch) { 108 mBitmap = patch.mBitmap; 109 mSrcName = patch.mSrcName; 110 if (patch.mPaint != null) { 111 mPaint = new Paint(patch.mPaint); 112 } 113 // No need to validate the 9patch chunk again, it was done by 114 // the instance we're copying from 115 mNativeChunk = patch.mNativeChunk; 116 } 117 118 @Override 119 protected void finalize() throws Throwable { 120 try { 121 if (mNativeChunk != 0) { 122 // only attempt to destroy correctly initilized chunks 123 nativeFinalize(mNativeChunk); 124 mNativeChunk = 0; 125 } 126 } finally { 127 super.finalize(); 128 } 129 } 130 131 /** 132 * Returns the name of this NinePatch object if one was specified 133 * when calling the constructor. 134 */ 135 public String getName() { 136 return mSrcName; 137 } 138 139 /** 140 * Returns the paint used to draw this NinePatch. The paint can be null. 141 * 142 * @see #setPaint(Paint) 143 * @see #draw(Canvas, Rect) 144 * @see #draw(Canvas, RectF) 145 */ 146 public Paint getPaint() { 147 return mPaint; 148 } 149 150 /** 151 * Sets the paint to use when drawing the NinePatch. 152 * 153 * @param p The paint that will be used to draw this NinePatch. 154 * 155 * @see #getPaint() 156 * @see #draw(Canvas, Rect) 157 * @see #draw(Canvas, RectF) 158 */ 159 public void setPaint(Paint p) { 160 mPaint = p; 161 } 162 163 /** 164 * Returns the bitmap used to draw this NinePatch. 165 */ 166 public Bitmap getBitmap() { 167 return mBitmap; 168 } 169 170 /** 171 * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}. 172 * 173 * @param canvas A container for the current matrix and clip used to draw the NinePatch. 174 * @param location Where to draw the NinePatch. 175 */ 176 public void draw(Canvas canvas, RectF location) { 177 canvas.drawPatch(this, location, mPaint); 178 } 179 180 /** 181 * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}. 182 * 183 * @param canvas A container for the current matrix and clip used to draw the NinePatch. 184 * @param location Where to draw the NinePatch. 185 */ 186 public void draw(Canvas canvas, Rect location) { 187 canvas.drawPatch(this, location, mPaint); 188 } 189 190 /** 191 * Draws the NinePatch. This method will ignore the paint returned 192 * by {@link #getPaint()} and use the specified paint instead. 193 * 194 * @param canvas A container for the current matrix and clip used to draw the NinePatch. 195 * @param location Where to draw the NinePatch. 196 * @param paint The Paint to draw through. 197 */ 198 public void draw(Canvas canvas, Rect location, Paint paint) { 199 canvas.drawPatch(this, location, paint); 200 } 201 202 void drawSoftware(Canvas canvas, RectF location, Paint paint) { 203 nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, 204 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity); 205 } 206 207 void drawSoftware(Canvas canvas, Rect location, Paint paint) { 208 nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, 209 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity); 210 } 211 212 /** 213 * Return the underlying bitmap's density, as per 214 * {@link Bitmap#getDensity() Bitmap.getDensity()}. 215 */ 216 public int getDensity() { 217 return mBitmap.mDensity; 218 } 219 220 /** 221 * Returns the intrinsic width, in pixels, of this NinePatch. This is equivalent 222 * to querying the width of the underlying bitmap returned by {@link #getBitmap()}. 223 */ 224 public int getWidth() { 225 return mBitmap.getWidth(); 226 } 227 228 /** 229 * Returns the intrinsic height, in pixels, of this NinePatch. This is equivalent 230 * to querying the height of the underlying bitmap returned by {@link #getBitmap()}. 231 */ 232 public int getHeight() { 233 return mBitmap.getHeight(); 234 } 235 236 /** 237 * Indicates whether this NinePatch contains transparent or translucent pixels. 238 * This is equivalent to calling <code>getBitmap().hasAlpha()</code> on this 239 * NinePatch. 240 */ 241 public final boolean hasAlpha() { 242 return mBitmap.hasAlpha(); 243 } 244 245 /** 246 * Returns a {@link Region} representing the parts of the NinePatch that are 247 * completely transparent. 248 * 249 * @param bounds The location and size of the NinePatch. 250 * 251 * @return null if the NinePatch has no transparent region to 252 * report, else a {@link Region} holding the parts of the specified bounds 253 * that are transparent. 254 */ 255 public final Region getTransparentRegion(Rect bounds) { 256 long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds); 257 return r != 0 ? new Region(r) : null; 258 } 259 260 /** 261 * Verifies that the specified byte array is a valid 9-patch data chunk. 262 * 263 * @param chunk A byte array representing a 9-patch data chunk. 264 * 265 * @return True if the specified byte array represents a 9-patch data chunk, 266 * false otherwise. 267 */ 268 public native static boolean isNinePatchChunk(byte[] chunk); 269 270 /** 271 * Validates the 9-patch chunk and throws an exception if the chunk is invalid. 272 * If validation is successful, this method returns a native Res_png_9patch* 273 * object used by the renderers. 274 */ 275 private static native long validateNinePatchChunk(long bitmap, byte[] chunk); 276 private static native void nativeFinalize(long chunk); 277 private static native void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance, 278 long c, long paint_instance_or_null, int destDensity, int srcDensity); 279 private static native void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance, 280 long c, long paint_instance_or_null, int destDensity, int srcDensity); 281 private static native long nativeGetTransparentRegion(long bitmap, long chunk, Rect location); 282} 283