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 or more sections.
22 * Essentially, it allows the creation of custom graphics that will scale the
23 * way that you define, when content added within the image exceeds the normal
24 * bounds of the graphic. For a thorough explanation of a NinePatch image,
25 * read the discussion in the
26 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D
27 * Graphics</a> document.
28 * <p>
29 * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a>
30 * tool offers an extremely handy way to create your NinePatch images,
31 * using a WYSIWYG graphics editor.
32 * </p>
33 */
34public class NinePatch {
35    private final Bitmap mBitmap;
36
37    /**
38     * Used by native code. This pointer is an instance of Res_png_9patch*.
39     *
40     * @hide
41     */
42    public final int mNativeChunk;
43
44    private Paint mPaint;
45    private String mSrcName;
46
47    /**
48     * Create a drawable projection from a bitmap to nine patches.
49     *
50     * @param bitmap The bitmap describing the patches.
51     * @param chunk The 9-patch data chunk describing how the underlying bitmap
52     *              is split apart and drawn.
53     */
54    public NinePatch(Bitmap bitmap, byte[] chunk) {
55        this(bitmap, chunk, null);
56    }
57
58    /**
59     * Create a drawable projection from a bitmap to nine patches.
60     *
61     * @param bitmap The bitmap describing the patches.
62     * @param chunk The 9-patch data chunk describing how the underlying
63     *              bitmap is split apart and drawn.
64     * @param srcName The name of the source for the bitmap. Might be null.
65     */
66    public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
67        mBitmap = bitmap;
68        mSrcName = srcName;
69        mNativeChunk = validateNinePatchChunk(mBitmap.ni(), chunk);
70    }
71
72    /**
73     * @hide
74     */
75    public NinePatch(NinePatch patch) {
76        mBitmap = patch.mBitmap;
77        mSrcName = patch.mSrcName;
78        if (patch.mPaint != null) {
79            mPaint = new Paint(patch.mPaint);
80        }
81        // No need to validate the 9patch chunk again, it was done by
82        // the instance we're copying from
83        mNativeChunk = patch.mNativeChunk;
84    }
85
86    @Override
87    protected void finalize() throws Throwable {
88        try {
89            nativeFinalize(mNativeChunk);
90        } finally {
91            super.finalize();
92        }
93    }
94
95    /**
96     * Returns the name of this NinePatch object if one was specified
97     * when calling the constructor.
98     */
99    public String getName() {
100        return mSrcName;
101    }
102
103    /**
104     * Returns the paint used to draw this NinePatch. The paint can be null.
105     *
106     * @see #setPaint(Paint)
107     * @see #draw(Canvas, Rect)
108     * @see #draw(Canvas, RectF)
109     */
110    public Paint getPaint() {
111        return mPaint;
112    }
113
114    /**
115     * Sets the paint to use when drawing the NinePatch.
116     *
117     * @param p The paint that will be used to draw this NinePatch.
118     *
119     * @see #getPaint()
120     * @see #draw(Canvas, Rect)
121     * @see #draw(Canvas, RectF)
122     */
123    public void setPaint(Paint p) {
124        mPaint = p;
125    }
126
127    /**
128     * Returns the bitmap used to draw this NinePatch.
129     */
130    public Bitmap getBitmap() {
131        return mBitmap;
132    }
133
134    /**
135     * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}.
136     *
137     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
138     * @param location Where to draw the NinePatch.
139     */
140    public void draw(Canvas canvas, RectF location) {
141        canvas.drawPatch(this, location, mPaint);
142    }
143
144    /**
145     * Draws the NinePatch. This method will use the paint returned by {@link #getPaint()}.
146     *
147     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
148     * @param location Where to draw the NinePatch.
149     */
150    public void draw(Canvas canvas, Rect location) {
151        canvas.drawPatch(this, location, mPaint);
152    }
153
154    /**
155     * Draws the NinePatch. This method will ignore the paint returned
156     * by {@link #getPaint()} and use the specified paint instead.
157     *
158     * @param canvas A container for the current matrix and clip used to draw the NinePatch.
159     * @param location Where to draw the NinePatch.
160     * @param paint The Paint to draw through.
161     */
162    public void draw(Canvas canvas, Rect location, Paint paint) {
163        canvas.drawPatch(this, location, paint);
164    }
165
166    void drawSoftware(Canvas canvas, RectF location, Paint paint) {
167        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
168                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
169    }
170
171    void drawSoftware(Canvas canvas, Rect location, Paint paint) {
172        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
173                paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
174    }
175
176    /**
177     * Return the underlying bitmap's density, as per
178     * {@link Bitmap#getDensity() Bitmap.getDensity()}.
179     */
180    public int getDensity() {
181        return mBitmap.mDensity;
182    }
183
184    /**
185     * Returns the intrinsic width, in pixels, of this NinePatch. This is equivalent
186     * to querying the width of the underlying bitmap returned by {@link #getBitmap()}.
187     */
188    public int getWidth() {
189        return mBitmap.getWidth();
190    }
191
192    /**
193     * Returns the intrinsic height, in pixels, of this NinePatch. This is equivalent
194     * to querying the height of the underlying bitmap returned by {@link #getBitmap()}.
195     */
196    public int getHeight() {
197        return mBitmap.getHeight();
198    }
199
200    /**
201     * Indicates whether this NinePatch contains transparent or translucent pixels.
202     * This is equivalent to calling <code>getBitmap().hasAlpha()</code> on this
203     * NinePatch.
204     */
205    public final boolean hasAlpha() {
206        return mBitmap.hasAlpha();
207    }
208
209    /**
210     * Returns a {@link Region} representing the parts of the NinePatch that are
211     * completely transparent.
212     *
213     * @param bounds The location and size of the NinePatch.
214     *
215     * @return null if the NinePatch has no transparent region to
216     * report, else a {@link Region} holding the parts of the specified bounds
217     * that are transparent.
218     */
219    public final Region getTransparentRegion(Rect bounds) {
220        int r = nativeGetTransparentRegion(mBitmap.ni(), mNativeChunk, bounds);
221        return r != 0 ? new Region(r) : null;
222    }
223
224    /**
225     * Verifies that the specified byte array is a valid 9-patch data chunk.
226     *
227     * @param chunk A byte array representing a 9-patch data chunk.
228     *
229     * @return True if the specified byte array represents a 9-patch data chunk,
230     *         false otherwise.
231     */
232    public native static boolean isNinePatchChunk(byte[] chunk);
233
234    /**
235     * Validates the 9-patch chunk and throws an exception if the chunk is invalid.
236     * If validation is successful, this method returns a native Res_png_9patch*
237     * object used by the renderers.
238     */
239    private static native int validateNinePatchChunk(int bitmap, byte[] chunk);
240    private static native void nativeFinalize(int chunk);
241    private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
242            int c, int paint_instance_or_null, int destDensity, int srcDensity);
243    private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
244            int c, int paint_instance_or_null, int destDensity, int srcDensity);
245    private static native int nativeGetTransparentRegion(int bitmap, int chunk, Rect location);
246}
247