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