Home | History | Annotate | Download | only in graphics
      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