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