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