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