Home | History | Annotate | Download | only in graphics
      1 #include "Paint.h"
      2 #include "SkBitmap.h"
      3 #include "SkPixelRef.h"
      4 #include "SkImageEncoder.h"
      5 #include "SkImageInfo.h"
      6 #include "SkColorPriv.h"
      7 #include "GraphicsJNI.h"
      8 #include "SkDither.h"
      9 #include "SkUnPreMultiply.h"
     10 #include "SkStream.h"
     11 
     12 #include <binder/Parcel.h>
     13 #include "android_os_Parcel.h"
     14 #include "android_util_Binder.h"
     15 #include "android_nio_utils.h"
     16 #include "CreateJavaOutputStreamAdaptor.h"
     17 
     18 #include <jni.h>
     19 
     20 #include <Caches.h>
     21 
     22 #if 0
     23     #define TRACE_BITMAP(code)  code
     24 #else
     25     #define TRACE_BITMAP(code)
     26 #endif
     27 
     28 ///////////////////////////////////////////////////////////////////////////////
     29 // Conversions to/from SkColor, for get/setPixels, and the create method, which
     30 // is basically like setPixels
     31 
     32 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
     33                               int x, int y);
     34 
     35 static void FromColor_D32(void* dst, const SkColor src[], int width,
     36                           int, int) {
     37     SkPMColor* d = (SkPMColor*)dst;
     38 
     39     for (int i = 0; i < width; i++) {
     40         *d++ = SkPreMultiplyColor(*src++);
     41     }
     42 }
     43 
     44 static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
     45                           int, int) {
     46     // SkColor's ordering may be different from SkPMColor
     47     if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
     48         memcpy(dst, src, width * sizeof(SkColor));
     49         return;
     50     }
     51 
     52     // order isn't same, repack each pixel manually
     53     SkPMColor* d = (SkPMColor*)dst;
     54     for (int i = 0; i < width; i++) {
     55         SkColor c = *src++;
     56         *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
     57                                    SkColorGetG(c), SkColorGetB(c));
     58     }
     59 }
     60 
     61 static void FromColor_D565(void* dst, const SkColor src[], int width,
     62                            int x, int y) {
     63     uint16_t* d = (uint16_t*)dst;
     64 
     65     DITHER_565_SCAN(y);
     66     for (int stop = x + width; x < stop; x++) {
     67         SkColor c = *src++;
     68         *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
     69                                 DITHER_VALUE(x));
     70     }
     71 }
     72 
     73 static void FromColor_D4444(void* dst, const SkColor src[], int width,
     74                             int x, int y) {
     75     SkPMColor16* d = (SkPMColor16*)dst;
     76 
     77     DITHER_4444_SCAN(y);
     78     for (int stop = x + width; x < stop; x++) {
     79         SkPMColor pmc = SkPreMultiplyColor(*src++);
     80         *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
     81 //        *d++ = SkPixel32ToPixel4444(pmc);
     82     }
     83 }
     84 
     85 static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
     86                             int x, int y) {
     87     SkPMColor16* d = (SkPMColor16*)dst;
     88 
     89     DITHER_4444_SCAN(y);
     90     for (int stop = x + width; x < stop; x++) {
     91         SkColor c = *src++;
     92 
     93         // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
     94         SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
     95                                             SkColorGetG(c), SkColorGetB(c));
     96         *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
     97 //        *d++ = SkPixel32ToPixel4444(pmc);
     98     }
     99 }
    100 
    101 // can return NULL
    102 static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
    103     switch (bitmap.colorType()) {
    104         case kN32_SkColorType:
    105             return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
    106         case kARGB_4444_SkColorType:
    107             return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
    108                     FromColor_D4444_Raw;
    109         case kRGB_565_SkColorType:
    110             return FromColor_D565;
    111         default:
    112             break;
    113     }
    114     return NULL;
    115 }
    116 
    117 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
    118         int x, int y, int width, int height, const SkBitmap& dstBitmap) {
    119     SkAutoLockPixels alp(dstBitmap);
    120     void* dst = dstBitmap.getPixels();
    121     FromColorProc proc = ChooseFromColorProc(dstBitmap);
    122 
    123     if (NULL == dst || NULL == proc) {
    124         return false;
    125     }
    126 
    127     const jint* array = env->GetIntArrayElements(srcColors, NULL);
    128     const SkColor* src = (const SkColor*)array + srcOffset;
    129 
    130     // reset to to actual choice from caller
    131     dst = dstBitmap.getAddr(x, y);
    132     // now copy/convert each scanline
    133     for (int y = 0; y < height; y++) {
    134         proc(dst, src, width, x, y);
    135         src += srcStride;
    136         dst = (char*)dst + dstBitmap.rowBytes();
    137     }
    138 
    139     dstBitmap.notifyPixelsChanged();
    140 
    141     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
    142                                  JNI_ABORT);
    143     return true;
    144 }
    145 
    146 //////////////////// ToColor procs
    147 
    148 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
    149                             SkColorTable*);
    150 
    151 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
    152                               SkColorTable*) {
    153     SkASSERT(width > 0);
    154     const SkPMColor* s = (const SkPMColor*)src;
    155     do {
    156         *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
    157     } while (--width != 0);
    158 }
    159 
    160 static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
    161                               SkColorTable*) {
    162     SkASSERT(width > 0);
    163     const SkPMColor* s = (const SkPMColor*)src;
    164     do {
    165         SkPMColor c = *s++;
    166         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
    167                                 SkGetPackedG32(c), SkGetPackedB32(c));
    168     } while (--width != 0);
    169 }
    170 
    171 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
    172                                SkColorTable*) {
    173     SkASSERT(width > 0);
    174     const SkPMColor* s = (const SkPMColor*)src;
    175     do {
    176         SkPMColor c = *s++;
    177         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
    178                                SkGetPackedB32(c));
    179     } while (--width != 0);
    180 }
    181 
    182 static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
    183                                 SkColorTable*) {
    184     SkASSERT(width > 0);
    185     const SkPMColor16* s = (const SkPMColor16*)src;
    186     do {
    187         *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
    188     } while (--width != 0);
    189 }
    190 
    191 static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
    192                                 SkColorTable*) {
    193     SkASSERT(width > 0);
    194     const SkPMColor16* s = (const SkPMColor16*)src;
    195     do {
    196         SkPMColor c = SkPixel4444ToPixel32(*s++);
    197         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
    198                                 SkGetPackedG32(c), SkGetPackedB32(c));
    199     } while (--width != 0);
    200 }
    201 
    202 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
    203                                  SkColorTable*) {
    204     SkASSERT(width > 0);
    205     const SkPMColor16* s = (const SkPMColor16*)src;
    206     do {
    207         SkPMColor c = SkPixel4444ToPixel32(*s++);
    208         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
    209                                SkGetPackedB32(c));
    210     } while (--width != 0);
    211 }
    212 
    213 static void ToColor_S565(SkColor dst[], const void* src, int width,
    214                          SkColorTable*) {
    215     SkASSERT(width > 0);
    216     const uint16_t* s = (const uint16_t*)src;
    217     do {
    218         uint16_t c = *s++;
    219         *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
    220                                 SkPacked16ToB32(c));
    221     } while (--width != 0);
    222 }
    223 
    224 static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
    225                               SkColorTable* ctable) {
    226     SkASSERT(width > 0);
    227     const uint8_t* s = (const uint8_t*)src;
    228     const SkPMColor* colors = ctable->lockColors();
    229     do {
    230         *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
    231     } while (--width != 0);
    232     ctable->unlockColors();
    233 }
    234 
    235 static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
    236                               SkColorTable* ctable) {
    237     SkASSERT(width > 0);
    238     const uint8_t* s = (const uint8_t*)src;
    239     const SkPMColor* colors = ctable->lockColors();
    240     do {
    241         SkPMColor c = colors[*s++];
    242         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
    243                                 SkGetPackedG32(c), SkGetPackedB32(c));
    244     } while (--width != 0);
    245     ctable->unlockColors();
    246 }
    247 
    248 static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
    249                                SkColorTable* ctable) {
    250     SkASSERT(width > 0);
    251     const uint8_t* s = (const uint8_t*)src;
    252     const SkPMColor* colors = ctable->lockColors();
    253     do {
    254         SkPMColor c = colors[*s++];
    255         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
    256                                SkGetPackedB32(c));
    257     } while (--width != 0);
    258     ctable->unlockColors();
    259 }
    260 
    261 // can return NULL
    262 static ToColorProc ChooseToColorProc(const SkBitmap& src) {
    263     switch (src.colorType()) {
    264         case kN32_SkColorType:
    265             switch (src.alphaType()) {
    266                 case kOpaque_SkAlphaType:
    267                     return ToColor_S32_Opaque;
    268                 case kPremul_SkAlphaType:
    269                     return ToColor_S32_Alpha;
    270                 case kUnpremul_SkAlphaType:
    271                     return ToColor_S32_Raw;
    272                 default:
    273                     return NULL;
    274             }
    275         case kARGB_4444_SkColorType:
    276             switch (src.alphaType()) {
    277                 case kOpaque_SkAlphaType:
    278                     return ToColor_S4444_Opaque;
    279                 case kPremul_SkAlphaType:
    280                     return ToColor_S4444_Alpha;
    281                 case kUnpremul_SkAlphaType:
    282                     return ToColor_S4444_Raw;
    283                 default:
    284                     return NULL;
    285             }
    286         case kRGB_565_SkColorType:
    287             return ToColor_S565;
    288         case kIndex_8_SkColorType:
    289             if (src.getColorTable() == NULL) {
    290                 return NULL;
    291             }
    292             switch (src.alphaType()) {
    293                 case kOpaque_SkAlphaType:
    294                     return ToColor_SI8_Opaque;
    295                 case kPremul_SkAlphaType:
    296                     return ToColor_SI8_Alpha;
    297                 case kUnpremul_SkAlphaType:
    298                     return ToColor_SI8_Raw;
    299                 default:
    300                     return NULL;
    301             }
    302         default:
    303             break;
    304     }
    305     return NULL;
    306 }
    307 
    308 ///////////////////////////////////////////////////////////////////////////////
    309 ///////////////////////////////////////////////////////////////////////////////
    310 
    311 static int getPremulBitmapCreateFlags(bool isMutable) {
    312     int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
    313     if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
    314     return flags;
    315 }
    316 
    317 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
    318                               jint offset, jint stride, jint width, jint height,
    319                               jint configHandle, jboolean isMutable) {
    320     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
    321     if (NULL != jColors) {
    322         size_t n = env->GetArrayLength(jColors);
    323         if (n < SkAbs32(stride) * (size_t)height) {
    324             doThrowAIOOBE(env);
    325             return NULL;
    326         }
    327     }
    328 
    329     // ARGB_4444 is a deprecated format, convert automatically to 8888
    330     if (colorType == kARGB_4444_SkColorType) {
    331         colorType = kN32_SkColorType;
    332     }
    333 
    334     SkBitmap bitmap;
    335     bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
    336 
    337     jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
    338     if (NULL == buff) {
    339         return NULL;
    340     }
    341 
    342     if (jColors != NULL) {
    343         GraphicsJNI::SetPixels(env, jColors, offset, stride,
    344                 0, 0, width, height, bitmap);
    345     }
    346 
    347     return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
    348             getPremulBitmapCreateFlags(isMutable), NULL, NULL);
    349 }
    350 
    351 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
    352                            jint dstConfigHandle, jboolean isMutable) {
    353     const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
    354     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
    355     SkBitmap            result;
    356     JavaPixelAllocator  allocator(env);
    357 
    358     if (!src->copyTo(&result, dstCT, &allocator)) {
    359         return NULL;
    360     }
    361     return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
    362             getPremulBitmapCreateFlags(isMutable), NULL, NULL);
    363 }
    364 
    365 static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
    366     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    367 #ifdef USE_OPENGL_RENDERER
    368     if (android::uirenderer::Caches::hasInstance()) {
    369         android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
    370         return;
    371     }
    372 #endif // USE_OPENGL_RENDERER
    373     delete bitmap;
    374 }
    375 
    376 static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
    377     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    378 #ifdef USE_OPENGL_RENDERER
    379     if (android::uirenderer::Caches::hasInstance()) {
    380         bool result;
    381         result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
    382         return result ? JNI_TRUE : JNI_FALSE;
    383     }
    384 #endif // USE_OPENGL_RENDERER
    385     bitmap->setPixels(NULL, NULL);
    386     return JNI_TRUE;
    387 }
    388 
    389 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    390         jint width, jint height, jint configHandle, jint allocSize,
    391         jboolean requestPremul) {
    392     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    393     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
    394 
    395     // ARGB_4444 is a deprecated format, convert automatically to 8888
    396     if (colorType == kARGB_4444_SkColorType) {
    397         colorType = kN32_SkColorType;
    398     }
    399 
    400     if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
    401         // done in native as there's no way to get BytesPerPixel in Java
    402         doThrowIAE(env, "Bitmap not large enough to support new configuration");
    403         return;
    404     }
    405     SkPixelRef* ref = bitmap->pixelRef();
    406     ref->ref();
    407     SkAlphaType alphaType;
    408     if (bitmap->colorType() != kRGB_565_SkColorType
    409             && bitmap->alphaType() == kOpaque_SkAlphaType) {
    410         // If the original bitmap was set to opaque, keep that setting, unless it
    411         // was 565, which is required to be opaque.
    412         alphaType = kOpaque_SkAlphaType;
    413     } else {
    414         // Otherwise respect the premultiplied request.
    415         alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
    416     }
    417     bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
    418     // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for
    419     // its alphatype), so it would make more sense from Skia's perspective to create a
    420     // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key
    421     // for its cache, so it won't realize this is the same Java Bitmap.
    422     SkImageInfo& info = const_cast<SkImageInfo&>(ref->info());
    423     // Use the updated from the SkBitmap, which may have corrected an invalid alphatype.
    424     // (e.g. 565 non-opaque)
    425     info = bitmap->info();
    426     bitmap->setPixelRef(ref);
    427 
    428     // notifyPixelsChanged will increment the generation ID even though the actual pixel data
    429     // hasn't been touched. This signals the renderer that the bitmap (including width, height,
    430     // colortype and alphatype) has changed.
    431     ref->notifyPixelsChanged();
    432     ref->unref();
    433 }
    434 
    435 // These must match the int values in Bitmap.java
    436 enum JavaEncodeFormat {
    437     kJPEG_JavaEncodeFormat = 0,
    438     kPNG_JavaEncodeFormat = 1,
    439     kWEBP_JavaEncodeFormat = 2
    440 };
    441 
    442 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    443                                 jint format, jint quality,
    444                                 jobject jstream, jbyteArray jstorage) {
    445     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    446     SkImageEncoder::Type fm;
    447 
    448     switch (format) {
    449     case kJPEG_JavaEncodeFormat:
    450         fm = SkImageEncoder::kJPEG_Type;
    451         break;
    452     case kPNG_JavaEncodeFormat:
    453         fm = SkImageEncoder::kPNG_Type;
    454         break;
    455     case kWEBP_JavaEncodeFormat:
    456         fm = SkImageEncoder::kWEBP_Type;
    457         break;
    458     default:
    459         return JNI_FALSE;
    460     }
    461 
    462     bool success = false;
    463     if (NULL != bitmap) {
    464         SkAutoLockPixels alp(*bitmap);
    465 
    466         if (NULL == bitmap->getPixels()) {
    467             return JNI_FALSE;
    468         }
    469 
    470         SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
    471         if (NULL == strm) {
    472             return JNI_FALSE;
    473         }
    474 
    475         SkImageEncoder* encoder = SkImageEncoder::Create(fm);
    476         if (NULL != encoder) {
    477             success = encoder->encodeStream(strm, *bitmap, quality);
    478             delete encoder;
    479         }
    480         delete strm;
    481     }
    482     return success ? JNI_TRUE : JNI_FALSE;
    483 }
    484 
    485 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
    486     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    487     bitmap->eraseColor(color);
    488 }
    489 
    490 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
    491     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    492     return static_cast<jint>(bitmap->rowBytes());
    493 }
    494 
    495 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
    496     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    497     return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->colorType());
    498 }
    499 
    500 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
    501     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    502     return static_cast<jint>(bitmap->getGenerationID());
    503 }
    504 
    505 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
    506     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    507     if (bitmap->alphaType() == kPremul_SkAlphaType) {
    508         return JNI_TRUE;
    509     }
    510     return JNI_FALSE;
    511 }
    512 
    513 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
    514     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    515     return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
    516 }
    517 
    518 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
    519         jboolean hasAlpha, jboolean requestPremul) {
    520     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    521     if (hasAlpha) {
    522         bitmap->setAlphaType(requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
    523     } else {
    524         bitmap->setAlphaType(kOpaque_SkAlphaType);
    525     }
    526 }
    527 
    528 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
    529         jboolean isPremul) {
    530     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    531     if (!bitmap->isOpaque()) {
    532         if (isPremul) {
    533             bitmap->setAlphaType(kPremul_SkAlphaType);
    534         } else {
    535             bitmap->setAlphaType(kUnpremul_SkAlphaType);
    536         }
    537     }
    538 }
    539 
    540 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
    541     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    542     return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
    543 }
    544 
    545 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
    546                                 jboolean hasMipMap) {
    547     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    548     bitmap->setHasHardwareMipMap(hasMipMap);
    549 }
    550 
    551 ///////////////////////////////////////////////////////////////////////////////
    552 
    553 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
    554     if (parcel == NULL) {
    555         SkDebugf("-------- unparcel parcel is NULL\n");
    556         return NULL;
    557     }
    558 
    559     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    560 
    561     const bool        isMutable = p->readInt32() != 0;
    562     const SkColorType colorType = (SkColorType)p->readInt32();
    563     const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
    564     const int         width = p->readInt32();
    565     const int         height = p->readInt32();
    566     const int         rowBytes = p->readInt32();
    567     const int         density = p->readInt32();
    568 
    569     if (kN32_SkColorType != colorType &&
    570             kRGB_565_SkColorType != colorType &&
    571             kARGB_4444_SkColorType != colorType &&
    572             kIndex_8_SkColorType != colorType &&
    573             kAlpha_8_SkColorType != colorType) {
    574         SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
    575         return NULL;
    576     }
    577 
    578     SkBitmap* bitmap = new SkBitmap;
    579 
    580     bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes);
    581 
    582     SkColorTable* ctable = NULL;
    583     if (colorType == kIndex_8_SkColorType) {
    584         int count = p->readInt32();
    585         if (count > 0) {
    586             size_t size = count * sizeof(SkPMColor);
    587             const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
    588             ctable = new SkColorTable(src, count);
    589         }
    590     }
    591 
    592     jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
    593     if (NULL == buffer) {
    594         SkSafeUnref(ctable);
    595         delete bitmap;
    596         return NULL;
    597     }
    598 
    599     SkSafeUnref(ctable);
    600 
    601     size_t size = bitmap->getSize();
    602 
    603     android::Parcel::ReadableBlob blob;
    604     android::status_t status = p->readBlob(size, &blob);
    605     if (status) {
    606         doThrowRE(env, "Could not read bitmap from parcel blob.");
    607         delete bitmap;
    608         return NULL;
    609     }
    610 
    611     bitmap->lockPixels();
    612     memcpy(bitmap->getPixels(), blob.data(), size);
    613     bitmap->unlockPixels();
    614 
    615     blob.release();
    616 
    617     return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
    618             NULL, NULL, density);
    619 }
    620 
    621 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
    622                                      jlong bitmapHandle,
    623                                      jboolean isMutable, jint density,
    624                                      jobject parcel) {
    625     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    626     if (parcel == NULL) {
    627         SkDebugf("------- writeToParcel null parcel\n");
    628         return JNI_FALSE;
    629     }
    630 
    631     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    632 
    633     p->writeInt32(isMutable);
    634     p->writeInt32(bitmap->colorType());
    635     p->writeInt32(bitmap->alphaType());
    636     p->writeInt32(bitmap->width());
    637     p->writeInt32(bitmap->height());
    638     p->writeInt32(bitmap->rowBytes());
    639     p->writeInt32(density);
    640 
    641     if (bitmap->colorType() == kIndex_8_SkColorType) {
    642         SkColorTable* ctable = bitmap->getColorTable();
    643         if (ctable != NULL) {
    644             int count = ctable->count();
    645             p->writeInt32(count);
    646             memcpy(p->writeInplace(count * sizeof(SkPMColor)),
    647                    ctable->lockColors(), count * sizeof(SkPMColor));
    648             ctable->unlockColors();
    649         } else {
    650             p->writeInt32(0);   // indicate no ctable
    651         }
    652     }
    653 
    654     size_t size = bitmap->getSize();
    655 
    656     android::Parcel::WritableBlob blob;
    657     android::status_t status = p->writeBlob(size, &blob);
    658     if (status) {
    659         doThrowRE(env, "Could not write bitmap to parcel blob.");
    660         return JNI_FALSE;
    661     }
    662 
    663     bitmap->lockPixels();
    664     const void* pSrc =  bitmap->getPixels();
    665     if (pSrc == NULL) {
    666         memset(blob.data(), 0, size);
    667     } else {
    668         memcpy(blob.data(), pSrc, size);
    669     }
    670     bitmap->unlockPixels();
    671 
    672     blob.release();
    673     return JNI_TRUE;
    674 }
    675 
    676 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
    677                                    jlong srcHandle, jlong paintHandle,
    678                                    jintArray offsetXY) {
    679     const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
    680     const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
    681     SkIPoint  offset;
    682     SkBitmap* dst = new SkBitmap;
    683     JavaPixelAllocator allocator(env);
    684 
    685     src->extractAlpha(dst, paint, &allocator, &offset);
    686     // If Skia can't allocate pixels for destination bitmap, it resets
    687     // it, that is set its pixels buffer to NULL, and zero width and height.
    688     if (dst->getPixels() == NULL && src->getPixels() != NULL) {
    689         delete dst;
    690         doThrowOOME(env, "failed to allocate pixels for alpha");
    691         return NULL;
    692     }
    693     if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
    694         int* array = env->GetIntArrayElements(offsetXY, NULL);
    695         array[0] = offset.fX;
    696         array[1] = offset.fY;
    697         env->ReleaseIntArrayElements(offsetXY, array, 0);
    698     }
    699 
    700     return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
    701             getPremulBitmapCreateFlags(true), NULL, NULL);
    702 }
    703 
    704 ///////////////////////////////////////////////////////////////////////////////
    705 
    706 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
    707         jint x, jint y) {
    708     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    709     SkAutoLockPixels alp(*bitmap);
    710 
    711     ToColorProc proc = ChooseToColorProc(*bitmap);
    712     if (NULL == proc) {
    713         return 0;
    714     }
    715     const void* src = bitmap->getAddr(x, y);
    716     if (NULL == src) {
    717         return 0;
    718     }
    719 
    720     SkColor dst[1];
    721     proc(dst, src, 1, bitmap->getColorTable());
    722     return static_cast<jint>(dst[0]);
    723 }
    724 
    725 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
    726         jintArray pixelArray, jint offset, jint stride,
    727         jint x, jint y, jint width, jint height) {
    728     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    729     SkAutoLockPixels alp(*bitmap);
    730 
    731     ToColorProc proc = ChooseToColorProc(*bitmap);
    732     if (NULL == proc) {
    733         return;
    734     }
    735     const void* src = bitmap->getAddr(x, y);
    736     if (NULL == src) {
    737         return;
    738     }
    739 
    740     SkColorTable* ctable = bitmap->getColorTable();
    741     jint* dst = env->GetIntArrayElements(pixelArray, NULL);
    742     SkColor* d = (SkColor*)dst + offset;
    743     while (--height >= 0) {
    744         proc(d, src, width, ctable);
    745         d += stride;
    746         src = (void*)((const char*)src + bitmap->rowBytes());
    747     }
    748     env->ReleaseIntArrayElements(pixelArray, dst, 0);
    749 }
    750 
    751 ///////////////////////////////////////////////////////////////////////////////
    752 
    753 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
    754         jint x, jint y, jint colorHandle) {
    755     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    756     SkColor color = static_cast<SkColor>(colorHandle);
    757     SkAutoLockPixels alp(*bitmap);
    758     if (NULL == bitmap->getPixels()) {
    759         return;
    760     }
    761 
    762     FromColorProc proc = ChooseFromColorProc(*bitmap);
    763     if (NULL == proc) {
    764         return;
    765     }
    766 
    767     proc(bitmap->getAddr(x, y), &color, 1, x, y);
    768     bitmap->notifyPixelsChanged();
    769 }
    770 
    771 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
    772         jintArray pixelArray, jint offset, jint stride,
    773         jint x, jint y, jint width, jint height) {
    774     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    775     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
    776             x, y, width, height, *bitmap);
    777 }
    778 
    779 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
    780                                       jlong bitmapHandle, jobject jbuffer) {
    781     const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    782     SkAutoLockPixels alp(*bitmap);
    783     const void* src = bitmap->getPixels();
    784 
    785     if (NULL != src) {
    786         android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
    787 
    788         // the java side has already checked that buffer is large enough
    789         memcpy(abp.pointer(), src, bitmap->getSize());
    790     }
    791 }
    792 
    793 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
    794                                         jlong bitmapHandle, jobject jbuffer) {
    795     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    796     SkAutoLockPixels alp(*bitmap);
    797     void* dst = bitmap->getPixels();
    798 
    799     if (NULL != dst) {
    800         android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
    801         // the java side has already checked that buffer is large enough
    802         memcpy(dst, abp.pointer(), bitmap->getSize());
    803         bitmap->notifyPixelsChanged();
    804     }
    805 }
    806 
    807 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
    808                               jlong bm1Handle) {
    809     const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
    810     const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
    811     if (bm0->width() != bm1->width() ||
    812         bm0->height() != bm1->height() ||
    813         bm0->colorType() != bm1->colorType()) {
    814         return JNI_FALSE;
    815     }
    816 
    817     SkAutoLockPixels alp0(*bm0);
    818     SkAutoLockPixels alp1(*bm1);
    819 
    820     // if we can't load the pixels, return false
    821     if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
    822         return JNI_FALSE;
    823     }
    824 
    825     if (bm0->colorType() == kIndex_8_SkColorType) {
    826         SkColorTable* ct0 = bm0->getColorTable();
    827         SkColorTable* ct1 = bm1->getColorTable();
    828         if (NULL == ct0 || NULL == ct1) {
    829             return JNI_FALSE;
    830         }
    831         if (ct0->count() != ct1->count()) {
    832             return JNI_FALSE;
    833         }
    834 
    835         SkAutoLockColors alc0(ct0);
    836         SkAutoLockColors alc1(ct1);
    837         const size_t size = ct0->count() * sizeof(SkPMColor);
    838         if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
    839             return JNI_FALSE;
    840         }
    841     }
    842 
    843     // now compare each scanline. We can't do the entire buffer at once,
    844     // since we don't care about the pixel values that might extend beyond
    845     // the width (since the scanline might be larger than the logical width)
    846     const int h = bm0->height();
    847     const size_t size = bm0->width() * bm0->bytesPerPixel();
    848     for (int y = 0; y < h; y++) {
    849         // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
    850         // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
    851         // and bm1 both have pixel data() (have passed NULL == getPixels() check),
    852         // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
    853         // to warn user those 2 unrecognized config bitmaps may be different.
    854         void *bm0Addr = bm0->getAddr(0, y);
    855         void *bm1Addr = bm1->getAddr(0, y);
    856 
    857         if(bm0Addr == NULL || bm1Addr == NULL) {
    858             return JNI_FALSE;
    859         }
    860 
    861         if (memcmp(bm0Addr, bm1Addr, size) != 0) {
    862             return JNI_FALSE;
    863         }
    864     }
    865     return JNI_TRUE;
    866 }
    867 
    868 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
    869     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
    870     bitmap->lockPixels();
    871     bitmap->unlockPixels();
    872 }
    873 
    874 ///////////////////////////////////////////////////////////////////////////////
    875 
    876 #include <android_runtime/AndroidRuntime.h>
    877 
    878 static JNINativeMethod gBitmapMethods[] = {
    879     {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
    880         (void*)Bitmap_creator },
    881     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
    882         (void*)Bitmap_copy },
    883     {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
    884     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
    885     {   "nativeReconfigure",        "(JIIIIZ)V", (void*)Bitmap_reconfigure },
    886     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
    887         (void*)Bitmap_compress },
    888     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
    889     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
    890     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
    891     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
    892     {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
    893     {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
    894     {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
    895     {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
    896     {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
    897     {   "nativeCreateFromParcel",
    898         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
    899         (void*)Bitmap_createFromParcel },
    900     {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
    901         (void*)Bitmap_writeToParcel },
    902     {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
    903         (void*)Bitmap_extractAlpha },
    904     {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
    905     {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
    906     {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
    907     {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
    908     {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
    909     {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
    910                                             (void*)Bitmap_copyPixelsToBuffer },
    911     {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
    912                                             (void*)Bitmap_copyPixelsFromBuffer },
    913     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
    914     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
    915 };
    916 
    917 #define kClassPathName  "android/graphics/Bitmap"
    918 
    919 int register_android_graphics_Bitmap(JNIEnv* env)
    920 {
    921     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
    922                                 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
    923 }
    924