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