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