Bitmap.cpp revision 5c13d89c1332fcc499379b9064b891187b75ca32
1#include "SkBitmap.h" 2#include "SkImageEncoder.h" 3#include "SkColorPriv.h" 4#include "GraphicsJNI.h" 5#include "SkDither.h" 6#include "SkUnPreMultiply.h" 7 8#include <binder/Parcel.h> 9#include "android_util_Binder.h" 10#include "android_nio_utils.h" 11#include "CreateJavaOutputStreamAdaptor.h" 12 13#include <jni.h> 14 15#include <Caches.h> 16 17#if 0 18 #define TRACE_BITMAP(code) code 19#else 20 #define TRACE_BITMAP(code) 21#endif 22 23/////////////////////////////////////////////////////////////////////////////// 24// Conversions to/from SkColor, for get/setPixels, and the create method, which 25// is basically like setPixels 26 27typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, 28 int x, int y); 29 30static void FromColor_D32(void* dst, const SkColor src[], int width, 31 int, int) { 32 SkPMColor* d = (SkPMColor*)dst; 33 34 for (int i = 0; i < width; i++) { 35 *d++ = SkPreMultiplyColor(*src++); 36 } 37} 38 39static void FromColor_D565(void* dst, const SkColor src[], int width, 40 int x, int y) { 41 uint16_t* d = (uint16_t*)dst; 42 43 DITHER_565_SCAN(y); 44 for (int stop = x + width; x < stop; x++) { 45 SkColor c = *src++; 46 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), 47 DITHER_VALUE(x)); 48 } 49} 50 51static void FromColor_D4444(void* dst, const SkColor src[], int width, 52 int x, int y) { 53 SkPMColor16* d = (SkPMColor16*)dst; 54 55 DITHER_4444_SCAN(y); 56 for (int stop = x + width; x < stop; x++) { 57 SkPMColor c = SkPreMultiplyColor(*src++); 58 *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x)); 59// *d++ = SkPixel32ToPixel4444(c); 60 } 61} 62 63// can return NULL 64static FromColorProc ChooseFromColorProc(SkBitmap::Config config) { 65 switch (config) { 66 case SkBitmap::kARGB_8888_Config: 67 return FromColor_D32; 68 case SkBitmap::kARGB_4444_Config: 69 return FromColor_D4444; 70 case SkBitmap::kRGB_565_Config: 71 return FromColor_D565; 72 default: 73 break; 74 } 75 return NULL; 76} 77 78bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, 79 int srcOffset, int srcStride, 80 int x, int y, int width, int height, 81 const SkBitmap& dstBitmap) { 82 SkAutoLockPixels alp(dstBitmap); 83 void* dst = dstBitmap.getPixels(); 84 FromColorProc proc = ChooseFromColorProc(dstBitmap.config()); 85 86 if (NULL == dst || NULL == proc) { 87 return false; 88 } 89 90 const jint* array = env->GetIntArrayElements(srcColors, NULL); 91 const SkColor* src = (const SkColor*)array + srcOffset; 92 93 // reset to to actual choice from caller 94 dst = dstBitmap.getAddr(x, y); 95 // now copy/convert each scanline 96 for (int y = 0; y < height; y++) { 97 proc(dst, src, width, x, y); 98 src += srcStride; 99 dst = (char*)dst + dstBitmap.rowBytes(); 100 } 101 102 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), 103 JNI_ABORT); 104 return true; 105} 106 107//////////////////// ToColor procs 108 109typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, 110 SkColorTable*); 111 112static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, 113 SkColorTable*) { 114 SkASSERT(width > 0); 115 const SkPMColor* s = (const SkPMColor*)src; 116 do { 117 *dst++ = SkUnPreMultiply::PMColorToColor(*s++); 118 } while (--width != 0); 119} 120 121static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, 122 SkColorTable*) { 123 SkASSERT(width > 0); 124 const SkPMColor* s = (const SkPMColor*)src; 125 do { 126 SkPMColor c = *s++; 127 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 128 SkGetPackedB32(c)); 129 } while (--width != 0); 130} 131 132static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, 133 SkColorTable*) { 134 SkASSERT(width > 0); 135 const SkPMColor16* s = (const SkPMColor16*)src; 136 do { 137 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); 138 } while (--width != 0); 139} 140 141static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, 142 SkColorTable*) { 143 SkASSERT(width > 0); 144 const SkPMColor* s = (const SkPMColor*)src; 145 do { 146 SkPMColor c = SkPixel4444ToPixel32(*s++); 147 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 148 SkGetPackedB32(c)); 149 } while (--width != 0); 150} 151 152static void ToColor_S565(SkColor dst[], const void* src, int width, 153 SkColorTable*) { 154 SkASSERT(width > 0); 155 const uint16_t* s = (const uint16_t*)src; 156 do { 157 uint16_t c = *s++; 158 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), 159 SkPacked16ToB32(c)); 160 } while (--width != 0); 161} 162 163static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, 164 SkColorTable* ctable) { 165 SkASSERT(width > 0); 166 const uint8_t* s = (const uint8_t*)src; 167 const SkPMColor* colors = ctable->lockColors(); 168 do { 169 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]); 170 } while (--width != 0); 171 ctable->unlockColors(false); 172} 173 174static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, 175 SkColorTable* ctable) { 176 SkASSERT(width > 0); 177 const uint8_t* s = (const uint8_t*)src; 178 const SkPMColor* colors = ctable->lockColors(); 179 do { 180 SkPMColor c = colors[*s++]; 181 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 182 SkGetPackedB32(c)); 183 } while (--width != 0); 184 ctable->unlockColors(false); 185} 186 187// can return NULL 188static ToColorProc ChooseToColorProc(const SkBitmap& src) { 189 switch (src.config()) { 190 case SkBitmap::kARGB_8888_Config: 191 return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha; 192 case SkBitmap::kARGB_4444_Config: 193 return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha; 194 case SkBitmap::kRGB_565_Config: 195 return ToColor_S565; 196 case SkBitmap::kIndex8_Config: 197 if (src.getColorTable() == NULL) { 198 return NULL; 199 } 200 return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha; 201 default: 202 break; 203 } 204 return NULL; 205} 206 207/////////////////////////////////////////////////////////////////////////////// 208/////////////////////////////////////////////////////////////////////////////// 209 210static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, 211 int offset, int stride, int width, int height, 212 SkBitmap::Config config, jboolean isMutable) { 213 if (width <= 0 || height <= 0) { 214 doThrowIAE(env, "width and height must be > 0"); 215 return NULL; 216 } 217 218 if (NULL != jColors) { 219 size_t n = env->GetArrayLength(jColors); 220 if (n < SkAbs32(stride) * (size_t)height) { 221 doThrowAIOOBE(env); 222 return NULL; 223 } 224 } 225 226 SkBitmap bitmap; 227 228 bitmap.setConfig(config, width, height); 229 if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) { 230 return NULL; 231 } 232 233 if (jColors != NULL) { 234 GraphicsJNI::SetPixels(env, jColors, offset, stride, 235 0, 0, width, height, bitmap); 236 } 237 238 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable, 239 NULL); 240} 241 242static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, 243 SkBitmap::Config dstConfig, jboolean isMutable) { 244 SkBitmap result; 245 JavaPixelAllocator allocator(env, true); 246 247 if (!src->copyTo(&result, dstConfig, &allocator)) { 248 return NULL; 249 } 250 251 return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable, 252 NULL); 253} 254 255static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) { 256#ifdef USE_OPENGL_RENDERER 257 if (android::uirenderer::Caches::hasInstance()) { 258 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap); 259 } 260#else // !USE_OPENGL_RENDERER 261 delete bitmap; 262#endif 263} 264 265static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) { 266#ifdef USE_OPENGL_RENDERER 267 if (android::uirenderer::Caches::hasInstance()) { 268 android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap); 269 } 270#else // !USE_OPENGL_RENDERER 271 bitmap->setPixels(NULL, NULL); 272#endif // USE_OPENGL_RENDERER 273} 274 275// These must match the int values in Bitmap.java 276enum JavaEncodeFormat { 277 kJPEG_JavaEncodeFormat = 0, 278 kPNG_JavaEncodeFormat = 1 279}; 280 281static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap, 282 int format, int quality, 283 jobject jstream, jbyteArray jstorage) { 284 SkImageEncoder::Type fm; 285 286 switch (format) { 287 case kJPEG_JavaEncodeFormat: 288 fm = SkImageEncoder::kJPEG_Type; 289 break; 290 case kPNG_JavaEncodeFormat: 291 fm = SkImageEncoder::kPNG_Type; 292 break; 293 default: 294 return false; 295 } 296 297 bool success = false; 298 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); 299 if (NULL != strm) { 300 SkImageEncoder* encoder = SkImageEncoder::Create(fm); 301 if (NULL != encoder) { 302 success = encoder->encodeStream(strm, *bitmap, quality); 303 delete encoder; 304 } 305 delete strm; 306 } 307 return success; 308} 309 310static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) { 311 bitmap->eraseColor(color); 312} 313 314static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) { 315 return bitmap->width(); 316} 317 318static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) { 319 return bitmap->height(); 320} 321 322static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) { 323 return bitmap->rowBytes(); 324} 325 326static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) { 327 return bitmap->config(); 328} 329 330static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) { 331 return bitmap->getGenerationID(); 332} 333 334static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) { 335 return !bitmap->isOpaque(); 336} 337 338static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap, 339 jboolean hasAlpha) { 340 bitmap->setIsOpaque(!hasAlpha); 341} 342 343/////////////////////////////////////////////////////////////////////////////// 344 345static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 346 if (parcel == NULL) { 347 SkDebugf("-------- unparcel parcel is NULL\n"); 348 return NULL; 349 } 350 351 android::Parcel* p = android::parcelForJavaObject(env, parcel); 352 353 const bool isMutable = p->readInt32() != 0; 354 const SkBitmap::Config config = (SkBitmap::Config)p->readInt32(); 355 const int width = p->readInt32(); 356 const int height = p->readInt32(); 357 const int rowBytes = p->readInt32(); 358 const int density = p->readInt32(); 359 360 if (SkBitmap::kARGB_8888_Config != config && 361 SkBitmap::kRGB_565_Config != config && 362 SkBitmap::kARGB_4444_Config != config && 363 SkBitmap::kIndex8_Config != config && 364 SkBitmap::kA8_Config != config) { 365 SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config); 366 return NULL; 367 } 368 369 SkBitmap* bitmap = new SkBitmap; 370 371 bitmap->setConfig(config, width, height, rowBytes); 372 373 SkColorTable* ctable = NULL; 374 if (config == SkBitmap::kIndex8_Config) { 375 int count = p->readInt32(); 376 if (count > 0) { 377 size_t size = count * sizeof(SkPMColor); 378 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 379 ctable = new SkColorTable(src, count); 380 } 381 } 382 383 if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, true)) { 384 ctable->safeUnref(); 385 delete bitmap; 386 return NULL; 387 } 388 389 ctable->safeUnref(); 390 391 size_t size = bitmap->getSize(); 392 bitmap->lockPixels(); 393 memcpy(bitmap->getPixels(), p->readInplace(size), size); 394 bitmap->unlockPixels(); 395 396 return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL, density); 397} 398 399static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 400 const SkBitmap* bitmap, 401 jboolean isMutable, jint density, 402 jobject parcel) { 403 if (parcel == NULL) { 404 SkDebugf("------- writeToParcel null parcel\n"); 405 return false; 406 } 407 408 android::Parcel* p = android::parcelForJavaObject(env, parcel); 409 410 p->writeInt32(isMutable); 411 p->writeInt32(bitmap->config()); 412 p->writeInt32(bitmap->width()); 413 p->writeInt32(bitmap->height()); 414 p->writeInt32(bitmap->rowBytes()); 415 p->writeInt32(density); 416 417 if (bitmap->getConfig() == SkBitmap::kIndex8_Config) { 418 SkColorTable* ctable = bitmap->getColorTable(); 419 if (ctable != NULL) { 420 int count = ctable->count(); 421 p->writeInt32(count); 422 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 423 ctable->lockColors(), count * sizeof(SkPMColor)); 424 ctable->unlockColors(false); 425 } else { 426 p->writeInt32(0); // indicate no ctable 427 } 428 } 429 430 size_t size = bitmap->getSize(); 431 bitmap->lockPixels(); 432 memcpy(p->writeInplace(size), bitmap->getPixels(), size); 433 bitmap->unlockPixels(); 434 return true; 435} 436 437static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 438 const SkBitmap* src, const SkPaint* paint, 439 jintArray offsetXY) { 440 SkIPoint offset; 441 SkBitmap* dst = new SkBitmap; 442 443 src->extractAlpha(dst, paint, &offset); 444 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 445 int* array = env->GetIntArrayElements(offsetXY, NULL); 446 array[0] = offset.fX; 447 array[1] = offset.fY; 448 env->ReleaseIntArrayElements(offsetXY, array, 0); 449 } 450 451 return GraphicsJNI::createBitmap(env, dst, true, NULL); 452} 453 454/////////////////////////////////////////////////////////////////////////////// 455 456static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, 457 int x, int y) { 458 SkAutoLockPixels alp(*bitmap); 459 460 ToColorProc proc = ChooseToColorProc(*bitmap); 461 if (NULL == proc) { 462 return 0; 463 } 464 const void* src = bitmap->getAddr(x, y); 465 if (NULL == src) { 466 return 0; 467 } 468 469 SkColor dst[1]; 470 proc(dst, src, 1, bitmap->getColorTable()); 471 return dst[0]; 472} 473 474static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, 475 jintArray pixelArray, int offset, int stride, 476 int x, int y, int width, int height) { 477 SkAutoLockPixels alp(*bitmap); 478 479 ToColorProc proc = ChooseToColorProc(*bitmap); 480 if (NULL == proc) { 481 return; 482 } 483 const void* src = bitmap->getAddr(x, y); 484 if (NULL == src) { 485 return; 486 } 487 488 SkColorTable* ctable = bitmap->getColorTable(); 489 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 490 SkColor* d = (SkColor*)dst + offset; 491 while (--height >= 0) { 492 proc(d, src, width, ctable); 493 d += stride; 494 src = (void*)((const char*)src + bitmap->rowBytes()); 495 } 496 env->ReleaseIntArrayElements(pixelArray, dst, 0); 497} 498 499/////////////////////////////////////////////////////////////////////////////// 500 501static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, 502 int x, int y, SkColor color) { 503 SkAutoLockPixels alp(*bitmap); 504 if (NULL == bitmap->getPixels()) { 505 return; 506 } 507 508 FromColorProc proc = ChooseFromColorProc(bitmap->config()); 509 if (NULL == proc) { 510 return; 511 } 512 513 proc(bitmap->getAddr(x, y), &color, 1, x, y); 514} 515 516static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, 517 jintArray pixelArray, int offset, int stride, 518 int x, int y, int width, int height) { 519 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 520 x, y, width, height, *bitmap); 521} 522 523static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 524 const SkBitmap* bitmap, jobject jbuffer) { 525 SkAutoLockPixels alp(*bitmap); 526 const void* src = bitmap->getPixels(); 527 528 if (NULL != src) { 529 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 530 531 // the java side has already checked that buffer is large enough 532 memcpy(abp.pointer(), src, bitmap->getSize()); 533 } 534} 535 536static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 537 const SkBitmap* bitmap, jobject jbuffer) { 538 SkAutoLockPixels alp(*bitmap); 539 void* dst = bitmap->getPixels(); 540 541 if (NULL != dst) { 542 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 543 // the java side has already checked that buffer is large enough 544 memcpy(dst, abp.pointer(), bitmap->getSize()); 545 } 546} 547 548static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0, 549 const SkBitmap* bm1) { 550 if (bm0->width() != bm1->width() || 551 bm0->height() != bm1->height() || 552 bm0->config() != bm1->config()) { 553 return false; 554 } 555 556 SkAutoLockPixels alp0(*bm0); 557 SkAutoLockPixels alp1(*bm1); 558 559 // if we can't load the pixels, return false 560 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) { 561 return false; 562 } 563 564 if (bm0->config() == SkBitmap::kIndex8_Config) { 565 SkColorTable* ct0 = bm0->getColorTable(); 566 SkColorTable* ct1 = bm1->getColorTable(); 567 if (NULL == ct0 || NULL == ct1) { 568 return false; 569 } 570 if (ct0->count() != ct1->count()) { 571 return false; 572 } 573 574 SkAutoLockColors alc0(ct0); 575 SkAutoLockColors alc1(ct1); 576 const size_t size = ct0->count() * sizeof(SkPMColor); 577 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) { 578 return false; 579 } 580 } 581 582 // now compare each scanline. We can't do the entire buffer at once, 583 // since we don't care about the pixel values that might extend beyond 584 // the width (since the scanline might be larger than the logical width) 585 const int h = bm0->height(); 586 const size_t size = bm0->width() * bm0->bytesPerPixel(); 587 for (int y = 0; y < h; y++) { 588 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) { 589 return false; 590 } 591 } 592 return true; 593} 594 595static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) { 596 bitmap->lockPixels(); 597 bitmap->unlockPixels(); 598} 599 600/////////////////////////////////////////////////////////////////////////////// 601 602#include <android_runtime/AndroidRuntime.h> 603 604static JNINativeMethod gBitmapMethods[] = { 605 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 606 (void*)Bitmap_creator }, 607 { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;", 608 (void*)Bitmap_copy }, 609 { "nativeDestructor", "(I)V", (void*)Bitmap_destructor }, 610 { "nativeRecycle", "(I)V", (void*)Bitmap_recycle }, 611 { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z", 612 (void*)Bitmap_compress }, 613 { "nativeErase", "(II)V", (void*)Bitmap_erase }, 614 { "nativeWidth", "(I)I", (void*)Bitmap_width }, 615 { "nativeHeight", "(I)I", (void*)Bitmap_height }, 616 { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes }, 617 { "nativeConfig", "(I)I", (void*)Bitmap_config }, 618 { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha }, 619 { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha }, 620 { "nativeCreateFromParcel", 621 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 622 (void*)Bitmap_createFromParcel }, 623 { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z", 624 (void*)Bitmap_writeToParcel }, 625 { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;", 626 (void*)Bitmap_extractAlpha }, 627 { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId }, 628 { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel }, 629 { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels }, 630 { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel }, 631 { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels }, 632 { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V", 633 (void*)Bitmap_copyPixelsToBuffer }, 634 { "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V", 635 (void*)Bitmap_copyPixelsFromBuffer }, 636 { "nativeSameAs", "(II)Z", (void*)Bitmap_sameAs }, 637 { "nativePrepareToDraw", "(I)V", (void*)Bitmap_prepareToDraw }, 638}; 639 640#define kClassPathName "android/graphics/Bitmap" 641 642int register_android_graphics_Bitmap(JNIEnv* env); 643int register_android_graphics_Bitmap(JNIEnv* env) 644{ 645 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, 646 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods)); 647} 648 649