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