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