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 "SkColorSpace.h"
     11 #include "GraphicsJNI.h"
     12 #include "SkStream.h"
     13 
     14 #include <binder/Parcel.h>
     15 #include "android_os_Parcel.h"
     16 #include "android_util_Binder.h"
     17 #include "android_nio_utils.h"
     18 #include "CreateJavaOutputStreamAdaptor.h"
     19 #include <hwui/Paint.h>
     20 #include <hwui/Bitmap.h>
     21 #include <renderthread/RenderProxy.h>
     22 #include <utils/Color.h>
     23 
     24 #include <android_runtime/android_hardware_HardwareBuffer.h>
     25 
     26 #include <private/android/AHardwareBufferHelpers.h>
     27 
     28 #include "core_jni_helpers.h"
     29 
     30 #include <jni.h>
     31 #include <string.h>
     32 #include <memory>
     33 #include <string>
     34 
     35 #define DEBUG_PARCEL 0
     36 #define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
     37 
     38 static jclass   gBitmap_class;
     39 static jfieldID gBitmap_nativePtr;
     40 static jmethodID gBitmap_constructorMethodID;
     41 static jmethodID gBitmap_reinitMethodID;
     42 
     43 namespace android {
     44 
     45 class BitmapWrapper {
     46 public:
     47     explicit BitmapWrapper(Bitmap* bitmap)
     48         : mBitmap(bitmap) { }
     49 
     50     void freePixels() {
     51         mInfo = mBitmap->info();
     52         mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
     53         mAllocationSize = mBitmap->getAllocationByteCount();
     54         mRowBytes = mBitmap->rowBytes();
     55         mGenerationId = mBitmap->getGenerationID();
     56         mIsHardware = mBitmap->isHardware();
     57         mBitmap.reset();
     58     }
     59 
     60     bool valid() {
     61         return mBitmap != nullptr;
     62     }
     63 
     64     Bitmap& bitmap() {
     65         assertValid();
     66         return *mBitmap;
     67     }
     68 
     69     void assertValid() {
     70         LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
     71     }
     72 
     73     void getSkBitmap(SkBitmap* outBitmap) {
     74         assertValid();
     75         mBitmap->getSkBitmap(outBitmap);
     76     }
     77 
     78     bool hasHardwareMipMap() {
     79         if (mBitmap) {
     80             return mBitmap->hasHardwareMipMap();
     81         }
     82         return mHasHardwareMipMap;
     83     }
     84 
     85     void setHasHardwareMipMap(bool hasMipMap) {
     86         assertValid();
     87         mBitmap->setHasHardwareMipMap(hasMipMap);
     88     }
     89 
     90     void setAlphaType(SkAlphaType alphaType) {
     91         assertValid();
     92         mBitmap->setAlphaType(alphaType);
     93     }
     94 
     95     void setColorSpace(sk_sp<SkColorSpace> colorSpace) {
     96         assertValid();
     97         mBitmap->setColorSpace(colorSpace);
     98     }
     99 
    100     const SkImageInfo& info() {
    101         if (mBitmap) {
    102             return mBitmap->info();
    103         }
    104         return mInfo;
    105     }
    106 
    107     size_t getAllocationByteCount() const {
    108         if (mBitmap) {
    109             return mBitmap->getAllocationByteCount();
    110         }
    111         return mAllocationSize;
    112     }
    113 
    114     size_t rowBytes() const {
    115         if (mBitmap) {
    116             return mBitmap->rowBytes();
    117         }
    118         return mRowBytes;
    119     }
    120 
    121     uint32_t getGenerationID() const {
    122         if (mBitmap) {
    123             return mBitmap->getGenerationID();
    124         }
    125         return mGenerationId;
    126     }
    127 
    128     bool isHardware() {
    129         if (mBitmap) {
    130             return mBitmap->isHardware();
    131         }
    132         return mIsHardware;
    133     }
    134 
    135     ~BitmapWrapper() { }
    136 
    137 private:
    138     sk_sp<Bitmap> mBitmap;
    139     SkImageInfo mInfo;
    140     bool mHasHardwareMipMap;
    141     size_t mAllocationSize;
    142     size_t mRowBytes;
    143     uint32_t mGenerationId;
    144     bool mIsHardware;
    145 };
    146 
    147 // Convenience class that does not take a global ref on the pixels, relying
    148 // on the caller already having a local JNI ref
    149 class LocalScopedBitmap {
    150 public:
    151     explicit LocalScopedBitmap(jlong bitmapHandle)
    152             : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
    153 
    154     BitmapWrapper* operator->() {
    155         return mBitmapWrapper;
    156     }
    157 
    158     void* pixels() {
    159         return mBitmapWrapper->bitmap().pixels();
    160     }
    161 
    162     bool valid() {
    163         return mBitmapWrapper && mBitmapWrapper->valid();
    164     }
    165 
    166 private:
    167     BitmapWrapper* mBitmapWrapper;
    168 };
    169 
    170 namespace bitmap {
    171 
    172 // Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
    173 static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
    174     // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
    175     // irrelevant. This just tests to ensure that the SkAlphaType is not
    176     // opposite of isPremultiplied.
    177     if (isPremultiplied) {
    178         SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
    179     } else {
    180         SkASSERT(info.alphaType() != kPremul_SkAlphaType);
    181     }
    182 }
    183 
    184 void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
    185         bool isPremultiplied)
    186 {
    187     // The caller needs to have already set the alpha type properly, so the
    188     // native SkBitmap stays in sync with the Java Bitmap.
    189     assert_premultiplied(info, isPremultiplied);
    190 
    191     env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
    192             info.width(), info.height(), isPremultiplied);
    193 }
    194 
    195 jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
    196         int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
    197         int density) {
    198     bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
    199     bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
    200     // The caller needs to have already set the alpha type properly, so the
    201     // native SkBitmap stays in sync with the Java Bitmap.
    202     assert_premultiplied(bitmap->info(), isPremultiplied);
    203     bool fromMalloc = bitmap->pixelStorageType() == PixelStorageType::Heap;
    204     BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
    205     if (!isMutable) {
    206         bitmapWrapper->bitmap().setImmutable();
    207     }
    208     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
    209             reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
    210             isPremultiplied, ninePatchChunk, ninePatchInsets, fromMalloc);
    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(jlong bitmapHandle) {
    234     LocalScopedBitmap localBitmap(bitmapHandle);
    235     return localBitmap->bitmap();
    236 }
    237 
    238 void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) {
    239     SkASSERT(info);
    240     SkASSERT(env);
    241     SkASSERT(bitmap);
    242     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    243     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    244     LocalScopedBitmap localBitmap(bitmapHandle);
    245 
    246     const SkImageInfo& imageInfo = localBitmap->info();
    247     info->width = imageInfo.width();
    248     info->height = imageInfo.height();
    249     info->stride = localBitmap->rowBytes();
    250     info->flags = 0;
    251     switch (imageInfo.colorType()) {
    252         case kN32_SkColorType:
    253             info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
    254             break;
    255         case kRGB_565_SkColorType:
    256             info->format = ANDROID_BITMAP_FORMAT_RGB_565;
    257             break;
    258         case kARGB_4444_SkColorType:
    259             info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
    260             break;
    261         case kAlpha_8_SkColorType:
    262             info->format = ANDROID_BITMAP_FORMAT_A_8;
    263             break;
    264         default:
    265             info->format = ANDROID_BITMAP_FORMAT_NONE;
    266             break;
    267     }
    268 }
    269 
    270 void* lockPixels(JNIEnv* env, jobject bitmap) {
    271     SkASSERT(env);
    272     SkASSERT(bitmap);
    273     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    274     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    275 
    276     LocalScopedBitmap localBitmap(bitmapHandle);
    277     if (!localBitmap->valid()) return nullptr;
    278 
    279     SkPixelRef& pixelRef = localBitmap->bitmap();
    280     if (!pixelRef.pixels()) {
    281         return nullptr;
    282     }
    283     pixelRef.ref();
    284     return pixelRef.pixels();
    285 }
    286 
    287 bool unlockPixels(JNIEnv* env, jobject bitmap) {
    288     SkASSERT(env);
    289     SkASSERT(bitmap);
    290     SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
    291     jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
    292 
    293     LocalScopedBitmap localBitmap(bitmapHandle);
    294     if (!localBitmap->valid()) return false;
    295 
    296     SkPixelRef& pixelRef = localBitmap->bitmap();
    297     pixelRef.notifyPixelsChanged();
    298     pixelRef.unref();
    299     return true;
    300 }
    301 
    302 } // namespace bitmap
    303 
    304 } // namespace android
    305 
    306 using namespace android;
    307 using namespace android::bitmap;
    308 
    309 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
    310         int x, int y, int width, int height, SkBitmap* dstBitmap) {
    311     const jint* array = env->GetIntArrayElements(srcColors, NULL);
    312     const SkColor* src = (const SkColor*)array + srcOffset;
    313 
    314     auto sRGB = SkColorSpace::MakeSRGB();
    315     SkImageInfo srcInfo = SkImageInfo::Make(
    316             width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
    317     SkPixmap srcPM(srcInfo, src, srcStride * 4);
    318 
    319     dstBitmap->writePixels(srcPM, x, y);
    320 
    321     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
    322     return true;
    323 }
    324 
    325 ///////////////////////////////////////////////////////////////////////////////
    326 ///////////////////////////////////////////////////////////////////////////////
    327 
    328 static int getPremulBitmapCreateFlags(bool isMutable) {
    329     int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
    330     if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
    331     return flags;
    332 }
    333 
    334 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
    335                               jint offset, jint stride, jint width, jint height,
    336                               jint configHandle, jboolean isMutable,
    337                               jlong colorSpacePtr) {
    338     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
    339     if (NULL != jColors) {
    340         size_t n = env->GetArrayLength(jColors);
    341         if (n < SkAbs32(stride) * (size_t)height) {
    342             doThrowAIOOBE(env);
    343             return NULL;
    344         }
    345     }
    346 
    347     // ARGB_4444 is a deprecated format, convert automatically to 8888
    348     if (colorType == kARGB_4444_SkColorType) {
    349         colorType = kN32_SkColorType;
    350     }
    351 
    352     sk_sp<SkColorSpace> colorSpace;
    353     if (colorType == kAlpha_8_SkColorType) {
    354         colorSpace = nullptr;
    355     } else {
    356         colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
    357     }
    358 
    359     SkBitmap bitmap;
    360     bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
    361                 colorSpace));
    362 
    363     sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
    364     if (!nativeBitmap) {
    365         ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
    366         doThrowOOME(env);
    367         return NULL;
    368     }
    369 
    370     if (jColors != NULL) {
    371         GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap);
    372     }
    373 
    374     return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
    375 }
    376 
    377 static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
    378         SkBitmap::Allocator* alloc) {
    379     SkPixmap srcPM;
    380     if (!src.peekPixels(&srcPM)) {
    381         return false;
    382     }
    383 
    384     SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
    385     switch (dstCT) {
    386         case kRGB_565_SkColorType:
    387             dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
    388             break;
    389         case kAlpha_8_SkColorType:
    390             dstInfo = dstInfo.makeColorSpace(nullptr);
    391             break;
    392         default:
    393             break;
    394     }
    395 
    396     if (!dstInfo.colorSpace() && dstCT != kAlpha_8_SkColorType) {
    397         dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGB());
    398     }
    399 
    400     if (!dst->setInfo(dstInfo)) {
    401         return false;
    402     }
    403     if (!dst->tryAllocPixels(alloc)) {
    404         return false;
    405     }
    406 
    407     SkPixmap dstPM;
    408     if (!dst->peekPixels(&dstPM)) {
    409         return false;
    410     }
    411 
    412     return srcPM.readPixels(dstPM);
    413 }
    414 
    415 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
    416                            jint dstConfigHandle, jboolean isMutable) {
    417     SkBitmap src;
    418     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    419     if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
    420         sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
    421         if (!bitmap.get()) {
    422             return NULL;
    423         }
    424         return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
    425     }
    426 
    427     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
    428     SkBitmap result;
    429     HeapAllocator allocator;
    430 
    431     if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
    432         return NULL;
    433     }
    434     auto bitmap = allocator.getStorageObjAndReset();
    435     return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
    436 }
    437 
    438 static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
    439     SkBitmap result;
    440 
    441     AshmemPixelAllocator allocator(env);
    442     if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
    443         return NULL;
    444     }
    445     auto bitmap = allocator.getStorageObjAndReset();
    446     bitmap->setImmutable();
    447     return bitmap;
    448 }
    449 
    450 static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
    451     SkBitmap src;
    452     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    453     SkColorType dstCT = src.colorType();
    454     auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
    455     jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
    456     return ret;
    457 }
    458 
    459 static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
    460     SkBitmap src;
    461     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    462     SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
    463     auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
    464     jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
    465     return ret;
    466 }
    467 
    468 static void Bitmap_destruct(BitmapWrapper* bitmap) {
    469     delete bitmap;
    470 }
    471 
    472 static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
    473     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
    474 }
    475 
    476 static void Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
    477     LocalScopedBitmap bitmap(bitmapHandle);
    478     bitmap->freePixels();
    479 }
    480 
    481 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    482         jint width, jint height, jint configHandle, jboolean requestPremul) {
    483     LocalScopedBitmap bitmap(bitmapHandle);
    484     bitmap->assertValid();
    485     SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
    486 
    487     // ARGB_4444 is a deprecated format, convert automatically to 8888
    488     if (colorType == kARGB_4444_SkColorType) {
    489         colorType = kN32_SkColorType;
    490     }
    491     size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
    492     if (requestedSize > bitmap->getAllocationByteCount()) {
    493         // done in native as there's no way to get BytesPerPixel in Java
    494         doThrowIAE(env, "Bitmap not large enough to support new configuration");
    495         return;
    496     }
    497     SkAlphaType alphaType;
    498     if (bitmap->info().colorType() != kRGB_565_SkColorType
    499             && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
    500         // If the original bitmap was set to opaque, keep that setting, unless it
    501         // was 565, which is required to be opaque.
    502         alphaType = kOpaque_SkAlphaType;
    503     } else {
    504         // Otherwise respect the premultiplied request.
    505         alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
    506     }
    507     bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
    508             sk_ref_sp(bitmap->info().colorSpace())));
    509 }
    510 
    511 // These must match the int values in Bitmap.java
    512 enum JavaEncodeFormat {
    513     kJPEG_JavaEncodeFormat = 0,
    514     kPNG_JavaEncodeFormat = 1,
    515     kWEBP_JavaEncodeFormat = 2
    516 };
    517 
    518 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    519                                 jint format, jint quality,
    520                                 jobject jstream, jbyteArray jstorage) {
    521     SkEncodedImageFormat fm;
    522     switch (format) {
    523     case kJPEG_JavaEncodeFormat:
    524         fm = SkEncodedImageFormat::kJPEG;
    525         break;
    526     case kPNG_JavaEncodeFormat:
    527         fm = SkEncodedImageFormat::kPNG;
    528         break;
    529     case kWEBP_JavaEncodeFormat:
    530         fm = SkEncodedImageFormat::kWEBP;
    531         break;
    532     default:
    533         return JNI_FALSE;
    534     }
    535 
    536     LocalScopedBitmap bitmap(bitmapHandle);
    537     if (!bitmap.valid()) {
    538         return JNI_FALSE;
    539     }
    540 
    541     std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
    542     if (!strm.get()) {
    543         return JNI_FALSE;
    544     }
    545 
    546     SkBitmap skbitmap;
    547     bitmap->getSkBitmap(&skbitmap);
    548     if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
    549         // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace
    550         // for wide gamuts.
    551         auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
    552         auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
    553                                    .makeColorSpace(std::move(cs));
    554         SkBitmap p3;
    555         if (!p3.tryAllocPixels(info)) {
    556             return JNI_FALSE;
    557         }
    558 
    559         SkPixmap pm;
    560         SkAssertResult(p3.peekPixels(&pm));  // should always work if tryAllocPixels() did.
    561         if (!skbitmap.readPixels(pm)) {
    562             return JNI_FALSE;
    563         }
    564         skbitmap = p3;
    565     }
    566     return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
    567 }
    568 
    569 static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
    570         const sk_sp<SkColorSpace>& colorSpace) {
    571     SkPaint p;
    572     p.setColor4f(color, colorSpace.get());
    573     p.setBlendMode(SkBlendMode::kSrc);
    574     SkCanvas canvas(bitmap);
    575     canvas.drawPaint(p);
    576 }
    577 
    578 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
    579     LocalScopedBitmap bitmap(bitmapHandle);
    580     SkBitmap skBitmap;
    581     bitmap->getSkBitmap(&skBitmap);
    582     bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
    583 }
    584 
    585 static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle,
    586         jlong colorSpaceHandle, jlong colorLong) {
    587     LocalScopedBitmap bitmap(bitmapHandle);
    588     SkBitmap skBitmap;
    589     bitmap->getSkBitmap(&skBitmap);
    590 
    591     SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
    592     sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
    593     bitmapErase(skBitmap, color, cs);
    594 }
    595 
    596 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
    597     LocalScopedBitmap bitmap(bitmapHandle);
    598     return static_cast<jint>(bitmap->rowBytes());
    599 }
    600 
    601 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
    602     LocalScopedBitmap bitmap(bitmapHandle);
    603     if (bitmap->isHardware()) {
    604         return GraphicsJNI::hardwareLegacyBitmapConfig();
    605     }
    606     return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
    607 }
    608 
    609 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
    610     LocalScopedBitmap bitmap(bitmapHandle);
    611     return static_cast<jint>(bitmap->getGenerationID());
    612 }
    613 
    614 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
    615     LocalScopedBitmap bitmap(bitmapHandle);
    616     if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
    617         return JNI_TRUE;
    618     }
    619     return JNI_FALSE;
    620 }
    621 
    622 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
    623     LocalScopedBitmap bitmap(bitmapHandle);
    624     return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
    625 }
    626 
    627 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
    628         jboolean hasAlpha, jboolean requestPremul) {
    629     LocalScopedBitmap bitmap(bitmapHandle);
    630     if (hasAlpha) {
    631         bitmap->setAlphaType(
    632                 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
    633     } else {
    634         bitmap->setAlphaType(kOpaque_SkAlphaType);
    635     }
    636 }
    637 
    638 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
    639         jboolean isPremul) {
    640     LocalScopedBitmap bitmap(bitmapHandle);
    641     if (!bitmap->info().isOpaque()) {
    642         if (isPremul) {
    643             bitmap->setAlphaType(kPremul_SkAlphaType);
    644         } else {
    645             bitmap->setAlphaType(kUnpremul_SkAlphaType);
    646         }
    647     }
    648 }
    649 
    650 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
    651     LocalScopedBitmap bitmap(bitmapHandle);
    652     return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
    653 }
    654 
    655 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
    656                                 jboolean hasMipMap) {
    657     LocalScopedBitmap bitmap(bitmapHandle);
    658     bitmap->setHasHardwareMipMap(hasMipMap);
    659 }
    660 
    661 ///////////////////////////////////////////////////////////////////////////////
    662 
    663 // This is the maximum possible size because the SkColorSpace must be
    664 // representable (and therefore serializable) using a matrix and numerical
    665 // transfer function.  If we allow more color space representations in the
    666 // framework, we may need to update this maximum size.
    667 static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
    668 
    669 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
    670     if (parcel == NULL) {
    671         SkDebugf("-------- unparcel parcel is NULL\n");
    672         return NULL;
    673     }
    674 
    675     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    676 
    677     const bool        isMutable = p->readInt32() != 0;
    678     const SkColorType colorType = (SkColorType)p->readInt32();
    679     const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
    680     const uint32_t    colorSpaceSize = p->readUint32();
    681     sk_sp<SkColorSpace> colorSpace;
    682     if (colorSpaceSize > 0) {
    683         if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
    684             ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
    685                     "%d bytes\n", colorSpaceSize);
    686         }
    687 
    688         const void* data = p->readInplace(colorSpaceSize);
    689         if (data) {
    690             colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
    691         } else {
    692             ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
    693         }
    694     }
    695     const int         width = p->readInt32();
    696     const int         height = p->readInt32();
    697     const int         rowBytes = p->readInt32();
    698     const int         density = p->readInt32();
    699 
    700     if (kN32_SkColorType != colorType &&
    701             kRGBA_F16_SkColorType != colorType &&
    702             kRGB_565_SkColorType != colorType &&
    703             kARGB_4444_SkColorType != colorType &&
    704             kAlpha_8_SkColorType != colorType) {
    705         SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
    706         return NULL;
    707     }
    708 
    709     std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
    710     if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
    711             rowBytes)) {
    712         return NULL;
    713     }
    714 
    715     // Read the bitmap blob.
    716     size_t size = bitmap->computeByteSize();
    717     android::Parcel::ReadableBlob blob;
    718     android::status_t status = p->readBlob(size, &blob);
    719     if (status) {
    720         doThrowRE(env, "Could not read bitmap blob.");
    721         return NULL;
    722     }
    723 
    724     // Map the bitmap in place from the ashmem region if possible otherwise copy.
    725     sk_sp<Bitmap> nativeBitmap;
    726     if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
    727 #if DEBUG_PARCEL
    728         ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
    729                 "(fds %s)",
    730                 isMutable ? "mutable" : "immutable",
    731                 blob.isMutable() ? "mutable" : "immutable",
    732                 p->allowFds() ? "allowed" : "forbidden");
    733 #endif
    734         // Dup the file descriptor so we can keep a reference to it after the Parcel
    735         // is disposed.
    736         int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0);
    737         if (dupFd < 0) {
    738             ALOGE("Error allocating dup fd. Error:%d", errno);
    739             blob.release();
    740             doThrowRE(env, "Could not allocate dup blob fd.");
    741             return NULL;
    742         }
    743 
    744         // Map the pixels in place and take ownership of the ashmem region. We must also respect the
    745         // rowBytes value already set on the bitmap instead of attempting to compute our own.
    746         nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd,
    747                                           const_cast<void*>(blob.data()), size, !isMutable);
    748         if (!nativeBitmap) {
    749             close(dupFd);
    750             blob.release();
    751             doThrowRE(env, "Could not allocate ashmem pixel ref.");
    752             return NULL;
    753         }
    754 
    755         // Clear the blob handle, don't release it.
    756         blob.clear();
    757     } else {
    758 #if DEBUG_PARCEL
    759         if (blob.fd() >= 0) {
    760             ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
    761                     "from immutable blob (fds %s)",
    762                     p->allowFds() ? "allowed" : "forbidden");
    763         } else {
    764             ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
    765                     "(fds %s)",
    766                     blob.isMutable() ? "mutable" : "immutable",
    767                     p->allowFds() ? "allowed" : "forbidden");
    768         }
    769 #endif
    770 
    771         // Copy the pixels into a new buffer.
    772         nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
    773         if (!nativeBitmap) {
    774             blob.release();
    775             doThrowRE(env, "Could not allocate java pixel ref.");
    776             return NULL;
    777         }
    778         memcpy(bitmap->getPixels(), blob.data(), size);
    779 
    780         // Release the blob handle.
    781         blob.release();
    782     }
    783 
    784     return createBitmap(env, nativeBitmap.release(),
    785             getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
    786 }
    787 
    788 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
    789                                      jlong bitmapHandle,
    790                                      jboolean isMutable, jint density,
    791                                      jobject parcel) {
    792     if (parcel == NULL) {
    793         SkDebugf("------- writeToParcel null parcel\n");
    794         return JNI_FALSE;
    795     }
    796 
    797     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    798     SkBitmap bitmap;
    799 
    800     auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
    801     bitmapWrapper->getSkBitmap(&bitmap);
    802 
    803     p->writeInt32(isMutable);
    804     p->writeInt32(bitmap.colorType());
    805     p->writeInt32(bitmap.alphaType());
    806     SkColorSpace* colorSpace = bitmap.colorSpace();
    807     if (colorSpace != nullptr) {
    808         sk_sp<SkData> data = colorSpace->serialize();
    809         size_t size = data->size();
    810         p->writeUint32(size);
    811         if (size > 0) {
    812             if (size > kMaxColorSpaceSerializedBytes) {
    813                 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
    814                         "%zu bytes\n", size);
    815             }
    816 
    817             p->write(data->data(), size);
    818         }
    819     } else {
    820         p->writeUint32(0);
    821     }
    822     p->writeInt32(bitmap.width());
    823     p->writeInt32(bitmap.height());
    824     p->writeInt32(bitmap.rowBytes());
    825     p->writeInt32(density);
    826 
    827     // Transfer the underlying ashmem region if we have one and it's immutable.
    828     android::status_t status;
    829     int fd = bitmapWrapper->bitmap().getAshmemFd();
    830     if (fd >= 0 && !isMutable && p->allowFds()) {
    831 #if DEBUG_PARCEL
    832         ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
    833                 "immutable blob (fds %s)",
    834                 p->allowFds() ? "allowed" : "forbidden");
    835 #endif
    836 
    837         status = p->writeDupImmutableBlobFileDescriptor(fd);
    838         if (status) {
    839             doThrowRE(env, "Could not write bitmap blob file descriptor.");
    840             return JNI_FALSE;
    841         }
    842         return JNI_TRUE;
    843     }
    844 
    845     // Copy the bitmap to a new blob.
    846     bool mutableCopy = isMutable;
    847 #if DEBUG_PARCEL
    848     ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
    849             isMutable ? "mutable" : "immutable",
    850             mutableCopy ? "mutable" : "immutable",
    851             p->allowFds() ? "allowed" : "forbidden");
    852 #endif
    853 
    854     size_t size = bitmap.computeByteSize();
    855     android::Parcel::WritableBlob blob;
    856     status = p->writeBlob(size, mutableCopy, &blob);
    857     if (status) {
    858         doThrowRE(env, "Could not copy bitmap to parcel blob.");
    859         return JNI_FALSE;
    860     }
    861 
    862     const void* pSrc =  bitmap.getPixels();
    863     if (pSrc == NULL) {
    864         memset(blob.data(), 0, size);
    865     } else {
    866         memcpy(blob.data(), pSrc, size);
    867     }
    868 
    869     blob.release();
    870     return JNI_TRUE;
    871 }
    872 
    873 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
    874                                    jlong srcHandle, jlong paintHandle,
    875                                    jintArray offsetXY) {
    876     SkBitmap src;
    877     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
    878     const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
    879     SkIPoint  offset;
    880     SkBitmap dst;
    881     HeapAllocator allocator;
    882 
    883     src.extractAlpha(&dst, paint, &allocator, &offset);
    884     // If Skia can't allocate pixels for destination bitmap, it resets
    885     // it, that is set its pixels buffer to NULL, and zero width and height.
    886     if (dst.getPixels() == NULL && src.getPixels() != NULL) {
    887         doThrowOOME(env, "failed to allocate pixels for alpha");
    888         return NULL;
    889     }
    890     if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
    891         int* array = env->GetIntArrayElements(offsetXY, NULL);
    892         array[0] = offset.fX;
    893         array[1] = offset.fY;
    894         env->ReleaseIntArrayElements(offsetXY, array, 0);
    895     }
    896 
    897     return createBitmap(env, allocator.getStorageObjAndReset(),
    898             getPremulBitmapCreateFlags(true));
    899 }
    900 
    901 ///////////////////////////////////////////////////////////////////////////////
    902 
    903 static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
    904     LocalScopedBitmap bitmapHolder(bitmapHandle);
    905     if (!bitmapHolder.valid()) return JNI_TRUE;
    906 
    907     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
    908     return colorSpace == nullptr || colorSpace->isSRGB();
    909 }
    910 
    911 static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
    912     LocalScopedBitmap bitmapHolder(bitmapHandle);
    913     if (!bitmapHolder.valid()) return JNI_FALSE;
    914 
    915     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
    916     sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
    917     return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
    918 }
    919 
    920 static jobject Bitmap_computeColorSpace(JNIEnv* env, jobject, jlong bitmapHandle) {
    921     LocalScopedBitmap bitmapHolder(bitmapHandle);
    922     if (!bitmapHolder.valid()) return nullptr;
    923 
    924     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
    925     if (colorSpace == nullptr) return nullptr;
    926 
    927     return GraphicsJNI::getColorSpace(env, colorSpace, bitmapHolder->info().colorType());
    928 }
    929 
    930 static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
    931     LocalScopedBitmap bitmapHolder(bitmapHandle);
    932     sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
    933     bitmapHolder->setColorSpace(cs);
    934 }
    935 
    936 ///////////////////////////////////////////////////////////////////////////////
    937 
    938 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
    939         jint x, jint y) {
    940     SkBitmap bitmap;
    941     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
    942 
    943     auto sRGB = SkColorSpace::MakeSRGB();
    944     SkImageInfo dstInfo = SkImageInfo::Make(
    945             1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
    946 
    947     SkColor dst;
    948     bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
    949     return static_cast<jint>(dst);
    950 }
    951 
    952 static jlong Bitmap_getColor(JNIEnv* env, jobject, jlong bitmapHandle,
    953         jint x, jint y) {
    954     SkBitmap bitmap;
    955     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
    956 
    957     SkImageInfo dstInfo = SkImageInfo::Make(
    958             1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType, bitmap.refColorSpace());
    959 
    960     uint64_t dst;
    961     bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
    962     return static_cast<jlong>(dst);
    963 }
    964 
    965 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
    966         jintArray pixelArray, jint offset, jint stride,
    967         jint x, jint y, jint width, jint height) {
    968     SkBitmap bitmap;
    969     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
    970 
    971     auto sRGB = SkColorSpace::MakeSRGB();
    972     SkImageInfo dstInfo = SkImageInfo::Make(
    973             width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
    974 
    975     jint* dst = env->GetIntArrayElements(pixelArray, NULL);
    976     bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
    977     env->ReleaseIntArrayElements(pixelArray, dst, 0);
    978 }
    979 
    980 ///////////////////////////////////////////////////////////////////////////////
    981 
    982 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
    983         jint x, jint y, jint colorHandle) {
    984     SkBitmap bitmap;
    985     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
    986     SkColor color = static_cast<SkColor>(colorHandle);
    987 
    988     auto sRGB = SkColorSpace::MakeSRGB();
    989     SkImageInfo srcInfo = SkImageInfo::Make(
    990             1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
    991     SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
    992 
    993     bitmap.writePixels(srcPM, x, y);
    994 }
    995 
    996 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
    997         jintArray pixelArray, jint offset, jint stride,
    998         jint x, jint y, jint width, jint height) {
    999     SkBitmap bitmap;
   1000     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1001     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
   1002             x, y, width, height, &bitmap);
   1003 }
   1004 
   1005 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
   1006                                       jlong bitmapHandle, jobject jbuffer) {
   1007     SkBitmap bitmap;
   1008     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1009     const void* src = bitmap.getPixels();
   1010 
   1011     if (NULL != src) {
   1012         android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
   1013 
   1014         // the java side has already checked that buffer is large enough
   1015         memcpy(abp.pointer(), src, bitmap.computeByteSize());
   1016     }
   1017 }
   1018 
   1019 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
   1020                                         jlong bitmapHandle, jobject jbuffer) {
   1021     SkBitmap bitmap;
   1022     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
   1023     void* dst = bitmap.getPixels();
   1024 
   1025     if (NULL != dst) {
   1026         android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
   1027         // the java side has already checked that buffer is large enough
   1028         memcpy(dst, abp.pointer(), bitmap.computeByteSize());
   1029         bitmap.notifyPixelsChanged();
   1030     }
   1031 }
   1032 
   1033 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
   1034     SkBitmap bm0;
   1035     SkBitmap bm1;
   1036 
   1037     LocalScopedBitmap bitmap0(bm0Handle);
   1038     LocalScopedBitmap bitmap1(bm1Handle);
   1039 
   1040     // Paying the price for making Hardware Bitmap as Config:
   1041     // later check for colorType will pass successfully,
   1042     // because Hardware Config internally may be RGBA8888 or smth like that.
   1043     if (bitmap0->isHardware() != bitmap1->isHardware()) {
   1044         return JNI_FALSE;
   1045     }
   1046 
   1047     bitmap0->bitmap().getSkBitmap(&bm0);
   1048     bitmap1->bitmap().getSkBitmap(&bm1);
   1049     if (bm0.width() != bm1.width()
   1050             || bm0.height() != bm1.height()
   1051             || bm0.colorType() != bm1.colorType()
   1052             || bm0.alphaType() != bm1.alphaType()
   1053             || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
   1054         return JNI_FALSE;
   1055     }
   1056 
   1057     // if we can't load the pixels, return false
   1058     if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
   1059         return JNI_FALSE;
   1060     }
   1061 
   1062     // now compare each scanline. We can't do the entire buffer at once,
   1063     // since we don't care about the pixel values that might extend beyond
   1064     // the width (since the scanline might be larger than the logical width)
   1065     const int h = bm0.height();
   1066     const size_t size = bm0.width() * bm0.bytesPerPixel();
   1067     for (int y = 0; y < h; y++) {
   1068         // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
   1069         // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
   1070         // and bm1 both have pixel data() (have passed NULL == getPixels() check),
   1071         // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
   1072         // to warn user those 2 unrecognized config bitmaps may be different.
   1073         void *bm0Addr = bm0.getAddr(0, y);
   1074         void *bm1Addr = bm1.getAddr(0, y);
   1075 
   1076         if(bm0Addr == NULL || bm1Addr == NULL) {
   1077             return JNI_FALSE;
   1078         }
   1079 
   1080         if (memcmp(bm0Addr, bm1Addr, size) != 0) {
   1081             return JNI_FALSE;
   1082         }
   1083     }
   1084     return JNI_TRUE;
   1085 }
   1086 
   1087 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
   1088     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1089     if (!bitmapHandle.valid()) return;
   1090     android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
   1091 }
   1092 
   1093 static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
   1094     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1095     return static_cast<jint>(bitmapHandle->getAllocationByteCount());
   1096 }
   1097 
   1098 static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
   1099     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1100     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
   1101             "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
   1102     Bitmap& hwuiBitmap = bitmapHandle->bitmap();
   1103     SkBitmap src;
   1104     hwuiBitmap.getSkBitmap(&src);
   1105 
   1106     if (src.pixelRef() == nullptr) {
   1107         doThrowRE(env, "Could not copy a hardware bitmap.");
   1108         return NULL;
   1109     }
   1110 
   1111     sk_sp<Bitmap> bitmap = Bitmap::createFrom(src.info(), *src.pixelRef());
   1112     return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
   1113 }
   1114 
   1115 static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
   1116                                                jlong colorSpacePtr) {
   1117     AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
   1118         hardwareBuffer);
   1119     sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
   1120     SkColorType ct = uirenderer::PixelFormatToColorType(buffer->getPixelFormat());
   1121     sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, ct,
   1122             GraphicsJNI::getNativeColorSpace(colorSpacePtr));
   1123     if (!bitmap.get()) {
   1124         ALOGW("failed to create hardware bitmap from hardware buffer");
   1125         return NULL;
   1126     }
   1127     return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
   1128 }
   1129 
   1130 static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
   1131     LocalScopedBitmap bitmapHandle(bitmapPtr);
   1132     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
   1133             "Hardware config is only supported config in Bitmap_getGraphicBuffer");
   1134 
   1135     Bitmap& hwuiBitmap = bitmapHandle->bitmap();
   1136     sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer());
   1137     return createJavaGraphicBuffer(env, buffer);
   1138 }
   1139 
   1140 static jboolean Bitmap_isImmutable(jlong bitmapHandle) {
   1141     LocalScopedBitmap bitmapHolder(bitmapHandle);
   1142     if (!bitmapHolder.valid()) return JNI_FALSE;
   1143 
   1144     return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
   1145 }
   1146 
   1147 static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
   1148     LocalScopedBitmap bitmapHolder(bitmapHandle);
   1149     if (!bitmapHolder.valid()) return;
   1150 
   1151     return bitmapHolder->bitmap().setImmutable();
   1152 }
   1153 
   1154 ///////////////////////////////////////////////////////////////////////////////
   1155 
   1156 static const JNINativeMethod gBitmapMethods[] = {
   1157     {   "nativeCreate",             "([IIIIIIZJ)Landroid/graphics/Bitmap;",
   1158         (void*)Bitmap_creator },
   1159     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
   1160         (void*)Bitmap_copy },
   1161     {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
   1162         (void*)Bitmap_copyAshmem },
   1163     {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
   1164         (void*)Bitmap_copyAshmemConfig },
   1165     {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
   1166     {   "nativeRecycle",            "(J)V", (void*)Bitmap_recycle },
   1167     {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
   1168     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
   1169         (void*)Bitmap_compress },
   1170     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
   1171     {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
   1172     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
   1173     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
   1174     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
   1175     {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
   1176     {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
   1177     {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
   1178     {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
   1179     {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
   1180     {   "nativeCreateFromParcel",
   1181         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
   1182         (void*)Bitmap_createFromParcel },
   1183     {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
   1184         (void*)Bitmap_writeToParcel },
   1185     {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
   1186         (void*)Bitmap_extractAlpha },
   1187     {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
   1188     {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
   1189     {   "nativeGetColor",           "(JII)J", (void*)Bitmap_getColor },
   1190     {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
   1191     {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
   1192     {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
   1193     {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
   1194                                             (void*)Bitmap_copyPixelsToBuffer },
   1195     {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
   1196                                             (void*)Bitmap_copyPixelsFromBuffer },
   1197     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
   1198     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
   1199     {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
   1200     {   "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
   1201         (void*)Bitmap_copyPreserveInternalConfig },
   1202     {   "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
   1203         (void*) Bitmap_wrapHardwareBufferBitmap },
   1204     {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
   1205         (void*) Bitmap_createGraphicBufferHandle },
   1206     {   "nativeComputeColorSpace",  "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
   1207     {   "nativeSetColorSpace",      "(JJ)V", (void*)Bitmap_setColorSpace },
   1208     {   "nativeIsSRGB",             "(J)Z", (void*)Bitmap_isSRGB },
   1209     {   "nativeIsSRGBLinear",       "(J)Z", (void*)Bitmap_isSRGBLinear},
   1210     {   "nativeSetImmutable",       "(J)V", (void*)Bitmap_setImmutable},
   1211 
   1212     // ------------ @CriticalNative ----------------
   1213     {   "nativeIsImmutable",        "(J)Z", (void*)Bitmap_isImmutable}
   1214 
   1215 };
   1216 
   1217 int register_android_graphics_Bitmap(JNIEnv* env)
   1218 {
   1219     gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
   1220     gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
   1221     gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
   1222     gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
   1223     return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
   1224                                          NELEM(gBitmapMethods));
   1225 }
   1226