Graphics.cpp revision ab22c1c792bc5f422a029a4ab6a23861e44136d8
1#define LOG_TAG "GraphicsJNI" 2 3#include "jni.h" 4#include "JNIHelp.h" 5#include "GraphicsJNI.h" 6 7#include "Canvas.h" 8#include "SkCanvas.h" 9#include "SkDevice.h" 10#include "SkMath.h" 11#include "SkPicture.h" 12#include "SkRegion.h" 13#include <android_runtime/AndroidRuntime.h> 14 15void doThrowNPE(JNIEnv* env) { 16 jniThrowNullPointerException(env, NULL); 17} 18 19void doThrowAIOOBE(JNIEnv* env) { 20 jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); 21} 22 23void doThrowRE(JNIEnv* env, const char* msg) { 24 jniThrowRuntimeException(env, msg); 25} 26 27void doThrowIAE(JNIEnv* env, const char* msg) { 28 jniThrowException(env, "java/lang/IllegalArgumentException", msg); 29} 30 31void doThrowISE(JNIEnv* env, const char* msg) { 32 jniThrowException(env, "java/lang/IllegalStateException", msg); 33} 34 35void doThrowOOME(JNIEnv* env, const char* msg) { 36 jniThrowException(env, "java/lang/OutOfMemoryError", msg); 37} 38 39void doThrowIOE(JNIEnv* env, const char* msg) { 40 jniThrowException(env, "java/io/IOException", msg); 41} 42 43bool GraphicsJNI::hasException(JNIEnv *env) { 44 if (env->ExceptionCheck() != 0) { 45 ALOGE("*** Uncaught exception returned from Java call!\n"); 46 env->ExceptionDescribe(); 47 return true; 48 } 49 return false; 50} 51 52/////////////////////////////////////////////////////////////////////////////// 53 54AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array, 55 int minLength, JNIAccess access) 56: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 57 SkASSERT(env); 58 if (array) { 59 fLen = env->GetArrayLength(array); 60 if (fLen < minLength) { 61 sk_throw(); 62 } 63 fPtr = env->GetFloatArrayElements(array, NULL); 64 } 65 fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0; 66} 67 68AutoJavaFloatArray::~AutoJavaFloatArray() { 69 if (fPtr) { 70 fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode); 71 } 72} 73 74AutoJavaIntArray::AutoJavaIntArray(JNIEnv* env, jintArray array, 75 int minLength) 76: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 77 SkASSERT(env); 78 if (array) { 79 fLen = env->GetArrayLength(array); 80 if (fLen < minLength) { 81 sk_throw(); 82 } 83 fPtr = env->GetIntArrayElements(array, NULL); 84 } 85} 86 87AutoJavaIntArray::~AutoJavaIntArray() { 88 if (fPtr) { 89 fEnv->ReleaseIntArrayElements(fArray, fPtr, 0); 90 } 91} 92 93AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array, 94 int minLength, JNIAccess access) 95: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 96 SkASSERT(env); 97 if (array) { 98 fLen = env->GetArrayLength(array); 99 if (fLen < minLength) { 100 sk_throw(); 101 } 102 fPtr = env->GetShortArrayElements(array, NULL); 103 } 104 fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0; 105} 106 107AutoJavaShortArray::~AutoJavaShortArray() { 108 if (fPtr) { 109 fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode); 110 } 111} 112 113AutoJavaByteArray::AutoJavaByteArray(JNIEnv* env, jbyteArray array, 114 int minLength) 115: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 116 SkASSERT(env); 117 if (array) { 118 fLen = env->GetArrayLength(array); 119 if (fLen < minLength) { 120 sk_throw(); 121 } 122 fPtr = env->GetByteArrayElements(array, NULL); 123 } 124} 125 126AutoJavaByteArray::~AutoJavaByteArray() { 127 if (fPtr) { 128 fEnv->ReleaseByteArrayElements(fArray, fPtr, 0); 129 } 130} 131 132/////////////////////////////////////////////////////////////////////////////// 133 134static jclass gRect_class; 135static jfieldID gRect_leftFieldID; 136static jfieldID gRect_topFieldID; 137static jfieldID gRect_rightFieldID; 138static jfieldID gRect_bottomFieldID; 139 140static jclass gRectF_class; 141static jfieldID gRectF_leftFieldID; 142static jfieldID gRectF_topFieldID; 143static jfieldID gRectF_rightFieldID; 144static jfieldID gRectF_bottomFieldID; 145 146static jclass gPoint_class; 147static jfieldID gPoint_xFieldID; 148static jfieldID gPoint_yFieldID; 149 150static jclass gPointF_class; 151static jfieldID gPointF_xFieldID; 152static jfieldID gPointF_yFieldID; 153 154static jclass gBitmap_class; 155static jfieldID gBitmap_nativeInstanceID; 156static jmethodID gBitmap_constructorMethodID; 157static jmethodID gBitmap_reinitMethodID; 158static jmethodID gBitmap_getAllocationByteCountMethodID; 159 160static jclass gBitmapConfig_class; 161static jfieldID gBitmapConfig_nativeInstanceID; 162 163static jclass gBitmapRegionDecoder_class; 164static jmethodID gBitmapRegionDecoder_constructorMethodID; 165 166static jclass gCanvas_class; 167static jfieldID gCanvas_nativeInstanceID; 168 169static jclass gPicture_class; 170static jfieldID gPicture_nativeInstanceID; 171 172static jclass gRegion_class; 173static jfieldID gRegion_nativeInstanceID; 174static jmethodID gRegion_constructorMethodID; 175 176static jclass gByte_class; 177static jobject gVMRuntime; 178static jclass gVMRuntime_class; 179static jmethodID gVMRuntime_newNonMovableArray; 180static jmethodID gVMRuntime_addressOf; 181 182/////////////////////////////////////////////////////////////////////////////// 183 184void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B) 185{ 186 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 187 188 *L = env->GetIntField(obj, gRect_leftFieldID); 189 *T = env->GetIntField(obj, gRect_topFieldID); 190 *R = env->GetIntField(obj, gRect_rightFieldID); 191 *B = env->GetIntField(obj, gRect_bottomFieldID); 192} 193 194void GraphicsJNI::set_jrect(JNIEnv* env, jobject obj, int L, int T, int R, int B) 195{ 196 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 197 198 env->SetIntField(obj, gRect_leftFieldID, L); 199 env->SetIntField(obj, gRect_topFieldID, T); 200 env->SetIntField(obj, gRect_rightFieldID, R); 201 env->SetIntField(obj, gRect_bottomFieldID, B); 202} 203 204SkIRect* GraphicsJNI::jrect_to_irect(JNIEnv* env, jobject obj, SkIRect* ir) 205{ 206 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 207 208 ir->set(env->GetIntField(obj, gRect_leftFieldID), 209 env->GetIntField(obj, gRect_topFieldID), 210 env->GetIntField(obj, gRect_rightFieldID), 211 env->GetIntField(obj, gRect_bottomFieldID)); 212 return ir; 213} 214 215void GraphicsJNI::irect_to_jrect(const SkIRect& ir, JNIEnv* env, jobject obj) 216{ 217 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 218 219 env->SetIntField(obj, gRect_leftFieldID, ir.fLeft); 220 env->SetIntField(obj, gRect_topFieldID, ir.fTop); 221 env->SetIntField(obj, gRect_rightFieldID, ir.fRight); 222 env->SetIntField(obj, gRect_bottomFieldID, ir.fBottom); 223} 224 225SkRect* GraphicsJNI::jrectf_to_rect(JNIEnv* env, jobject obj, SkRect* r) 226{ 227 SkASSERT(env->IsInstanceOf(obj, gRectF_class)); 228 229 r->set(env->GetFloatField(obj, gRectF_leftFieldID), 230 env->GetFloatField(obj, gRectF_topFieldID), 231 env->GetFloatField(obj, gRectF_rightFieldID), 232 env->GetFloatField(obj, gRectF_bottomFieldID)); 233 return r; 234} 235 236SkRect* GraphicsJNI::jrect_to_rect(JNIEnv* env, jobject obj, SkRect* r) 237{ 238 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 239 240 r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)), 241 SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)), 242 SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)), 243 SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID))); 244 return r; 245} 246 247void GraphicsJNI::rect_to_jrectf(const SkRect& r, JNIEnv* env, jobject obj) 248{ 249 SkASSERT(env->IsInstanceOf(obj, gRectF_class)); 250 251 env->SetFloatField(obj, gRectF_leftFieldID, SkScalarToFloat(r.fLeft)); 252 env->SetFloatField(obj, gRectF_topFieldID, SkScalarToFloat(r.fTop)); 253 env->SetFloatField(obj, gRectF_rightFieldID, SkScalarToFloat(r.fRight)); 254 env->SetFloatField(obj, gRectF_bottomFieldID, SkScalarToFloat(r.fBottom)); 255} 256 257SkIPoint* GraphicsJNI::jpoint_to_ipoint(JNIEnv* env, jobject obj, SkIPoint* point) 258{ 259 SkASSERT(env->IsInstanceOf(obj, gPoint_class)); 260 261 point->set(env->GetIntField(obj, gPoint_xFieldID), 262 env->GetIntField(obj, gPoint_yFieldID)); 263 return point; 264} 265 266void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj) 267{ 268 SkASSERT(env->IsInstanceOf(obj, gPoint_class)); 269 270 env->SetIntField(obj, gPoint_xFieldID, ir.fX); 271 env->SetIntField(obj, gPoint_yFieldID, ir.fY); 272} 273 274SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point) 275{ 276 SkASSERT(env->IsInstanceOf(obj, gPointF_class)); 277 278 point->set(env->GetIntField(obj, gPointF_xFieldID), 279 env->GetIntField(obj, gPointF_yFieldID)); 280 return point; 281} 282 283void GraphicsJNI::point_to_jpointf(const SkPoint& r, JNIEnv* env, jobject obj) 284{ 285 SkASSERT(env->IsInstanceOf(obj, gPointF_class)); 286 287 env->SetFloatField(obj, gPointF_xFieldID, SkScalarToFloat(r.fX)); 288 env->SetFloatField(obj, gPointF_yFieldID, SkScalarToFloat(r.fY)); 289} 290 291// This enum must keep these int values, to match the int values 292// in the java Bitmap.Config enum. 293enum LegacyBitmapConfig { 294 kNo_LegacyBitmapConfig = 0, 295 kA8_LegacyBitmapConfig = 1, 296 kIndex8_LegacyBitmapConfig = 2, 297 kRGB_565_LegacyBitmapConfig = 3, 298 kARGB_4444_LegacyBitmapConfig = 4, 299 kARGB_8888_LegacyBitmapConfig = 5, 300 301 kLastEnum_LegacyBitmapConfig = kARGB_8888_LegacyBitmapConfig 302}; 303 304jint GraphicsJNI::colorTypeToLegacyBitmapConfig(SkColorType colorType) { 305 switch (colorType) { 306 case kN32_SkColorType: 307 return kARGB_8888_LegacyBitmapConfig; 308 case kARGB_4444_SkColorType: 309 return kARGB_4444_LegacyBitmapConfig; 310 case kRGB_565_SkColorType: 311 return kRGB_565_LegacyBitmapConfig; 312 case kIndex_8_SkColorType: 313 return kIndex8_LegacyBitmapConfig; 314 case kAlpha_8_SkColorType: 315 return kA8_LegacyBitmapConfig; 316 case kUnknown_SkColorType: 317 default: 318 break; 319 } 320 return kNo_LegacyBitmapConfig; 321} 322 323SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { 324 const uint8_t gConfig2ColorType[] = { 325 kUnknown_SkColorType, 326 kAlpha_8_SkColorType, 327 kIndex_8_SkColorType, 328 kRGB_565_SkColorType, 329 kARGB_4444_SkColorType, 330 kN32_SkColorType 331 }; 332 333 if (legacyConfig < 0 || legacyConfig > kLastEnum_LegacyBitmapConfig) { 334 legacyConfig = kNo_LegacyBitmapConfig; 335 } 336 return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]); 337} 338 339SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) { 340 SkASSERT(env); 341 SkASSERT(bitmap); 342 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 343 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativeInstanceID); 344 SkBitmap* b = reinterpret_cast<SkBitmap*>(bitmapHandle); 345 SkASSERT(b); 346 return b; 347} 348 349SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) { 350 SkASSERT(env); 351 if (NULL == jconfig) { 352 return kUnknown_SkColorType; 353 } 354 SkASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class)); 355 int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID); 356 return legacyBitmapConfigToColorType(c); 357} 358 359SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) { 360 SkASSERT(env); 361 SkASSERT(canvas); 362 SkASSERT(env->IsInstanceOf(canvas, gCanvas_class)); 363 jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID); 364 SkCanvas* c = reinterpret_cast<android::Canvas*>(canvasHandle)->getSkCanvas(); 365 SkASSERT(c); 366 return c; 367} 368 369SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region) 370{ 371 SkASSERT(env); 372 SkASSERT(region); 373 SkASSERT(env->IsInstanceOf(region, gRegion_class)); 374 jlong regionHandle = env->GetLongField(region, gRegion_nativeInstanceID); 375 SkRegion* r = reinterpret_cast<SkRegion*>(regionHandle); 376 SkASSERT(r); 377 return r; 378} 379 380/////////////////////////////////////////////////////////////////////////////////////////// 381 382// Assert that bitmap's SkAlphaType is consistent with isPremultiplied. 383static void assert_premultiplied(const SkBitmap& bitmap, bool isPremultiplied) { 384 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is 385 // irrelevant. This just tests to ensure that the SkAlphaType is not 386 // opposite of isPremultiplied. 387 if (isPremultiplied) { 388 SkASSERT(bitmap.alphaType() != kUnpremul_SkAlphaType); 389 } else { 390 SkASSERT(bitmap.alphaType() != kPremul_SkAlphaType); 391 } 392} 393 394jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer, 395 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets, int density) 396{ 397 SkASSERT(bitmap); 398 SkASSERT(bitmap->pixelRef()); 399 SkASSERT(!env->ExceptionCheck()); 400 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable; 401 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied; 402 403 // The caller needs to have already set the alpha type properly, so the 404 // native SkBitmap stays in sync with the Java Bitmap. 405 assert_premultiplied(*bitmap, isPremultiplied); 406 407 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID, 408 reinterpret_cast<jlong>(bitmap), buffer, 409 bitmap->width(), bitmap->height(), density, isMutable, isPremultiplied, 410 ninePatchChunk, ninePatchInsets); 411 hasException(env); // For the side effect of logging. 412 return obj; 413} 414 415void GraphicsJNI::reinitBitmap(JNIEnv* env, jobject javaBitmap, SkBitmap* bitmap, 416 bool isPremultiplied) 417{ 418 // The caller needs to have already set the alpha type properly, so the 419 // native SkBitmap stays in sync with the Java Bitmap. 420 assert_premultiplied(*bitmap, isPremultiplied); 421 422 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID, 423 bitmap->width(), bitmap->height(), isPremultiplied); 424} 425 426int GraphicsJNI::getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap) 427{ 428 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID); 429} 430 431jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap) 432{ 433 SkASSERT(bitmap != NULL); 434 435 jobject obj = env->NewObject(gBitmapRegionDecoder_class, 436 gBitmapRegionDecoder_constructorMethodID, 437 reinterpret_cast<jlong>(bitmap)); 438 hasException(env); // For the side effect of logging. 439 return obj; 440} 441 442jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region) 443{ 444 SkASSERT(region != NULL); 445 jobject obj = env->NewObject(gRegion_class, gRegion_constructorMethodID, 446 reinterpret_cast<jlong>(region), 0); 447 hasException(env); // For the side effect of logging. 448 return obj; 449} 450 451static JNIEnv* vm2env(JavaVM* vm) 452{ 453 JNIEnv* env = NULL; 454 if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env) 455 { 456 SkDebugf("------- [%p] vm->GetEnv() failed\n", vm); 457 sk_throw(); 458 } 459 return env; 460} 461 462/////////////////////////////////////////////////////////////////////////////// 463 464AndroidPixelRef::AndroidPixelRef(JNIEnv* env, const SkImageInfo& info, void* storage, 465 size_t rowBytes, jbyteArray storageObj, SkColorTable* ctable) : 466 SkMallocPixelRef(info, storage, rowBytes, ctable, (storageObj == NULL)), 467 fWrappedPixelRef(NULL) { 468 SkASSERT(storage); 469 SkASSERT(env); 470 471 if (env->GetJavaVM(&fVM) != JNI_OK) { 472 SkDebugf("------ [%p] env->GetJavaVM failed\n", env); 473 sk_throw(); 474 } 475 fStorageObj = storageObj; 476 fHasGlobalRef = false; 477 fGlobalRefCnt = 0; 478 479 // If storageObj is NULL, the memory was NOT allocated on the Java heap 480 fOnJavaHeap = (storageObj != NULL); 481 482} 483 484AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImageInfo& info, 485 size_t rowBytes, SkColorTable* ctable) : 486 SkMallocPixelRef(info, wrappedPixelRef.getAddr(), rowBytes, ctable, false), 487 fWrappedPixelRef(wrappedPixelRef.fWrappedPixelRef ? 488 wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef) 489{ 490 SkASSERT(fWrappedPixelRef); 491 SkSafeRef(fWrappedPixelRef); 492 493 // don't need to initialize these, as all the relevant logic delegates to the wrapped ref 494 fStorageObj = NULL; 495 fHasGlobalRef = false; 496 fGlobalRefCnt = 0; 497 fOnJavaHeap = false; 498} 499 500AndroidPixelRef::~AndroidPixelRef() { 501 if (fWrappedPixelRef) { 502 SkSafeUnref(fWrappedPixelRef); 503 } else if (fOnJavaHeap) { 504 JNIEnv* env = vm2env(fVM); 505 506 if (fStorageObj && fHasGlobalRef) { 507 env->DeleteGlobalRef(fStorageObj); 508 } 509 fStorageObj = NULL; 510 } 511} 512jbyteArray AndroidPixelRef::getStorageObj() { 513 if (fWrappedPixelRef) { 514 return fWrappedPixelRef->fStorageObj; 515 } 516 return fStorageObj; 517} 518 519void AndroidPixelRef::setLocalJNIRef(jbyteArray arr) { 520 if (fWrappedPixelRef) { 521 // delegate java obj management to the wrapped ref 522 fWrappedPixelRef->setLocalJNIRef(arr); 523 } else if (!fHasGlobalRef) { 524 fStorageObj = arr; 525 } 526} 527 528void AndroidPixelRef::globalRef(void* localref) { 529 if (fWrappedPixelRef) { 530 // delegate java obj management to the wrapped ref 531 fWrappedPixelRef->globalRef(localref); 532 533 // Note: we only ref and unref the wrapped AndroidPixelRef so that 534 // bitmap->pixelRef()->globalRef() and globalUnref() can be used in a pair, even if 535 // the bitmap has its underlying AndroidPixelRef swapped out/wrapped 536 return; 537 } 538 if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) { 539 JNIEnv *env = vm2env(fVM); 540 541 // If JNI ref was passed, it is always used 542 if (localref) fStorageObj = (jbyteArray) localref; 543 544 if (fStorageObj == NULL) { 545 SkDebugf("No valid local ref to create a JNI global ref\n"); 546 sk_throw(); 547 } 548 if (fHasGlobalRef) { 549 // This should never happen 550 SkDebugf("Already holding a JNI global ref"); 551 sk_throw(); 552 } 553 554 fStorageObj = (jbyteArray) env->NewGlobalRef(fStorageObj); 555 // TODO: Check for failure here 556 fHasGlobalRef = true; 557 } 558 ref(); 559} 560 561void AndroidPixelRef::globalUnref() { 562 if (fWrappedPixelRef) { 563 // delegate java obj management to the wrapped ref 564 fWrappedPixelRef->globalUnref(); 565 return; 566 } 567 if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) { 568 JNIEnv *env = vm2env(fVM); 569 if (!fHasGlobalRef) { 570 SkDebugf("We don't have a global ref!"); 571 sk_throw(); 572 } 573 env->DeleteGlobalRef(fStorageObj); 574 fStorageObj = NULL; 575 fHasGlobalRef = false; 576 } 577 unref(); 578} 579 580/////////////////////////////////////////////////////////////////////////////// 581 582jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, 583 SkColorTable* ctable) { 584 const SkImageInfo& info = bitmap->info(); 585 if (info.fColorType == kUnknown_SkColorType) { 586 doThrowIAE(env, "unknown bitmap configuration"); 587 return NULL; 588 } 589 590 const size_t size = bitmap->getSize(); 591 jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime, 592 gVMRuntime_newNonMovableArray, 593 gByte_class, size); 594 if (env->ExceptionCheck() != 0) { 595 return NULL; 596 } 597 SkASSERT(arrayObj); 598 jbyte* addr = (jbyte*) env->CallLongMethod(gVMRuntime, gVMRuntime_addressOf, arrayObj); 599 if (env->ExceptionCheck() != 0) { 600 return NULL; 601 } 602 SkASSERT(addr); 603 SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr, 604 bitmap->rowBytes(), arrayObj, ctable); 605 bitmap->setPixelRef(pr)->unref(); 606 // since we're already allocated, we lockPixels right away 607 // HeapAllocator behaves this way too 608 bitmap->lockPixels(); 609 610 return arrayObj; 611} 612 613/////////////////////////////////////////////////////////////////////////////// 614 615JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) 616 : fStorageObj(NULL), 617 fAllocCount(0) { 618 if (env->GetJavaVM(&fVM) != JNI_OK) { 619 SkDebugf("------ [%p] env->GetJavaVM failed\n", env); 620 sk_throw(); 621 } 622} 623 624bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { 625 JNIEnv* env = vm2env(fVM); 626 627 fStorageObj = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable); 628 fAllocCount += 1; 629 return fStorageObj != NULL; 630} 631 632//////////////////////////////////////////////////////////////////////////////// 633 634JavaHeapBitmapRef::JavaHeapBitmapRef(JNIEnv* env, SkBitmap* nativeBitmap, jbyteArray buffer) { 635 fEnv = env; 636 fNativeBitmap = nativeBitmap; 637 fBuffer = buffer; 638 639 // If the buffer is NULL, the backing memory wasn't allocated on the Java heap 640 if (fBuffer) { 641 ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(fBuffer); 642 } 643} 644 645JavaHeapBitmapRef::~JavaHeapBitmapRef() { 646 if (fBuffer) { 647 ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(NULL); 648 } 649} 650 651//////////////////////////////////////////////////////////////////////////////// 652 653static jclass make_globalref(JNIEnv* env, const char classname[]) 654{ 655 jclass c = env->FindClass(classname); 656 SkASSERT(c); 657 return (jclass) env->NewGlobalRef(c); 658} 659 660static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 661 const char fieldname[], const char type[]) 662{ 663 jfieldID id = env->GetFieldID(clazz, fieldname, type); 664 SkASSERT(id); 665 return id; 666} 667 668int register_android_graphics_Graphics(JNIEnv* env) 669{ 670 jmethodID m; 671 jclass c; 672 673 gRect_class = make_globalref(env, "android/graphics/Rect"); 674 gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I"); 675 gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I"); 676 gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I"); 677 gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I"); 678 679 gRectF_class = make_globalref(env, "android/graphics/RectF"); 680 gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F"); 681 gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F"); 682 gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F"); 683 gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F"); 684 685 gPoint_class = make_globalref(env, "android/graphics/Point"); 686 gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I"); 687 gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I"); 688 689 gPointF_class = make_globalref(env, "android/graphics/PointF"); 690 gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F"); 691 gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F"); 692 693 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 694 gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "J"); 695 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 696 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); 697 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); 698 gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder"); 699 gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V"); 700 701 gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config"); 702 gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class, 703 "nativeInt", "I"); 704 705 gCanvas_class = make_globalref(env, "android/graphics/Canvas"); 706 gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J"); 707 708 gPicture_class = make_globalref(env, "android/graphics/Picture"); 709 gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J"); 710 711 gRegion_class = make_globalref(env, "android/graphics/Region"); 712 gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "J"); 713 gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>", 714 "(JI)V"); 715 716 c = env->FindClass("java/lang/Byte"); 717 gByte_class = (jclass) env->NewGlobalRef( 718 env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;"))); 719 720 gVMRuntime_class = make_globalref(env, "dalvik/system/VMRuntime"); 721 m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;"); 722 gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m)); 723 gVMRuntime_newNonMovableArray = env->GetMethodID(gVMRuntime_class, "newNonMovableArray", 724 "(Ljava/lang/Class;I)Ljava/lang/Object;"); 725 gVMRuntime_addressOf = env->GetMethodID(gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J"); 726 727 return 0; 728} 729