Home | History | Annotate | Download | only in graphics
      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