Graphics.cpp revision a2f0e2d6b7f9dff3a52dd78d6db307070a71e9b2
1#define LOG_TAG "GraphicsJNI" 2 3#include "jni.h" 4#include "GraphicsJNI.h" 5 6#include "SkCanvas.h" 7#include "SkDevice.h" 8#include "SkPicture.h" 9#include "SkRegion.h" 10#include <android_runtime/AndroidRuntime.h> 11 12//#define REPORT_SIZE_TO_JVM 13//#define TRACK_LOCK_COUNT 14 15void doThrow(JNIEnv* env, const char* exc, const char* msg) { 16 // don't throw a new exception if we already have one pending 17 if (env->ExceptionCheck() == JNI_FALSE) { 18 jclass npeClazz; 19 20 npeClazz = env->FindClass(exc); 21 LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc); 22 23 env->ThrowNew(npeClazz, msg); 24 } 25} 26 27void doThrowNPE(JNIEnv* env) { 28 doThrow(env, "java/lang/NullPointerException"); 29} 30 31void doThrowAIOOBE(JNIEnv* env) { 32 doThrow(env, "java/lang/ArrayIndexOutOfBoundsException"); 33} 34 35void doThrowRE(JNIEnv* env, const char* msg) { 36 doThrow(env, "java/lang/RuntimeException", msg); 37} 38 39void doThrowIAE(JNIEnv* env, const char* msg) { 40 doThrow(env, "java/lang/IllegalArgumentException", msg); 41} 42 43void doThrowISE(JNIEnv* env, const char* msg) { 44 doThrow(env, "java/lang/IllegalStateException", msg); 45} 46 47void doThrowOOME(JNIEnv* env, const char* msg) { 48 doThrow(env, "java/lang/OutOfMemoryError", msg); 49} 50 51void doThrowIOE(JNIEnv* env, const char* msg) { 52 doThrow(env, "java/io/IOException", msg); 53} 54 55bool GraphicsJNI::hasException(JNIEnv *env) { 56 if (env->ExceptionCheck() != 0) { 57 LOGE("*** Uncaught exception returned from Java call!\n"); 58 env->ExceptionDescribe(); 59 return true; 60 } 61 return false; 62} 63 64/////////////////////////////////////////////////////////////////////////////// 65 66AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array, 67 int minLength, JNIAccess access) 68: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 69 SkASSERT(env); 70 if (array) { 71 fLen = env->GetArrayLength(array); 72 if (fLen < minLength) { 73 sk_throw(); 74 } 75 fPtr = env->GetFloatArrayElements(array, NULL); 76 } 77 fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0; 78} 79 80AutoJavaFloatArray::~AutoJavaFloatArray() { 81 if (fPtr) { 82 fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode); 83 } 84} 85 86AutoJavaIntArray::AutoJavaIntArray(JNIEnv* env, jintArray array, 87 int minLength) 88: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 89 SkASSERT(env); 90 if (array) { 91 fLen = env->GetArrayLength(array); 92 if (fLen < minLength) { 93 sk_throw(); 94 } 95 fPtr = env->GetIntArrayElements(array, NULL); 96 } 97} 98 99AutoJavaIntArray::~AutoJavaIntArray() { 100 if (fPtr) { 101 fEnv->ReleaseIntArrayElements(fArray, fPtr, 0); 102 } 103} 104 105AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array, 106 int minLength, JNIAccess access) 107: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 108 SkASSERT(env); 109 if (array) { 110 fLen = env->GetArrayLength(array); 111 if (fLen < minLength) { 112 sk_throw(); 113 } 114 fPtr = env->GetShortArrayElements(array, NULL); 115 } 116 fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0; 117} 118 119AutoJavaShortArray::~AutoJavaShortArray() { 120 if (fPtr) { 121 fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode); 122 } 123} 124 125AutoJavaByteArray::AutoJavaByteArray(JNIEnv* env, jbyteArray array, 126 int minLength) 127: fEnv(env), fArray(array), fPtr(NULL), fLen(0) { 128 SkASSERT(env); 129 if (array) { 130 fLen = env->GetArrayLength(array); 131 if (fLen < minLength) { 132 sk_throw(); 133 } 134 fPtr = env->GetByteArrayElements(array, NULL); 135 } 136} 137 138AutoJavaByteArray::~AutoJavaByteArray() { 139 if (fPtr) { 140 fEnv->ReleaseByteArrayElements(fArray, fPtr, 0); 141 } 142} 143 144/////////////////////////////////////////////////////////////////////////////// 145 146static jclass gRect_class; 147static jfieldID gRect_leftFieldID; 148static jfieldID gRect_topFieldID; 149static jfieldID gRect_rightFieldID; 150static jfieldID gRect_bottomFieldID; 151 152static jclass gRectF_class; 153static jfieldID gRectF_leftFieldID; 154static jfieldID gRectF_topFieldID; 155static jfieldID gRectF_rightFieldID; 156static jfieldID gRectF_bottomFieldID; 157 158static jclass gPoint_class; 159static jfieldID gPoint_xFieldID; 160static jfieldID gPoint_yFieldID; 161 162static jclass gPointF_class; 163static jfieldID gPointF_xFieldID; 164static jfieldID gPointF_yFieldID; 165 166static jclass gBitmap_class; 167static jfieldID gBitmap_nativeInstanceID; 168static jmethodID gBitmap_constructorMethodID; 169 170static jclass gBitmapConfig_class; 171static jfieldID gBitmapConfig_nativeInstanceID; 172 173static jclass gBitmapRegionDecoder_class; 174static jmethodID gBitmapRegionDecoder_constructorMethodID; 175 176static jclass gCanvas_class; 177static jfieldID gCanvas_nativeInstanceID; 178 179static jclass gPaint_class; 180static jfieldID gPaint_nativeInstanceID; 181 182static jclass gPicture_class; 183static jfieldID gPicture_nativeInstanceID; 184 185static jclass gRegion_class; 186static jfieldID gRegion_nativeInstanceID; 187static jmethodID gRegion_constructorMethodID; 188 189static jobject gVMRuntime_singleton; 190static jmethodID gVMRuntime_trackExternalAllocationMethodID; 191static jmethodID gVMRuntime_trackExternalFreeMethodID; 192 193/////////////////////////////////////////////////////////////////////////////// 194 195void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B) 196{ 197 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 198 199 *L = env->GetIntField(obj, gRect_leftFieldID); 200 *T = env->GetIntField(obj, gRect_topFieldID); 201 *R = env->GetIntField(obj, gRect_rightFieldID); 202 *B = env->GetIntField(obj, gRect_bottomFieldID); 203} 204 205void GraphicsJNI::set_jrect(JNIEnv* env, jobject obj, int L, int T, int R, int B) 206{ 207 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 208 209 env->SetIntField(obj, gRect_leftFieldID, L); 210 env->SetIntField(obj, gRect_topFieldID, T); 211 env->SetIntField(obj, gRect_rightFieldID, R); 212 env->SetIntField(obj, gRect_bottomFieldID, B); 213} 214 215SkIRect* GraphicsJNI::jrect_to_irect(JNIEnv* env, jobject obj, SkIRect* ir) 216{ 217 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 218 219 ir->set(env->GetIntField(obj, gRect_leftFieldID), 220 env->GetIntField(obj, gRect_topFieldID), 221 env->GetIntField(obj, gRect_rightFieldID), 222 env->GetIntField(obj, gRect_bottomFieldID)); 223 return ir; 224} 225 226void GraphicsJNI::irect_to_jrect(const SkIRect& ir, JNIEnv* env, jobject obj) 227{ 228 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 229 230 env->SetIntField(obj, gRect_leftFieldID, ir.fLeft); 231 env->SetIntField(obj, gRect_topFieldID, ir.fTop); 232 env->SetIntField(obj, gRect_rightFieldID, ir.fRight); 233 env->SetIntField(obj, gRect_bottomFieldID, ir.fBottom); 234} 235 236SkRect* GraphicsJNI::jrectf_to_rect(JNIEnv* env, jobject obj, SkRect* r) 237{ 238 SkASSERT(env->IsInstanceOf(obj, gRectF_class)); 239 240 r->set(SkFloatToScalar(env->GetFloatField(obj, gRectF_leftFieldID)), 241 SkFloatToScalar(env->GetFloatField(obj, gRectF_topFieldID)), 242 SkFloatToScalar(env->GetFloatField(obj, gRectF_rightFieldID)), 243 SkFloatToScalar(env->GetFloatField(obj, gRectF_bottomFieldID))); 244 return r; 245} 246 247SkRect* GraphicsJNI::jrect_to_rect(JNIEnv* env, jobject obj, SkRect* r) 248{ 249 SkASSERT(env->IsInstanceOf(obj, gRect_class)); 250 251 r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)), 252 SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)), 253 SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)), 254 SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID))); 255 return r; 256} 257 258void GraphicsJNI::rect_to_jrectf(const SkRect& r, JNIEnv* env, jobject obj) 259{ 260 SkASSERT(env->IsInstanceOf(obj, gRectF_class)); 261 262 env->SetFloatField(obj, gRectF_leftFieldID, SkScalarToFloat(r.fLeft)); 263 env->SetFloatField(obj, gRectF_topFieldID, SkScalarToFloat(r.fTop)); 264 env->SetFloatField(obj, gRectF_rightFieldID, SkScalarToFloat(r.fRight)); 265 env->SetFloatField(obj, gRectF_bottomFieldID, SkScalarToFloat(r.fBottom)); 266} 267 268SkIPoint* GraphicsJNI::jpoint_to_ipoint(JNIEnv* env, jobject obj, SkIPoint* point) 269{ 270 SkASSERT(env->IsInstanceOf(obj, gPoint_class)); 271 272 point->set(env->GetIntField(obj, gPoint_xFieldID), 273 env->GetIntField(obj, gPoint_yFieldID)); 274 return point; 275} 276 277void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj) 278{ 279 SkASSERT(env->IsInstanceOf(obj, gPoint_class)); 280 281 env->SetIntField(obj, gPoint_xFieldID, ir.fX); 282 env->SetIntField(obj, gPoint_yFieldID, ir.fY); 283} 284 285SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point) 286{ 287 SkASSERT(env->IsInstanceOf(obj, gPointF_class)); 288 289 point->set(SkFloatToScalar(env->GetIntField(obj, gPointF_xFieldID)), 290 SkFloatToScalar(env->GetIntField(obj, gPointF_yFieldID))); 291 return point; 292} 293 294void GraphicsJNI::point_to_jpointf(const SkPoint& r, JNIEnv* env, jobject obj) 295{ 296 SkASSERT(env->IsInstanceOf(obj, gPointF_class)); 297 298 env->SetFloatField(obj, gPointF_xFieldID, SkScalarToFloat(r.fX)); 299 env->SetFloatField(obj, gPointF_yFieldID, SkScalarToFloat(r.fY)); 300} 301 302SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) { 303 SkASSERT(env); 304 SkASSERT(bitmap); 305 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 306 SkBitmap* b = (SkBitmap*)env->GetIntField(bitmap, gBitmap_nativeInstanceID); 307 SkASSERT(b); 308 return b; 309} 310 311SkBitmap::Config GraphicsJNI::getNativeBitmapConfig(JNIEnv* env, 312 jobject jconfig) { 313 SkASSERT(env); 314 if (NULL == jconfig) { 315 return SkBitmap::kNo_Config; 316 } 317 SkASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class)); 318 int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID); 319 if (c < 0 || c >= SkBitmap::kConfigCount) { 320 c = SkBitmap::kNo_Config; 321 } 322 return static_cast<SkBitmap::Config>(c); 323} 324 325SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) { 326 SkASSERT(env); 327 SkASSERT(canvas); 328 SkASSERT(env->IsInstanceOf(canvas, gCanvas_class)); 329 SkCanvas* c = (SkCanvas*)env->GetIntField(canvas, gCanvas_nativeInstanceID); 330 SkASSERT(c); 331 return c; 332} 333 334SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) { 335 SkASSERT(env); 336 SkASSERT(paint); 337 SkASSERT(env->IsInstanceOf(paint, gPaint_class)); 338 SkPaint* p = (SkPaint*)env->GetIntField(paint, gPaint_nativeInstanceID); 339 SkASSERT(p); 340 return p; 341} 342 343SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture) 344{ 345 SkASSERT(env); 346 SkASSERT(picture); 347 SkASSERT(env->IsInstanceOf(picture, gPicture_class)); 348 SkPicture* p = (SkPicture*)env->GetIntField(picture, gPicture_nativeInstanceID); 349 SkASSERT(p); 350 return p; 351} 352 353SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region) 354{ 355 SkASSERT(env); 356 SkASSERT(region); 357 SkASSERT(env->IsInstanceOf(region, gRegion_class)); 358 SkRegion* r = (SkRegion*)env->GetIntField(region, gRegion_nativeInstanceID); 359 SkASSERT(r); 360 return r; 361} 362 363/////////////////////////////////////////////////////////////////////////////////////////// 364 365jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer, 366 bool isMutable, jbyteArray ninepatch, int density) 367{ 368 SkASSERT(bitmap); 369 SkASSERT(bitmap->pixelRef()); 370 371 jobject obj = env->AllocObject(gBitmap_class); 372 if (obj) { 373 env->CallVoidMethod(obj, gBitmap_constructorMethodID, 374 (jint)bitmap, buffer, isMutable, ninepatch, density); 375 if (hasException(env)) { 376 obj = NULL; 377 } 378 } 379 return obj; 380} 381 382jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable, 383 jbyteArray ninepatch, int density) 384{ 385 return createBitmap(env, bitmap, NULL, isMutable, ninepatch, density); 386} 387 388 389jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap) 390{ 391 SkASSERT(bitmap != NULL); 392 393 jobject obj = env->AllocObject(gBitmapRegionDecoder_class); 394 if (hasException(env)) { 395 obj = NULL; 396 return obj; 397 } 398 if (obj) { 399 env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap); 400 if (hasException(env)) { 401 obj = NULL; 402 } 403 } 404 return obj; 405} 406 407jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region) 408{ 409 SkASSERT(region != NULL); 410 jobject obj = env->AllocObject(gRegion_class); 411 if (obj) { 412 env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0); 413 if (hasException(env)) { 414 obj = NULL; 415 } 416 } 417 return obj; 418} 419 420static JNIEnv* vm2env(JavaVM* vm) 421{ 422 JNIEnv* env = NULL; 423 if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env) 424 { 425 SkDebugf("------- [%p] vm->GetEnv() failed\n", vm); 426 sk_throw(); 427 } 428 return env; 429} 430 431#ifdef TRACK_LOCK_COUNT 432 static int gLockCount; 433#endif 434 435/////////////////////////////////////////////////////////////////////////////// 436 437AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj, 438 SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) { 439 SkASSERT(storage); 440 SkASSERT(env); 441 442 if (env->GetJavaVM(&fVM) != JNI_OK) { 443 SkDebugf("------ [%p] env->GetJavaVM failed\n", env); 444 sk_throw(); 445 } 446 fStorageObj = storageObj; 447 fHasGlobalRef = false; 448 fGlobalRefCnt = 0; 449 450 // If storageObj is NULL, the memory was NOT allocated on the Java heap 451 fOnJavaHeap = (storageObj != NULL); 452 453} 454 455AndroidPixelRef::~AndroidPixelRef() { 456 if (fOnJavaHeap) { 457 JNIEnv* env = vm2env(fVM); 458 459 if (fStorageObj && fHasGlobalRef) { 460 env->DeleteGlobalRef(fStorageObj); 461 } 462 fStorageObj = NULL; 463 464 // Set this to NULL to prevent the SkMallocPixelRef destructor 465 // from freeing the memory. 466 fStorage = NULL; 467 } 468} 469 470void AndroidPixelRef::setLocalJNIRef(jbyteArray arr) { 471 if (!fHasGlobalRef) { 472 fStorageObj = arr; 473 } 474} 475 476void AndroidPixelRef::globalRef(void* localref) { 477 if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) { 478 JNIEnv *env = vm2env(fVM); 479 480 // If JNI ref was passed, it is always used 481 if (localref) fStorageObj = (jbyteArray) localref; 482 483 if (fStorageObj == NULL) { 484 SkDebugf("No valid local ref to create a JNI global ref\n"); 485 sk_throw(); 486 } 487 if (fHasGlobalRef) { 488 // This should never happen 489 SkDebugf("Already holding a JNI global ref"); 490 sk_throw(); 491 } 492 493 fStorageObj = (jbyteArray) env->NewGlobalRef(fStorageObj); 494 // TODO: Check for failure here 495 fHasGlobalRef = true; 496 } 497 ref(); 498} 499 500void AndroidPixelRef::globalUnref() { 501 if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) { 502 JNIEnv *env = vm2env(fVM); 503 if (!fHasGlobalRef) { 504 SkDebugf("We don't have a global ref!"); 505 sk_throw(); 506 } 507 env->DeleteGlobalRef(fStorageObj); 508 fStorageObj = NULL; 509 fHasGlobalRef = false; 510 } 511 unref(); 512} 513 514/////////////////////////////////////////////////////////////////////////////// 515 516jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, 517 SkColorTable* ctable) { 518 Sk64 size64 = bitmap->getSize64(); 519 if (size64.isNeg() || !size64.is32()) { 520 doThrow(env, "java/lang/IllegalArgumentException", 521 "bitmap size exceeds 32bits"); 522 return NULL; 523 } 524 525 size_t size = size64.get32(); 526 jbyteArray arrayObj = env->NewByteArray(size); 527 if (arrayObj) { 528 jbyte *addr = env->GetByteArrayElements(arrayObj, NULL); 529 env->ReleaseByteArrayElements(arrayObj, addr, 0); 530 if (addr) { 531 SkPixelRef* pr = new AndroidPixelRef(env, (void*) addr, size, arrayObj, ctable); 532 bitmap->setPixelRef(pr)->unref(); 533 // since we're already allocated, we lockPixels right away 534 // HeapAllocator behaves this way too 535 bitmap->lockPixels(); 536 } 537 } 538 539 return arrayObj; 540} 541 542bool GraphicsJNI::mallocPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) { 543 Sk64 size64 = bitmap->getSize64(); 544 if (size64.isNeg() || !size64.is32()) { 545 doThrow(env, "java/lang/IllegalArgumentException", 546 "bitmap size exceeds 32bits"); 547 return false; 548 } 549 550 size_t size = size64.get32(); 551 552 // call the version of malloc that returns null on failure 553 void* addr = sk_malloc_flags(size, 0); 554 555 if (NULL == addr) { 556 return false; 557 } 558 559 SkPixelRef* pr = new AndroidPixelRef(env, addr, size, NULL, ctable); 560 bitmap->setPixelRef(pr)->unref(); 561 // since we're already allocated, we lockPixels right away 562 // HeapAllocator behaves this way too 563 bitmap->lockPixels(); 564 return true; 565} 566 567/////////////////////////////////////////////////////////////////////////////// 568 569JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool allocateInJavaHeap) 570 : fAllocateInJavaHeap(allocateInJavaHeap), 571 fStorageObj(NULL), 572 fAllocCount(0) { 573 if (env->GetJavaVM(&fVM) != JNI_OK) { 574 SkDebugf("------ [%p] env->GetJavaVM failed\n", env); 575 sk_throw(); 576 } 577} 578 579bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { 580 JNIEnv* env = vm2env(fVM); 581 582 // If allocating in the Java heap, only allow a single object to be 583 // allocated for the lifetime of this object. 584 if (fStorageObj != NULL) { 585 SkDebugf("WARNING: One-shot allocator has already allocated (alloc count = %d)\n", fAllocCount); 586// sk_throw(); 587 } 588 589 if (fAllocateInJavaHeap) { 590 fStorageObj = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable); 591 fAllocCount += 1; 592 return fStorageObj != NULL; 593 } 594 return GraphicsJNI::mallocPixelRef(env, bitmap, ctable); 595} 596 597//////////////////////////////////////////////////////////////////////////////// 598 599JavaMemoryUsageReporter::JavaMemoryUsageReporter(JNIEnv* env) 600 : fTotalSize(0) { 601 if (env->GetJavaVM(&fVM) != JNI_OK) { 602 SkDebugf("------ [%p] env->GetJavaVM failed\n", env); 603 sk_throw(); 604 } 605} 606 607JavaMemoryUsageReporter::~JavaMemoryUsageReporter() { 608 JNIEnv* env = vm2env(fVM); 609 jlong jtotalSize = fTotalSize; 610 env->CallVoidMethod(gVMRuntime_singleton, 611 gVMRuntime_trackExternalFreeMethodID, 612 jtotalSize); 613} 614 615bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) { 616 jlong jsize = memorySize; // the VM wants longs for the size 617 JNIEnv* env = vm2env(fVM); 618 bool r = env->CallBooleanMethod(gVMRuntime_singleton, 619 gVMRuntime_trackExternalAllocationMethodID, 620 jsize); 621 if (GraphicsJNI::hasException(env)) { 622 return false; 623 } 624 if (!r) { 625 LOGE("VM won't let us allocate %zd bytes\n", memorySize); 626 doThrowOOME(env, "bitmap size exceeds VM budget"); 627 return false; 628 } 629 fTotalSize += memorySize; 630 return true; 631} 632 633//////////////////////////////////////////////////////////////////////////////// 634 635JavaHeapBitmapRef::JavaHeapBitmapRef(JNIEnv* env, SkBitmap* nativeBitmap, jbyteArray buffer) { 636 fEnv = env; 637 fNativeBitmap = nativeBitmap; 638 fBuffer = buffer; 639 640 // If the buffer is NULL, the backing memory wasn't allocated on the Java heap 641 if (fBuffer) { 642 ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(fBuffer); 643 } 644} 645 646JavaHeapBitmapRef::~JavaHeapBitmapRef() { 647 if (fBuffer) { 648 ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(NULL); 649 } 650} 651 652//////////////////////////////////////////////////////////////////////////////// 653 654static jclass make_globalref(JNIEnv* env, const char classname[]) 655{ 656 jclass c = env->FindClass(classname); 657 SkASSERT(c); 658 return (jclass)env->NewGlobalRef(c); 659} 660 661static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 662 const char fieldname[], const char type[]) 663{ 664 jfieldID id = env->GetFieldID(clazz, fieldname, type); 665 SkASSERT(id); 666 return id; 667} 668 669int register_android_graphics_Graphics(JNIEnv* env) 670{ 671 jmethodID m; 672 jclass c; 673 674 gRect_class = make_globalref(env, "android/graphics/Rect"); 675 gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I"); 676 gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I"); 677 gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I"); 678 gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I"); 679 680 gRectF_class = make_globalref(env, "android/graphics/RectF"); 681 gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F"); 682 gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F"); 683 gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F"); 684 gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F"); 685 686 gPoint_class = make_globalref(env, "android/graphics/Point"); 687 gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I"); 688 gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I"); 689 690 gPointF_class = make_globalref(env, "android/graphics/PointF"); 691 gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F"); 692 gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F"); 693 694 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 695 gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I"); 696 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", 697 "(I[BZ[BI)V"); 698 gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder"); 699 gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)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, "mNativeCanvas", "I"); 707 708 gPaint_class = make_globalref(env, "android/graphics/Paint"); 709 gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I"); 710 711 gPicture_class = make_globalref(env, "android/graphics/Picture"); 712 gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "I"); 713 714 gRegion_class = make_globalref(env, "android/graphics/Region"); 715 gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "I"); 716 gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>", 717 "(II)V"); 718 719 // Get the VMRuntime class. 720 c = env->FindClass("dalvik/system/VMRuntime"); 721 SkASSERT(c); 722 // Look up VMRuntime.getRuntime(). 723 m = env->GetStaticMethodID(c, "getRuntime", "()Ldalvik/system/VMRuntime;"); 724 SkASSERT(m); 725 // Call VMRuntime.getRuntime() and hold onto its result. 726 gVMRuntime_singleton = env->CallStaticObjectMethod(c, m); 727 SkASSERT(gVMRuntime_singleton); 728 gVMRuntime_singleton = (jobject)env->NewGlobalRef(gVMRuntime_singleton); 729 // Look up the VMRuntime methods we'll be using. 730 gVMRuntime_trackExternalAllocationMethodID = 731 env->GetMethodID(c, "trackExternalAllocation", "(J)Z"); 732 gVMRuntime_trackExternalFreeMethodID = 733 env->GetMethodID(c, "trackExternalFree", "(J)V"); 734 735 return 0; 736} 737