Bitmap.cpp revision 05126d151eb3caa85bd3a039cffb6e37940c3fa4
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 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) { 577 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src)); 578 if (!bitmap.get()) { 579 return NULL; 580 } 581 return createBitmap(env, bitmap.release(), kBitmapCreateFlag_None); 582 } 583 584 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 585 SkBitmap result; 586 HeapAllocator allocator; 587 588 if (!src.copyTo(&result, dstCT, &allocator)) { 589 return NULL; 590 } 591 auto bitmap = allocator.getStorageObjAndReset(); 592 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable)); 593} 594 595static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) { 596 SkBitmap result; 597 598 AshmemPixelAllocator allocator(env); 599 if (!src.copyTo(&result, dstCT, &allocator)) { 600 return NULL; 601 } 602 auto bitmap = allocator.getStorageObjAndReset(); 603 bitmap->setImmutable(); 604 return bitmap; 605} 606 607static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) { 608 SkBitmap src; 609 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 610 SkColorType dstCT = src.colorType(); 611 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 612 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 613 return ret; 614} 615 616static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) { 617 SkBitmap src; 618 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 619 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 620 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 621 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 622 return ret; 623} 624 625static void Bitmap_destruct(BitmapWrapper* bitmap) { 626 delete bitmap; 627} 628 629static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) { 630 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct)); 631} 632 633static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 634 LocalScopedBitmap bitmap(bitmapHandle); 635 bitmap->freePixels(); 636 return JNI_TRUE; 637} 638 639static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 640 jint width, jint height, jint configHandle, jboolean requestPremul) { 641 LocalScopedBitmap bitmap(bitmapHandle); 642 bitmap->assertValid(); 643 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 644 645 // ARGB_4444 is a deprecated format, convert automatically to 8888 646 if (colorType == kARGB_4444_SkColorType) { 647 colorType = kN32_SkColorType; 648 } 649 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType); 650 if (requestedSize > bitmap->getAllocationByteCount()) { 651 // done in native as there's no way to get BytesPerPixel in Java 652 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 653 return; 654 } 655 SkAlphaType alphaType; 656 if (bitmap->info().colorType() != kRGB_565_SkColorType 657 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 658 // If the original bitmap was set to opaque, keep that setting, unless it 659 // was 565, which is required to be opaque. 660 alphaType = kOpaque_SkAlphaType; 661 } else { 662 // Otherwise respect the premultiplied request. 663 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 664 } 665 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType, 666 sk_ref_sp(bitmap->info().colorSpace()))); 667} 668 669// These must match the int values in Bitmap.java 670enum JavaEncodeFormat { 671 kJPEG_JavaEncodeFormat = 0, 672 kPNG_JavaEncodeFormat = 1, 673 kWEBP_JavaEncodeFormat = 2 674}; 675 676static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 677 jint format, jint quality, 678 jobject jstream, jbyteArray jstorage) { 679 SkEncodedImageFormat fm; 680 switch (format) { 681 case kJPEG_JavaEncodeFormat: 682 fm = SkEncodedImageFormat::kJPEG; 683 break; 684 case kPNG_JavaEncodeFormat: 685 fm = SkEncodedImageFormat::kPNG; 686 break; 687 case kWEBP_JavaEncodeFormat: 688 fm = SkEncodedImageFormat::kWEBP; 689 break; 690 default: 691 return JNI_FALSE; 692 } 693 694 LocalScopedBitmap bitmap(bitmapHandle); 695 if (!bitmap.valid()) { 696 return JNI_FALSE; 697 } 698 699 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 700 if (!strm.get()) { 701 return JNI_FALSE; 702 } 703 704 SkBitmap skbitmap; 705 bitmap->getSkBitmap(&skbitmap); 706 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? 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 if (bitmap->bitmap().isHardware()) { 724 return GraphicsJNI::hardwareLegacyBitmapConfig(); 725 } 726 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 727} 728 729static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 730 LocalScopedBitmap bitmap(bitmapHandle); 731 return static_cast<jint>(bitmap->getGenerationID()); 732} 733 734static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 735 LocalScopedBitmap bitmap(bitmapHandle); 736 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 737 return JNI_TRUE; 738 } 739 return JNI_FALSE; 740} 741 742static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 743 LocalScopedBitmap bitmap(bitmapHandle); 744 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 745} 746 747static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 748 jboolean hasAlpha, jboolean requestPremul) { 749 LocalScopedBitmap bitmap(bitmapHandle); 750 if (hasAlpha) { 751 bitmap->setAlphaType( 752 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 753 } else { 754 bitmap->setAlphaType(kOpaque_SkAlphaType); 755 } 756} 757 758static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 759 jboolean isPremul) { 760 LocalScopedBitmap bitmap(bitmapHandle); 761 if (!bitmap->info().isOpaque()) { 762 if (isPremul) { 763 bitmap->setAlphaType(kPremul_SkAlphaType); 764 } else { 765 bitmap->setAlphaType(kUnpremul_SkAlphaType); 766 } 767 } 768} 769 770static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 771 LocalScopedBitmap bitmap(bitmapHandle); 772 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 773} 774 775static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 776 jboolean hasMipMap) { 777 LocalScopedBitmap bitmap(bitmapHandle); 778 bitmap->setHasHardwareMipMap(hasMipMap); 779} 780 781/////////////////////////////////////////////////////////////////////////////// 782 783static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 784 if (parcel == NULL) { 785 SkDebugf("-------- unparcel parcel is NULL\n"); 786 return NULL; 787 } 788 789 android::Parcel* p = android::parcelForJavaObject(env, parcel); 790 791 const bool isMutable = p->readInt32() != 0; 792 const SkColorType colorType = (SkColorType)p->readInt32(); 793 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 794 const bool isSRGB = p->readInt32() != 0; 795 const int width = p->readInt32(); 796 const int height = p->readInt32(); 797 const int rowBytes = p->readInt32(); 798 const int density = p->readInt32(); 799 800 if (kN32_SkColorType != colorType && 801 kRGB_565_SkColorType != colorType && 802 kARGB_4444_SkColorType != colorType && 803 kIndex_8_SkColorType != colorType && 804 kAlpha_8_SkColorType != colorType) { 805 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 806 return NULL; 807 } 808 809 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 810 811 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, 812 isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) { 813 return NULL; 814 } 815 816 SkColorTable* ctable = NULL; 817 if (colorType == kIndex_8_SkColorType) { 818 int count = p->readInt32(); 819 if (count < 0 || count > 256) { 820 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 821 // inclusive. 822 return NULL; 823 } 824 if (count > 0) { 825 size_t size = count * sizeof(SkPMColor); 826 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 827 if (src == NULL) { 828 return NULL; 829 } 830 ctable = new SkColorTable(src, count); 831 } 832 } 833 834 // Read the bitmap blob. 835 size_t size = bitmap->getSize(); 836 android::Parcel::ReadableBlob blob; 837 android::status_t status = p->readBlob(size, &blob); 838 if (status) { 839 SkSafeUnref(ctable); 840 doThrowRE(env, "Could not read bitmap blob."); 841 return NULL; 842 } 843 844 // Map the bitmap in place from the ashmem region if possible otherwise copy. 845 sk_sp<Bitmap> nativeBitmap; 846 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 847#if DEBUG_PARCEL 848 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 849 "(fds %s)", 850 isMutable ? "mutable" : "immutable", 851 blob.isMutable() ? "mutable" : "immutable", 852 p->allowFds() ? "allowed" : "forbidden"); 853#endif 854 // Dup the file descriptor so we can keep a reference to it after the Parcel 855 // is disposed. 856 int dupFd = dup(blob.fd()); 857 if (dupFd < 0) { 858 ALOGE("Error allocating dup fd. Error:%d", errno); 859 blob.release(); 860 SkSafeUnref(ctable); 861 doThrowRE(env, "Could not allocate dup blob fd."); 862 return NULL; 863 } 864 865 // Map the pixels in place and take ownership of the ashmem region. 866 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), 867 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable)); 868 SkSafeUnref(ctable); 869 if (!nativeBitmap) { 870 close(dupFd); 871 blob.release(); 872 doThrowRE(env, "Could not allocate ashmem pixel ref."); 873 return NULL; 874 } 875 876 // Clear the blob handle, don't release it. 877 blob.clear(); 878 } else { 879#if DEBUG_PARCEL 880 if (blob.fd() >= 0) { 881 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 882 "from immutable blob (fds %s)", 883 p->allowFds() ? "allowed" : "forbidden"); 884 } else { 885 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 886 "(fds %s)", 887 blob.isMutable() ? "mutable" : "immutable", 888 p->allowFds() ? "allowed" : "forbidden"); 889 } 890#endif 891 892 // Copy the pixels into a new buffer. 893 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable); 894 SkSafeUnref(ctable); 895 if (!nativeBitmap) { 896 blob.release(); 897 doThrowRE(env, "Could not allocate java pixel ref."); 898 return NULL; 899 } 900 bitmap->lockPixels(); 901 memcpy(bitmap->getPixels(), blob.data(), size); 902 bitmap->unlockPixels(); 903 904 // Release the blob handle. 905 blob.release(); 906 } 907 908 return createBitmap(env, nativeBitmap.release(), 909 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 910} 911 912static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 913 jlong bitmapHandle, 914 jboolean isMutable, jint density, 915 jobject parcel) { 916 if (parcel == NULL) { 917 SkDebugf("------- writeToParcel null parcel\n"); 918 return JNI_FALSE; 919 } 920 921 android::Parcel* p = android::parcelForJavaObject(env, parcel); 922 SkBitmap bitmap; 923 924 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); 925 bitmapWrapper->getSkBitmap(&bitmap); 926 927 sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); 928 bool isSRGB = bitmap.colorSpace() == sRGB.get(); 929 930 p->writeInt32(isMutable); 931 p->writeInt32(bitmap.colorType()); 932 p->writeInt32(bitmap.alphaType()); 933 p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280) 934 p->writeInt32(bitmap.width()); 935 p->writeInt32(bitmap.height()); 936 p->writeInt32(bitmap.rowBytes()); 937 p->writeInt32(density); 938 939 if (bitmap.colorType() == kIndex_8_SkColorType) { 940 // The bitmap needs to be locked to access its color table. 941 SkAutoLockPixels alp(bitmap); 942 SkColorTable* ctable = bitmap.getColorTable(); 943 if (ctable != NULL) { 944 int count = ctable->count(); 945 p->writeInt32(count); 946 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 947 ctable->readColors(), count * sizeof(SkPMColor)); 948 } else { 949 p->writeInt32(0); // indicate no ctable 950 } 951 } 952 953 // Transfer the underlying ashmem region if we have one and it's immutable. 954 android::status_t status; 955 int fd = bitmapWrapper->bitmap().getAshmemFd(); 956 if (fd >= 0 && !isMutable && p->allowFds()) { 957#if DEBUG_PARCEL 958 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 959 "immutable blob (fds %s)", 960 p->allowFds() ? "allowed" : "forbidden"); 961#endif 962 963 status = p->writeDupImmutableBlobFileDescriptor(fd); 964 if (status) { 965 doThrowRE(env, "Could not write bitmap blob file descriptor."); 966 return JNI_FALSE; 967 } 968 return JNI_TRUE; 969 } 970 971 // Copy the bitmap to a new blob. 972 bool mutableCopy = isMutable; 973#if DEBUG_PARCEL 974 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 975 isMutable ? "mutable" : "immutable", 976 mutableCopy ? "mutable" : "immutable", 977 p->allowFds() ? "allowed" : "forbidden"); 978#endif 979 980 size_t size = bitmap.getSize(); 981 android::Parcel::WritableBlob blob; 982 status = p->writeBlob(size, mutableCopy, &blob); 983 if (status) { 984 doThrowRE(env, "Could not copy bitmap to parcel blob."); 985 return JNI_FALSE; 986 } 987 988 bitmap.lockPixels(); 989 const void* pSrc = bitmap.getPixels(); 990 if (pSrc == NULL) { 991 memset(blob.data(), 0, size); 992 } else { 993 memcpy(blob.data(), pSrc, size); 994 } 995 bitmap.unlockPixels(); 996 997 blob.release(); 998 return JNI_TRUE; 999} 1000 1001static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1002 jlong srcHandle, jlong paintHandle, 1003 jintArray offsetXY) { 1004 SkBitmap src; 1005 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 1006 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1007 SkIPoint offset; 1008 SkBitmap dst; 1009 HeapAllocator allocator; 1010 1011 src.extractAlpha(&dst, paint, &allocator, &offset); 1012 // If Skia can't allocate pixels for destination bitmap, it resets 1013 // it, that is set its pixels buffer to NULL, and zero width and height. 1014 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1015 doThrowOOME(env, "failed to allocate pixels for alpha"); 1016 return NULL; 1017 } 1018 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1019 int* array = env->GetIntArrayElements(offsetXY, NULL); 1020 array[0] = offset.fX; 1021 array[1] = offset.fY; 1022 env->ReleaseIntArrayElements(offsetXY, array, 0); 1023 } 1024 1025 return createBitmap(env, allocator.getStorageObjAndReset(), 1026 getPremulBitmapCreateFlags(true)); 1027} 1028 1029/////////////////////////////////////////////////////////////////////////////// 1030 1031static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1032 jint x, jint y) { 1033 SkBitmap bitmap; 1034 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1035 SkAutoLockPixels alp(bitmap); 1036 1037 ToColorProc proc = ChooseToColorProc(bitmap); 1038 if (NULL == proc) { 1039 return 0; 1040 } 1041 const void* src = bitmap.getAddr(x, y); 1042 if (NULL == src) { 1043 return 0; 1044 } 1045 1046 SkColor dst[1]; 1047 proc(dst, src, 1, bitmap.getColorTable()); 1048 return static_cast<jint>(dst[0]); 1049} 1050 1051static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1052 jintArray pixelArray, jint offset, jint stride, 1053 jint x, jint y, jint width, jint height) { 1054 SkBitmap bitmap; 1055 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1056 SkAutoLockPixels alp(bitmap); 1057 1058 ToColorProc proc = ChooseToColorProc(bitmap); 1059 if (NULL == proc) { 1060 return; 1061 } 1062 const void* src = bitmap.getAddr(x, y); 1063 if (NULL == src) { 1064 return; 1065 } 1066 1067 SkColorTable* ctable = bitmap.getColorTable(); 1068 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1069 SkColor* d = (SkColor*)dst + offset; 1070 while (--height >= 0) { 1071 proc(d, src, width, ctable); 1072 d += stride; 1073 src = (void*)((const char*)src + bitmap.rowBytes()); 1074 } 1075 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1076} 1077 1078/////////////////////////////////////////////////////////////////////////////// 1079 1080static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1081 jint x, jint y, jint colorHandle) { 1082 SkBitmap bitmap; 1083 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1084 SkColor color = static_cast<SkColor>(colorHandle); 1085 SkAutoLockPixels alp(bitmap); 1086 if (NULL == bitmap.getPixels()) { 1087 return; 1088 } 1089 1090 FromColorProc proc = ChooseFromColorProc(bitmap); 1091 if (NULL == proc) { 1092 return; 1093 } 1094 1095 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1096 bitmap.notifyPixelsChanged(); 1097} 1098 1099static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1100 jintArray pixelArray, jint offset, jint stride, 1101 jint x, jint y, jint width, jint height) { 1102 SkBitmap bitmap; 1103 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1104 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1105 x, y, width, height, bitmap); 1106} 1107 1108static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1109 jlong bitmapHandle, jobject jbuffer) { 1110 SkBitmap bitmap; 1111 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1112 SkAutoLockPixels alp(bitmap); 1113 const void* src = bitmap.getPixels(); 1114 1115 if (NULL != src) { 1116 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1117 1118 // the java side has already checked that buffer is large enough 1119 memcpy(abp.pointer(), src, bitmap.getSize()); 1120 } 1121} 1122 1123static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1124 jlong bitmapHandle, jobject jbuffer) { 1125 SkBitmap bitmap; 1126 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1127 SkAutoLockPixels alp(bitmap); 1128 void* dst = bitmap.getPixels(); 1129 1130 if (NULL != dst) { 1131 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1132 // the java side has already checked that buffer is large enough 1133 memcpy(dst, abp.pointer(), bitmap.getSize()); 1134 bitmap.notifyPixelsChanged(); 1135 } 1136} 1137 1138static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 1139 jlong bm1Handle) { 1140 SkBitmap bm0; 1141 SkBitmap bm1; 1142 reinterpret_cast<BitmapWrapper*>(bm0Handle)->getSkBitmap(&bm0); 1143 reinterpret_cast<BitmapWrapper*>(bm1Handle)->getSkBitmap(&bm1); 1144 if (bm0.width() != bm1.width() || 1145 bm0.height() != bm1.height() || 1146 bm0.colorType() != bm1.colorType() || 1147 bm0.alphaType() != bm1.alphaType() || 1148 bm0.colorSpace() != bm1.colorSpace()) { 1149 return JNI_FALSE; 1150 } 1151 1152 SkAutoLockPixels alp0(bm0); 1153 SkAutoLockPixels alp1(bm1); 1154 1155 // if we can't load the pixels, return false 1156 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1157 return JNI_FALSE; 1158 } 1159 1160 if (bm0.colorType() == kIndex_8_SkColorType) { 1161 SkColorTable* ct0 = bm0.getColorTable(); 1162 SkColorTable* ct1 = bm1.getColorTable(); 1163 if (NULL == ct0 || NULL == ct1) { 1164 return JNI_FALSE; 1165 } 1166 if (ct0->count() != ct1->count()) { 1167 return JNI_FALSE; 1168 } 1169 1170 const size_t size = ct0->count() * sizeof(SkPMColor); 1171 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1172 return JNI_FALSE; 1173 } 1174 } 1175 1176 // now compare each scanline. We can't do the entire buffer at once, 1177 // since we don't care about the pixel values that might extend beyond 1178 // the width (since the scanline might be larger than the logical width) 1179 const int h = bm0.height(); 1180 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1181 for (int y = 0; y < h; y++) { 1182 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1183 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1184 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1185 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1186 // to warn user those 2 unrecognized config bitmaps may be different. 1187 void *bm0Addr = bm0.getAddr(0, y); 1188 void *bm1Addr = bm1.getAddr(0, y); 1189 1190 if(bm0Addr == NULL || bm1Addr == NULL) { 1191 return JNI_FALSE; 1192 } 1193 1194 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1195 return JNI_FALSE; 1196 } 1197 } 1198 return JNI_TRUE; 1199} 1200 1201static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1202 LocalScopedBitmap bitmapHandle(bitmapPtr); 1203 if (!bitmapHandle.valid()) return; 1204 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->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 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1269 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1270}; 1271 1272int register_android_graphics_Bitmap(JNIEnv* env) 1273{ 1274 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 1275 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J"); 1276 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1277 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); 1278 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); 1279 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1280 NELEM(gBitmapMethods)); 1281} 1282