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