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