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