Bitmap.cpp revision 9192d5e8d78b826a665ce048c007e6eaf0f5b003
1#define LOG_TAG "Bitmap" 2#include "Bitmap.h" 3 4#include "SkBitmap.h" 5#include "SkPixelRef.h" 6#include "SkImageEncoder.h" 7#include "SkImageInfo.h" 8#include "SkColorPriv.h" 9#include "GraphicsJNI.h" 10#include "SkDither.h" 11#include "SkUnPreMultiply.h" 12#include "SkStream.h" 13 14#include <binder/Parcel.h> 15#include "android_os_Parcel.h" 16#include "android_util_Binder.h" 17#include "android_nio_utils.h" 18#include "CreateJavaOutputStreamAdaptor.h" 19#include <hwui/Paint.h> 20#include <hwui/Bitmap.h> 21#include <renderthread/RenderProxy.h> 22 23#include "core_jni_helpers.h" 24 25#include <jni.h> 26#include <memory> 27#include <string> 28 29#define DEBUG_PARCEL 0 30#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10)) 31 32static jclass gBitmap_class; 33static jfieldID gBitmap_nativePtr; 34static jmethodID gBitmap_constructorMethodID; 35static jmethodID gBitmap_reinitMethodID; 36static jmethodID gBitmap_getAllocationByteCountMethodID; 37 38namespace android { 39 40class BitmapWrapper { 41public: 42 BitmapWrapper(Bitmap* bitmap) 43 : mBitmap(bitmap) { } 44 45 void freePixels() { 46 mInfo = mBitmap->info(); 47 mHasHardwareMipMap = mBitmap->hasHardwareMipMap(); 48 mAllocationSize = mBitmap->getAllocationByteCount(); 49 mRowBytes = mBitmap->rowBytes(); 50 mGenerationId = mBitmap->getGenerationID(); 51 mBitmap.reset(); 52 } 53 54 bool valid() { 55 return mBitmap; 56 } 57 58 Bitmap& bitmap() { 59 assertValid(); 60 return *mBitmap; 61 } 62 63 void assertValid() { 64 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!"); 65 } 66 67 void getSkBitmap(SkBitmap* outBitmap) { 68 assertValid(); 69 mBitmap->getSkBitmap(outBitmap); 70 } 71 72 bool hasHardwareMipMap() { 73 if (mBitmap) { 74 return mBitmap->hasHardwareMipMap(); 75 } 76 return mHasHardwareMipMap; 77 } 78 79 void setHasHardwareMipMap(bool hasMipMap) { 80 assertValid(); 81 mBitmap->setHasHardwareMipMap(hasMipMap); 82 } 83 84 void setAlphaType(SkAlphaType alphaType) { 85 assertValid(); 86 mBitmap->setAlphaType(alphaType); 87 } 88 89 const SkImageInfo& info() { 90 if (mBitmap) { 91 return mBitmap->info(); 92 } 93 return mInfo; 94 } 95 96 size_t getAllocationByteCount() const { 97 if (mBitmap) { 98 return mBitmap->getAllocationByteCount(); 99 } 100 return mAllocationSize; 101 } 102 103 size_t rowBytes() const { 104 if (mBitmap) { 105 return mBitmap->rowBytes(); 106 } 107 return mRowBytes; 108 } 109 110 uint32_t getGenerationID() const { 111 if (mBitmap) { 112 return mBitmap->getGenerationID(); 113 } 114 return mGenerationId; 115 } 116 117 ~BitmapWrapper() { } 118 119private: 120 sk_sp<Bitmap> mBitmap; 121 SkImageInfo mInfo; 122 bool mHasHardwareMipMap; 123 size_t mAllocationSize; 124 size_t mRowBytes; 125 uint32_t mGenerationId; 126}; 127 128// Convenience class that does not take a global ref on the pixels, relying 129// on the caller already having a local JNI ref 130class LocalScopedBitmap { 131public: 132 explicit LocalScopedBitmap(jlong bitmapHandle) 133 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {} 134 135 BitmapWrapper* operator->() { 136 return mBitmapWrapper; 137 } 138 139 void* pixels() { 140 return mBitmapWrapper->bitmap().pixels(); 141 } 142 143 bool valid() { 144 return mBitmapWrapper && mBitmapWrapper->valid(); 145 } 146 147private: 148 BitmapWrapper* mBitmapWrapper; 149}; 150 151namespace bitmap { 152 153// Assert that bitmap's SkAlphaType is consistent with isPremultiplied. 154static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) { 155 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is 156 // irrelevant. This just tests to ensure that the SkAlphaType is not 157 // opposite of isPremultiplied. 158 if (isPremultiplied) { 159 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType); 160 } else { 161 SkASSERT(info.alphaType() != kPremul_SkAlphaType); 162 } 163} 164 165void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info, 166 bool isPremultiplied) 167{ 168 // The caller needs to have already set the alpha type properly, so the 169 // native SkBitmap stays in sync with the Java Bitmap. 170 assert_premultiplied(info, isPremultiplied); 171 172 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID, 173 info.width(), info.height(), isPremultiplied); 174} 175 176int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap) 177{ 178 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID); 179} 180 181jobject createBitmap(JNIEnv* env, Bitmap* bitmap, 182 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets, 183 int density) { 184 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable; 185 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied; 186 // The caller needs to have already set the alpha type properly, so the 187 // native SkBitmap stays in sync with the Java Bitmap. 188 assert_premultiplied(bitmap->info(), isPremultiplied); 189 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap); 190 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID, 191 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density, 192 isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets); 193 194 if (env->ExceptionCheck() != 0) { 195 ALOGE("*** Uncaught exception returned from Java call!\n"); 196 env->ExceptionDescribe(); 197 } 198 return obj; 199} 200 201void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) { 202 LocalScopedBitmap bitmap(bitmapHandle); 203 bitmap->getSkBitmap(outBitmap); 204} 205 206Bitmap& toBitmap(JNIEnv* env, jobject bitmap) { 207 SkASSERT(env); 208 SkASSERT(bitmap); 209 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 210 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); 211 LocalScopedBitmap localBitmap(bitmapHandle); 212 return localBitmap->bitmap(); 213} 214 215Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) { 216 SkASSERT(env); 217 LocalScopedBitmap localBitmap(bitmapHandle); 218 return localBitmap->bitmap(); 219} 220 221} // namespace bitmap 222 223} // namespace android 224 225using namespace android; 226using namespace android::bitmap; 227 228/////////////////////////////////////////////////////////////////////////////// 229// Conversions to/from SkColor, for get/setPixels, and the create method, which 230// is basically like setPixels 231 232typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, 233 int x, int y); 234 235static void FromColor_D32(void* dst, const SkColor src[], int width, 236 int, int) { 237 SkPMColor* d = (SkPMColor*)dst; 238 239 for (int i = 0; i < width; i++) { 240 *d++ = SkPreMultiplyColor(*src++); 241 } 242} 243 244static void FromColor_D32_Raw(void* dst, const SkColor src[], int width, 245 int, int) { 246 // Needed to thwart the unreachable code detection from clang. 247 static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER; 248 249 // SkColor's ordering may be different from SkPMColor 250 if (sk_color_ne_zero) { 251 memcpy(dst, src, width * sizeof(SkColor)); 252 return; 253 } 254 255 // order isn't same, repack each pixel manually 256 SkPMColor* d = (SkPMColor*)dst; 257 for (int i = 0; i < width; i++) { 258 SkColor c = *src++; 259 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), 260 SkColorGetG(c), SkColorGetB(c)); 261 } 262} 263 264static void FromColor_D565(void* dst, const SkColor src[], int width, 265 int x, int y) { 266 uint16_t* d = (uint16_t*)dst; 267 268 DITHER_565_SCAN(y); 269 for (int stop = x + width; x < stop; x++) { 270 SkColor c = *src++; 271 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), 272 DITHER_VALUE(x)); 273 } 274} 275 276static void FromColor_D4444(void* dst, const SkColor src[], int width, 277 int x, int y) { 278 SkPMColor16* d = (SkPMColor16*)dst; 279 280 DITHER_4444_SCAN(y); 281 for (int stop = x + width; x < stop; x++) { 282 SkPMColor pmc = SkPreMultiplyColor(*src++); 283 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); 284// *d++ = SkPixel32ToPixel4444(pmc); 285 } 286} 287 288static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width, 289 int x, int y) { 290 SkPMColor16* d = (SkPMColor16*)dst; 291 292 DITHER_4444_SCAN(y); 293 for (int stop = x + width; x < stop; x++) { 294 SkColor c = *src++; 295 296 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied 297 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), 298 SkColorGetG(c), SkColorGetB(c)); 299 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); 300// *d++ = SkPixel32ToPixel4444(pmc); 301 } 302} 303 304static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) { 305 uint8_t* d = (uint8_t*)dst; 306 307 for (int stop = x + width; x < stop; x++) { 308 *d++ = SkColorGetA(*src++); 309 } 310} 311 312// can return NULL 313static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) { 314 switch (bitmap.colorType()) { 315 case kN32_SkColorType: 316 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw; 317 case kARGB_4444_SkColorType: 318 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 : 319 FromColor_D4444_Raw; 320 case kRGB_565_SkColorType: 321 return FromColor_D565; 322 case kAlpha_8_SkColorType: 323 return FromColor_DA8; 324 default: 325 break; 326 } 327 return NULL; 328} 329 330bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, 331 int x, int y, int width, int height, const SkBitmap& dstBitmap) { 332 SkAutoLockPixels alp(dstBitmap); 333 void* dst = dstBitmap.getPixels(); 334 FromColorProc proc = ChooseFromColorProc(dstBitmap); 335 336 if (NULL == dst || NULL == proc) { 337 return false; 338 } 339 340 const jint* array = env->GetIntArrayElements(srcColors, NULL); 341 const SkColor* src = (const SkColor*)array + srcOffset; 342 343 // reset to to actual choice from caller 344 dst = dstBitmap.getAddr(x, y); 345 // now copy/convert each scanline 346 for (int y = 0; y < height; y++) { 347 proc(dst, src, width, x, y); 348 src += srcStride; 349 dst = (char*)dst + dstBitmap.rowBytes(); 350 } 351 352 dstBitmap.notifyPixelsChanged(); 353 354 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), 355 JNI_ABORT); 356 return true; 357} 358 359//////////////////// ToColor procs 360 361typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, 362 SkColorTable*); 363 364static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, 365 SkColorTable*) { 366 SkASSERT(width > 0); 367 const SkPMColor* s = (const SkPMColor*)src; 368 do { 369 *dst++ = SkUnPreMultiply::PMColorToColor(*s++); 370 } while (--width != 0); 371} 372 373static void ToColor_S32_Raw(SkColor dst[], const void* src, int width, 374 SkColorTable*) { 375 SkASSERT(width > 0); 376 const SkPMColor* s = (const SkPMColor*)src; 377 do { 378 SkPMColor c = *s++; 379 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 380 SkGetPackedG32(c), SkGetPackedB32(c)); 381 } while (--width != 0); 382} 383 384static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, 385 SkColorTable*) { 386 SkASSERT(width > 0); 387 const SkPMColor* s = (const SkPMColor*)src; 388 do { 389 SkPMColor c = *s++; 390 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 391 SkGetPackedB32(c)); 392 } while (--width != 0); 393} 394 395static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, 396 SkColorTable*) { 397 SkASSERT(width > 0); 398 const SkPMColor16* s = (const SkPMColor16*)src; 399 do { 400 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); 401 } while (--width != 0); 402} 403 404static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width, 405 SkColorTable*) { 406 SkASSERT(width > 0); 407 const SkPMColor16* s = (const SkPMColor16*)src; 408 do { 409 SkPMColor c = SkPixel4444ToPixel32(*s++); 410 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 411 SkGetPackedG32(c), SkGetPackedB32(c)); 412 } while (--width != 0); 413} 414 415static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, 416 SkColorTable*) { 417 SkASSERT(width > 0); 418 const SkPMColor16* s = (const SkPMColor16*)src; 419 do { 420 SkPMColor c = SkPixel4444ToPixel32(*s++); 421 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 422 SkGetPackedB32(c)); 423 } while (--width != 0); 424} 425 426static void ToColor_S565(SkColor dst[], const void* src, int width, 427 SkColorTable*) { 428 SkASSERT(width > 0); 429 const uint16_t* s = (const uint16_t*)src; 430 do { 431 uint16_t c = *s++; 432 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), 433 SkPacked16ToB32(c)); 434 } while (--width != 0); 435} 436 437static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, 438 SkColorTable* ctable) { 439 SkASSERT(width > 0); 440 const uint8_t* s = (const uint8_t*)src; 441 const SkPMColor* colors = ctable->readColors(); 442 do { 443 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]); 444 } while (--width != 0); 445} 446 447static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width, 448 SkColorTable* ctable) { 449 SkASSERT(width > 0); 450 const uint8_t* s = (const uint8_t*)src; 451 const SkPMColor* colors = ctable->readColors(); 452 do { 453 SkPMColor c = colors[*s++]; 454 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 455 SkGetPackedG32(c), SkGetPackedB32(c)); 456 } while (--width != 0); 457} 458 459static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, 460 SkColorTable* ctable) { 461 SkASSERT(width > 0); 462 const uint8_t* s = (const uint8_t*)src; 463 const SkPMColor* colors = ctable->readColors(); 464 do { 465 SkPMColor c = colors[*s++]; 466 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 467 SkGetPackedB32(c)); 468 } while (--width != 0); 469} 470 471static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) { 472 SkASSERT(width > 0); 473 const uint8_t* s = (const uint8_t*)src; 474 do { 475 uint8_t c = *s++; 476 *dst++ = SkColorSetARGB(c, c, c, c); 477 } while (--width != 0); 478} 479 480// can return NULL 481static ToColorProc ChooseToColorProc(const SkBitmap& src) { 482 switch (src.colorType()) { 483 case kN32_SkColorType: 484 switch (src.alphaType()) { 485 case kOpaque_SkAlphaType: 486 return ToColor_S32_Opaque; 487 case kPremul_SkAlphaType: 488 return ToColor_S32_Alpha; 489 case kUnpremul_SkAlphaType: 490 return ToColor_S32_Raw; 491 default: 492 return NULL; 493 } 494 case kARGB_4444_SkColorType: 495 switch (src.alphaType()) { 496 case kOpaque_SkAlphaType: 497 return ToColor_S4444_Opaque; 498 case kPremul_SkAlphaType: 499 return ToColor_S4444_Alpha; 500 case kUnpremul_SkAlphaType: 501 return ToColor_S4444_Raw; 502 default: 503 return NULL; 504 } 505 case kRGB_565_SkColorType: 506 return ToColor_S565; 507 case kIndex_8_SkColorType: 508 if (src.getColorTable() == NULL) { 509 return NULL; 510 } 511 switch (src.alphaType()) { 512 case kOpaque_SkAlphaType: 513 return ToColor_SI8_Opaque; 514 case kPremul_SkAlphaType: 515 return ToColor_SI8_Alpha; 516 case kUnpremul_SkAlphaType: 517 return ToColor_SI8_Raw; 518 default: 519 return NULL; 520 } 521 case kAlpha_8_SkColorType: 522 return ToColor_SA8; 523 default: 524 break; 525 } 526 return NULL; 527} 528 529/////////////////////////////////////////////////////////////////////////////// 530/////////////////////////////////////////////////////////////////////////////// 531 532static int getPremulBitmapCreateFlags(bool isMutable) { 533 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied; 534 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable; 535 return flags; 536} 537 538static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, 539 jint offset, jint stride, jint width, jint height, 540 jint configHandle, jboolean isMutable) { 541 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 542 if (NULL != jColors) { 543 size_t n = env->GetArrayLength(jColors); 544 if (n < SkAbs32(stride) * (size_t)height) { 545 doThrowAIOOBE(env); 546 return NULL; 547 } 548 } 549 550 // ARGB_4444 is a deprecated format, convert automatically to 8888 551 if (colorType == kARGB_4444_SkColorType) { 552 colorType = kN32_SkColorType; 553 } 554 555 SkBitmap bitmap; 556 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, 557 GraphicsJNI::defaultColorSpace())); 558 559 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL); 560 if (!nativeBitmap) { 561 return NULL; 562 } 563 564 if (jColors != NULL) { 565 GraphicsJNI::SetPixels(env, jColors, offset, stride, 566 0, 0, width, height, bitmap); 567 } 568 569 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable)); 570} 571 572static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, 573 jint dstConfigHandle, jboolean isMutable) { 574 SkBitmap src; 575 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 576 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 577 SkBitmap result; 578 HeapAllocator allocator; 579 580 if (!src.copyTo(&result, dstCT, &allocator)) { 581 return NULL; 582 } 583 auto bitmap = allocator.getStorageObjAndReset(); 584 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable)); 585} 586 587static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) { 588 SkBitmap result; 589 590 AshmemPixelAllocator allocator(env); 591 if (!src.copyTo(&result, dstCT, &allocator)) { 592 return NULL; 593 } 594 auto bitmap = allocator.getStorageObjAndReset(); 595 bitmap->setImmutable(); 596 return bitmap; 597} 598 599static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) { 600 SkBitmap src; 601 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 602 SkColorType dstCT = src.colorType(); 603 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 604 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 605 return ret; 606} 607 608static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) { 609 SkBitmap src; 610 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 611 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 612 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 613 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 614 return ret; 615} 616 617static void Bitmap_destruct(BitmapWrapper* bitmap) { 618 delete bitmap; 619} 620 621static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) { 622 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct)); 623} 624 625static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 626 LocalScopedBitmap bitmap(bitmapHandle); 627 bitmap->freePixels(); 628 return JNI_TRUE; 629} 630 631static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 632 jint width, jint height, jint configHandle, jboolean requestPremul) { 633 LocalScopedBitmap bitmap(bitmapHandle); 634 bitmap->assertValid(); 635 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 636 637 // ARGB_4444 is a deprecated format, convert automatically to 8888 638 if (colorType == kARGB_4444_SkColorType) { 639 colorType = kN32_SkColorType; 640 } 641 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType); 642 if (requestedSize > bitmap->getAllocationByteCount()) { 643 // done in native as there's no way to get BytesPerPixel in Java 644 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 645 return; 646 } 647 SkAlphaType alphaType; 648 if (bitmap->info().colorType() != kRGB_565_SkColorType 649 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 650 // If the original bitmap was set to opaque, keep that setting, unless it 651 // was 565, which is required to be opaque. 652 alphaType = kOpaque_SkAlphaType; 653 } else { 654 // Otherwise respect the premultiplied request. 655 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 656 } 657 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType, 658 sk_sp<SkColorSpace>(bitmap->info().colorSpace()))); 659} 660 661// These must match the int values in Bitmap.java 662enum JavaEncodeFormat { 663 kJPEG_JavaEncodeFormat = 0, 664 kPNG_JavaEncodeFormat = 1, 665 kWEBP_JavaEncodeFormat = 2 666}; 667 668static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 669 jint format, jint quality, 670 jobject jstream, jbyteArray jstorage) { 671 672 LocalScopedBitmap bitmap(bitmapHandle); 673 SkImageEncoder::Type fm; 674 675 switch (format) { 676 case kJPEG_JavaEncodeFormat: 677 fm = SkImageEncoder::kJPEG_Type; 678 break; 679 case kPNG_JavaEncodeFormat: 680 fm = SkImageEncoder::kPNG_Type; 681 break; 682 case kWEBP_JavaEncodeFormat: 683 fm = SkImageEncoder::kWEBP_Type; 684 break; 685 default: 686 return JNI_FALSE; 687 } 688 689 if (!bitmap.valid()) { 690 return JNI_FALSE; 691 } 692 693 bool success = false; 694 695 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 696 if (!strm.get()) { 697 return JNI_FALSE; 698 } 699 700 std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm)); 701 if (encoder.get()) { 702 SkBitmap skbitmap; 703 bitmap->getSkBitmap(&skbitmap); 704 success = encoder->encodeStream(strm.get(), skbitmap, quality); 705 } 706 return success ? JNI_TRUE : JNI_FALSE; 707} 708 709static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 710 LocalScopedBitmap bitmap(bitmapHandle); 711 SkBitmap skBitmap; 712 bitmap->getSkBitmap(&skBitmap); 713 skBitmap.eraseColor(color); 714} 715 716static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 717 LocalScopedBitmap bitmap(bitmapHandle); 718 return static_cast<jint>(bitmap->rowBytes()); 719} 720 721static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 722 LocalScopedBitmap bitmap(bitmapHandle); 723 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 724} 725 726static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 727 LocalScopedBitmap bitmap(bitmapHandle); 728 return static_cast<jint>(bitmap->getGenerationID()); 729} 730 731static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 732 LocalScopedBitmap bitmap(bitmapHandle); 733 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 734 return JNI_TRUE; 735 } 736 return JNI_FALSE; 737} 738 739static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 740 LocalScopedBitmap bitmap(bitmapHandle); 741 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 742} 743 744static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 745 jboolean hasAlpha, jboolean requestPremul) { 746 LocalScopedBitmap bitmap(bitmapHandle); 747 if (hasAlpha) { 748 bitmap->setAlphaType( 749 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 750 } else { 751 bitmap->setAlphaType(kOpaque_SkAlphaType); 752 } 753} 754 755static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 756 jboolean isPremul) { 757 LocalScopedBitmap bitmap(bitmapHandle); 758 if (!bitmap->info().isOpaque()) { 759 if (isPremul) { 760 bitmap->setAlphaType(kPremul_SkAlphaType); 761 } else { 762 bitmap->setAlphaType(kUnpremul_SkAlphaType); 763 } 764 } 765} 766 767static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 768 LocalScopedBitmap bitmap(bitmapHandle); 769 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 770} 771 772static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 773 jboolean hasMipMap) { 774 LocalScopedBitmap bitmap(bitmapHandle); 775 bitmap->setHasHardwareMipMap(hasMipMap); 776} 777 778/////////////////////////////////////////////////////////////////////////////// 779 780static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 781 if (parcel == NULL) { 782 SkDebugf("-------- unparcel parcel is NULL\n"); 783 return NULL; 784 } 785 786 android::Parcel* p = android::parcelForJavaObject(env, parcel); 787 788 const bool isMutable = p->readInt32() != 0; 789 const SkColorType colorType = (SkColorType)p->readInt32(); 790 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 791 const bool isSRGB = p->readInt32() != 0; 792 const int width = p->readInt32(); 793 const int height = p->readInt32(); 794 const int rowBytes = p->readInt32(); 795 const int density = p->readInt32(); 796 797 if (kN32_SkColorType != colorType && 798 kRGB_565_SkColorType != colorType && 799 kARGB_4444_SkColorType != colorType && 800 kIndex_8_SkColorType != colorType && 801 kAlpha_8_SkColorType != colorType) { 802 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 803 return NULL; 804 } 805 806 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 807 808 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, 809 isSRGB ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) { 810 return NULL; 811 } 812 813 SkColorTable* ctable = NULL; 814 if (colorType == kIndex_8_SkColorType) { 815 int count = p->readInt32(); 816 if (count < 0 || count > 256) { 817 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 818 // inclusive. 819 return NULL; 820 } 821 if (count > 0) { 822 size_t size = count * sizeof(SkPMColor); 823 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 824 if (src == NULL) { 825 return NULL; 826 } 827 ctable = new SkColorTable(src, count); 828 } 829 } 830 831 // Read the bitmap blob. 832 size_t size = bitmap->getSize(); 833 android::Parcel::ReadableBlob blob; 834 android::status_t status = p->readBlob(size, &blob); 835 if (status) { 836 SkSafeUnref(ctable); 837 doThrowRE(env, "Could not read bitmap blob."); 838 return NULL; 839 } 840 841 // Map the bitmap in place from the ashmem region if possible otherwise copy. 842 sk_sp<Bitmap> nativeBitmap; 843 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 844#if DEBUG_PARCEL 845 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 846 "(fds %s)", 847 isMutable ? "mutable" : "immutable", 848 blob.isMutable() ? "mutable" : "immutable", 849 p->allowFds() ? "allowed" : "forbidden"); 850#endif 851 // Dup the file descriptor so we can keep a reference to it after the Parcel 852 // is disposed. 853 int dupFd = dup(blob.fd()); 854 if (dupFd < 0) { 855 ALOGE("Error allocating dup fd. Error:%d", errno); 856 blob.release(); 857 SkSafeUnref(ctable); 858 doThrowRE(env, "Could not allocate dup blob fd."); 859 return NULL; 860 } 861 862 // Map the pixels in place and take ownership of the ashmem region. 863 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), 864 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable)); 865 SkSafeUnref(ctable); 866 if (!nativeBitmap) { 867 close(dupFd); 868 blob.release(); 869 doThrowRE(env, "Could not allocate ashmem pixel ref."); 870 return NULL; 871 } 872 873 // Clear the blob handle, don't release it. 874 blob.clear(); 875 } else { 876#if DEBUG_PARCEL 877 if (blob.fd() >= 0) { 878 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 879 "from immutable blob (fds %s)", 880 p->allowFds() ? "allowed" : "forbidden"); 881 } else { 882 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 883 "(fds %s)", 884 blob.isMutable() ? "mutable" : "immutable", 885 p->allowFds() ? "allowed" : "forbidden"); 886 } 887#endif 888 889 // Copy the pixels into a new buffer. 890 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable); 891 SkSafeUnref(ctable); 892 if (!nativeBitmap) { 893 blob.release(); 894 doThrowRE(env, "Could not allocate java pixel ref."); 895 return NULL; 896 } 897 bitmap->lockPixels(); 898 memcpy(bitmap->getPixels(), blob.data(), size); 899 bitmap->unlockPixels(); 900 901 // Release the blob handle. 902 blob.release(); 903 } 904 905 return createBitmap(env, nativeBitmap.release(), 906 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 907} 908 909static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 910 jlong bitmapHandle, 911 jboolean isMutable, jint density, 912 jobject parcel) { 913 if (parcel == NULL) { 914 SkDebugf("------- writeToParcel null parcel\n"); 915 return JNI_FALSE; 916 } 917 918 android::Parcel* p = android::parcelForJavaObject(env, parcel); 919 SkBitmap bitmap; 920 921 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); 922 bitmapWrapper->getSkBitmap(&bitmap); 923 924 sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); 925 bool isSRGB = bitmap.colorSpace() == sRGB.get(); 926 927 p->writeInt32(isMutable); 928 p->writeInt32(bitmap.colorType()); 929 p->writeInt32(bitmap.alphaType()); 930 p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280) 931 p->writeInt32(bitmap.width()); 932 p->writeInt32(bitmap.height()); 933 p->writeInt32(bitmap.rowBytes()); 934 p->writeInt32(density); 935 936 if (bitmap.colorType() == kIndex_8_SkColorType) { 937 // The bitmap needs to be locked to access its color table. 938 SkAutoLockPixels alp(bitmap); 939 SkColorTable* ctable = bitmap.getColorTable(); 940 if (ctable != NULL) { 941 int count = ctable->count(); 942 p->writeInt32(count); 943 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 944 ctable->readColors(), count * sizeof(SkPMColor)); 945 } else { 946 p->writeInt32(0); // indicate no ctable 947 } 948 } 949 950 // Transfer the underlying ashmem region if we have one and it's immutable. 951 android::status_t status; 952 int fd = bitmapWrapper->bitmap().getAshmemFd(); 953 if (fd >= 0 && !isMutable && p->allowFds()) { 954#if DEBUG_PARCEL 955 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 956 "immutable blob (fds %s)", 957 p->allowFds() ? "allowed" : "forbidden"); 958#endif 959 960 status = p->writeDupImmutableBlobFileDescriptor(fd); 961 if (status) { 962 doThrowRE(env, "Could not write bitmap blob file descriptor."); 963 return JNI_FALSE; 964 } 965 return JNI_TRUE; 966 } 967 968 // Copy the bitmap to a new blob. 969 bool mutableCopy = isMutable; 970#if DEBUG_PARCEL 971 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 972 isMutable ? "mutable" : "immutable", 973 mutableCopy ? "mutable" : "immutable", 974 p->allowFds() ? "allowed" : "forbidden"); 975#endif 976 977 size_t size = bitmap.getSize(); 978 android::Parcel::WritableBlob blob; 979 status = p->writeBlob(size, mutableCopy, &blob); 980 if (status) { 981 doThrowRE(env, "Could not copy bitmap to parcel blob."); 982 return JNI_FALSE; 983 } 984 985 bitmap.lockPixels(); 986 const void* pSrc = bitmap.getPixels(); 987 if (pSrc == NULL) { 988 memset(blob.data(), 0, size); 989 } else { 990 memcpy(blob.data(), pSrc, size); 991 } 992 bitmap.unlockPixels(); 993 994 blob.release(); 995 return JNI_TRUE; 996} 997 998static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 999 jlong srcHandle, jlong paintHandle, 1000 jintArray offsetXY) { 1001 SkBitmap src; 1002 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 1003 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1004 SkIPoint offset; 1005 SkBitmap dst; 1006 HeapAllocator allocator; 1007 1008 src.extractAlpha(&dst, paint, &allocator, &offset); 1009 // If Skia can't allocate pixels for destination bitmap, it resets 1010 // it, that is set its pixels buffer to NULL, and zero width and height. 1011 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1012 doThrowOOME(env, "failed to allocate pixels for alpha"); 1013 return NULL; 1014 } 1015 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1016 int* array = env->GetIntArrayElements(offsetXY, NULL); 1017 array[0] = offset.fX; 1018 array[1] = offset.fY; 1019 env->ReleaseIntArrayElements(offsetXY, array, 0); 1020 } 1021 1022 return createBitmap(env, allocator.getStorageObjAndReset(), 1023 getPremulBitmapCreateFlags(true)); 1024} 1025 1026/////////////////////////////////////////////////////////////////////////////// 1027 1028static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1029 jint x, jint y) { 1030 SkBitmap bitmap; 1031 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1032 SkAutoLockPixels alp(bitmap); 1033 1034 ToColorProc proc = ChooseToColorProc(bitmap); 1035 if (NULL == proc) { 1036 return 0; 1037 } 1038 const void* src = bitmap.getAddr(x, y); 1039 if (NULL == src) { 1040 return 0; 1041 } 1042 1043 SkColor dst[1]; 1044 proc(dst, src, 1, bitmap.getColorTable()); 1045 return static_cast<jint>(dst[0]); 1046} 1047 1048static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1049 jintArray pixelArray, jint offset, jint stride, 1050 jint x, jint y, jint width, jint height) { 1051 SkBitmap bitmap; 1052 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1053 SkAutoLockPixels alp(bitmap); 1054 1055 ToColorProc proc = ChooseToColorProc(bitmap); 1056 if (NULL == proc) { 1057 return; 1058 } 1059 const void* src = bitmap.getAddr(x, y); 1060 if (NULL == src) { 1061 return; 1062 } 1063 1064 SkColorTable* ctable = bitmap.getColorTable(); 1065 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1066 SkColor* d = (SkColor*)dst + offset; 1067 while (--height >= 0) { 1068 proc(d, src, width, ctable); 1069 d += stride; 1070 src = (void*)((const char*)src + bitmap.rowBytes()); 1071 } 1072 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1073} 1074 1075/////////////////////////////////////////////////////////////////////////////// 1076 1077static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1078 jint x, jint y, jint colorHandle) { 1079 SkBitmap bitmap; 1080 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1081 SkColor color = static_cast<SkColor>(colorHandle); 1082 SkAutoLockPixels alp(bitmap); 1083 if (NULL == bitmap.getPixels()) { 1084 return; 1085 } 1086 1087 FromColorProc proc = ChooseFromColorProc(bitmap); 1088 if (NULL == proc) { 1089 return; 1090 } 1091 1092 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1093 bitmap.notifyPixelsChanged(); 1094} 1095 1096static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1097 jintArray pixelArray, jint offset, jint stride, 1098 jint x, jint y, jint width, jint height) { 1099 SkBitmap bitmap; 1100 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1101 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1102 x, y, width, height, bitmap); 1103} 1104 1105static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1106 jlong bitmapHandle, jobject jbuffer) { 1107 SkBitmap bitmap; 1108 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1109 SkAutoLockPixels alp(bitmap); 1110 const void* src = bitmap.getPixels(); 1111 1112 if (NULL != src) { 1113 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1114 1115 // the java side has already checked that buffer is large enough 1116 memcpy(abp.pointer(), src, bitmap.getSize()); 1117 } 1118} 1119 1120static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1121 jlong bitmapHandle, jobject jbuffer) { 1122 SkBitmap bitmap; 1123 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1124 SkAutoLockPixels alp(bitmap); 1125 void* dst = bitmap.getPixels(); 1126 1127 if (NULL != dst) { 1128 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1129 // the java side has already checked that buffer is large enough 1130 memcpy(dst, abp.pointer(), bitmap.getSize()); 1131 bitmap.notifyPixelsChanged(); 1132 } 1133} 1134 1135static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 1136 jlong bm1Handle) { 1137 SkBitmap bm0; 1138 SkBitmap bm1; 1139 reinterpret_cast<BitmapWrapper*>(bm0Handle)->getSkBitmap(&bm0); 1140 reinterpret_cast<BitmapWrapper*>(bm1Handle)->getSkBitmap(&bm1); 1141 if (bm0.width() != bm1.width() || 1142 bm0.height() != bm1.height() || 1143 bm0.colorType() != bm1.colorType() || 1144 bm0.alphaType() != bm1.alphaType() || 1145 bm0.colorSpace() != bm1.colorSpace()) { 1146 return JNI_FALSE; 1147 } 1148 1149 SkAutoLockPixels alp0(bm0); 1150 SkAutoLockPixels alp1(bm1); 1151 1152 // if we can't load the pixels, return false 1153 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1154 return JNI_FALSE; 1155 } 1156 1157 if (bm0.colorType() == kIndex_8_SkColorType) { 1158 SkColorTable* ct0 = bm0.getColorTable(); 1159 SkColorTable* ct1 = bm1.getColorTable(); 1160 if (NULL == ct0 || NULL == ct1) { 1161 return JNI_FALSE; 1162 } 1163 if (ct0->count() != ct1->count()) { 1164 return JNI_FALSE; 1165 } 1166 1167 const size_t size = ct0->count() * sizeof(SkPMColor); 1168 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1169 return JNI_FALSE; 1170 } 1171 } 1172 1173 // now compare each scanline. We can't do the entire buffer at once, 1174 // since we don't care about the pixel values that might extend beyond 1175 // the width (since the scanline might be larger than the logical width) 1176 const int h = bm0.height(); 1177 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1178 for (int y = 0; y < h; y++) { 1179 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1180 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1181 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1182 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1183 // to warn user those 2 unrecognized config bitmaps may be different. 1184 void *bm0Addr = bm0.getAddr(0, y); 1185 void *bm1Addr = bm1.getAddr(0, y); 1186 1187 if(bm0Addr == NULL || bm1Addr == NULL) { 1188 return JNI_FALSE; 1189 } 1190 1191 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1192 return JNI_FALSE; 1193 } 1194 } 1195 return JNI_TRUE; 1196} 1197 1198static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1199 LocalScopedBitmap bitmapHandle(bitmapPtr); 1200 if (!bitmapHandle.valid()) return; 1201 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap()); 1202} 1203 1204static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { 1205 LocalScopedBitmap bitmapHandle(bitmapPtr); 1206 return static_cast<jint>(bitmapHandle->getAllocationByteCount()); 1207} 1208 1209/////////////////////////////////////////////////////////////////////////////// 1210static jclass make_globalref(JNIEnv* env, const char classname[]) 1211{ 1212 jclass c = env->FindClass(classname); 1213 SkASSERT(c); 1214 return (jclass) env->NewGlobalRef(c); 1215} 1216 1217static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 1218 const char fieldname[], const char type[]) 1219{ 1220 jfieldID id = env->GetFieldID(clazz, fieldname, type); 1221 SkASSERT(id); 1222 return id; 1223} 1224 1225static const JNINativeMethod gBitmapMethods[] = { 1226 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 1227 (void*)Bitmap_creator }, 1228 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1229 (void*)Bitmap_copy }, 1230 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1231 (void*)Bitmap_copyAshmem }, 1232 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", 1233 (void*)Bitmap_copyAshmemConfig }, 1234 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer }, 1235 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1236 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure }, 1237 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1238 (void*)Bitmap_compress }, 1239 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1240 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1241 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1242 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1243 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1244 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1245 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1246 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1247 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1248 { "nativeCreateFromParcel", 1249 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1250 (void*)Bitmap_createFromParcel }, 1251 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1252 (void*)Bitmap_writeToParcel }, 1253 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1254 (void*)Bitmap_extractAlpha }, 1255 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1256 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1257 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1258 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1259 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1260 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1261 (void*)Bitmap_copyPixelsToBuffer }, 1262 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1263 (void*)Bitmap_copyPixelsFromBuffer }, 1264 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1265 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1266 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1267}; 1268 1269int register_android_graphics_Bitmap(JNIEnv* env) 1270{ 1271 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 1272 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J"); 1273 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1274 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); 1275 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); 1276 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1277 NELEM(gBitmapMethods)); 1278} 1279