NinePatch.java revision 47cd8e921db73e894f94ec4729ade90da50996f5
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, boolean outlineFilled, 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.outlineFilled = outlineFilled; 59 } 60 61 public final Rect opticalRect; 62 public final Rect outlineRect; 63 public final float outlineRadius; 64 public final boolean outlineFilled; 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 final 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 nativeFinalize(mNativeChunk); 122 } finally { 123 super.finalize(); 124 } 125 } 126 127 /** 128 * Returns the name of this NinePatch object if one was specified 129 * when calling the constructor. 130 */ 131 public String getName() { 132 return mSrcName; 133 } 134 135 /** 136 * Returns the paint used to draw this NinePatch. The paint can be null. 137 * 138 * @see #setPaint(Paint) 139 * @see #draw(Canvas, Rect) 140 * @see #draw(Canvas, RectF) 141 */ 142 public Paint getPaint() { 143 return mPaint; 144 } 145 146 /** 147 * Sets the paint to use when drawing the NinePatch. 148 * 149 * @param p The paint that will be used to draw this NinePatch. 150 * 151 * @see #getPaint() 152 * @see #draw(Canvas, Rect) 153 * @see #draw(Canvas, RectF) 154 */ 155 public void setPaint(Paint p) { 156 mPaint = p; 157 } 158 159 /** 160 * Returns the bitmap used to draw this NinePatch. 161 */ 162 public Bitmap getBitmap() { 163 return mBitmap; 164 } 165 166 /** 167 * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}. 168 * 169 * @param canvas A container for the current matrix and clip used to draw the NinePatch. 170 * @param location Where to draw the NinePatch. 171 */ 172 public void draw(Canvas canvas, RectF location) { 173 canvas.drawPatch(this, location, mPaint); 174 } 175 176 /** 177 * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}. 178 * 179 * @param canvas A container for the current matrix and clip used to draw the NinePatch. 180 * @param location Where to draw the NinePatch. 181 */ 182 public void draw(Canvas canvas, Rect location) { 183 canvas.drawPatch(this, location, mPaint); 184 } 185 186 /** 187 * Draws the NinePatch. This method will ignore the paint returned 188 * by {@link #getPaint()} and use the specified paint instead. 189 * 190 * @param canvas A container for the current matrix and clip used to draw the NinePatch. 191 * @param location Where to draw the NinePatch. 192 * @param paint The Paint to draw through. 193 */ 194 public void draw(Canvas canvas, Rect location, Paint paint) { 195 canvas.drawPatch(this, location, paint); 196 } 197 198 void drawSoftware(Canvas canvas, RectF location, Paint paint) { 199 nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, 200 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity); 201 } 202 203 void drawSoftware(Canvas canvas, Rect location, Paint paint) { 204 nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk, 205 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity); 206 } 207 208 /** 209 * Return the underlying bitmap's density, as per 210 * {@link Bitmap#getDensity() Bitmap.getDensity()}. 211 */ 212 public int getDensity() { 213 return mBitmap.mDensity; 214 } 215 216 /** 217 * Returns the intrinsic width, in pixels, of this NinePatch. This is equivalent 218 * to querying the width of the underlying bitmap returned by {@link #getBitmap()}. 219 */ 220 public int getWidth() { 221 return mBitmap.getWidth(); 222 } 223 224 /** 225 * Returns the intrinsic height, in pixels, of this NinePatch. This is equivalent 226 * to querying the height of the underlying bitmap returned by {@link #getBitmap()}. 227 */ 228 public int getHeight() { 229 return mBitmap.getHeight(); 230 } 231 232 /** 233 * Indicates whether this NinePatch contains transparent or translucent pixels. 234 * This is equivalent to calling <code>getBitmap().hasAlpha()</code> on this 235 * NinePatch. 236 */ 237 public final boolean hasAlpha() { 238 return mBitmap.hasAlpha(); 239 } 240 241 /** 242 * Returns a {@link Region} representing the parts of the NinePatch that are 243 * completely transparent. 244 * 245 * @param bounds The location and size of the NinePatch. 246 * 247 * @return null if the NinePatch has no transparent region to 248 * report, else a {@link Region} holding the parts of the specified bounds 249 * that are transparent. 250 */ 251 public final Region getTransparentRegion(Rect bounds) { 252 long r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds); 253 return r != 0 ? new Region(r) : null; 254 } 255 256 /** 257 * Verifies that the specified byte array is a valid 9-patch data chunk. 258 * 259 * @param chunk A byte array representing a 9-patch data chunk. 260 * 261 * @return True if the specified byte array represents a 9-patch data chunk, 262 * false otherwise. 263 */ 264 public native static boolean isNinePatchChunk(byte[] chunk); 265 266 /** 267 * Validates the 9-patch chunk and throws an exception if the chunk is invalid. 268 * If validation is successful, this method returns a native Res_png_9patch* 269 * object used by the renderers. 270 */ 271 private static native long validateNinePatchChunk(long bitmap, byte[] chunk); 272 private static native void nativeFinalize(long chunk); 273 private static native void nativeDraw(long canvas_instance, RectF loc, long bitmap_instance, 274 long c, long paint_instance_or_null, int destDensity, int srcDensity); 275 private static native void nativeDraw(long canvas_instance, Rect loc, long bitmap_instance, 276 long c, long paint_instance_or_null, int destDensity, int srcDensity); 277 private static native long nativeGetTransparentRegion(long bitmap, long chunk, Rect location); 278} 279