Bitmap.cpp revision 1eabed3d14fdc47ac6939cfa98521adcb45bc224
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_ref_sp(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 SkEncodedImageFormat fm; 672 switch (format) { 673 case kJPEG_JavaEncodeFormat: 674 fm = SkEncodedImageFormat::kJPEG; 675 break; 676 case kPNG_JavaEncodeFormat: 677 fm = SkEncodedImageFormat::kPNG; 678 break; 679 case kWEBP_JavaEncodeFormat: 680 fm = SkEncodedImageFormat::kWEBP; 681 break; 682 default: 683 return JNI_FALSE; 684 } 685 686 LocalScopedBitmap bitmap(bitmapHandle); 687 if (!bitmap.valid()) { 688 return JNI_FALSE; 689 } 690 691 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 692 if (!strm.get()) { 693 return JNI_FALSE; 694 } 695 696 SkBitmap skbitmap; 697 bitmap->getSkBitmap(&skbitmap); 698 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; 699} 700 701static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 702 LocalScopedBitmap bitmap(bitmapHandle); 703 SkBitmap skBitmap; 704 bitmap->getSkBitmap(&skBitmap); 705 skBitmap.eraseColor(color); 706} 707 708static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 709 LocalScopedBitmap bitmap(bitmapHandle); 710 return static_cast<jint>(bitmap->rowBytes()); 711} 712 713static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 714 LocalScopedBitmap bitmap(bitmapHandle); 715 if (bitmap->bitmap().isHardware()) { 716 return GraphicsJNI::hardwareLegacyBitmapConfig(); 717 } 718 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 719} 720 721static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 722 LocalScopedBitmap bitmap(bitmapHandle); 723 return static_cast<jint>(bitmap->getGenerationID()); 724} 725 726static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 727 LocalScopedBitmap bitmap(bitmapHandle); 728 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 729 return JNI_TRUE; 730 } 731 return JNI_FALSE; 732} 733 734static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 735 LocalScopedBitmap bitmap(bitmapHandle); 736 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 737} 738 739static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 740 jboolean hasAlpha, jboolean requestPremul) { 741 LocalScopedBitmap bitmap(bitmapHandle); 742 if (hasAlpha) { 743 bitmap->setAlphaType( 744 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 745 } else { 746 bitmap->setAlphaType(kOpaque_SkAlphaType); 747 } 748} 749 750static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 751 jboolean isPremul) { 752 LocalScopedBitmap bitmap(bitmapHandle); 753 if (!bitmap->info().isOpaque()) { 754 if (isPremul) { 755 bitmap->setAlphaType(kPremul_SkAlphaType); 756 } else { 757 bitmap->setAlphaType(kUnpremul_SkAlphaType); 758 } 759 } 760} 761 762static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 763 LocalScopedBitmap bitmap(bitmapHandle); 764 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 765} 766 767static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 768 jboolean hasMipMap) { 769 LocalScopedBitmap bitmap(bitmapHandle); 770 bitmap->setHasHardwareMipMap(hasMipMap); 771} 772 773/////////////////////////////////////////////////////////////////////////////// 774 775static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 776 if (parcel == NULL) { 777 SkDebugf("-------- unparcel parcel is NULL\n"); 778 return NULL; 779 } 780 781 android::Parcel* p = android::parcelForJavaObject(env, parcel); 782 783 const bool isMutable = p->readInt32() != 0; 784 const SkColorType colorType = (SkColorType)p->readInt32(); 785 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 786 const bool isSRGB = p->readInt32() != 0; 787 const int width = p->readInt32(); 788 const int height = p->readInt32(); 789 const int rowBytes = p->readInt32(); 790 const int density = p->readInt32(); 791 792 if (kN32_SkColorType != colorType && 793 kRGB_565_SkColorType != colorType && 794 kARGB_4444_SkColorType != colorType && 795 kIndex_8_SkColorType != colorType && 796 kAlpha_8_SkColorType != colorType) { 797 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 798 return NULL; 799 } 800 801 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 802 803 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, 804 isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) { 805 return NULL; 806 } 807 808 SkColorTable* ctable = NULL; 809 if (colorType == kIndex_8_SkColorType) { 810 int count = p->readInt32(); 811 if (count < 0 || count > 256) { 812 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 813 // inclusive. 814 return NULL; 815 } 816 if (count > 0) { 817 size_t size = count * sizeof(SkPMColor); 818 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 819 if (src == NULL) { 820 return NULL; 821 } 822 ctable = new SkColorTable(src, count); 823 } 824 } 825 826 // Read the bitmap blob. 827 size_t size = bitmap->getSize(); 828 android::Parcel::ReadableBlob blob; 829 android::status_t status = p->readBlob(size, &blob); 830 if (status) { 831 SkSafeUnref(ctable); 832 doThrowRE(env, "Could not read bitmap blob."); 833 return NULL; 834 } 835 836 // Map the bitmap in place from the ashmem region if possible otherwise copy. 837 sk_sp<Bitmap> nativeBitmap; 838 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 839#if DEBUG_PARCEL 840 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 841 "(fds %s)", 842 isMutable ? "mutable" : "immutable", 843 blob.isMutable() ? "mutable" : "immutable", 844 p->allowFds() ? "allowed" : "forbidden"); 845#endif 846 // Dup the file descriptor so we can keep a reference to it after the Parcel 847 // is disposed. 848 int dupFd = dup(blob.fd()); 849 if (dupFd < 0) { 850 ALOGE("Error allocating dup fd. Error:%d", errno); 851 blob.release(); 852 SkSafeUnref(ctable); 853 doThrowRE(env, "Could not allocate dup blob fd."); 854 return NULL; 855 } 856 857 // Map the pixels in place and take ownership of the ashmem region. 858 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), 859 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable)); 860 SkSafeUnref(ctable); 861 if (!nativeBitmap) { 862 close(dupFd); 863 blob.release(); 864 doThrowRE(env, "Could not allocate ashmem pixel ref."); 865 return NULL; 866 } 867 868 // Clear the blob handle, don't release it. 869 blob.clear(); 870 } else { 871#if DEBUG_PARCEL 872 if (blob.fd() >= 0) { 873 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 874 "from immutable blob (fds %s)", 875 p->allowFds() ? "allowed" : "forbidden"); 876 } else { 877 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 878 "(fds %s)", 879 blob.isMutable() ? "mutable" : "immutable", 880 p->allowFds() ? "allowed" : "forbidden"); 881 } 882#endif 883 884 // Copy the pixels into a new buffer. 885 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable); 886 SkSafeUnref(ctable); 887 if (!nativeBitmap) { 888 blob.release(); 889 doThrowRE(env, "Could not allocate java pixel ref."); 890 return NULL; 891 } 892 bitmap->lockPixels(); 893 memcpy(bitmap->getPixels(), blob.data(), size); 894 bitmap->unlockPixels(); 895 896 // Release the blob handle. 897 blob.release(); 898 } 899 900 return createBitmap(env, nativeBitmap.release(), 901 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 902} 903 904static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 905 jlong bitmapHandle, 906 jboolean isMutable, jint density, 907 jobject parcel) { 908 if (parcel == NULL) { 909 SkDebugf("------- writeToParcel null parcel\n"); 910 return JNI_FALSE; 911 } 912 913 android::Parcel* p = android::parcelForJavaObject(env, parcel); 914 SkBitmap bitmap; 915 916 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); 917 bitmapWrapper->getSkBitmap(&bitmap); 918 919 sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); 920 bool isSRGB = bitmap.colorSpace() == sRGB.get(); 921 922 p->writeInt32(isMutable); 923 p->writeInt32(bitmap.colorType()); 924 p->writeInt32(bitmap.alphaType()); 925 p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280) 926 p->writeInt32(bitmap.width()); 927 p->writeInt32(bitmap.height()); 928 p->writeInt32(bitmap.rowBytes()); 929 p->writeInt32(density); 930 931 if (bitmap.colorType() == kIndex_8_SkColorType) { 932 // The bitmap needs to be locked to access its color table. 933 SkAutoLockPixels alp(bitmap); 934 SkColorTable* ctable = bitmap.getColorTable(); 935 if (ctable != NULL) { 936 int count = ctable->count(); 937 p->writeInt32(count); 938 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 939 ctable->readColors(), count * sizeof(SkPMColor)); 940 } else { 941 p->writeInt32(0); // indicate no ctable 942 } 943 } 944 945 // Transfer the underlying ashmem region if we have one and it's immutable. 946 android::status_t status; 947 int fd = bitmapWrapper->bitmap().getAshmemFd(); 948 if (fd >= 0 && !isMutable && p->allowFds()) { 949#if DEBUG_PARCEL 950 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 951 "immutable blob (fds %s)", 952 p->allowFds() ? "allowed" : "forbidden"); 953#endif 954 955 status = p->writeDupImmutableBlobFileDescriptor(fd); 956 if (status) { 957 doThrowRE(env, "Could not write bitmap blob file descriptor."); 958 return JNI_FALSE; 959 } 960 return JNI_TRUE; 961 } 962 963 // Copy the bitmap to a new blob. 964 bool mutableCopy = isMutable; 965#if DEBUG_PARCEL 966 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 967 isMutable ? "mutable" : "immutable", 968 mutableCopy ? "mutable" : "immutable", 969 p->allowFds() ? "allowed" : "forbidden"); 970#endif 971 972 size_t size = bitmap.getSize(); 973 android::Parcel::WritableBlob blob; 974 status = p->writeBlob(size, mutableCopy, &blob); 975 if (status) { 976 doThrowRE(env, "Could not copy bitmap to parcel blob."); 977 return JNI_FALSE; 978 } 979 980 bitmap.lockPixels(); 981 const void* pSrc = bitmap.getPixels(); 982 if (pSrc == NULL) { 983 memset(blob.data(), 0, size); 984 } else { 985 memcpy(blob.data(), pSrc, size); 986 } 987 bitmap.unlockPixels(); 988 989 blob.release(); 990 return JNI_TRUE; 991} 992 993static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 994 jlong srcHandle, jlong paintHandle, 995 jintArray offsetXY) { 996 SkBitmap src; 997 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 998 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 999 SkIPoint offset; 1000 SkBitmap dst; 1001 HeapAllocator allocator; 1002 1003 src.extractAlpha(&dst, paint, &allocator, &offset); 1004 // If Skia can't allocate pixels for destination bitmap, it resets 1005 // it, that is set its pixels buffer to NULL, and zero width and height. 1006 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1007 doThrowOOME(env, "failed to allocate pixels for alpha"); 1008 return NULL; 1009 } 1010 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1011 int* array = env->GetIntArrayElements(offsetXY, NULL); 1012 array[0] = offset.fX; 1013 array[1] = offset.fY; 1014 env->ReleaseIntArrayElements(offsetXY, array, 0); 1015 } 1016 1017 return createBitmap(env, allocator.getStorageObjAndReset(), 1018 getPremulBitmapCreateFlags(true)); 1019} 1020 1021/////////////////////////////////////////////////////////////////////////////// 1022 1023static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1024 jint x, jint y) { 1025 SkBitmap bitmap; 1026 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1027 SkAutoLockPixels alp(bitmap); 1028 1029 ToColorProc proc = ChooseToColorProc(bitmap); 1030 if (NULL == proc) { 1031 return 0; 1032 } 1033 const void* src = bitmap.getAddr(x, y); 1034 if (NULL == src) { 1035 return 0; 1036 } 1037 1038 SkColor dst[1]; 1039 proc(dst, src, 1, bitmap.getColorTable()); 1040 return static_cast<jint>(dst[0]); 1041} 1042 1043static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1044 jintArray pixelArray, jint offset, jint stride, 1045 jint x, jint y, jint width, jint height) { 1046 SkBitmap bitmap; 1047 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1048 SkAutoLockPixels alp(bitmap); 1049 1050 ToColorProc proc = ChooseToColorProc(bitmap); 1051 if (NULL == proc) { 1052 return; 1053 } 1054 const void* src = bitmap.getAddr(x, y); 1055 if (NULL == src) { 1056 return; 1057 } 1058 1059 SkColorTable* ctable = bitmap.getColorTable(); 1060 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1061 SkColor* d = (SkColor*)dst + offset; 1062 while (--height >= 0) { 1063 proc(d, src, width, ctable); 1064 d += stride; 1065 src = (void*)((const char*)src + bitmap.rowBytes()); 1066 } 1067 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1068} 1069 1070/////////////////////////////////////////////////////////////////////////////// 1071 1072static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1073 jint x, jint y, jint colorHandle) { 1074 SkBitmap bitmap; 1075 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1076 SkColor color = static_cast<SkColor>(colorHandle); 1077 SkAutoLockPixels alp(bitmap); 1078 if (NULL == bitmap.getPixels()) { 1079 return; 1080 } 1081 1082 FromColorProc proc = ChooseFromColorProc(bitmap); 1083 if (NULL == proc) { 1084 return; 1085 } 1086 1087 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1088 bitmap.notifyPixelsChanged(); 1089} 1090 1091static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1092 jintArray pixelArray, jint offset, jint stride, 1093 jint x, jint y, jint width, jint height) { 1094 SkBitmap bitmap; 1095 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1096 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1097 x, y, width, height, bitmap); 1098} 1099 1100static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1101 jlong bitmapHandle, jobject jbuffer) { 1102 SkBitmap bitmap; 1103 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1104 SkAutoLockPixels alp(bitmap); 1105 const void* src = bitmap.getPixels(); 1106 1107 if (NULL != src) { 1108 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1109 1110 // the java side has already checked that buffer is large enough 1111 memcpy(abp.pointer(), src, bitmap.getSize()); 1112 } 1113} 1114 1115static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1116 jlong bitmapHandle, jobject jbuffer) { 1117 SkBitmap bitmap; 1118 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1119 SkAutoLockPixels alp(bitmap); 1120 void* dst = bitmap.getPixels(); 1121 1122 if (NULL != dst) { 1123 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1124 // the java side has already checked that buffer is large enough 1125 memcpy(dst, abp.pointer(), bitmap.getSize()); 1126 bitmap.notifyPixelsChanged(); 1127 } 1128} 1129 1130static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 1131 jlong bm1Handle) { 1132 SkBitmap bm0; 1133 SkBitmap bm1; 1134 1135 LocalScopedBitmap bitmap0(bm0Handle); 1136 LocalScopedBitmap bitmap1(bm1Handle); 1137 1138 // Paying the price for making Hardware Bitmap as Config: 1139 // later check for colorType will pass successfully, 1140 // because Hardware Config internally may be RGBA8888 or smth like that. 1141 if (bitmap0->bitmap().isHardware() != bitmap1->bitmap().isHardware()) { 1142 return JNI_FALSE; 1143 } 1144 1145 bitmap0->bitmap().getSkBitmap(&bm0); 1146 bitmap1->bitmap().getSkBitmap(&bm1); 1147 if (bm0.width() != bm1.width() || 1148 bm0.height() != bm1.height() || 1149 bm0.colorType() != bm1.colorType() || 1150 bm0.alphaType() != bm1.alphaType() || 1151 bm0.colorSpace() != bm1.colorSpace()) { 1152 return JNI_FALSE; 1153 } 1154 1155 SkAutoLockPixels alp0(bm0); 1156 SkAutoLockPixels alp1(bm1); 1157 1158 // if we can't load the pixels, return false 1159 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1160 return JNI_FALSE; 1161 } 1162 1163 if (bm0.colorType() == kIndex_8_SkColorType) { 1164 SkColorTable* ct0 = bm0.getColorTable(); 1165 SkColorTable* ct1 = bm1.getColorTable(); 1166 if (NULL == ct0 || NULL == ct1) { 1167 return JNI_FALSE; 1168 } 1169 if (ct0->count() != ct1->count()) { 1170 return JNI_FALSE; 1171 } 1172 1173 const size_t size = ct0->count() * sizeof(SkPMColor); 1174 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1175 return JNI_FALSE; 1176 } 1177 } 1178 1179 // now compare each scanline. We can't do the entire buffer at once, 1180 // since we don't care about the pixel values that might extend beyond 1181 // the width (since the scanline might be larger than the logical width) 1182 const int h = bm0.height(); 1183 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1184 for (int y = 0; y < h; y++) { 1185 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1186 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1187 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1188 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1189 // to warn user those 2 unrecognized config bitmaps may be different. 1190 void *bm0Addr = bm0.getAddr(0, y); 1191 void *bm1Addr = bm1.getAddr(0, y); 1192 1193 if(bm0Addr == NULL || bm1Addr == NULL) { 1194 return JNI_FALSE; 1195 } 1196 1197 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1198 return JNI_FALSE; 1199 } 1200 } 1201 return JNI_TRUE; 1202} 1203 1204static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1205 LocalScopedBitmap bitmapHandle(bitmapPtr); 1206 if (!bitmapHandle.valid()) return; 1207 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap()); 1208} 1209 1210static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { 1211 LocalScopedBitmap bitmapHandle(bitmapPtr); 1212 return static_cast<jint>(bitmapHandle->getAllocationByteCount()); 1213} 1214 1215/////////////////////////////////////////////////////////////////////////////// 1216static jclass make_globalref(JNIEnv* env, const char classname[]) 1217{ 1218 jclass c = env->FindClass(classname); 1219 SkASSERT(c); 1220 return (jclass) env->NewGlobalRef(c); 1221} 1222 1223static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 1224 const char fieldname[], const char type[]) 1225{ 1226 jfieldID id = env->GetFieldID(clazz, fieldname, type); 1227 SkASSERT(id); 1228 return id; 1229} 1230 1231static const JNINativeMethod gBitmapMethods[] = { 1232 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 1233 (void*)Bitmap_creator }, 1234 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1235 (void*)Bitmap_copy }, 1236 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1237 (void*)Bitmap_copyAshmem }, 1238 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", 1239 (void*)Bitmap_copyAshmemConfig }, 1240 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer }, 1241 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1242 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure }, 1243 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1244 (void*)Bitmap_compress }, 1245 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1246 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1247 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1248 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1249 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1250 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1251 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1252 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1253 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1254 { "nativeCreateFromParcel", 1255 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1256 (void*)Bitmap_createFromParcel }, 1257 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1258 (void*)Bitmap_writeToParcel }, 1259 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1260 (void*)Bitmap_extractAlpha }, 1261 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1262 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1263 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1264 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1265 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1266 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1267 (void*)Bitmap_copyPixelsToBuffer }, 1268 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1269 (void*)Bitmap_copyPixelsFromBuffer }, 1270 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1271 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1272 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1273}; 1274 1275int register_android_graphics_Bitmap(JNIEnv* env) 1276{ 1277 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 1278 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J"); 1279 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1280 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); 1281 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); 1282 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1283 NELEM(gBitmapMethods)); 1284} 1285