NinePatch.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(obj, 0);
25        if (array != NULL)
26        {
27            Res_png_9patch* chunk = (Res_png_9patch*)array;
28            int8_t numXDivs = chunk->numXDivs;
29            env->ReleasePrimitiveArrayCritical(obj, array, 0);
30            return array[0] != -1;
31        }
32        return false;
33    }
34
35    static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj)
36    {
37        if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) {
38            jniThrowException(env, "java/lang/RuntimeException",
39                              "Array too small for chunk.");
40            return;
41        }
42
43        // XXX Also check that dimensions are correct.
44    }
45
46    static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
47                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
48    {
49        jbyte* array = env->GetByteArrayElements(chunkObj, 0);
50        if (array != NULL)
51        {
52            size_t chunkSize = env->GetArrayLength(chunkObj);
53            void* deserializedArray = alloca(chunkSize);
54            Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray;
55            assert(chunkSize == ((Res_png_9patch*) array)->serializedSize());
56            memcpy(chunk, array, chunkSize);
57            Res_png_9patch::deserialize(chunk);
58            NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
59            env->ReleaseByteArrayElements(chunkObj, array, 0);
60        }
61    }
62
63    static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
64                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
65    {
66        SkASSERT(canvas);
67        SkASSERT(boundsRectF);
68        SkASSERT(bitmap);
69        SkASSERT(chunkObj);
70        // paint is optional
71
72        SkRect      bounds;
73        GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
74
75        draw(env, canvas, bounds, bitmap, chunkObj, paint);
76    }
77
78    static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
79                      const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint)
80    {
81        SkASSERT(canvas);
82        SkASSERT(boundsRect);
83        SkASSERT(bitmap);
84        SkASSERT(chunkObj);
85        // paint is optional
86
87        SkRect      bounds;
88        GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
89        draw(env, canvas, bounds, bitmap, chunkObj, paint);
90    }
91
92    static jint getTransparentRegion(JNIEnv* env, jobject,
93                    const SkBitmap* bitmap, jbyteArray chunkObj,
94                    jobject boundsRect)
95    {
96        SkASSERT(bitmap);
97        SkASSERT(chunkObj);
98        SkASSERT(boundsRect);
99
100        SkRect      bounds;
101        GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
102        jbyte* array = (jbyte*)env->GetByteArrayElements(chunkObj, 0);
103        if (array != NULL)
104        {
105            size_t chunkSize = env->GetArrayLength(chunkObj);
106            void* deserializedArray = alloca(chunkSize);
107            Res_png_9patch* chunk = (Res_png_9patch*) deserializedArray;
108            assert(chunkSize == ((Res_png_9patch*) array)->serializedSize());
109            memcpy(chunk, array, chunkSize);
110            Res_png_9patch::deserialize(chunk);
111            SkRegion* region = NULL;
112            NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
113            env->ReleaseByteArrayElements(chunkObj, array, 0);
114            return (jint)region;
115        }
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