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