Home | History | Annotate | Download | only in graphics
      1 #define LOG_TAG "Bitmap"
      2 #include "Bitmap.h"
      3 
      4 #include "GraphicBuffer.h"
      5 #include "SkBitmap.h"
      6 #include "SkPixelRef.h"
      7 #include "SkImageEncoder.h"
      8 #include "SkImageInfo.h"
      9 #include "SkColor.h"
     10 #include "SkColorPriv.h"
     11 #include "SkColorSpace.h"
     12 #include "SkColorSpaceXform.h"
     13 #include "SkHalf.h"
     14 #include "SkMatrix44.h"
     15 #include "SkPM4f.h"
     16 #include "SkPM4fPriv.h"
     17 #include "GraphicsJNI.h"
     18 #include "SkDither.h"
     19 #include "SkUnPreMultiply.h"
     20 #include "SkStream.h"
     21 
     22 #include <binder/Parcel.h>
     23 #include "android_os_Parcel.h"
     24 #include "android_util_Binder.h"
     25 #include "android_nio_utils.h"
     26 #include "CreateJavaOutputStreamAdaptor.h"
     27 #include <hwui/Paint.h>
     28 #include <hwui/Bitmap.h>
     29 #include <renderthread/RenderProxy.h>
     30 
     31 #include "core_jni_helpers.h"
     32 
     33 #include <jni.h>
     34 #include <string.h>
     35 #include <memory>
     36 #include <string>
     37 
     38 #define DEBUG_PARCEL 0
     39 #define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
     40 
     41 static jclass   gBitmap_class;
     42 static jfieldID gBitmap_nativePtr;
     43 static jmethodID gBitmap_constructorMethodID;
     44 static jmethodID gBitmap_reinitMethodID;
     45 static jmethodID gBitmap_getAllocationByteCountMethodID;
     46 
     47 namespace android {
     48 
     49 class BitmapWrapper {
     50 public:
     51     BitmapWrapper(Bitmap* bitmap)
     52         : mBitmap(bitmap) { }
     53 
     54     void freePixels() {
     55         mInfo = mBitmap->info();
     56         mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
     57         mAllocationSize = mBitmap->getAllocationByteCount();
     58         mRowBytes = mBitmap->rowBytes();
     59         mGenerationId = mBitmap->getGenerationID();
     60         mIsHardware = mBitmap->isHardware();
     61         mBitmap.reset();
     62     }
     63 
     64     bool valid() {
     65         return mBitmap;
     66     }
     67 
     68     Bitmap& bitmap() {
     69         assertValid();
     70         return *mBitmap;
     71     }
     72 
     73     void assertValid() {
     74         LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
     75     }
     76 
     77     void getSkBitmap(SkBitmap* outBitmap) {
     78         assertValid();
     79         mBitmap->getSkBitmap(outBitmap);
     80     }
     81 
     82     bool hasHardwareMipMap() {
     83         if (mBitmap) {
     84             return mBitmap->hasHardwareMipMap();
     85         }
     86         return mHasHardwareMipMap;
     87     }
     88 
     89     void setHasHardwareMipMap(bool hasMipMap) {
     90         assertValid();
     91         mBitmap->setHasHardwareMipMap(hasMipMap);
     92     }
     93 
     94     void setAlphaType(SkAlphaType alphaType) {
     95         assertValid();
     96         mBitmap->setAlphaType(alphaType);
     97     }
     98 
     99     const SkImageInfo& info() {
    100         if (mBitmap) {
    101             return mBitmap->info();
    102         }
    103         return mInfo;
    104     }
    105 
    106     size_t getAllocationByteCount() const {
    107         if (mBitmap) {
    108             return mBitmap->getAllocationByteCount();
    109         }
    110         return mAllocationSize;
    111     }
    112 
    113     size_t rowBytes() const {
    114         if (mBitmap) {
    115             return mBitmap->rowBytes();
    116         }
    117         return mRowBytes;
    118     }
    119 
    120     uint32_t getGenerationID() const {
    121         if (mBitmap) {
    122             return mBitmap->getGenerationID();
    123         }
    124         return mGenerationId;
    125     }
    126 
    127     bool isHardware() {
    128         if (mBitmap) {
    129             return mBitmap->isHardware();
    130         }
    131         return mIsHardware;
    132     }
    133 
    134     ~BitmapWrapper() { }
    135 
    136 private:
    137     sk_sp<Bitmap> mBitmap;
    138     SkImageInfo mInfo;
    139     bool mHasHardwareMipMap;
    140     size_t mAllocationSize;
    141     size_t mRowBytes;
    142     uint32_t mGenerationId;
    143     bool mIsHardware;
    144 };
    145 
    146 // Convenience class that does not take a global ref on the pixels, relying
    147 // on the caller already having a local JNI ref
    148 class LocalScopedBitmap {
    149 public:
    150     explicit LocalScopedBitmap(jlong bitmapHandle)
    151             : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
    152 
    153     BitmapWrapper* operator->() {
    154         return mBitmapWrapper;
    155     }
    156 
    157     void* pixels() {
    158         return mBitmapWrapper->bitmap().pixels();
    159     }
    160 
    161     bool valid() {
    162         return mBitmapWrapper && mBitmapWrapper->valid();
    163     }
    164 
    165 private:
    166     BitmapWrapper* mBitmapWrapper;
    167 };
    168 
    169 namespace bitmap {
    170 
    171 // Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
    172 static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
    173     // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
    174     // irrelevant. This just tests to ensure that the SkAlphaType is not
    175     // opposite of isPremultiplied.
    176     if (isPremultiplied) {
    177         SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
    178     } else {
    179         SkASSERT(info.alphaType() != kPremul_SkAlphaType);
    180     }
    181 }
    182 
    183 void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
    184         bool isPremultiplied)
    185 {
    186     // The caller needs to have already set the alpha type properly, so the
    187     // native SkBitmap stays in sync with the Java Bitmap.
    188     assert_premultiplied(info, isPremultiplied);
    189 
    190     env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
    191             info.width(), info.height(), isPremultiplied);
    192 }
    193 
    194 int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
    195 {
    196     return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
    197 }
    198 
    199 jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
    200         int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
    201         int density) {
    202     bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
    203     bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
    204     // The caller needs to have already set the alpha type properly, so the
    205     // native SkBitmap stays in sync with the Java Bitmap.
    206     assert_premultiplied(bitmap->info(), isPremultiplied);
    207     BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
    208     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
    209             reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
    210             isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets);
    211 
    212     if (env->ExceptionCheck() != 0) {
    213         ALOGE("*** Uncaught exception returned from Java call!\n");
    214         env->ExceptionDescribe();
    215     }
    216     return obj;
    217 }
    218 
    219 void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
    220     LocalScopedBitmap bitmap(bitmapHandle);
    221     bitmap->getSkBitmap(outBitmap);
    222 }
    223 
    224 Bitmap& toBitmap(JNIEnv* env, jobject bitmap) {
    225     SkASSERT(env);
    226     SkASSERT(bitmap);
    227     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    228     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    229     LocalScopedBitmap localBitmap(bitmapHandle);
    230     return localBitmap->bitmap();
    231 }
    232 
    233 Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) {
    234     SkASSERT(env);
    235     LocalScopedBitmap localBitmap(bitmapHandle);
    236     return localBitmap->bitmap();
    237 }
    238 
    239 void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) {
    240     SkASSERT(info);
    241     SkASSERT(env);
    242     SkASSERT(bitmap);
    243     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    244     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    245     LocalScopedBitmap localBitmap(bitmapHandle);
    246 
    247     const SkImageInfo& imageInfo = localBitmap->info();
    248     info->width = imageInfo.width();
    249     info->height = imageInfo.height();
    250     info->stride = localBitmap->rowBytes();
    251     info->flags = 0;
    252     switch (imageInfo.colorType()) {
    253         case kN32_SkColorType:
    254             info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
    255             break;
    256         case kRGB_565_SkColorType:
    257             info->format = ANDROID_BITMAP_FORMAT_RGB_565;
    258             break;
    259         case kARGB_4444_SkColorType:
    260             info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
    261             break;
    262         case kAlpha_8_SkColorType:
    263             info->format = ANDROID_BITMAP_FORMAT_A_8;
    264             break;
    265         default:
    266             info->format = ANDROID_BITMAP_FORMAT_NONE;
    267             break;
    268     }
    269 }
    270 
    271 void* lockPixels(JNIEnv* env, jobject bitmap) {
    272     SkASSERT(env);
    273     SkASSERT(bitmap);
    274     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    275     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    276 
    277     LocalScopedBitmap localBitmap(bitmapHandle);
    278     if (!localBitmap->valid()) return nullptr;
    279 
    280     SkPixelRef& pixelRef = localBitmap->bitmap();
    281     if (!pixelRef.pixels()) {
    282         return nullptr;
    283     }
    284     pixelRef.ref();
    285     return pixelRef.pixels();
    286 }
    287 
    288 bool unlockPixels(JNIEnv* env, jobject bitmap) {
    289     SkASSERT(env);
    290     SkASSERT(bitmap);
    291     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    292     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    293 
    294     LocalScopedBitmap localBitmap(bitmapHandle);
    295     if (!localBitmap->valid()) return false;
    296 
    297     SkPixelRef& pixelRef = localBitmap->bitmap();
    298     pixelRef.notifyPixelsChanged();
    299     pixelRef.unref();
    300     return true;
    301 }
    302 
    303 } // namespace bitmap
    304 
    305 } // namespace android
    306 
    307 using namespace android;
    308 using namespace android::bitmap;
    309 
    310 ///////////////////////////////////////////////////////////////////////////////
    311 // Conversions to/from SkColor, for get/setPixels, and the create method, which
    312 // is basically like setPixels
    313 
    314 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
    315                               int x, int y);
    316 
    317 static void FromColor_F16(void* dst, const SkColor src[], int width,
    318                           int, int) {
    319     uint64_t* d = (uint64_t*)dst;
    320 
    321     for (int i = 0; i < width; i++) {
    322         *d++ = SkColor4f::FromColor(*src++).premul().toF16();
    323     }
    324 }
    325 
    326 static void FromColor_F16_Raw(void* dst, const SkColor src[], int width,
    327                           int, int) {
    328     uint64_t* d = (uint64_t*)dst;
    329 
    330     for (int i = 0; i < width; i++) {
    331         const SkColor4f color = SkColor4f::FromColor(*src++);
    332         uint16_t* scratch = reinterpret_cast<uint16_t*>(d++);
    333         scratch[0] = SkFloatToHalf(color.fR);
    334         scratch[1] = SkFloatToHalf(color.fG);
    335         scratch[2] = SkFloatToHalf(color.fB);
    336         scratch[3] = SkFloatToHalf(color.fA);
    337     }
    338 }
    339 
    340 static void FromColor_D32(void* dst, const SkColor src[], int width,
    341                           int, int) {
    342     SkPMColor* d = (SkPMColor*)dst;
    343 
    344     for (int i = 0; i < width; i++) {
    345         *d++ = SkPreMultiplyColor(*src++);
    346     }
    347 }
    348 
    349 static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
    350                           int, int) {
    351     // Needed to thwart the unreachable code detection from clang.
    352     static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
    353 
    354     // SkColor's ordering may be different from SkPMColor
    355     if (sk_color_ne_zero) {
    356         memcpy(dst, src, width * sizeof(SkColor));
    357         return;
    358     }
    359 
    360     // order isn't same, repack each pixel manually
    361     SkPMColor* d = (SkPMColor*)dst;
    362     for (int i = 0; i < width; i++) {
    363         SkColor c = *src++;
    364         *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
    365                                    SkColorGetG(c), SkColorGetB(c));
    366     }
    367 }
    368 
    369 static void FromColor_D565(void* dst, const SkColor src[], int width,
    370                            int x, int y) {
    371     uint16_t* d = (uint16_t*)dst;
    372 
    373     DITHER_565_SCAN(y);
    374     for (int stop = x + width; x < stop; x++) {
    375         SkColor c = *src++;
    376         *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
    377                                 DITHER_VALUE(x));
    378     }
    379 }
    380 
    381 static void FromColor_D4444(void* dst, const SkColor src[], int width,
    382                             int x, int y) {
    383     SkPMColor16* d = (SkPMColor16*)dst;
    384 
    385     DITHER_4444_SCAN(y);
    386     for (int stop = x + width; x < stop; x++) {
    387         SkPMColor pmc = SkPreMultiplyColor(*src++);
    388         *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
    389 //        *d++ = SkPixel32ToPixel4444(pmc);
    390     }
    391 }
    392 
    393 static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
    394                             int x, int y) {
    395     SkPMColor16* d = (SkPMColor16*)dst;
    396 
    397     DITHER_4444_SCAN(y);
    398     for (int stop = x + width; x < stop; x++) {
    399         SkColor c = *src++;
    400 
    401         // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
    402         SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
    403                                             SkColorGetG(c), SkColorGetB(c));
    404         *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
    405 //        *d++ = SkPixel32ToPixel4444(pmc);
    406     }
    407 }
    408 
    409 static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
    410     uint8_t* d = (uint8_t*)dst;
    411 
    412     for (int stop = x + width; x < stop; x++) {
    413         *d++ = SkColorGetA(*src++);
    414     }
    415 }
    416 
    417 // can return NULL
    418 static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
    419     switch (bitmap.colorType()) {
    420         case kN32_SkColorType:
    421             return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
    422         case kARGB_4444_SkColorType:
    423             return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
    424                     FromColor_D4444_Raw;
    425         case kRGB_565_SkColorType:
    426             return FromColor_D565;
    427         case kAlpha_8_SkColorType:
    428             return FromColor_DA8;
    429         case kRGBA_F16_SkColorType:
    430             return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw;
    431         default:
    432             break;
    433     }
    434     return NULL;
    435 }
    436 
    437 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
    438         int x, int y, int width, int height, const SkBitmap& dstBitmap) {
    439     void* dst = dstBitmap.getPixels();
    440     FromColorProc proc = ChooseFromColorProc(dstBitmap);
    441 
    442     if (NULL == dst || NULL == proc) {
    443         return false;
    444     }
    445 
    446     const jint* array = env->GetIntArrayElements(srcColors, NULL);
    447     const SkColor* src = (const SkColor*)array + srcOffset;
    448 
    449     // reset to to actual choice from caller
    450     dst = dstBitmap.getAddr(x, y);
    451 
    452     SkColorSpace* colorSpace = dstBitmap.colorSpace();
    453     if (dstBitmap.colorType() == kRGBA_F16_SkColorType ||
    454             GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
    455         // now copy/convert each scanline
    456         for (int y = 0; y < height; y++) {
    457             proc(dst, src, width, x, y);
    458             src += srcStride;
    459             dst = (char*)dst + dstBitmap.rowBytes();
    460         }
    461     } else {
    462         auto sRGB = SkColorSpace::MakeSRGB();
    463         auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
    464 
    465         std::unique_ptr<SkColor[]> row(new SkColor[width]);
    466 
    467         // now copy/convert each scanline
    468         for (int y = 0; y < height; y++) {
    469             memcpy(row.get(), src, sizeof(SkColor) * width);
    470             xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(),
    471                     SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), width,
    472                     SkAlphaType::kUnpremul_SkAlphaType);
    473 
    474             proc(dst, row.get(), width, x, y);
    475             src += srcStride;
    476             dst = (char*)dst + dstBitmap.rowBytes();
    477         }
    478     }
    479 
    480     dstBitmap.notifyPixelsChanged();
    481 
    482     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
    483     return true;
    484 }
    485 
    486 //////////////////// ToColor procs
    487 
    488 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width);
    489 
    490 static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width) {
    491     SkASSERT(width > 0);
    492     uint64_t* s = (uint64_t*)src;
    493     do {
    494         *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor();
    495     } while (--width != 0);
    496 }
    497 
    498 static void ToColor_F16_Raw(SkColor dst[], const void* src, int width) {
    499     SkASSERT(width > 0);
    500     uint64_t* s = (uint64_t*)src;
    501     do {
    502         *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++)));
    503     } while (--width != 0);
    504 }
    505 
    506 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width) {
    507     SkASSERT(width > 0);
    508     const SkPMColor* s = (const SkPMColor*)src;
    509     do {
    510         *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
    511     } while (--width != 0);
    512 }
    513 
    514 static void ToColor_S32_Raw(SkColor dst[], const void* src, int width) {
    515     SkASSERT(width > 0);
    516     const SkPMColor* s = (const SkPMColor*)src;
    517     do {
    518         SkPMColor c = *s++;
    519         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
    520                                 SkGetPackedG32(c), SkGetPackedB32(c));
    521     } while (--width != 0);
    522 }
    523 
    524 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width) {
    525     SkASSERT(width > 0);
    526     const SkPMColor* s = (const SkPMColor*)src;
    527     do {
    528         SkPMColor c = *s++;
    529         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
    530                                SkGetPackedB32(c));
    531     } while (--width != 0);
    532 }
    533 
    534 static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width) {
    535     SkASSERT(width > 0);
    536     const SkPMColor16* s = (const SkPMColor16*)src;
    537     do {
    538         *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
    539     } while (--width != 0);
    540 }
    541 
    542 static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width) {
    543     SkASSERT(width > 0);
    544     const SkPMColor16* s = (const SkPMColor16*)src;
    545     do {
    546         SkPMColor c = SkPixel4444ToPixel32(*s++);
    547         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
    548                                 SkGetPackedG32(c), SkGetPackedB32(c));
    549     } while (--width != 0);
    550 }
    551 
    552 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width) {
    553     SkASSERT(width > 0);
    554     const SkPMColor16* s = (const SkPMColor16*)src;
    555     do {
    556         SkPMColor c = SkPixel4444ToPixel32(*s++);
    557         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
    558                                SkGetPackedB32(c));
    559     } while (--width != 0);
    560 }
    561 
    562 static void ToColor_S565(SkColor dst[], const void* src, int width) {
    563     SkASSERT(width > 0);
    564     const uint16_t* s = (const uint16_t*)src;
    565     do {
    566         uint16_t c = *s++;
    567         *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
    568                                 SkPacked16ToB32(c));
    569     } while (--width != 0);
    570 }
    571 
    572 static void ToColor_SA8(SkColor dst[], const void* src, int width) {
    573     SkASSERT(width > 0);
    574     const uint8_t* s = (const uint8_t*)src;
    575     do {
    576         uint8_t c = *s++;
    577         *dst++ = SkColorSetARGB(c, 0, 0, 0);
    578     } while (--width != 0);
    579 }
    580 
    581 // can return NULL
    582 static ToColorProc ChooseToColorProc(const SkBitmap& src) {
    583     switch (src.colorType()) {
    584         case kN32_SkColorType:
    585             switch (src.alphaType()) {
    586                 case kOpaque_SkAlphaType:
    587                     return ToColor_S32_Opaque;
    588                 case kPremul_SkAlphaType:
    589                     return ToColor_S32_Alpha;
    590                 case kUnpremul_SkAlphaType:
    591                     return ToColor_S32_Raw;
    592                 default:
    593                     return NULL;
    594             }
    595         case kARGB_4444_SkColorType:
    596             switch (src.alphaType()) {
    597                 case kOpaque_SkAlphaType:
    598                     return ToColor_S4444_Opaque;
    599                 case kPremul_SkAlphaType:
    600                     return ToColor_S4444_Alpha;
    601                 case kUnpremul_SkAlphaType:
    602                     return ToColor_S4444_Raw;
    603                 default:
    604                     return NULL;
    605             }
    606         case kRGB_565_SkColorType:
    607             return ToColor_S565;
    608         case kAlpha_8_SkColorType:
    609             return ToColor_SA8;
    610         case kRGBA_F16_SkColorType:
    611             switch (src.alphaType()) {
    612                 case kOpaque_SkAlphaType:
    613                     return ToColor_F16_Raw;
    614                 case kPremul_SkAlphaType:
    615                     return ToColor_F16_Alpha;
    616                 case kUnpremul_SkAlphaType:
    617                     return ToColor_F16_Raw;
    618                 default:
    619                     return NULL;
    620             }
    621         default:
    622             break;
    623     }
    624     return NULL;
    625 }
    626 
    627 static void ToF16_SA8(void* dst, const void* src, int width) {
    628     SkASSERT(width > 0);
    629     uint64_t* d = (uint64_t*)dst;
    630     const uint8_t* s = (const uint8_t*)src;
    631 
    632     for (int i = 0; i < width; i++) {
    633         uint8_t c = *s++;
    634         SkPM4f a;
    635         a.fVec[SkPM4f::R] = 0.0f;
    636         a.fVec[SkPM4f::G] = 0.0f;
    637         a.fVec[SkPM4f::B] = 0.0f;
    638         a.fVec[SkPM4f::A] = c / 255.0f;
    639         *d++ = a.toF16();
    640     }
    641 }
    642 
    643 ///////////////////////////////////////////////////////////////////////////////
    644 ///////////////////////////////////////////////////////////////////////////////
    645 
    646 static int getPremulBitmapCreateFlags(bool isMutable) {
    647     int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
    648     if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
    649     return flags;
    650 }
    651 
    652 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
    653                               jint offset, jint stride, jint width, jint height,
    654                               jint configHandle, jboolean isMutable,
    655                               jfloatArray xyzD50, jobject transferParameters) {
    656     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
    657     if (NULL != jColors) {
    658         size_t n = env->GetArrayLength(jColors);
    659         if (n < SkAbs32(stride) * (size_t)height) {
    660             doThrowAIOOBE(env);
    661             return NULL;
    662         }
    663     }
    664 
    665     // ARGB_4444 is a deprecated format, convert automatically to 8888
    666     if (colorType == kARGB_4444_SkColorType) {
    667         colorType = kN32_SkColorType;
    668     }
    669 
    670     SkBitmap bitmap;
    671     sk_sp<SkColorSpace> colorSpace;
    672 
    673     if (colorType != kN32_SkColorType || xyzD50 == nullptr || transferParameters == nullptr) {
    674         colorSpace = GraphicsJNI::colorSpaceForType(colorType);
    675     } else {
    676         SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
    677         SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
    678         colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
    679     }
    680 
    681     bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace));
    682 
    683     sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
    684     if (!nativeBitmap) {
    685         return NULL;
    686     }
    687 
    688     if (jColors != NULL) {
    689         GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);
    690     }
    691 
    692     return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
    693 }
    694 
    695 static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
    696         SkBitmap::Allocator* alloc) {
    697     SkPixmap srcPM;
    698     if (!src.peekPixels(&srcPM)) {
    699         return false;
    700     }
    701 
    702     SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
    703     switch (dstCT) {
    704         case kRGB_565_SkColorType:
    705             // copyTo() has never been strict on alpha type.  Here we set the src to opaque to
    706             // allow the call to readPixels() to succeed and preserve this lenient behavior.
    707             if (kOpaque_SkAlphaType != srcPM.alphaType()) {
    708                 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
    709                                  srcPM.rowBytes());
    710                 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
    711             }
    712             break;
    713         case kRGBA_F16_SkColorType:
    714             // The caller does not have an opportunity to pass a dst color space.  Assume that
    715             // they want linear sRGB.
    716             dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
    717 
    718             if (!srcPM.colorSpace()) {
    719                 // Skia needs a color space to convert to F16.  nullptr should be treated as sRGB.
    720                 srcPM.setColorSpace(SkColorSpace::MakeSRGB());
    721             }
    722             break;
    723         default:
    724             break;
    725     }
    726 
    727     if (!dst->setInfo(dstInfo)) {
    728         return false;
    729     }
    730     if (!dst->tryAllocPixels(alloc)) {
    731         return false;
    732     }
    733 
    734     // Skia does not support copying from kAlpha8 to types that are not alpha only.
    735     // We will handle this case here.
    736     if (kAlpha_8_SkColorType == srcPM.colorType() && kAlpha_8_SkColorType != dstCT) {
    737         switch (dstCT) {
    738             case kRGBA_8888_SkColorType:
    739             case kBGRA_8888_SkColorType: {
    740                 for (int y = 0; y < src.height(); y++) {
    741                     const uint8_t* srcRow = srcPM.addr8(0, y);
    742                     uint32_t* dstRow = dst->getAddr32(0, y);
    743                     ToColor_SA8(dstRow, srcRow, src.width());
    744                 }
    745                 return true;
    746             }
    747             case kRGB_565_SkColorType: {
    748                 for (int y = 0; y < src.height(); y++) {
    749                     uint16_t* dstRow = dst->getAddr16(0, y);
    750                     memset(dstRow, 0, sizeof(uint16_t) * src.width());
    751                 }
    752                 return true;
    753             }
    754             case kRGBA_F16_SkColorType: {
    755                for (int y = 0; y < src.height(); y++) {
    756                    const uint8_t* srcRow = srcPM.addr8(0, y);
    757                    void* dstRow = dst->getAddr(0, y);
    758                    ToF16_SA8(dstRow, srcRow, src.width());
    759                }
    760                return true;
    761            }
    762             default:
    763                 return false;
    764         }
    765     }
    766 
    767     SkPixmap dstPM;
    768     if (!dst->peekPixels(&dstPM)) {
    769         return false;
    770     }
    771 
    772     // Skia needs a color space to convert from F16.  nullptr should be treated as sRGB.
    773     if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
    774         dstPM.setColorSpace(SkColorSpace::MakeSRGB());
    775     }
    776 
    777     // readPixels does not support color spaces with parametric transfer functions.  This
    778     // works around that restriction when the color spaces are equal.
    779     if (kRGBA_F16_SkColorType != dstCT && kRGBA_F16_SkColorType != srcPM.colorType() &&
    780             dstPM.colorSpace() == srcPM.colorSpace()) {
    781         dstPM.setColorSpace(nullptr);
    782         srcPM.setColorSpace(nullptr);
    783     }
    784 
    785     return srcPM.readPixels(dstPM);
    786 }
    787 
    788 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
    789                            jint dstConfigHandle, jboolean isMutable) {
    790     SkBitmap src;
    791     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    792     if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
    793         sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
    794         if (!bitmap.get()) {
    795             return NULL;
    796         }
    797         return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
    798     }
    799 
    800     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
    801     SkBitmap result;
    802     HeapAllocator allocator;
    803 
    804     if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
    805         return NULL;
    806     }
    807     auto bitmap = allocator.getStorageObjAndReset();
    808     return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
    809 }
    810 
    811 static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
    812     SkBitmap result;
    813 
    814     AshmemPixelAllocator allocator(env);
    815     if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
    816         return NULL;
    817     }
    818     auto bitmap = allocator.getStorageObjAndReset();
    819     bitmap->setImmutable();
    820     return bitmap;
    821 }
    822 
    823 static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
    824     SkBitmap src;
    825     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    826     SkColorType dstCT = src.colorType();
    827     auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
    828     jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
    829     return ret;
    830 }
    831 
    832 static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
    833     SkBitmap src;
    834     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    835     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
    836     auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
    837     jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
    838     return ret;
    839 }
    840 
    841 static void Bitmap_destruct(BitmapWrapper* bitmap) {
    842     delete bitmap;
    843 }
    844 
    845 static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
    846     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
    847 }
    848 
    849 static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
    850     LocalScopedBitmap bitmap(bitmapHandle);
    851     bitmap->freePixels();
    852     return JNI_TRUE;
    853 }
    854 
    855 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    856         jint width, jint height, jint configHandle, jboolean requestPremul) {
    857     LocalScopedBitmap bitmap(bitmapHandle);
    858     bitmap->assertValid();
    859     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
    860 
    861     // ARGB_4444 is a deprecated format, convert automatically to 8888
    862     if (colorType == kARGB_4444_SkColorType) {
    863         colorType = kN32_SkColorType;
    864     }
    865     size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
    866     if (requestedSize > bitmap->getAllocationByteCount()) {
    867         // done in native as there's no way to get BytesPerPixel in Java
    868         doThrowIAE(env, "Bitmap not large enough to support new configuration");
    869         return;
    870     }
    871     SkAlphaType alphaType;
    872     if (bitmap->info().colorType() != kRGB_565_SkColorType
    873             && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
    874         // If the original bitmap was set to opaque, keep that setting, unless it
    875         // was 565, which is required to be opaque.
    876         alphaType = kOpaque_SkAlphaType;
    877     } else {
    878         // Otherwise respect the premultiplied request.
    879         alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
    880     }
    881     bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
    882             sk_ref_sp(bitmap->info().colorSpace())));
    883 }
    884 
    885 // These must match the int values in Bitmap.java
    886 enum JavaEncodeFormat {
    887     kJPEG_JavaEncodeFormat = 0,
    888     kPNG_JavaEncodeFormat = 1,
    889     kWEBP_JavaEncodeFormat = 2
    890 };
    891 
    892 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    893                                 jint format, jint quality,
    894                                 jobject jstream, jbyteArray jstorage) {
    895     SkEncodedImageFormat fm;
    896     switch (format) {
    897     case kJPEG_JavaEncodeFormat:
    898         fm = SkEncodedImageFormat::kJPEG;
    899         break;
    900     case kPNG_JavaEncodeFormat:
    901         fm = SkEncodedImageFormat::kPNG;
    902         break;
    903     case kWEBP_JavaEncodeFormat:
    904         fm = SkEncodedImageFormat::kWEBP;
    905         break;
    906     default:
    907         return JNI_FALSE;
    908     }
    909 
    910     LocalScopedBitmap bitmap(bitmapHandle);
    911     if (!bitmap.valid()) {
    912         return JNI_FALSE;
    913     }
    914 
    915     std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
    916     if (!strm.get()) {
    917         return JNI_FALSE;
    918     }
    919 
    920     SkBitmap skbitmap;
    921     bitmap->getSkBitmap(&skbitmap);
    922     return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
    923 }
    924 
    925 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
    926     LocalScopedBitmap bitmap(bitmapHandle);
    927     SkBitmap skBitmap;
    928     bitmap->getSkBitmap(&skBitmap);
    929     skBitmap.eraseColor(color);
    930 }
    931 
    932 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
    933     LocalScopedBitmap bitmap(bitmapHandle);
    934     return static_cast<jint>(bitmap->rowBytes());
    935 }
    936 
    937 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
    938     LocalScopedBitmap bitmap(bitmapHandle);
    939     if (bitmap->isHardware()) {
    940         return GraphicsJNI::hardwareLegacyBitmapConfig();
    941     }
    942     return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
    943 }
    944 
    945 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
    946     LocalScopedBitmap bitmap(bitmapHandle);
    947     return static_cast<jint>(bitmap->getGenerationID());
    948 }
    949 
    950 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
    951     LocalScopedBitmap bitmap(bitmapHandle);
    952     if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
    953         return JNI_TRUE;
    954     }
    955     return JNI_FALSE;
    956 }
    957 
    958 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
    959     LocalScopedBitmap bitmap(bitmapHandle);
    960     return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
    961 }
    962 
    963 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
    964         jboolean hasAlpha, jboolean requestPremul) {
    965     LocalScopedBitmap bitmap(bitmapHandle);
    966     if (hasAlpha) {
    967         bitmap->setAlphaType(
    968                 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
    969     } else {
    970         bitmap->setAlphaType(kOpaque_SkAlphaType);
    971     }
    972 }
    973 
    974 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
    975         jboolean isPremul) {
    976     LocalScopedBitmap bitmap(bitmapHandle);
    977     if (!bitmap->info().isOpaque()) {
    978         if (isPremul) {
    979             bitmap->setAlphaType(kPremul_SkAlphaType);
    980         } else {
    981             bitmap->setAlphaType(kUnpremul_SkAlphaType);
    982         }
    983     }
    984 }
    985 
    986 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
    987     LocalScopedBitmap bitmap(bitmapHandle);
    988     return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
    989 }
    990 
    991 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
    992                                 jboolean hasMipMap) {
    993     LocalScopedBitmap bitmap(bitmapHandle);
    994     bitmap->setHasHardwareMipMap(hasMipMap);
    995 }
    996 
    997 ///////////////////////////////////////////////////////////////////////////////
    998 
    999 // This is the maximum possible size because the SkColorSpace must be
   1000 // representable (and therefore serializable) using a matrix and numerical
   1001 // transfer function.  If we allow more color space representations in the
   1002 // framework, we may need to update this maximum size.
   1003 static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
   1004 
   1005 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
   1006     if (parcel == NULL) {
   1007         SkDebugf("-------- unparcel parcel is NULL\n");
   1008         return NULL;
   1009     }
   1010 
   1011     android::Parcel* p = android::parcelForJavaObject(env, parcel);
   1012 
   1013     const bool        isMutable = p->readInt32() != 0;
   1014     const SkColorType colorType = (SkColorType)p->readInt32();
   1015     const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
   1016     const uint32_t    colorSpaceSize = p->readUint32();
   1017     sk_sp<SkColorSpace> colorSpace;
   1018     if (kRGBA_F16_SkColorType == colorType) {
   1019         colorSpace = SkColorSpace::MakeSRGBLinear();
   1020     } else if (colorSpaceSize > 0) {
   1021         if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
   1022             ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
   1023                     "%d bytes\n", colorSpaceSize);
   1024         }
   1025 
   1026         const void* data = p->readInplace(colorSpaceSize);
   1027         if (data) {
   1028             colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
   1029         } else {
   1030             ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
   1031         }
   1032     }
   1033     const int         width = p->readInt32();
   1034     const int         height = p->readInt32();
   1035     const int         rowBytes = p->readInt32();
   1036     const int         density = p->readInt32();
   1037 
   1038     if (kN32_SkColorType != colorType &&
   1039             kRGBA_F16_SkColorType != colorType &&
   1040             kRGB_565_SkColorType != colorType &&
   1041             kARGB_4444_SkColorType != colorType &&
   1042             kAlpha_8_SkColorType != colorType) {
   1043         SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
   1044         return NULL;
   1045     }
   1046 
   1047     std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
   1048     if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
   1049             rowBytes)) {
   1050         return NULL;
   1051     }
   1052 
   1053     // Read the bitmap blob.
   1054     size_t size = bitmap->getSize();
   1055     android::Parcel::ReadableBlob blob;
   1056     android::status_t status = p->readBlob(size, &blob);
   1057     if (status) {
   1058         doThrowRE(env, "Could not read bitmap blob.");
   1059         return NULL;
   1060     }
   1061 
   1062     // Map the bitmap in place from the ashmem region if possible otherwise copy.
   1063     sk_sp<Bitmap> nativeBitmap;
   1064     if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
   1065 #if DEBUG_PARCEL
   1066         ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
   1067                 "(fds %s)",
   1068                 isMutable ? "mutable" : "immutable",
   1069                 blob.isMutable() ? "mutable" : "immutable",
   1070                 p->allowFds() ? "allowed" : "forbidden");
   1071 #endif
   1072         // Dup the file descriptor so we can keep a reference to it after the Parcel
   1073         // is disposed.
   1074         int dupFd = dup(blob.fd());
   1075         if (dupFd < 0) {
   1076             ALOGE("Error allocating dup fd. Error:%d", errno);
   1077             blob.release();
   1078             doThrowRE(env, "Could not allocate dup blob fd.");
   1079             return NULL;
   1080         }
   1081 
   1082         // Map the pixels in place and take ownership of the ashmem region.
   1083         nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
   1084                 dupFd, const_cast<void*>(blob.data()), size, !isMutable));
   1085         if (!nativeBitmap) {
   1086             close(dupFd);
   1087             blob.release();
   1088             doThrowRE(env, "Could not allocate ashmem pixel ref.");
   1089             return NULL;
   1090         }
   1091 
   1092         // Clear the blob handle, don't release it.
   1093         blob.clear();
   1094     } else {
   1095 #if DEBUG_PARCEL
   1096         if (blob.fd() >= 0) {
   1097             ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
   1098                     "from immutable blob (fds %s)",
   1099                     p->allowFds() ? "allowed" : "forbidden");
   1100         } else {
   1101             ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
   1102                     "(fds %s)",
   1103                     blob.isMutable() ? "mutable" : "immutable",
   1104                     p->allowFds() ? "allowed" : "forbidden");
   1105         }
   1106 #endif
   1107 
   1108         // Copy the pixels into a new buffer.
   1109         nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
   1110         if (!nativeBitmap) {
   1111             blob.release();
   1112             doThrowRE(env, "Could not allocate java pixel ref.");
   1113             return NULL;
   1114         }
   1115         memcpy(bitmap->getPixels(), blob.data(), size);
   1116 
   1117         // Release the blob handle.
   1118         blob.release();
   1119     }
   1120 
   1121     return createBitmap(env, nativeBitmap.release(),
   1122             getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
   1123 }
   1124 
   1125 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
   1126                                      jlong bitmapHandle,
   1127                                      jboolean isMutable, jint density,
   1128                                      jobject parcel) {
   1129     if (parcel == NULL) {
   1130         SkDebugf("------- writeToParcel null parcel\n");
   1131         return JNI_FALSE;
   1132     }
   1133 
   1134     android::Parcel* p = android::parcelForJavaObject(env, parcel);
   1135     SkBitmap bitmap;
   1136 
   1137     auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
   1138     bitmapWrapper->getSkBitmap(&bitmap);
   1139 
   1140     p->writeInt32(isMutable);
   1141     p->writeInt32(bitmap.colorType());
   1142     p->writeInt32(bitmap.alphaType());
   1143     SkColorSpace* colorSpace = bitmap.colorSpace();
   1144     if (colorSpace != nullptr && bitmap.colorType() != kRGBA_F16_SkColorType) {
   1145         sk_sp<SkData> data = colorSpace->serialize();
   1146         size_t size = data->size();
   1147         p->writeUint32(size);
   1148         if (size > 0) {
   1149             if (size > kMaxColorSpaceSerializedBytes) {
   1150                 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
   1151                         "%zu bytes\n", size);
   1152             }
   1153 
   1154             p->write(data->data(), size);
   1155         }
   1156     } else {
   1157         p->writeUint32(0);
   1158     }
   1159     p->writeInt32(bitmap.width());
   1160     p->writeInt32(bitmap.height());
   1161     p->writeInt32(bitmap.rowBytes());
   1162     p->writeInt32(density);
   1163 
   1164     // Transfer the underlying ashmem region if we have one and it's immutable.
   1165     android::status_t status;
   1166     int fd = bitmapWrapper->bitmap().getAshmemFd();
   1167     if (fd >= 0 && !isMutable && p->allowFds()) {
   1168 #if DEBUG_PARCEL
   1169         ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
   1170                 "immutable blob (fds %s)",
   1171                 p->allowFds() ? "allowed" : "forbidden");
   1172 #endif
   1173 
   1174         status = p->writeDupImmutableBlobFileDescriptor(fd);
   1175         if (status) {
   1176             doThrowRE(env, "Could not write bitmap blob file descriptor.");
   1177             return JNI_FALSE;
   1178         }
   1179         return JNI_TRUE;
   1180     }
   1181 
   1182     // Copy the bitmap to a new blob.
   1183     bool mutableCopy = isMutable;
   1184 #if DEBUG_PARCEL
   1185     ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
   1186             isMutable ? "mutable" : "immutable",
   1187             mutableCopy ? "mutable" : "immutable",
   1188             p->allowFds() ? "allowed" : "forbidden");
   1189 #endif
   1190 
   1191     size_t size = bitmap.getSize();
   1192     android::Parcel::WritableBlob blob;
   1193     status = p->writeBlob(size, mutableCopy, &blob);
   1194     if (status) {
   1195         doThrowRE(env, "Could not copy bitmap to parcel blob.");
   1196         return JNI_FALSE;
   1197     }
   1198 
   1199     const void* pSrc =  bitmap.getPixels();
   1200     if (pSrc == NULL) {
   1201         memset(blob.data(), 0, size);
   1202     } else {
   1203         memcpy(blob.data(), pSrc, size);
   1204     }
   1205 
   1206     blob.release();
   1207     return JNI_TRUE;
   1208 }
   1209 
   1210 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
   1211                                    jlong srcHandle, jlong paintHandle,
   1212                                    jintArray offsetXY) {
   1213     SkBitmap src;
   1214     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
   1215     const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
   1216     SkIPoint  offset;
   1217     SkBitmap dst;
   1218     HeapAllocator allocator;
   1219 
   1220     src.extractAlpha(&dst, paint, &allocator, &offset);
   1221     // If Skia can't allocate pixels for destination bitmap, it resets
   1222     // it, that is set its pixels buffer to NULL, and zero width and height.
   1223     if (dst.getPixels() == NULL && src.getPixels() != NULL) {
   1224         doThrowOOME(env, "failed to allocate pixels for alpha");
   1225         return NULL;
   1226     }
   1227     if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
   1228         int* array = env->GetIntArrayElements(offsetXY, NULL);
   1229         array[0] = offset.fX;
   1230         array[1] = offset.fY;
   1231         env->ReleaseIntArrayElements(offsetXY, array, 0);
   1232     }
   1233 
   1234     return createBitmap(env, allocator.getStorageObjAndReset(),
   1235             getPremulBitmapCreateFlags(true));
   1236 }
   1237 
   1238 ///////////////////////////////////////////////////////////////////////////////
   1239 
   1240 static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
   1241     LocalScopedBitmap bitmapHolder(bitmapHandle);
   1242     if (!bitmapHolder.valid()) return JNI_TRUE;
   1243 
   1244     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
   1245     return GraphicsJNI::isColorSpaceSRGB(colorSpace);
   1246 }
   1247 
   1248 static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
   1249         jfloatArray xyzArray, jfloatArray paramsArray) {
   1250 
   1251     LocalScopedBitmap bitmapHolder(bitmapHandle);
   1252     if (!bitmapHolder.valid()) return JNI_FALSE;
   1253 
   1254     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
   1255     if (colorSpace == nullptr) return JNI_FALSE;
   1256 
   1257     SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
   1258     if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
   1259 
   1260     jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
   1261     xyz[0] = xyzMatrix.getFloat(0, 0);
   1262     xyz[1] = xyzMatrix.getFloat(1, 0);
   1263     xyz[2] = xyzMatrix.getFloat(2, 0);
   1264     xyz[3] = xyzMatrix.getFloat(0, 1);
   1265     xyz[4] = xyzMatrix.getFloat(1, 1);
   1266     xyz[5] = xyzMatrix.getFloat(2, 1);
   1267     xyz[6] = xyzMatrix.getFloat(0, 2);
   1268     xyz[7] = xyzMatrix.getFloat(1, 2);
   1269     xyz[8] = xyzMatrix.getFloat(2, 2);
   1270     env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
   1271 
   1272     SkColorSpaceTransferFn transferParams;
   1273     if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
   1274 
   1275     jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
   1276     params[0] = transferParams.fA;
   1277     params[1] = transferParams.fB;
   1278     params[2] = transferParams.fC;
   1279     params[3] = transferParams.fD;
   1280     params[4] = transferParams.fE;
   1281     params[5] = transferParams.fF;
   1282     params[6] = transferParams.fG;
   1283     env->ReleaseFloatArrayElements(paramsArray, params, 0);
   1284 
   1285     return JNI_TRUE;
   1286 }
   1287 
   1288 ///////////////////////////////////////////////////////////////////////////////
   1289 
   1290 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
   1291         jint x, jint y) {
   1292     SkBitmap bitmap;
   1293     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1294 
   1295     ToColorProc proc = ChooseToColorProc(bitmap);
   1296     if (NULL == proc) {
   1297         return 0;
   1298     }
   1299     const void* src = bitmap.getAddr(x, y);
   1300     if (NULL == src) {
   1301         return 0;
   1302     }
   1303 
   1304     SkColor dst[1];
   1305     proc(dst, src, 1);
   1306 
   1307     SkColorSpace* colorSpace = bitmap.colorSpace();
   1308     if (bitmap.colorType() != kRGBA_F16_SkColorType &&
   1309             !GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
   1310         auto sRGB = SkColorSpace::MakeSRGB();
   1311         auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
   1312         xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0],
   1313                 SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1,
   1314                 SkAlphaType::kUnpremul_SkAlphaType);
   1315     }
   1316 
   1317     return static_cast<jint>(dst[0]);
   1318 }
   1319 
   1320 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
   1321         jintArray pixelArray, jint offset, jint stride,
   1322         jint x, jint y, jint width, jint height) {
   1323     SkBitmap bitmap;
   1324     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1325 
   1326     ToColorProc proc = ChooseToColorProc(bitmap);
   1327     if (NULL == proc) {
   1328         return;
   1329     }
   1330     const void* src = bitmap.getAddr(x, y);
   1331     if (NULL == src) {
   1332         return;
   1333     }
   1334 
   1335     jint* dst = env->GetIntArrayElements(pixelArray, NULL);
   1336     SkColor* d = (SkColor*)dst + offset;
   1337 
   1338     SkColorSpace* colorSpace = bitmap.colorSpace();
   1339     if (bitmap.colorType() == kRGBA_F16_SkColorType ||
   1340             GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
   1341         while (--height >= 0) {
   1342             proc(d, src, width);
   1343             d += stride;
   1344             src = (void*)((const char*)src + bitmap.rowBytes());
   1345         }
   1346     } else {
   1347         auto sRGB = SkColorSpace::MakeSRGB();
   1348         auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
   1349 
   1350         while (--height >= 0) {
   1351             proc(d, src, width);
   1352 
   1353             xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d,
   1354                     SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width,
   1355                     SkAlphaType::kUnpremul_SkAlphaType);
   1356 
   1357             d += stride;
   1358             src = (void*)((const char*)src + bitmap.rowBytes());
   1359         }
   1360     }
   1361 
   1362     env->ReleaseIntArrayElements(pixelArray, dst, 0);
   1363 }
   1364 
   1365 ///////////////////////////////////////////////////////////////////////////////
   1366 
   1367 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
   1368         jint x, jint y, jint colorHandle) {
   1369     SkBitmap bitmap;
   1370     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1371     SkColor color = static_cast<SkColor>(colorHandle);
   1372     if (NULL == bitmap.getPixels()) {
   1373         return;
   1374     }
   1375 
   1376     FromColorProc proc = ChooseFromColorProc(bitmap);
   1377     if (NULL == proc) {
   1378         return;
   1379     }
   1380 
   1381     SkColorSpace* colorSpace = bitmap.colorSpace();
   1382     if (bitmap.colorType() != kRGBA_F16_SkColorType &&
   1383             !GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
   1384         auto sRGB = SkColorSpace::MakeSRGB();
   1385         auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
   1386         xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color,
   1387                 SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1,
   1388                 SkAlphaType::kUnpremul_SkAlphaType);
   1389     }
   1390 
   1391     proc(bitmap.getAddr(x, y), &color, 1, x, y);
   1392     bitmap.notifyPixelsChanged();
   1393 }
   1394 
   1395 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
   1396         jintArray pixelArray, jint offset, jint stride,
   1397         jint x, jint y, jint width, jint height) {
   1398     SkBitmap bitmap;
   1399     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1400     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
   1401             x, y, width, height, bitmap);
   1402 }
   1403 
   1404 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
   1405                                       jlong bitmapHandle, jobject jbuffer) {
   1406     SkBitmap bitmap;
   1407     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1408     const void* src = bitmap.getPixels();
   1409 
   1410     if (NULL != src) {
   1411         android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
   1412 
   1413         // the java side has already checked that buffer is large enough
   1414         memcpy(abp.pointer(), src, bitmap.getSize());
   1415     }
   1416 }
   1417 
   1418 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
   1419                                         jlong bitmapHandle, jobject jbuffer) {
   1420     SkBitmap bitmap;
   1421     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1422     void* dst = bitmap.getPixels();
   1423 
   1424     if (NULL != dst) {
   1425         android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
   1426         // the java side has already checked that buffer is large enough
   1427         memcpy(dst, abp.pointer(), bitmap.getSize());
   1428         bitmap.notifyPixelsChanged();
   1429     }
   1430 }
   1431 
   1432 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
   1433     SkBitmap bm0;
   1434     SkBitmap bm1;
   1435 
   1436     LocalScopedBitmap bitmap0(bm0Handle);
   1437     LocalScopedBitmap bitmap1(bm1Handle);
   1438 
   1439     // Paying the price for making Hardware Bitmap as Config:
   1440     // later check for colorType will pass successfully,
   1441     // because Hardware Config internally may be RGBA8888 or smth like that.
   1442     if (bitmap0->isHardware() != bitmap1->isHardware()) {
   1443         return JNI_FALSE;
   1444     }
   1445 
   1446     bitmap0->bitmap().getSkBitmap(&bm0);
   1447     bitmap1->bitmap().getSkBitmap(&bm1);
   1448     if (bm0.width() != bm1.width()
   1449             || bm0.height() != bm1.height()
   1450             || bm0.colorType() != bm1.colorType()
   1451             || bm0.alphaType() != bm1.alphaType()
   1452             || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
   1453         return JNI_FALSE;
   1454     }
   1455 
   1456     // if we can't load the pixels, return false
   1457     if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
   1458         return JNI_FALSE;
   1459     }
   1460 
   1461     // now compare each scanline. We can't do the entire buffer at once,
   1462     // since we don't care about the pixel values that might extend beyond
   1463     // the width (since the scanline might be larger than the logical width)
   1464     const int h = bm0.height();
   1465     const size_t size = bm0.width() * bm0.bytesPerPixel();
   1466     for (int y = 0; y < h; y++) {
   1467         // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
   1468         // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
   1469         // and bm1 both have pixel data() (have passed NULL == getPixels() check),
   1470         // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
   1471         // to warn user those 2 unrecognized config bitmaps may be different.
   1472         void *bm0Addr = bm0.getAddr(0, y);
   1473         void *bm1Addr = bm1.getAddr(0, y);
   1474 
   1475         if(bm0Addr == NULL || bm1Addr == NULL) {
   1476             return JNI_FALSE;
   1477         }
   1478 
   1479         if (memcmp(bm0Addr, bm1Addr, size) != 0) {
   1480             return JNI_FALSE;
   1481         }
   1482     }
   1483     return JNI_TRUE;
   1484 }
   1485 
   1486 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
   1487     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1488     if (!bitmapHandle.valid()) return;
   1489     android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
   1490 }
   1491 
   1492 static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
   1493     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1494     return static_cast<jint>(bitmapHandle->getAllocationByteCount());
   1495 }
   1496 
   1497 static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
   1498     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1499     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
   1500             "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
   1501     Bitmap& hwuiBitmap = bitmapHandle->bitmap();
   1502     SkBitmap src;
   1503     hwuiBitmap.getSkBitmap(&src);
   1504 
   1505     SkBitmap result;
   1506     HeapAllocator allocator;
   1507     if (!bitmapCopyTo(&result, hwuiBitmap.info().colorType(), src, &allocator)) {
   1508         doThrowRE(env, "Could not copy a hardware bitmap.");
   1509         return NULL;
   1510     }
   1511     return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false));
   1512 }
   1513 
   1514 static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
   1515     sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
   1516     sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
   1517     if (!bitmap.get()) {
   1518         ALOGW("failed to create hardware bitmap from graphic buffer");
   1519         return NULL;
   1520     }
   1521     return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
   1522 }
   1523 
   1524 static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
   1525     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1526     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
   1527             "Hardware config is only supported config in Bitmap_getGraphicBuffer");
   1528 
   1529     Bitmap& hwuiBitmap = bitmapHandle->bitmap();
   1530     sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer());
   1531     return createJavaGraphicBuffer(env, buffer);
   1532 }
   1533 
   1534 static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) {
   1535     LocalScopedBitmap srcBitmapHandle(srcBitmapPtr);
   1536     LocalScopedBitmap dstBitmapHandle(dstBitmapPtr);
   1537 
   1538     dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace());
   1539 }
   1540 
   1541 ///////////////////////////////////////////////////////////////////////////////
   1542 
   1543 static const JNINativeMethod gBitmapMethods[] = {
   1544     {   "nativeCreate",             "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
   1545         (void*)Bitmap_creator },
   1546     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
   1547         (void*)Bitmap_copy },
   1548     {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
   1549         (void*)Bitmap_copyAshmem },
   1550     {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
   1551         (void*)Bitmap_copyAshmemConfig },
   1552     {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
   1553     {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
   1554     {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
   1555     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
   1556         (void*)Bitmap_compress },
   1557     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
   1558     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
   1559     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
   1560     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
   1561     {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
   1562     {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
   1563     {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
   1564     {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
   1565     {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
   1566     {   "nativeCreateFromParcel",
   1567         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
   1568         (void*)Bitmap_createFromParcel },
   1569     {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
   1570         (void*)Bitmap_writeToParcel },
   1571     {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
   1572         (void*)Bitmap_extractAlpha },
   1573     {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
   1574     {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
   1575     {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
   1576     {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
   1577     {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
   1578     {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
   1579                                             (void*)Bitmap_copyPixelsToBuffer },
   1580     {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
   1581                                             (void*)Bitmap_copyPixelsFromBuffer },
   1582     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
   1583     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
   1584     {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
   1585     {   "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
   1586         (void*)Bitmap_copyPreserveInternalConfig },
   1587     {   "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
   1588         (void*) Bitmap_createHardwareBitmap },
   1589     {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
   1590         (void*) Bitmap_createGraphicBufferHandle },
   1591     {   "nativeGetColorSpace",      "(J[F[F)Z", (void*)Bitmap_getColorSpace },
   1592     {   "nativeIsSRGB",             "(J)Z", (void*)Bitmap_isSRGB },
   1593     {   "nativeCopyColorSpace",     "(JJ)V",
   1594         (void*)Bitmap_copyColorSpace },
   1595 };
   1596 
   1597 int register_android_graphics_Bitmap(JNIEnv* env)
   1598 {
   1599     gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
   1600     gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
   1601     gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
   1602     gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
   1603     gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
   1604     return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
   1605                                          NELEM(gBitmapMethods));
   1606 }
   1607