blob: 204bb74b03f1705f2485432040c21533a6f04424 [file] [log] [blame]
Ficus Kirkpatrick1a9c27c2010-03-05 17:05:08 -08001#define LOG_TAG "GraphicsJNI"
2
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003#include "jni.h"
4#include "GraphicsJNI.h"
5#include "NIOBuffer.h"
6#include "SkPicture.h"
7#include "SkRegion.h"
8#include <android_runtime/AndroidRuntime.h>
9
Mike Reed1b22b972009-07-17 11:21:47 -040010//#define REPORT_SIZE_TO_JVM
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011//#define TRACK_LOCK_COUNT
12
13void doThrow(JNIEnv* env, const char* exc, const char* msg) {
14 // don't throw a new exception if we already have one pending
15 if (env->ExceptionCheck() == JNI_FALSE) {
16 jclass npeClazz;
17
18 npeClazz = env->FindClass(exc);
19 LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
20
21 env->ThrowNew(npeClazz, msg);
22 }
23}
24
25void doThrowNPE(JNIEnv* env) {
26 doThrow(env, "java/lang/NullPointerException");
27}
28
29void doThrowAIOOBE(JNIEnv* env) {
30 doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
31}
32
33void doThrowRE(JNIEnv* env, const char* msg) {
34 doThrow(env, "java/lang/RuntimeException", msg);
35}
36
37void doThrowIAE(JNIEnv* env, const char* msg) {
38 doThrow(env, "java/lang/IllegalArgumentException", msg);
39}
40
41void doThrowISE(JNIEnv* env, const char* msg) {
42 doThrow(env, "java/lang/IllegalStateException", msg);
43}
44
45void doThrowOOME(JNIEnv* env, const char* msg) {
46 doThrow(env, "java/lang/OutOfMemoryError", msg);
47}
48
Joseph Wenf1f48bc2010-07-19 16:59:51 +080049void doThrowIOE(JNIEnv* env, const char* msg) {
50 doThrow(env, "java/lang/IOException", msg);
51}
52
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053bool GraphicsJNI::hasException(JNIEnv *env) {
54 if (env->ExceptionCheck() != 0) {
55 LOGE("*** Uncaught exception returned from Java call!\n");
56 env->ExceptionDescribe();
57 return true;
58 }
59 return false;
60}
61
62///////////////////////////////////////////////////////////////////////////////
63
64AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
Mike Reedc04851f2009-10-28 15:09:45 -040065 int minLength, JNIAccess access)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
67 SkASSERT(env);
68 if (array) {
69 fLen = env->GetArrayLength(array);
70 if (fLen < minLength) {
71 sk_throw();
72 }
73 fPtr = env->GetFloatArrayElements(array, NULL);
74 }
Mike Reedc04851f2009-10-28 15:09:45 -040075 fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076}
77
78AutoJavaFloatArray::~AutoJavaFloatArray() {
79 if (fPtr) {
Mike Reedc04851f2009-10-28 15:09:45 -040080 fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82}
83
84AutoJavaIntArray::AutoJavaIntArray(JNIEnv* env, jintArray array,
85 int minLength)
86: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
87 SkASSERT(env);
88 if (array) {
89 fLen = env->GetArrayLength(array);
90 if (fLen < minLength) {
91 sk_throw();
92 }
93 fPtr = env->GetIntArrayElements(array, NULL);
94 }
95}
96
97AutoJavaIntArray::~AutoJavaIntArray() {
98 if (fPtr) {
99 fEnv->ReleaseIntArrayElements(fArray, fPtr, 0);
100 }
101}
102
103AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array,
Mike Reedc04851f2009-10-28 15:09:45 -0400104 int minLength, JNIAccess access)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
106 SkASSERT(env);
107 if (array) {
108 fLen = env->GetArrayLength(array);
109 if (fLen < minLength) {
110 sk_throw();
111 }
112 fPtr = env->GetShortArrayElements(array, NULL);
113 }
Mike Reedc04851f2009-10-28 15:09:45 -0400114 fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115}
116
117AutoJavaShortArray::~AutoJavaShortArray() {
118 if (fPtr) {
Mike Reedc04851f2009-10-28 15:09:45 -0400119 fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 }
121}
122
123AutoJavaByteArray::AutoJavaByteArray(JNIEnv* env, jbyteArray array,
124 int minLength)
125: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
126 SkASSERT(env);
127 if (array) {
128 fLen = env->GetArrayLength(array);
129 if (fLen < minLength) {
130 sk_throw();
131 }
132 fPtr = env->GetByteArrayElements(array, NULL);
133 }
134}
135
136AutoJavaByteArray::~AutoJavaByteArray() {
137 if (fPtr) {
138 fEnv->ReleaseByteArrayElements(fArray, fPtr, 0);
139 }
140}
141
142///////////////////////////////////////////////////////////////////////////////
143
144static jclass gRect_class;
145static jfieldID gRect_leftFieldID;
146static jfieldID gRect_topFieldID;
147static jfieldID gRect_rightFieldID;
148static jfieldID gRect_bottomFieldID;
149
150static jclass gRectF_class;
151static jfieldID gRectF_leftFieldID;
152static jfieldID gRectF_topFieldID;
153static jfieldID gRectF_rightFieldID;
154static jfieldID gRectF_bottomFieldID;
155
156static jclass gPoint_class;
157static jfieldID gPoint_xFieldID;
158static jfieldID gPoint_yFieldID;
159
160static jclass gPointF_class;
161static jfieldID gPointF_xFieldID;
162static jfieldID gPointF_yFieldID;
163
164static jclass gBitmap_class;
165static jfieldID gBitmap_nativeInstanceID;
166static jmethodID gBitmap_constructorMethodID;
167static jmethodID gBitmap_allocBufferMethodID;
168
169static jclass gBitmapConfig_class;
170static jfieldID gBitmapConfig_nativeInstanceID;
171
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800172static jclass gLargeBitmap_class;
173static jmethodID gLargeBitmap_constructorMethodID;
174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175static jclass gCanvas_class;
176static jfieldID gCanvas_nativeInstanceID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177
178static jclass gPaint_class;
179static jfieldID gPaint_nativeInstanceID;
180
181static jclass gPicture_class;
182static jfieldID gPicture_nativeInstanceID;
183
184static jclass gRegion_class;
185static jfieldID gRegion_nativeInstanceID;
186static jmethodID gRegion_constructorMethodID;
187
188static jobject gVMRuntime_singleton;
189static jmethodID gVMRuntime_trackExternalAllocationMethodID;
190static jmethodID gVMRuntime_trackExternalFreeMethodID;
191
192///////////////////////////////////////////////////////////////////////////////
193
194void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
195{
196 SkASSERT(env->IsInstanceOf(obj, gRect_class));
197
198 *L = env->GetIntField(obj, gRect_leftFieldID);
199 *T = env->GetIntField(obj, gRect_topFieldID);
200 *R = env->GetIntField(obj, gRect_rightFieldID);
201 *B = env->GetIntField(obj, gRect_bottomFieldID);
202}
203
204void GraphicsJNI::set_jrect(JNIEnv* env, jobject obj, int L, int T, int R, int B)
205{
206 SkASSERT(env->IsInstanceOf(obj, gRect_class));
207
208 env->SetIntField(obj, gRect_leftFieldID, L);
209 env->SetIntField(obj, gRect_topFieldID, T);
210 env->SetIntField(obj, gRect_rightFieldID, R);
211 env->SetIntField(obj, gRect_bottomFieldID, B);
212}
213
214SkIRect* GraphicsJNI::jrect_to_irect(JNIEnv* env, jobject obj, SkIRect* ir)
215{
216 SkASSERT(env->IsInstanceOf(obj, gRect_class));
217
218 ir->set(env->GetIntField(obj, gRect_leftFieldID),
219 env->GetIntField(obj, gRect_topFieldID),
220 env->GetIntField(obj, gRect_rightFieldID),
221 env->GetIntField(obj, gRect_bottomFieldID));
222 return ir;
223}
224
225void GraphicsJNI::irect_to_jrect(const SkIRect& ir, JNIEnv* env, jobject obj)
226{
227 SkASSERT(env->IsInstanceOf(obj, gRect_class));
228
229 env->SetIntField(obj, gRect_leftFieldID, ir.fLeft);
230 env->SetIntField(obj, gRect_topFieldID, ir.fTop);
231 env->SetIntField(obj, gRect_rightFieldID, ir.fRight);
232 env->SetIntField(obj, gRect_bottomFieldID, ir.fBottom);
233}
234
235SkRect* GraphicsJNI::jrectf_to_rect(JNIEnv* env, jobject obj, SkRect* r)
236{
237 SkASSERT(env->IsInstanceOf(obj, gRectF_class));
238
239 r->set(SkFloatToScalar(env->GetFloatField(obj, gRectF_leftFieldID)),
240 SkFloatToScalar(env->GetFloatField(obj, gRectF_topFieldID)),
241 SkFloatToScalar(env->GetFloatField(obj, gRectF_rightFieldID)),
242 SkFloatToScalar(env->GetFloatField(obj, gRectF_bottomFieldID)));
243 return r;
244}
245
246SkRect* GraphicsJNI::jrect_to_rect(JNIEnv* env, jobject obj, SkRect* r)
247{
248 SkASSERT(env->IsInstanceOf(obj, gRect_class));
249
250 r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)),
251 SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)),
252 SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)),
253 SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID)));
254 return r;
255}
256
257void GraphicsJNI::rect_to_jrectf(const SkRect& r, JNIEnv* env, jobject obj)
258{
259 SkASSERT(env->IsInstanceOf(obj, gRectF_class));
260
261 env->SetFloatField(obj, gRectF_leftFieldID, SkScalarToFloat(r.fLeft));
262 env->SetFloatField(obj, gRectF_topFieldID, SkScalarToFloat(r.fTop));
263 env->SetFloatField(obj, gRectF_rightFieldID, SkScalarToFloat(r.fRight));
264 env->SetFloatField(obj, gRectF_bottomFieldID, SkScalarToFloat(r.fBottom));
265}
266
267SkIPoint* GraphicsJNI::jpoint_to_ipoint(JNIEnv* env, jobject obj, SkIPoint* point)
268{
269 SkASSERT(env->IsInstanceOf(obj, gPoint_class));
270
271 point->set(env->GetIntField(obj, gPoint_xFieldID),
272 env->GetIntField(obj, gPoint_yFieldID));
273 return point;
274}
275
276void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj)
277{
278 SkASSERT(env->IsInstanceOf(obj, gPoint_class));
279
280 env->SetIntField(obj, gPoint_xFieldID, ir.fX);
281 env->SetIntField(obj, gPoint_yFieldID, ir.fY);
282}
283
284SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point)
285{
286 SkASSERT(env->IsInstanceOf(obj, gPointF_class));
287
288 point->set(SkFloatToScalar(env->GetIntField(obj, gPointF_xFieldID)),
289 SkFloatToScalar(env->GetIntField(obj, gPointF_yFieldID)));
290 return point;
291}
292
293void GraphicsJNI::point_to_jpointf(const SkPoint& r, JNIEnv* env, jobject obj)
294{
295 SkASSERT(env->IsInstanceOf(obj, gPointF_class));
296
297 env->SetFloatField(obj, gPointF_xFieldID, SkScalarToFloat(r.fX));
298 env->SetFloatField(obj, gPointF_yFieldID, SkScalarToFloat(r.fY));
299}
300
301SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
302 SkASSERT(env);
303 SkASSERT(bitmap);
304 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
305 SkBitmap* b = (SkBitmap*)env->GetIntField(bitmap, gBitmap_nativeInstanceID);
306 SkASSERT(b);
307 return b;
308}
309
310SkBitmap::Config GraphicsJNI::getNativeBitmapConfig(JNIEnv* env,
311 jobject jconfig) {
312 SkASSERT(env);
313 if (NULL == jconfig) {
314 return SkBitmap::kNo_Config;
315 }
316 SkASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class));
317 int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
318 if (c < 0 || c >= SkBitmap::kConfigCount) {
319 c = SkBitmap::kNo_Config;
320 }
321 return static_cast<SkBitmap::Config>(c);
322}
323
324SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
325 SkASSERT(env);
326 SkASSERT(canvas);
327 SkASSERT(env->IsInstanceOf(canvas, gCanvas_class));
328 SkCanvas* c = (SkCanvas*)env->GetIntField(canvas, gCanvas_nativeInstanceID);
329 SkASSERT(c);
330 return c;
331}
332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
334 SkASSERT(env);
335 SkASSERT(paint);
336 SkASSERT(env->IsInstanceOf(paint, gPaint_class));
337 SkPaint* p = (SkPaint*)env->GetIntField(paint, gPaint_nativeInstanceID);
338 SkASSERT(p);
339 return p;
340}
341
342SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
343{
344 SkASSERT(env);
345 SkASSERT(picture);
346 SkASSERT(env->IsInstanceOf(picture, gPicture_class));
347 SkPicture* p = (SkPicture*)env->GetIntField(picture, gPicture_nativeInstanceID);
348 SkASSERT(p);
349 return p;
350}
351
352SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
353{
354 SkASSERT(env);
355 SkASSERT(region);
356 SkASSERT(env->IsInstanceOf(region, gRegion_class));
357 SkRegion* r = (SkRegion*)env->GetIntField(region, gRegion_nativeInstanceID);
358 SkASSERT(r);
359 return r;
360}
361
362///////////////////////////////////////////////////////////////////////////////////////////
363
364jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700365 jbyteArray ninepatch, int density)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366{
367 SkASSERT(bitmap != NULL);
368 SkASSERT(NULL != bitmap->pixelRef());
369
370 jobject obj = env->AllocObject(gBitmap_class);
371 if (obj) {
372 env->CallVoidMethod(obj, gBitmap_constructorMethodID,
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700373 (jint)bitmap, isMutable, ninepatch, density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 if (hasException(env)) {
375 obj = NULL;
376 }
377 }
378 return obj;
379}
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800380jobject GraphicsJNI::createLargeBitmap(JNIEnv* env, SkLargeBitmap* bitmap)
381{
382 SkASSERT(bitmap != NULL);
383
384 jobject obj = env->AllocObject(gLargeBitmap_class);
385 if (hasException(env)) {
386 obj = NULL;
387 return obj;
388 }
389 if (obj) {
390 env->CallVoidMethod(obj, gLargeBitmap_constructorMethodID, (jint)bitmap);
391 if (hasException(env)) {
392 obj = NULL;
393 }
394 }
395 return obj;
396}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397
398jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
399{
400 SkASSERT(region != NULL);
401 jobject obj = env->AllocObject(gRegion_class);
402 if (obj) {
403 env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0);
404 if (hasException(env)) {
405 obj = NULL;
406 }
407 }
408 return obj;
409}
410
411#include "SkPixelRef.h"
412
413static JNIEnv* vm2env(JavaVM* vm)
414{
415 JNIEnv* env = NULL;
416 if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env)
417 {
418 SkDebugf("------- [%p] vm->GetEnv() failed\n", vm);
419 sk_throw();
420 }
421 return env;
422}
423
424#ifdef TRACK_LOCK_COUNT
425 static int gLockCount;
426#endif
427
428///////////////////////////////////////////////////////////////////////////////
429
430#include "SkMallocPixelRef.h"
431
432/* Extend SkMallocPixelRef to inform the VM when we free up the storage
433*/
434class AndroidPixelRef : public SkMallocPixelRef {
435public:
436 /** Allocate the specified buffer for pixels. The memory is freed when the
437 last owner of this pixelref is gone. Our caller has already informed
438 the VM of our allocation.
439 */
440 AndroidPixelRef(JNIEnv* env, void* storage, size_t size,
441 SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
442 SkASSERT(storage);
443 SkASSERT(env);
444
445 if (env->GetJavaVM(&fVM) != JNI_OK) {
446 SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
447 sk_throw();
448 }
449 }
450
451 virtual ~AndroidPixelRef() {
452 JNIEnv* env = vm2env(fVM);
453// SkDebugf("-------------- inform VM we're releasing %d bytes\n", this->getSize());
454 jlong jsize = this->getSize(); // the VM wants longs for the size
455 env->CallVoidMethod(gVMRuntime_singleton,
456 gVMRuntime_trackExternalFreeMethodID,
457 jsize);
458 if (GraphicsJNI::hasException(env)) {
459 env->ExceptionClear();
460 }
461 }
462
463private:
464 JavaVM* fVM;
465};
466
467bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
Mike Reed1b22b972009-07-17 11:21:47 -0400468 SkColorTable* ctable, bool reportSizeToVM) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 Sk64 size64 = bitmap->getSize64();
470 if (size64.isNeg() || !size64.is32()) {
471 doThrow(env, "java/lang/IllegalArgumentException",
472 "bitmap size exceeds 32bits");
473 return false;
474 }
475
476 size_t size = size64.get32();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 jlong jsize = size; // the VM wants longs for the size
Mike Reed1b22b972009-07-17 11:21:47 -0400478 if (reportSizeToVM) {
479 // SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
480 bool r = env->CallBooleanMethod(gVMRuntime_singleton,
481 gVMRuntime_trackExternalAllocationMethodID,
482 jsize);
483 if (GraphicsJNI::hasException(env)) {
484 return false;
485 }
486 if (!r) {
487 LOGE("VM won't let us allocate %zd bytes\n", size);
488 doThrowOOME(env, "bitmap size exceeds VM budget");
489 return false;
490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 // call the version of malloc that returns null on failure
493 void* addr = sk_malloc_flags(size, 0);
494 if (NULL == addr) {
Mike Reed1b22b972009-07-17 11:21:47 -0400495 if (reportSizeToVM) {
496 // SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
497 // we didn't actually allocate it, so inform the VM
498 env->CallVoidMethod(gVMRuntime_singleton,
499 gVMRuntime_trackExternalFreeMethodID,
500 jsize);
501 if (!GraphicsJNI::hasException(env)) {
502 doThrowOOME(env, "bitmap size too large for malloc");
503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 }
505 return false;
506 }
507
Mike Reed1b22b972009-07-17 11:21:47 -0400508 SkPixelRef* pr = reportSizeToVM ?
509 new AndroidPixelRef(env, addr, size, ctable) :
510 new SkMallocPixelRef(addr, size, ctable);
511 bitmap->setPixelRef(pr)->unref();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 // since we're already allocated, we lockPixels right away
513 // HeapAllocator behaves this way too
514 bitmap->lockPixels();
515 return true;
516}
517
518///////////////////////////////////////////////////////////////////////////////
519
Mike Reed1b22b972009-07-17 11:21:47 -0400520JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
521 : fEnv(env), fReportSizeToVM(reportSizeToVM) {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522
523bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
Mike Reed1b22b972009-07-17 11:21:47 -0400524 return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525}
526
527////////////////////////////////////////////////////////////////////////////////
528
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800529JavaMemoryUsageReporter::JavaMemoryUsageReporter(JNIEnv* env)
530 : fEnv(env), fTotalSize(0) {}
531
532JavaMemoryUsageReporter::~JavaMemoryUsageReporter() {
533 jlong jtotalSize = fTotalSize;
534 fEnv->CallVoidMethod(gVMRuntime_singleton,
535 gVMRuntime_trackExternalFreeMethodID,
536 jtotalSize);
537}
538
539bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) {
540 jlong jsize = memorySize; // the VM wants longs for the size
541 bool r = fEnv->CallBooleanMethod(gVMRuntime_singleton,
542 gVMRuntime_trackExternalAllocationMethodID,
543 jsize);
544 if (GraphicsJNI::hasException(fEnv)) {
545 return false;
546 }
547 if (!r) {
548 LOGE("VM won't let us allocate %zd bytes\n", memorySize);
549 doThrowOOME(fEnv, "bitmap size exceeds VM budget");
550 return false;
551 }
552 fTotalSize += memorySize;
553 return true;
554}
555
556////////////////////////////////////////////////////////////////////////////////
557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558static jclass make_globalref(JNIEnv* env, const char classname[])
559{
560 jclass c = env->FindClass(classname);
561 SkASSERT(c);
562 return (jclass)env->NewGlobalRef(c);
563}
564
565static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
566 const char fieldname[], const char type[])
567{
568 jfieldID id = env->GetFieldID(clazz, fieldname, type);
569 SkASSERT(id);
570 return id;
571}
572
573int register_android_graphics_Graphics(JNIEnv* env)
574{
575 jmethodID m;
576 jclass c;
577
578 gRect_class = make_globalref(env, "android/graphics/Rect");
579 gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I");
580 gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I");
581 gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I");
582 gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I");
583
584 gRectF_class = make_globalref(env, "android/graphics/RectF");
585 gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F");
586 gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F");
587 gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F");
588 gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F");
589
590 gPoint_class = make_globalref(env, "android/graphics/Point");
591 gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I");
592 gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I");
593
594 gPointF_class = make_globalref(env, "android/graphics/PointF");
595 gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
596 gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
597
598 gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
599 gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
600 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700601 "(IZ[BI)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800603 gLargeBitmap_class = make_globalref(env, "android/graphics/LargeBitmap");
604 gLargeBitmap_constructorMethodID = env->GetMethodID(gLargeBitmap_class, "<init>", "(I)V");
605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
607 gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
608 "nativeInt", "I");
609
610 gCanvas_class = make_globalref(env, "android/graphics/Canvas");
611 gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612
613 gPaint_class = make_globalref(env, "android/graphics/Paint");
614 gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I");
615
616 gPicture_class = make_globalref(env, "android/graphics/Picture");
617 gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "I");
618
619 gRegion_class = make_globalref(env, "android/graphics/Region");
620 gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "I");
621 gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>",
622 "(II)V");
623
624 // Get the VMRuntime class.
625 c = env->FindClass("dalvik/system/VMRuntime");
626 SkASSERT(c);
627 // Look up VMRuntime.getRuntime().
628 m = env->GetStaticMethodID(c, "getRuntime", "()Ldalvik/system/VMRuntime;");
629 SkASSERT(m);
630 // Call VMRuntime.getRuntime() and hold onto its result.
631 gVMRuntime_singleton = env->CallStaticObjectMethod(c, m);
632 SkASSERT(gVMRuntime_singleton);
633 gVMRuntime_singleton = (jobject)env->NewGlobalRef(gVMRuntime_singleton);
634 // Look up the VMRuntime methods we'll be using.
635 gVMRuntime_trackExternalAllocationMethodID =
636 env->GetMethodID(c, "trackExternalAllocation", "(J)Z");
637 gVMRuntime_trackExternalFreeMethodID =
638 env->GetMethodID(c, "trackExternalFree", "(J)V");
639
640 NIOBuffer::RegisterJNI(env);
641
642 return 0;
643}
644