NinePatch.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1#include <utils/ResourceTypes.h>
2
3#include "SkRegion.h"
4#include "GraphicsJNI.h"
5
6#include "JNIHelp.h"
7
8extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
9                const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
10                           const SkPaint* paint, SkRegion** outRegion);
11
12using namespace android;
13
14class SkNinePatchGlue {
15public:
16    static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj)
17    {
18        if (NULL == obj) {
19            return false;
20        }
21        if (env->GetArrayLength(obj) < (int)sizeof(Res_png_9patch)) {
22            return false;
23        }
24        const jbyte* array = env->GetByteArrayElements(obj, 0);
25        if (array != NULL) {
26            const Res_png_9patch* chunk =
27                                reinterpret_cast<const Res_png_9patch*>(array);
28            int8_t wasDeserialized = chunk->wasDeserialized;
29            env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array),
30                                          JNI_ABORT);
31            return wasDeserialized != -1;
32        }
33        return false;
34    }
35
36    static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj)
37    {
38        if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) {
39            jniThrowException(env, "java/lang/RuntimeException",
40                              "Array too small for chunk.");
41            return;
42        }
43
44        // XXX Also check that dimensions are correct.
45    }
46
47    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
48                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
49    {
50        size_t chunkSize = env->GetArrayLength(chunkObj);
51        void* storage = alloca(chunkSize);
52        env->GetByteArrayRegion(chunkObj, 0, chunkSize,
53                                reinterpret_cast<jbyte*>(storage));
54        if (!env->ExceptionCheck()) {
55            // need to deserialize the chunk
56            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
57            assert(chunkSize == chunk->serializedSize());
58            // this relies on deserialization being done in place
59            Res_png_9patch::deserialize(chunk);
60            NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
61        }
62    }
63
64    static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
65                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
66    {
67        SkASSERT(canvas);
68        SkASSERT(boundsRectF);
69        SkASSERT(bitmap);
70        SkASSERT(chunkObj);
71        // paint is optional
72
73        SkRect      bounds;
74        GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
75
76        draw(env, canvas, bounds, bitmap, chunkObj, paint);
77    }
78
79    static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
80                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
81    {
82        SkASSERT(canvas);
83        SkASSERT(boundsRect);
84        SkASSERT(bitmap);
85        SkASSERT(chunkObj);
86        // paint is optional
87
88        SkRect      bounds;
89        GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
90        draw(env, canvas, bounds, bitmap, chunkObj, paint);
91    }
92
93    static jint getTransparentRegion(JNIEnv* env, jobject,
94                    const SkBitmap* bitmap, jbyteArray chunkObj,
95                    jobject boundsRect)
96    {
97        SkASSERT(bitmap);
98        SkASSERT(chunkObj);
99        SkASSERT(boundsRect);
100
101        SkRect      bounds;
102        GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
103        size_t chunkSize = env->GetArrayLength(chunkObj);
104        void* storage = alloca(chunkSize);
105        env->GetByteArrayRegion(chunkObj, 0, chunkSize,
106                                reinterpret_cast<jbyte*>(storage));
107        if (!env->ExceptionCheck()) {
108            // need to deserialize the chunk
109            Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
110            assert(chunkSize == chunk->serializedSize());
111            // this relies on deserialization being done in place
112            Res_png_9patch::deserialize(chunk);
113            SkRegion* region = NULL;
114            NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
115            return (jint)region;
116        }
117        return 0;
118    }
119
120};
121
122/////////////////////////////////////////////////////////////////////////////////////////
123
124#include <android_runtime/AndroidRuntime.h>
125
126static JNINativeMethod gNinePatchMethods[] = {
127    { "isNinePatchChunk", "([B)Z",                      (void*)SkNinePatchGlue::isNinePatchChunk   },
128    { "validateNinePatchChunk", "(I[B)V",               (void*)SkNinePatchGlue::validateNinePatchChunk   },
129    { "nativeDraw", "(ILandroid/graphics/RectF;I[BI)V", (void*)SkNinePatchGlue::drawF   },
130    { "nativeDraw", "(ILandroid/graphics/Rect;I[BI)V",  (void*)SkNinePatchGlue::drawI   },
131    { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I",
132                                                        (void*)SkNinePatchGlue::getTransparentRegion   }
133};
134
135int register_android_graphics_NinePatch(JNIEnv* env);
136int register_android_graphics_NinePatch(JNIEnv* env)
137{
138    return android::AndroidRuntime::registerNativeMethods(env,
139                                                       "android/graphics/NinePatch",
140                                                       gNinePatchMethods,
141                                                       SK_ARRAY_COUNT(gNinePatchMethods));
142}
143