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