18cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn/* 28cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** 38cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** Copyright 2006, The Android Open Source Project 48cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** 58cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** Licensed under the Apache License, Version 2.0 (the "License"); 68cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** you may not use this file except in compliance with the License. 78cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** You may obtain a copy of the License at 88cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** 98cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** http://www.apache.org/licenses/LICENSE-2.0 108cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** 118cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** Unless required by applicable law or agreed to in writing, software 128cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** distributed under the License is distributed on an "AS IS" BASIS, 138cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 148cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** See the License for the specific language governing permissions and 158cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn** limitations under the License. 168cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn*/ 178cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn 188cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#define LOG_TAG "9patch" 198cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#define LOG_NDEBUG 1 208cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn 21b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/ResourceTypes.h> 228cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn#include <utils/Log.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn#include "SkCanvas.h" 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkRegion.h" 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "GraphicsJNI.h" 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "JNIHelp.h" 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectextern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkBitmap& bitmap, const android::Res_png_9patch& chunk, 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkPaint* paint, SkRegion** outRegion); 3369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass SkNinePatchGlue { 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic: 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj) 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL == obj) { 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (env->GetArrayLength(obj) < (int)sizeof(Res_png_9patch)) { 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const jbyte* array = env->GetByteArrayElements(obj, 0); 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (array != NULL) { 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const Res_png_9patch* chunk = 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reinterpret_cast<const Res_png_9patch*>(array); 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int8_t wasDeserialized = chunk->wasDeserialized; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array), 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project JNI_ABORT); 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return wasDeserialized != -1; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj) 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) { 6169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes jniThrowRuntimeException(env, "Array too small for chunk."); 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX Also check that dimensions are correct. 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, 6911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint, 7011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn jint destDensity, jint srcDensity) 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size_t chunkSize = env->GetArrayLength(chunkObj); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void* storage = alloca(chunkSize); 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->GetByteArrayRegion(chunkObj, 0, chunkSize, 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reinterpret_cast<jbyte*>(storage)); 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!env->ExceptionCheck()) { 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to deserialize the chunk 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage); 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assert(chunkSize == chunk->serializedSize()); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this relies on deserialization being done in place 8111ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn Res_png_9patch::deserialize(chunk); 8269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 8311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn if (destDensity == srcDensity || destDensity == 0 8411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn || srcDensity == 0) { 8571f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)", 868cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop), 878cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom)); 8811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL); 8911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn } else { 9011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn canvas->save(); 9169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 9211ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn SkScalar scale = SkFloatToScalar(destDensity / (float)srcDensity); 9311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn canvas->translate(bounds.fLeft, bounds.fTop); 9411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn canvas->scale(scale, scale); 9569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 9611ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale); 9711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale); 9811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn bounds.fLeft = bounds.fTop = 0; 9969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 10071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block ALOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d", 1018cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop), 1028cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom), 1038cae124af2142687a6833dbaab8a43df6dd67b43Dianne Hackborn srcDensity, destDensity); 10469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 10511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL); 10669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 10711ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn canvas->restore(); 10811ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn } 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes } 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF, 11311ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint, 11411ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn jint destDensity, jint srcDensity) 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(canvas); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(boundsRectF); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(bitmap); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(chunkObj); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // paint is optional 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkRect bounds; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12511ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity); 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect, 12911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint, 13011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn jint destDensity, jint srcDensity) 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(canvas); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(boundsRect); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(bitmap); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(chunkObj); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // paint is optional 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkRect bounds; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds); 14011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity); 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static jint getTransparentRegion(JNIEnv* env, jobject, 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const SkBitmap* bitmap, jbyteArray chunkObj, 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject boundsRect) 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(bitmap); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(chunkObj); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(boundsRect); 15069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkRect bounds; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size_t chunkSize = env->GetArrayLength(chunkObj); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void* storage = alloca(chunkSize); 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->GetByteArrayRegion(chunkObj, 0, chunkSize, 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reinterpret_cast<jbyte*>(storage)); 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!env->ExceptionCheck()) { 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to deserialize the chunk 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage); 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assert(chunkSize == chunk->serializedSize()); 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this relies on deserialization being done in place 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Res_png_9patch::deserialize(chunk); 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkRegion* region = NULL; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, ®ion); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (jint)region; 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////////////// 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h> 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod gNinePatchMethods[] = { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "isNinePatchChunk", "([B)Z", (void*)SkNinePatchGlue::isNinePatchChunk }, 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "validateNinePatchChunk", "(I[B)V", (void*)SkNinePatchGlue::validateNinePatchChunk }, 17911ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn { "nativeDraw", "(ILandroid/graphics/RectF;I[BIII)V", (void*)SkNinePatchGlue::drawF }, 18011ea33471e1a14a8594f0b2cd012d86340dd3bd8Dianne Hackborn { "nativeDraw", "(ILandroid/graphics/Rect;I[BIII)V", (void*)SkNinePatchGlue::drawI }, 18169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I", 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)SkNinePatchGlue::getTransparentRegion } 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_graphics_NinePatch(JNIEnv* env) 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return android::AndroidRuntime::registerNativeMethods(env, 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "android/graphics/NinePatch", 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gNinePatchMethods, 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SK_ARRAY_COUNT(gNinePatchMethods)); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 192