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/**
21 * The NinePatch class permits drawing a bitmap in nine sections.
22 * The four corners are unscaled; the four edges are scaled in one axis,
23 * and the middle is scaled in both axes. Normally, the middle is
24 * transparent so that the patch can provide a selection about a rectangle.
25 * Essentially, it allows the creation of custom graphics that will scale the
26 * way that you define, when content added within the image exceeds the normal
27 * bounds of the graphic. For a thorough explanation of a NinePatch image,
28 * read the discussion in the
29 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D
30 * Graphics</a> document.
31 * <p>
32 * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a>
33 * tool offers an extremely handy way to create your NinePatch images,
34 * using a WYSIWYG graphics editor.
35 * </p>
36 */
37public class NinePatch {
38    private final Bitmap mBitmap;
39    private final byte[] mChunk;
40    private Paint mPaint;
41    private String mSrcName;  // Useful for debugging
42    private final RectF mRect = new RectF();
43
44    /**
45     * Create a drawable projection from a bitmap to nine patches.
46     *
47     * @param bitmap    The bitmap describing the patches.
48     * @param chunk     The 9-patch data chunk describing how the underlying
49     *                  bitmap is split apart and drawn.
50     * @param srcName   The name of the source for the bitmap. Might be null.
51     */
52    public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
53        mBitmap = bitmap;
54        mChunk = chunk;
55        mSrcName = srcName;
56        validateNinePatchChunk(mBitmap.ni(), chunk);
57    }
58
59    /**
60     * @hide
61     */
62    public NinePatch(NinePatch patch) {
63        mBitmap = patch.mBitmap;
64        mChunk = patch.mChunk;
65        mSrcName = patch.mSrcName;
66        if (patch.mPaint != null) {
67            mPaint = new Paint(patch.mPaint);
68        }
69        validateNinePatchChunk(mBitmap.ni(), mChunk);
70    }
71
72    public void setPaint(Paint p) {
73        mPaint = p;
74    }
75
76    /**
77     * Draw a bitmap of nine patches.
78     *
79     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
80     * @param location  Where to draw the bitmap.
81     */
82    public void draw(Canvas canvas, RectF location) {
83        if (!canvas.isHardwareAccelerated()) {
84            nativeDraw(canvas.mNativeCanvas, location,
85                       mBitmap.ni(), mChunk,
86                       mPaint != null ? mPaint.mNativePaint : 0,
87                       canvas.mDensity, mBitmap.mDensity);
88        } else {
89            canvas.drawPatch(mBitmap, mChunk, location, mPaint);
90        }
91    }
92
93    /**
94     * Draw a bitmap of nine patches.
95     *
96     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
97     * @param location  Where to draw the bitmap.
98     */
99    public void draw(Canvas canvas, Rect location) {
100        if (!canvas.isHardwareAccelerated()) {
101            nativeDraw(canvas.mNativeCanvas, location,
102                        mBitmap.ni(), mChunk,
103                        mPaint != null ? mPaint.mNativePaint : 0,
104                        canvas.mDensity, mBitmap.mDensity);
105        } else {
106            mRect.set(location);
107            canvas.drawPatch(mBitmap, mChunk, mRect, mPaint);
108        }
109    }
110
111    /**
112     * Draw a bitmap of nine patches.
113     *
114     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
115     * @param location  Where to draw the bitmap.
116     * @param paint     The Paint to draw through.
117     */
118    public void draw(Canvas canvas, Rect location, Paint paint) {
119        if (!canvas.isHardwareAccelerated()) {
120            nativeDraw(canvas.mNativeCanvas, location,
121                    mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0,
122                    canvas.mDensity, mBitmap.mDensity);
123        } else {
124            mRect.set(location);
125            canvas.drawPatch(mBitmap, mChunk, mRect, paint);
126        }
127    }
128
129    /**
130     * Return the underlying bitmap's density, as per
131     * {@link Bitmap#getDensity() Bitmap.getDensity()}.
132     */
133    public int getDensity() {
134        return mBitmap.mDensity;
135    }
136
137    public int getWidth() {
138        return mBitmap.getWidth();
139    }
140
141    public int getHeight() {
142        return mBitmap.getHeight();
143    }
144
145    public final boolean hasAlpha() {
146        return mBitmap.hasAlpha();
147    }
148
149    public final Region getTransparentRegion(Rect location) {
150        int r = nativeGetTransparentRegion(mBitmap.ni(), mChunk, location);
151        return r != 0 ? new Region(r) : null;
152    }
153
154    public native static boolean isNinePatchChunk(byte[] chunk);
155
156    private static native void validateNinePatchChunk(int bitmap, byte[] chunk);
157    private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
158                                          byte[] c, int paint_instance_or_null,
159                                          int destDensity, int srcDensity);
160    private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
161                                          byte[] c, int paint_instance_or_null,
162                                          int destDensity, int srcDensity);
163    private static native int nativeGetTransparentRegion(
164            int bitmap, byte[] chunk, Rect location);
165}
166