19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The NinePatch class permits drawing a bitmap in nine sections.
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The four corners are unscaled; the four edges are scaled in one axis,
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and the middle is scaled in both axes. Normally, the middle is
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * transparent so that the patch can provide a selection about a rectangle.
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Essentially, it allows the creation of custom graphics that will scale the
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * way that you define, when content added within the image exceeds the normal
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * bounds of the graphic. For a thorough explanation of a NinePatch image,
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * read the discussion in the
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Graphics</a> document.
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-Patch</a>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * tool offers an extremely handy way to create your NinePatch images,
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * using a WYSIWYG graphics editor.
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </p>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class NinePatch {
38deba785f122a47915756ffd991f5540d952cf937Romain Guy    private final Bitmap mBitmap;
39deba785f122a47915756ffd991f5540d952cf937Romain Guy    private final byte[] mChunk;
40deba785f122a47915756ffd991f5540d952cf937Romain Guy    private Paint mPaint;
41deba785f122a47915756ffd991f5540d952cf937Romain Guy    private String mSrcName;  // Useful for debugging
42deba785f122a47915756ffd991f5540d952cf937Romain Guy    private final RectF mRect = new RectF();
43deba785f122a47915756ffd991f5540d952cf937Romain Guy
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a drawable projection from a bitmap to nine patches.
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param bitmap    The bitmap describing the patches.
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param chunk     The 9-patch data chunk describing how the underlying
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                  bitmap is split apart and drawn.
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param srcName   The name of the source for the bitmap. Might be null.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public NinePatch(Bitmap bitmap, byte[] chunk, String srcName) {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmap = bitmap;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mChunk = chunk;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSrcName = srcName;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        validateNinePatchChunk(mBitmap.ni(), chunk);
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public NinePatch(NinePatch patch) {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmap = patch.mBitmap;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mChunk = patch.mChunk;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSrcName = patch.mSrcName;
6654285f2cbfb6e307d594ca264f7230b4e1e3cdcePhil Dubach        if (patch.mPaint != null) {
6754285f2cbfb6e307d594ca264f7230b4e1e3cdcePhil Dubach            mPaint = new Paint(patch.mPaint);
6854285f2cbfb6e307d594ca264f7230b4e1e3cdcePhil Dubach        }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        validateNinePatchChunk(mBitmap.ni(), mChunk);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setPaint(Paint p) {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPaint = p;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Draw a bitmap of nine patches.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param location  Where to draw the bitmap.
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas, RectF location) {
83deba785f122a47915756ffd991f5540d952cf937Romain Guy        if (!canvas.isHardwareAccelerated()) {
84deba785f122a47915756ffd991f5540d952cf937Romain Guy            nativeDraw(canvas.mNativeCanvas, location,
85deba785f122a47915756ffd991f5540d952cf937Romain Guy                       mBitmap.ni(), mChunk,
86deba785f122a47915756ffd991f5540d952cf937Romain Guy                       mPaint != null ? mPaint.mNativePaint : 0,
87deba785f122a47915756ffd991f5540d952cf937Romain Guy                       canvas.mDensity, mBitmap.mDensity);
88deba785f122a47915756ffd991f5540d952cf937Romain Guy        } else {
894bb942083a0d4db746adf95349108dd8ef842e32Romain Guy            canvas.drawPatch(mBitmap, mChunk, location, mPaint);
90deba785f122a47915756ffd991f5540d952cf937Romain Guy        }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Draw a bitmap of nine patches.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param location  Where to draw the bitmap.
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas, Rect location) {
100deba785f122a47915756ffd991f5540d952cf937Romain Guy        if (!canvas.isHardwareAccelerated()) {
101deba785f122a47915756ffd991f5540d952cf937Romain Guy            nativeDraw(canvas.mNativeCanvas, location,
102deba785f122a47915756ffd991f5540d952cf937Romain Guy                        mBitmap.ni(), mChunk,
103deba785f122a47915756ffd991f5540d952cf937Romain Guy                        mPaint != null ? mPaint.mNativePaint : 0,
104deba785f122a47915756ffd991f5540d952cf937Romain Guy                        canvas.mDensity, mBitmap.mDensity);
105deba785f122a47915756ffd991f5540d952cf937Romain Guy        } else {
106deba785f122a47915756ffd991f5540d952cf937Romain Guy            mRect.set(location);
1074bb942083a0d4db746adf95349108dd8ef842e32Romain Guy            canvas.drawPatch(mBitmap, mChunk, mRect, mPaint);
108deba785f122a47915756ffd991f5540d952cf937Romain Guy        }
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Draw a bitmap of nine patches.
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param canvas    A container for the current matrix and clip used to draw the bitmap.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param location  Where to draw the bitmap.
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param paint     The Paint to draw through.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas, Rect location, Paint paint) {
119deba785f122a47915756ffd991f5540d952cf937Romain Guy        if (!canvas.isHardwareAccelerated()) {
120deba785f122a47915756ffd991f5540d952cf937Romain Guy            nativeDraw(canvas.mNativeCanvas, location,
121deba785f122a47915756ffd991f5540d952cf937Romain Guy                    mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0,
122deba785f122a47915756ffd991f5540d952cf937Romain Guy                    canvas.mDensity, mBitmap.mDensity);
123deba785f122a47915756ffd991f5540d952cf937Romain Guy        } else {
124deba785f122a47915756ffd991f5540d952cf937Romain Guy            mRect.set(location);
125deba785f122a47915756ffd991f5540d952cf937Romain Guy            canvas.drawPatch(mBitmap, mChunk, mRect, paint);
126deba785f122a47915756ffd991f5540d952cf937Romain Guy        }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    /**
13011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * Return the underlying bitmap's density, as per
13111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     * {@link Bitmap#getDensity() Bitmap.getDensity()}.
13211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn     */
13311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    public int getDensity() {
13411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn        return mBitmap.mDensity;
13511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn    }
13611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getWidth() {
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmap.getWidth();
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getHeight() {
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmap.getHeight();
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final boolean hasAlpha() {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBitmap.hasAlpha();
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Region getTransparentRegion(Rect location) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int r = nativeGetTransparentRegion(mBitmap.ni(), mChunk, location);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return r != 0 ? new Region(r) : null;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native static boolean isNinePatchChunk(byte[] chunk);
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void validateNinePatchChunk(int bitmap, byte[] chunk);
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
15811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn                                          byte[] c, int paint_instance_or_null,
15911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn                                          int destDensity, int srcDensity);
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
16111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn                                          byte[] c, int paint_instance_or_null,
16211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn                                          int destDensity, int srcDensity);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static native int nativeGetTransparentRegion(
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int bitmap, byte[] chunk, Rect location);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
166