Bitmap.cpp revision 39d7f30ebe490c1d6aee76b0b61e3e67dec13e34
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 void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) { 723 LocalScopedBitmap bitmap(bitmapHandle); 724 bitmap->detachFromJava(); 725} 726 727static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 728 LocalScopedBitmap bitmap(bitmapHandle); 729 bitmap->freePixels(); 730 return JNI_TRUE; 731} 732 733static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 734 jint width, jint height, jint configHandle, jint allocSize, 735 jboolean requestPremul) { 736 LocalScopedBitmap bitmap(bitmapHandle); 737 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 738 739 // ARGB_4444 is a deprecated format, convert automatically to 8888 740 if (colorType == kARGB_4444_SkColorType) { 741 colorType = kN32_SkColorType; 742 } 743 744 if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) { 745 // done in native as there's no way to get BytesPerPixel in Java 746 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 747 return; 748 } 749 SkAlphaType alphaType; 750 if (bitmap->info().colorType() != kRGB_565_SkColorType 751 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 752 // If the original bitmap was set to opaque, keep that setting, unless it 753 // was 565, which is required to be opaque. 754 alphaType = kOpaque_SkAlphaType; 755 } else { 756 // Otherwise respect the premultiplied request. 757 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 758 } 759 bitmap->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType)); 760} 761 762// These must match the int values in Bitmap.java 763enum JavaEncodeFormat { 764 kJPEG_JavaEncodeFormat = 0, 765 kPNG_JavaEncodeFormat = 1, 766 kWEBP_JavaEncodeFormat = 2 767}; 768 769static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 770 jint format, jint quality, 771 jobject jstream, jbyteArray jstorage) { 772 773 LocalScopedBitmap bitmap(bitmapHandle); 774 SkImageEncoder::Type fm; 775 776 switch (format) { 777 case kJPEG_JavaEncodeFormat: 778 fm = SkImageEncoder::kJPEG_Type; 779 break; 780 case kPNG_JavaEncodeFormat: 781 fm = SkImageEncoder::kPNG_Type; 782 break; 783 case kWEBP_JavaEncodeFormat: 784 fm = SkImageEncoder::kWEBP_Type; 785 break; 786 default: 787 return JNI_FALSE; 788 } 789 790 if (!bitmap.valid()) { 791 return JNI_FALSE; 792 } 793 794 bool success = false; 795 796 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 797 if (!strm.get()) { 798 return JNI_FALSE; 799 } 800 801 std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm)); 802 if (encoder.get()) { 803 SkBitmap skbitmap; 804 bitmap->getSkBitmap(&skbitmap); 805 success = encoder->encodeStream(strm.get(), skbitmap, quality); 806 } 807 return success ? JNI_TRUE : JNI_FALSE; 808} 809 810static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 811 LocalScopedBitmap bitmap(bitmapHandle); 812 SkBitmap skBitmap; 813 bitmap->getSkBitmap(&skBitmap); 814 skBitmap.eraseColor(color); 815} 816 817static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 818 LocalScopedBitmap bitmap(bitmapHandle); 819 return static_cast<jint>(bitmap->rowBytes()); 820} 821 822static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 823 LocalScopedBitmap bitmap(bitmapHandle); 824 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 825} 826 827static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 828 LocalScopedBitmap bitmap(bitmapHandle); 829 return static_cast<jint>(bitmap->peekAtPixelRef()->getGenerationID()); 830} 831 832static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 833 LocalScopedBitmap bitmap(bitmapHandle); 834 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 835 return JNI_TRUE; 836 } 837 return JNI_FALSE; 838} 839 840static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 841 LocalScopedBitmap bitmap(bitmapHandle); 842 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 843} 844 845static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 846 jboolean hasAlpha, jboolean requestPremul) { 847 LocalScopedBitmap bitmap(bitmapHandle); 848 if (hasAlpha) { 849 bitmap->peekAtPixelRef()->changeAlphaType( 850 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 851 } else { 852 bitmap->peekAtPixelRef()->changeAlphaType(kOpaque_SkAlphaType); 853 } 854} 855 856static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 857 jboolean isPremul) { 858 LocalScopedBitmap bitmap(bitmapHandle); 859 if (!bitmap->info().isOpaque()) { 860 if (isPremul) { 861 bitmap->peekAtPixelRef()->changeAlphaType(kPremul_SkAlphaType); 862 } else { 863 bitmap->peekAtPixelRef()->changeAlphaType(kUnpremul_SkAlphaType); 864 } 865 } 866} 867 868static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 869 LocalScopedBitmap bitmap(bitmapHandle); 870 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 871} 872 873static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 874 jboolean hasMipMap) { 875 LocalScopedBitmap bitmap(bitmapHandle); 876 bitmap->setHasHardwareMipMap(hasMipMap); 877} 878 879/////////////////////////////////////////////////////////////////////////////// 880 881static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 882 if (parcel == NULL) { 883 SkDebugf("-------- unparcel parcel is NULL\n"); 884 return NULL; 885 } 886 887 android::Parcel* p = android::parcelForJavaObject(env, parcel); 888 889 const bool isMutable = p->readInt32() != 0; 890 const SkColorType colorType = (SkColorType)p->readInt32(); 891 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 892 const int width = p->readInt32(); 893 const int height = p->readInt32(); 894 const int rowBytes = p->readInt32(); 895 const int density = p->readInt32(); 896 897 if (kN32_SkColorType != colorType && 898 kRGB_565_SkColorType != colorType && 899 kARGB_4444_SkColorType != colorType && 900 kIndex_8_SkColorType != colorType && 901 kAlpha_8_SkColorType != colorType) { 902 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 903 return NULL; 904 } 905 906 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 907 908 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes)) { 909 return NULL; 910 } 911 912 SkColorTable* ctable = NULL; 913 if (colorType == kIndex_8_SkColorType) { 914 int count = p->readInt32(); 915 if (count < 0 || count > 256) { 916 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 917 // inclusive. 918 return NULL; 919 } 920 if (count > 0) { 921 size_t size = count * sizeof(SkPMColor); 922 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 923 if (src == NULL) { 924 return NULL; 925 } 926 ctable = new SkColorTable(src, count); 927 } 928 } 929 930 int fd = p->readFileDescriptor(); 931 int dupFd = dup(fd); 932 if (dupFd < 0) { 933 SkSafeUnref(ctable); 934 doThrowRE(env, "Could not dup parcel fd."); 935 return NULL; 936 } 937 938 bool readOnlyMapping = !isMutable; 939 Bitmap* nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), 940 ctable, dupFd, readOnlyMapping); 941 SkSafeUnref(ctable); 942 if (!nativeBitmap) { 943 close(dupFd); 944 doThrowRE(env, "Could not allocate ashmem pixel ref."); 945 return NULL; 946 } 947 bitmap->pixelRef()->setImmutable(); 948 949 return GraphicsJNI::createBitmap(env, nativeBitmap, 950 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 951} 952 953class Ashmem { 954public: 955 Ashmem(size_t sz, bool removeWritePerm) : mSize(sz) { 956 int fd = -1; 957 void *addr = nullptr; 958 959 // Create new ashmem region with read/write priv 960 fd = ashmem_create_region("bitmap", sz); 961 if (fd < 0) { 962 goto error; 963 } 964 addr = mmap(nullptr, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 965 if (addr == MAP_FAILED) { 966 goto error; 967 } 968 // If requested, remove the ability to make additional writeable to 969 // this memory. 970 if (removeWritePerm) { 971 if (ashmem_set_prot_region(fd, PROT_READ) < 0) { 972 goto error; 973 } 974 } 975 mFd = fd; 976 mPtr = addr; 977 return; 978error: 979 if (fd >= 0) { 980 close(fd); 981 } 982 if (addr) { 983 munmap(addr, sz); 984 } 985 } 986 ~Ashmem() { 987 if (mPtr) { 988 close(mFd); 989 munmap(mPtr, mSize); 990 } 991 } 992 void *getPtr() const { return mPtr; } 993 int getFd() const { return mFd; } 994private: 995 int mFd = -1; 996 int mSize; 997 void* mPtr = nullptr; 998}; 999 1000static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 1001 jlong bitmapHandle, 1002 jboolean isMutable, jint density, 1003 jobject parcel) { 1004 if (parcel == NULL) { 1005 SkDebugf("------- writeToParcel null parcel\n"); 1006 return JNI_FALSE; 1007 } 1008 1009 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1010 SkBitmap bitmap; 1011 1012 android::Bitmap* androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle); 1013 androidBitmap->getSkBitmap(&bitmap); 1014 1015 p->writeInt32(isMutable); 1016 p->writeInt32(bitmap.colorType()); 1017 p->writeInt32(bitmap.alphaType()); 1018 p->writeInt32(bitmap.width()); 1019 p->writeInt32(bitmap.height()); 1020 p->writeInt32(bitmap.rowBytes()); 1021 p->writeInt32(density); 1022 1023 if (bitmap.colorType() == kIndex_8_SkColorType) { 1024 SkColorTable* ctable = bitmap.getColorTable(); 1025 if (ctable != NULL) { 1026 int count = ctable->count(); 1027 p->writeInt32(count); 1028 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 1029 ctable->readColors(), count * sizeof(SkPMColor)); 1030 } else { 1031 p->writeInt32(0); // indicate no ctable 1032 } 1033 } 1034 1035 bool ashmemSrc = androidBitmap->getAshmemFd() >= 0; 1036 if (ashmemSrc && !isMutable) { 1037 p->writeDupFileDescriptor(androidBitmap->getAshmemFd()); 1038 } else { 1039 Ashmem dstAshmem(bitmap.getSize(), !isMutable); 1040 if (!dstAshmem.getPtr()) { 1041 doThrowRE(env, "Could not allocate ashmem for new bitmap."); 1042 return JNI_FALSE; 1043 } 1044 1045 bitmap.lockPixels(); 1046 const void* pSrc = bitmap.getPixels(); 1047 if (pSrc == NULL) { 1048 memset(dstAshmem.getPtr(), 0, bitmap.getSize()); 1049 } else { 1050 memcpy(dstAshmem.getPtr(), pSrc, bitmap.getSize()); 1051 } 1052 bitmap.unlockPixels(); 1053 p->writeDupFileDescriptor(dstAshmem.getFd()); 1054 } 1055 return JNI_TRUE; 1056} 1057 1058static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1059 jlong srcHandle, jlong paintHandle, 1060 jintArray offsetXY) { 1061 SkBitmap src; 1062 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src); 1063 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1064 SkIPoint offset; 1065 SkBitmap dst; 1066 JavaPixelAllocator allocator(env); 1067 1068 src.extractAlpha(&dst, paint, &allocator, &offset); 1069 // If Skia can't allocate pixels for destination bitmap, it resets 1070 // it, that is set its pixels buffer to NULL, and zero width and height. 1071 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1072 doThrowOOME(env, "failed to allocate pixels for alpha"); 1073 return NULL; 1074 } 1075 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1076 int* array = env->GetIntArrayElements(offsetXY, NULL); 1077 array[0] = offset.fX; 1078 array[1] = offset.fY; 1079 env->ReleaseIntArrayElements(offsetXY, array, 0); 1080 } 1081 1082 return GraphicsJNI::createBitmap(env, allocator.getStorageObjAndReset(), 1083 getPremulBitmapCreateFlags(true)); 1084} 1085 1086/////////////////////////////////////////////////////////////////////////////// 1087 1088static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1089 jint x, jint y) { 1090 SkBitmap bitmap; 1091 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1092 SkAutoLockPixels alp(bitmap); 1093 1094 ToColorProc proc = ChooseToColorProc(bitmap); 1095 if (NULL == proc) { 1096 return 0; 1097 } 1098 const void* src = bitmap.getAddr(x, y); 1099 if (NULL == src) { 1100 return 0; 1101 } 1102 1103 SkColor dst[1]; 1104 proc(dst, src, 1, bitmap.getColorTable()); 1105 return static_cast<jint>(dst[0]); 1106} 1107 1108static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1109 jintArray pixelArray, jint offset, jint stride, 1110 jint x, jint y, jint width, jint height) { 1111 SkBitmap bitmap; 1112 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1113 SkAutoLockPixels alp(bitmap); 1114 1115 ToColorProc proc = ChooseToColorProc(bitmap); 1116 if (NULL == proc) { 1117 return; 1118 } 1119 const void* src = bitmap.getAddr(x, y); 1120 if (NULL == src) { 1121 return; 1122 } 1123 1124 SkColorTable* ctable = bitmap.getColorTable(); 1125 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1126 SkColor* d = (SkColor*)dst + offset; 1127 while (--height >= 0) { 1128 proc(d, src, width, ctable); 1129 d += stride; 1130 src = (void*)((const char*)src + bitmap.rowBytes()); 1131 } 1132 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1133} 1134 1135/////////////////////////////////////////////////////////////////////////////// 1136 1137static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1138 jint x, jint y, jint colorHandle) { 1139 SkBitmap bitmap; 1140 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1141 SkColor color = static_cast<SkColor>(colorHandle); 1142 SkAutoLockPixels alp(bitmap); 1143 if (NULL == bitmap.getPixels()) { 1144 return; 1145 } 1146 1147 FromColorProc proc = ChooseFromColorProc(bitmap); 1148 if (NULL == proc) { 1149 return; 1150 } 1151 1152 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1153 bitmap.notifyPixelsChanged(); 1154} 1155 1156static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1157 jintArray pixelArray, jint offset, jint stride, 1158 jint x, jint y, jint width, jint height) { 1159 SkBitmap bitmap; 1160 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1161 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1162 x, y, width, height, bitmap); 1163} 1164 1165static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1166 jlong bitmapHandle, jobject jbuffer) { 1167 SkBitmap bitmap; 1168 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1169 SkAutoLockPixels alp(bitmap); 1170 const void* src = bitmap.getPixels(); 1171 1172 if (NULL != src) { 1173 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1174 1175 // the java side has already checked that buffer is large enough 1176 memcpy(abp.pointer(), src, bitmap.getSize()); 1177 } 1178} 1179 1180static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1181 jlong bitmapHandle, jobject jbuffer) { 1182 SkBitmap bitmap; 1183 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1184 SkAutoLockPixels alp(bitmap); 1185 void* dst = bitmap.getPixels(); 1186 1187 if (NULL != dst) { 1188 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1189 // the java side has already checked that buffer is large enough 1190 memcpy(dst, abp.pointer(), bitmap.getSize()); 1191 bitmap.notifyPixelsChanged(); 1192 } 1193} 1194 1195static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 1196 jlong bm1Handle) { 1197 SkBitmap bm0; 1198 SkBitmap bm1; 1199 reinterpret_cast<Bitmap*>(bm0Handle)->getSkBitmap(&bm0); 1200 reinterpret_cast<Bitmap*>(bm1Handle)->getSkBitmap(&bm1); 1201 if (bm0.width() != bm1.width() || 1202 bm0.height() != bm1.height() || 1203 bm0.colorType() != bm1.colorType()) { 1204 return JNI_FALSE; 1205 } 1206 1207 SkAutoLockPixels alp0(bm0); 1208 SkAutoLockPixels alp1(bm1); 1209 1210 // if we can't load the pixels, return false 1211 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1212 return JNI_FALSE; 1213 } 1214 1215 if (bm0.colorType() == kIndex_8_SkColorType) { 1216 SkColorTable* ct0 = bm0.getColorTable(); 1217 SkColorTable* ct1 = bm1.getColorTable(); 1218 if (NULL == ct0 || NULL == ct1) { 1219 return JNI_FALSE; 1220 } 1221 if (ct0->count() != ct1->count()) { 1222 return JNI_FALSE; 1223 } 1224 1225 const size_t size = ct0->count() * sizeof(SkPMColor); 1226 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1227 return JNI_FALSE; 1228 } 1229 } 1230 1231 // now compare each scanline. We can't do the entire buffer at once, 1232 // since we don't care about the pixel values that might extend beyond 1233 // the width (since the scanline might be larger than the logical width) 1234 const int h = bm0.height(); 1235 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1236 for (int y = 0; y < h; y++) { 1237 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1238 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1239 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1240 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1241 // to warn user those 2 unrecognized config bitmaps may be different. 1242 void *bm0Addr = bm0.getAddr(0, y); 1243 void *bm1Addr = bm1.getAddr(0, y); 1244 1245 if(bm0Addr == NULL || bm1Addr == NULL) { 1246 return JNI_FALSE; 1247 } 1248 1249 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1250 return JNI_FALSE; 1251 } 1252 } 1253 return JNI_TRUE; 1254} 1255 1256static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) { 1257 LocalScopedBitmap bitmap(bitmapHandle); 1258 SkPixelRef* pixelRef = bitmap.valid() ? bitmap->peekAtPixelRef() : nullptr; 1259 SkSafeRef(pixelRef); 1260 return reinterpret_cast<jlong>(pixelRef); 1261} 1262 1263/////////////////////////////////////////////////////////////////////////////// 1264 1265static JNINativeMethod gBitmapMethods[] = { 1266 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 1267 (void*)Bitmap_creator }, 1268 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1269 (void*)Bitmap_copy }, 1270 { "nativeDestructor", "(J)V", (void*)Bitmap_destructor }, 1271 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1272 { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure }, 1273 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1274 (void*)Bitmap_compress }, 1275 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1276 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1277 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1278 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1279 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1280 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1281 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1282 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1283 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1284 { "nativeCreateFromParcel", 1285 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1286 (void*)Bitmap_createFromParcel }, 1287 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1288 (void*)Bitmap_writeToParcel }, 1289 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1290 (void*)Bitmap_extractAlpha }, 1291 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1292 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1293 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1294 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1295 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1296 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1297 (void*)Bitmap_copyPixelsToBuffer }, 1298 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1299 (void*)Bitmap_copyPixelsFromBuffer }, 1300 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1301 { "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef }, 1302}; 1303 1304int register_android_graphics_Bitmap(JNIEnv* env) 1305{ 1306 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1307 NELEM(gBitmapMethods)); 1308} 1309