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