Bitmap.cpp revision 8cee7c17119b204be88860feb812f2374d0de732
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_destructor(JNIEnv* env, jobject, jlong bitmapHandle) { 778 LocalScopedBitmap bitmap(bitmapHandle); 779 bitmap->detachFromJava(); 780} 781 782static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 783 LocalScopedBitmap bitmap(bitmapHandle); 784 bitmap->freePixels(); 785 return JNI_TRUE; 786} 787 788static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 789 jint width, jint height, jint configHandle, jint allocSize, 790 jboolean requestPremul) { 791 LocalScopedBitmap bitmap(bitmapHandle); 792 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 793 794 // ARGB_4444 is a deprecated format, convert automatically to 8888 795 if (colorType == kARGB_4444_SkColorType) { 796 colorType = kN32_SkColorType; 797 } 798 799 if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) { 800 // done in native as there's no way to get BytesPerPixel in Java 801 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 802 return; 803 } 804 SkAlphaType alphaType; 805 if (bitmap->info().colorType() != kRGB_565_SkColorType 806 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 807 // If the original bitmap was set to opaque, keep that setting, unless it 808 // was 565, which is required to be opaque. 809 alphaType = kOpaque_SkAlphaType; 810 } else { 811 // Otherwise respect the premultiplied request. 812 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 813 } 814 bitmap->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType)); 815} 816 817// These must match the int values in Bitmap.java 818enum JavaEncodeFormat { 819 kJPEG_JavaEncodeFormat = 0, 820 kPNG_JavaEncodeFormat = 1, 821 kWEBP_JavaEncodeFormat = 2 822}; 823 824static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 825 jint format, jint quality, 826 jobject jstream, jbyteArray jstorage) { 827 828 LocalScopedBitmap bitmap(bitmapHandle); 829 SkImageEncoder::Type fm; 830 831 switch (format) { 832 case kJPEG_JavaEncodeFormat: 833 fm = SkImageEncoder::kJPEG_Type; 834 break; 835 case kPNG_JavaEncodeFormat: 836 fm = SkImageEncoder::kPNG_Type; 837 break; 838 case kWEBP_JavaEncodeFormat: 839 fm = SkImageEncoder::kWEBP_Type; 840 break; 841 default: 842 return JNI_FALSE; 843 } 844 845 if (!bitmap.valid()) { 846 return JNI_FALSE; 847 } 848 849 bool success = false; 850 851 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 852 if (!strm.get()) { 853 return JNI_FALSE; 854 } 855 856 std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm)); 857 if (encoder.get()) { 858 SkBitmap skbitmap; 859 bitmap->getSkBitmap(&skbitmap); 860 success = encoder->encodeStream(strm.get(), skbitmap, quality); 861 } 862 return success ? JNI_TRUE : JNI_FALSE; 863} 864 865static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 866 LocalScopedBitmap bitmap(bitmapHandle); 867 SkBitmap skBitmap; 868 bitmap->getSkBitmap(&skBitmap); 869 skBitmap.eraseColor(color); 870} 871 872static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 873 LocalScopedBitmap bitmap(bitmapHandle); 874 return static_cast<jint>(bitmap->rowBytes()); 875} 876 877static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 878 LocalScopedBitmap bitmap(bitmapHandle); 879 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 880} 881 882static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 883 LocalScopedBitmap bitmap(bitmapHandle); 884 return static_cast<jint>(bitmap->peekAtPixelRef()->getGenerationID()); 885} 886 887static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 888 LocalScopedBitmap bitmap(bitmapHandle); 889 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 890 return JNI_TRUE; 891 } 892 return JNI_FALSE; 893} 894 895static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 896 LocalScopedBitmap bitmap(bitmapHandle); 897 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 898} 899 900static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 901 jboolean hasAlpha, jboolean requestPremul) { 902 LocalScopedBitmap bitmap(bitmapHandle); 903 if (hasAlpha) { 904 bitmap->setAlphaType( 905 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 906 } else { 907 bitmap->setAlphaType(kOpaque_SkAlphaType); 908 } 909} 910 911static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 912 jboolean isPremul) { 913 LocalScopedBitmap bitmap(bitmapHandle); 914 if (!bitmap->info().isOpaque()) { 915 if (isPremul) { 916 bitmap->setAlphaType(kPremul_SkAlphaType); 917 } else { 918 bitmap->setAlphaType(kUnpremul_SkAlphaType); 919 } 920 } 921} 922 923static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 924 LocalScopedBitmap bitmap(bitmapHandle); 925 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 926} 927 928static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 929 jboolean hasMipMap) { 930 LocalScopedBitmap bitmap(bitmapHandle); 931 bitmap->setHasHardwareMipMap(hasMipMap); 932} 933 934/////////////////////////////////////////////////////////////////////////////// 935 936static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 937 if (parcel == NULL) { 938 SkDebugf("-------- unparcel parcel is NULL\n"); 939 return NULL; 940 } 941 942 android::Parcel* p = android::parcelForJavaObject(env, parcel); 943 944 const bool isMutable = p->readInt32() != 0; 945 const SkColorType colorType = (SkColorType)p->readInt32(); 946 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 947 const int width = p->readInt32(); 948 const int height = p->readInt32(); 949 const int rowBytes = p->readInt32(); 950 const int density = p->readInt32(); 951 952 if (kN32_SkColorType != colorType && 953 kRGB_565_SkColorType != colorType && 954 kARGB_4444_SkColorType != colorType && 955 kIndex_8_SkColorType != colorType && 956 kAlpha_8_SkColorType != colorType) { 957 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 958 return NULL; 959 } 960 961 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 962 963 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes)) { 964 return NULL; 965 } 966 967 SkColorTable* ctable = NULL; 968 if (colorType == kIndex_8_SkColorType) { 969 int count = p->readInt32(); 970 if (count < 0 || count > 256) { 971 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 972 // inclusive. 973 return NULL; 974 } 975 if (count > 0) { 976 size_t size = count * sizeof(SkPMColor); 977 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 978 if (src == NULL) { 979 return NULL; 980 } 981 ctable = new SkColorTable(src, count); 982 } 983 } 984 985 // Read the bitmap blob. 986 size_t size = bitmap->getSize(); 987 android::Parcel::ReadableBlob blob; 988 android::status_t status = p->readBlob(size, &blob); 989 if (status) { 990 SkSafeUnref(ctable); 991 doThrowRE(env, "Could not read bitmap blob."); 992 return NULL; 993 } 994 995 // Map the bitmap in place from the ashmem region if possible otherwise copy. 996 Bitmap* nativeBitmap; 997 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 998#if DEBUG_PARCEL 999 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 1000 "(fds %s)", 1001 isMutable ? "mutable" : "immutable", 1002 blob.isMutable() ? "mutable" : "immutable", 1003 p->allowFds() ? "allowed" : "forbidden"); 1004#endif 1005 // Dup the file descriptor so we can keep a reference to it after the Parcel 1006 // is disposed. 1007 int dupFd = dup(blob.fd()); 1008 if (dupFd < 0) { 1009 blob.release(); 1010 SkSafeUnref(ctable); 1011 doThrowRE(env, "Could not allocate dup blob fd."); 1012 return NULL; 1013 } 1014 1015 // Map the pixels in place and take ownership of the ashmem region. 1016 nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), 1017 ctable, dupFd, const_cast<void*>(blob.data()), !isMutable); 1018 SkSafeUnref(ctable); 1019 if (!nativeBitmap) { 1020 close(dupFd); 1021 blob.release(); 1022 doThrowRE(env, "Could not allocate ashmem pixel ref."); 1023 return NULL; 1024 } 1025 1026 // Clear the blob handle, don't release it. 1027 blob.clear(); 1028 } else { 1029#if DEBUG_PARCEL 1030 if (blob.fd() >= 0) { 1031 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 1032 "from immutable blob (fds %s)", 1033 p->allowFds() ? "allowed" : "forbidden"); 1034 } else { 1035 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 1036 "(fds %s)", 1037 blob.isMutable() ? "mutable" : "immutable", 1038 p->allowFds() ? "allowed" : "forbidden"); 1039 } 1040#endif 1041 1042 // Copy the pixels into a new buffer. 1043 nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable); 1044 SkSafeUnref(ctable); 1045 if (!nativeBitmap) { 1046 blob.release(); 1047 doThrowRE(env, "Could not allocate java pixel ref."); 1048 return NULL; 1049 } 1050 bitmap->lockPixels(); 1051 memcpy(bitmap->getPixels(), blob.data(), size); 1052 bitmap->unlockPixels(); 1053 1054 // Release the blob handle. 1055 blob.release(); 1056 } 1057 1058 return GraphicsJNI::createBitmap(env, nativeBitmap, 1059 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 1060} 1061 1062static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 1063 jlong bitmapHandle, 1064 jboolean isMutable, jint density, 1065 jobject parcel) { 1066 if (parcel == NULL) { 1067 SkDebugf("------- writeToParcel null parcel\n"); 1068 return JNI_FALSE; 1069 } 1070 1071 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1072 SkBitmap bitmap; 1073 1074 android::Bitmap* androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle); 1075 androidBitmap->getSkBitmap(&bitmap); 1076 1077 p->writeInt32(isMutable); 1078 p->writeInt32(bitmap.colorType()); 1079 p->writeInt32(bitmap.alphaType()); 1080 p->writeInt32(bitmap.width()); 1081 p->writeInt32(bitmap.height()); 1082 p->writeInt32(bitmap.rowBytes()); 1083 p->writeInt32(density); 1084 1085 if (bitmap.colorType() == kIndex_8_SkColorType) { 1086 SkColorTable* ctable = bitmap.getColorTable(); 1087 if (ctable != NULL) { 1088 int count = ctable->count(); 1089 p->writeInt32(count); 1090 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 1091 ctable->readColors(), count * sizeof(SkPMColor)); 1092 } else { 1093 p->writeInt32(0); // indicate no ctable 1094 } 1095 } 1096 1097 // Transfer the underlying ashmem region if we have one and it's immutable. 1098 android::status_t status; 1099 int fd = androidBitmap->getAshmemFd(); 1100 if (fd >= 0 && !isMutable && p->allowFds()) { 1101#if DEBUG_PARCEL 1102 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 1103 "immutable blob (fds %s)", 1104 p->allowFds() ? "allowed" : "forbidden"); 1105#endif 1106 1107 status = p->writeDupImmutableBlobFileDescriptor(fd); 1108 if (status) { 1109 doThrowRE(env, "Could not write bitmap blob file descriptor."); 1110 return JNI_FALSE; 1111 } 1112 return JNI_TRUE; 1113 } 1114 1115 // Copy the bitmap to a new blob. 1116 bool mutableCopy = isMutable; 1117#if DEBUG_PARCEL 1118 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 1119 isMutable ? "mutable" : "immutable", 1120 mutableCopy ? "mutable" : "immutable", 1121 p->allowFds() ? "allowed" : "forbidden"); 1122#endif 1123 1124 size_t size = bitmap.getSize(); 1125 android::Parcel::WritableBlob blob; 1126 status = p->writeBlob(size, mutableCopy, &blob); 1127 if (status) { 1128 doThrowRE(env, "Could not copy bitmap to parcel blob."); 1129 return JNI_FALSE; 1130 } 1131 1132 bitmap.lockPixels(); 1133 const void* pSrc = bitmap.getPixels(); 1134 if (pSrc == NULL) { 1135 memset(blob.data(), 0, size); 1136 } else { 1137 memcpy(blob.data(), pSrc, size); 1138 } 1139 bitmap.unlockPixels(); 1140 1141 blob.release(); 1142 return JNI_TRUE; 1143} 1144 1145static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1146 jlong srcHandle, jlong paintHandle, 1147 jintArray offsetXY) { 1148 SkBitmap src; 1149 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src); 1150 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1151 SkIPoint offset; 1152 SkBitmap dst; 1153 JavaPixelAllocator allocator(env); 1154 1155 src.extractAlpha(&dst, paint, &allocator, &offset); 1156 // If Skia can't allocate pixels for destination bitmap, it resets 1157 // it, that is set its pixels buffer to NULL, and zero width and height. 1158 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1159 doThrowOOME(env, "failed to allocate pixels for alpha"); 1160 return NULL; 1161 } 1162 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1163 int* array = env->GetIntArrayElements(offsetXY, NULL); 1164 array[0] = offset.fX; 1165 array[1] = offset.fY; 1166 env->ReleaseIntArrayElements(offsetXY, array, 0); 1167 } 1168 1169 return GraphicsJNI::createBitmap(env, allocator.getStorageObjAndReset(), 1170 getPremulBitmapCreateFlags(true)); 1171} 1172 1173/////////////////////////////////////////////////////////////////////////////// 1174 1175static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1176 jint x, jint y) { 1177 SkBitmap bitmap; 1178 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1179 SkAutoLockPixels alp(bitmap); 1180 1181 ToColorProc proc = ChooseToColorProc(bitmap); 1182 if (NULL == proc) { 1183 return 0; 1184 } 1185 const void* src = bitmap.getAddr(x, y); 1186 if (NULL == src) { 1187 return 0; 1188 } 1189 1190 SkColor dst[1]; 1191 proc(dst, src, 1, bitmap.getColorTable()); 1192 return static_cast<jint>(dst[0]); 1193} 1194 1195static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1196 jintArray pixelArray, jint offset, jint stride, 1197 jint x, jint y, jint width, jint height) { 1198 SkBitmap bitmap; 1199 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1200 SkAutoLockPixels alp(bitmap); 1201 1202 ToColorProc proc = ChooseToColorProc(bitmap); 1203 if (NULL == proc) { 1204 return; 1205 } 1206 const void* src = bitmap.getAddr(x, y); 1207 if (NULL == src) { 1208 return; 1209 } 1210 1211 SkColorTable* ctable = bitmap.getColorTable(); 1212 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1213 SkColor* d = (SkColor*)dst + offset; 1214 while (--height >= 0) { 1215 proc(d, src, width, ctable); 1216 d += stride; 1217 src = (void*)((const char*)src + bitmap.rowBytes()); 1218 } 1219 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1220} 1221 1222/////////////////////////////////////////////////////////////////////////////// 1223 1224static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1225 jint x, jint y, jint colorHandle) { 1226 SkBitmap bitmap; 1227 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1228 SkColor color = static_cast<SkColor>(colorHandle); 1229 SkAutoLockPixels alp(bitmap); 1230 if (NULL == bitmap.getPixels()) { 1231 return; 1232 } 1233 1234 FromColorProc proc = ChooseFromColorProc(bitmap); 1235 if (NULL == proc) { 1236 return; 1237 } 1238 1239 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1240 bitmap.notifyPixelsChanged(); 1241} 1242 1243static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1244 jintArray pixelArray, jint offset, jint stride, 1245 jint x, jint y, jint width, jint height) { 1246 SkBitmap bitmap; 1247 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1248 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1249 x, y, width, height, bitmap); 1250} 1251 1252static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1253 jlong bitmapHandle, jobject jbuffer) { 1254 SkBitmap bitmap; 1255 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1256 SkAutoLockPixels alp(bitmap); 1257 const void* src = bitmap.getPixels(); 1258 1259 if (NULL != src) { 1260 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1261 1262 // the java side has already checked that buffer is large enough 1263 memcpy(abp.pointer(), src, bitmap.getSize()); 1264 } 1265} 1266 1267static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1268 jlong bitmapHandle, jobject jbuffer) { 1269 SkBitmap bitmap; 1270 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1271 SkAutoLockPixels alp(bitmap); 1272 void* dst = bitmap.getPixels(); 1273 1274 if (NULL != dst) { 1275 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1276 // the java side has already checked that buffer is large enough 1277 memcpy(dst, abp.pointer(), bitmap.getSize()); 1278 bitmap.notifyPixelsChanged(); 1279 } 1280} 1281 1282static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 1283 jlong bm1Handle) { 1284 SkBitmap bm0; 1285 SkBitmap bm1; 1286 reinterpret_cast<Bitmap*>(bm0Handle)->getSkBitmap(&bm0); 1287 reinterpret_cast<Bitmap*>(bm1Handle)->getSkBitmap(&bm1); 1288 if (bm0.width() != bm1.width() || 1289 bm0.height() != bm1.height() || 1290 bm0.colorType() != bm1.colorType()) { 1291 return JNI_FALSE; 1292 } 1293 1294 SkAutoLockPixels alp0(bm0); 1295 SkAutoLockPixels alp1(bm1); 1296 1297 // if we can't load the pixels, return false 1298 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1299 return JNI_FALSE; 1300 } 1301 1302 if (bm0.colorType() == kIndex_8_SkColorType) { 1303 SkColorTable* ct0 = bm0.getColorTable(); 1304 SkColorTable* ct1 = bm1.getColorTable(); 1305 if (NULL == ct0 || NULL == ct1) { 1306 return JNI_FALSE; 1307 } 1308 if (ct0->count() != ct1->count()) { 1309 return JNI_FALSE; 1310 } 1311 1312 const size_t size = ct0->count() * sizeof(SkPMColor); 1313 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1314 return JNI_FALSE; 1315 } 1316 } 1317 1318 // now compare each scanline. We can't do the entire buffer at once, 1319 // since we don't care about the pixel values that might extend beyond 1320 // the width (since the scanline might be larger than the logical width) 1321 const int h = bm0.height(); 1322 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1323 for (int y = 0; y < h; y++) { 1324 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1325 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1326 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1327 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1328 // to warn user those 2 unrecognized config bitmaps may be different. 1329 void *bm0Addr = bm0.getAddr(0, y); 1330 void *bm1Addr = bm1.getAddr(0, y); 1331 1332 if(bm0Addr == NULL || bm1Addr == NULL) { 1333 return JNI_FALSE; 1334 } 1335 1336 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1337 return JNI_FALSE; 1338 } 1339 } 1340 return JNI_TRUE; 1341} 1342 1343static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) { 1344 LocalScopedBitmap bitmap(bitmapHandle); 1345 SkPixelRef* pixelRef = bitmap.valid() ? bitmap->peekAtPixelRef() : nullptr; 1346 SkSafeRef(pixelRef); 1347 return reinterpret_cast<jlong>(pixelRef); 1348} 1349 1350/////////////////////////////////////////////////////////////////////////////// 1351 1352static JNINativeMethod gBitmapMethods[] = { 1353 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 1354 (void*)Bitmap_creator }, 1355 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1356 (void*)Bitmap_copy }, 1357 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1358 (void*)Bitmap_copyAshmem }, 1359 { "nativeDestructor", "(J)V", (void*)Bitmap_destructor }, 1360 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1361 { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure }, 1362 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1363 (void*)Bitmap_compress }, 1364 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1365 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1366 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1367 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1368 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1369 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1370 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1371 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1372 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1373 { "nativeCreateFromParcel", 1374 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1375 (void*)Bitmap_createFromParcel }, 1376 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1377 (void*)Bitmap_writeToParcel }, 1378 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1379 (void*)Bitmap_extractAlpha }, 1380 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1381 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1382 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1383 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1384 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1385 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1386 (void*)Bitmap_copyPixelsToBuffer }, 1387 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1388 (void*)Bitmap_copyPixelsFromBuffer }, 1389 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1390 { "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef }, 1391}; 1392 1393int register_android_graphics_Bitmap(JNIEnv* env) 1394{ 1395 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1396 NELEM(gBitmapMethods)); 1397} 1398