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