Home | History | Annotate | Download | only in graphics
      1 #define LOG_TAG "BitmapFactory"
      2 
      3 #include "BitmapFactory.h"
      4 #include "CreateJavaOutputStreamAdaptor.h"
      5 #include "GraphicsJNI.h"
      6 #include "NinePatchPeeker.h"
      7 #include "SkAndroidCodec.h"
      8 #include "SkBRDAllocator.h"
      9 #include "SkFrontBufferedStream.h"
     10 #include "SkMath.h"
     11 #include "SkPixelRef.h"
     12 #include "SkStream.h"
     13 #include "SkUtils.h"
     14 #include "Utils.h"
     15 #include "core_jni_helpers.h"
     16 
     17 #include <nativehelper/JNIHelp.h>
     18 #include <androidfw/Asset.h>
     19 #include <androidfw/ResourceTypes.h>
     20 #include <cutils/compiler.h>
     21 #include <memory>
     22 #include <netinet/in.h>
     23 #include <stdio.h>
     24 #include <sys/mman.h>
     25 #include <sys/stat.h>
     26 
     27 jfieldID gOptions_justBoundsFieldID;
     28 jfieldID gOptions_sampleSizeFieldID;
     29 jfieldID gOptions_configFieldID;
     30 jfieldID gOptions_colorSpaceFieldID;
     31 jfieldID gOptions_premultipliedFieldID;
     32 jfieldID gOptions_mutableFieldID;
     33 jfieldID gOptions_ditherFieldID;
     34 jfieldID gOptions_preferQualityOverSpeedFieldID;
     35 jfieldID gOptions_scaledFieldID;
     36 jfieldID gOptions_densityFieldID;
     37 jfieldID gOptions_screenDensityFieldID;
     38 jfieldID gOptions_targetDensityFieldID;
     39 jfieldID gOptions_widthFieldID;
     40 jfieldID gOptions_heightFieldID;
     41 jfieldID gOptions_mimeFieldID;
     42 jfieldID gOptions_outConfigFieldID;
     43 jfieldID gOptions_outColorSpaceFieldID;
     44 jfieldID gOptions_mCancelID;
     45 jfieldID gOptions_bitmapFieldID;
     46 
     47 jfieldID gBitmap_ninePatchInsetsFieldID;
     48 
     49 jclass gInsetStruct_class;
     50 jmethodID gInsetStruct_constructorMethodID;
     51 
     52 jclass gBitmapConfig_class;
     53 jmethodID gBitmapConfig_nativeToConfigMethodID;
     54 
     55 using namespace android;
     56 
     57 jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format) {
     58     const char* mimeType;
     59     switch (format) {
     60         case SkEncodedImageFormat::kBMP:
     61             mimeType = "image/bmp";
     62             break;
     63         case SkEncodedImageFormat::kGIF:
     64             mimeType = "image/gif";
     65             break;
     66         case SkEncodedImageFormat::kICO:
     67             mimeType = "image/x-ico";
     68             break;
     69         case SkEncodedImageFormat::kJPEG:
     70             mimeType = "image/jpeg";
     71             break;
     72         case SkEncodedImageFormat::kPNG:
     73             mimeType = "image/png";
     74             break;
     75         case SkEncodedImageFormat::kWEBP:
     76             mimeType = "image/webp";
     77             break;
     78         case SkEncodedImageFormat::kHEIF:
     79             mimeType = "image/heif";
     80             break;
     81         case SkEncodedImageFormat::kWBMP:
     82             mimeType = "image/vnd.wap.wbmp";
     83             break;
     84         case SkEncodedImageFormat::kDNG:
     85             mimeType = "image/x-adobe-dng";
     86             break;
     87         default:
     88             mimeType = nullptr;
     89             break;
     90     }
     91 
     92     jstring jstr = nullptr;
     93     if (mimeType) {
     94         // NOTE: Caller should env->ExceptionCheck() for OOM
     95         // (can't check for nullptr as it's a valid return value)
     96         jstr = env->NewStringUTF(mimeType);
     97     }
     98     return jstr;
     99 }
    100 
    101 static void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) {
    102     for (int i = 0; i < count; i++) {
    103         divs[i] = int32_t(divs[i] * scale + 0.5f);
    104         if (i > 0 && divs[i] == divs[i - 1]) {
    105             divs[i]++; // avoid collisions
    106         }
    107     }
    108 
    109     if (CC_UNLIKELY(divs[count - 1] > maxValue)) {
    110         // if the collision avoidance above put some divs outside the bounds of the bitmap,
    111         // slide outer stretchable divs inward to stay within bounds
    112         int highestAvailable = maxValue;
    113         for (int i = count - 1; i >= 0; i--) {
    114             divs[i] = highestAvailable;
    115             if (i > 0 && divs[i] <= divs[i-1]){
    116                 // keep shifting
    117                 highestAvailable = divs[i] - 1;
    118             } else {
    119                 break;
    120             }
    121         }
    122     }
    123 }
    124 
    125 static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale,
    126         int scaledWidth, int scaledHeight) {
    127     chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
    128     chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
    129     chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
    130     chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
    131 
    132     scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth);
    133     scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight);
    134 }
    135 
    136 class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
    137 public:
    138     ScaleCheckingAllocator(float scale, int size)
    139             : mScale(scale), mSize(size) {
    140     }
    141 
    142     virtual bool allocPixelRef(SkBitmap* bitmap) {
    143         // accounts for scale in final allocation, using eventual size and config
    144         const int bytesPerPixel = SkColorTypeBytesPerPixel(bitmap->colorType());
    145         const int requestedSize = bytesPerPixel *
    146                 int(bitmap->width() * mScale + 0.5f) *
    147                 int(bitmap->height() * mScale + 0.5f);
    148         if (requestedSize > mSize) {
    149             ALOGW("bitmap for alloc reuse (%d bytes) can't fit scaled bitmap (%d bytes)",
    150                     mSize, requestedSize);
    151             return false;
    152         }
    153         return SkBitmap::HeapAllocator::allocPixelRef(bitmap);
    154     }
    155 private:
    156     const float mScale;
    157     const int mSize;
    158 };
    159 
    160 class RecyclingPixelAllocator : public SkBitmap::Allocator {
    161 public:
    162     RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size)
    163             : mBitmap(bitmap), mSize(size) {
    164     }
    165 
    166     ~RecyclingPixelAllocator() {
    167     }
    168 
    169     virtual bool allocPixelRef(SkBitmap* bitmap) {
    170         const SkImageInfo& info = bitmap->info();
    171         if (info.colorType() == kUnknown_SkColorType) {
    172             ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
    173             return false;
    174         }
    175 
    176         const int64_t size64 = info.getSafeSize64(bitmap->rowBytes());
    177         if (!sk_64_isS32(size64)) {
    178             ALOGW("bitmap is too large");
    179             return false;
    180         }
    181 
    182         const size_t size = sk_64_asS32(size64);
    183         if (size > mSize) {
    184             ALOGW("bitmap marked for reuse (%u bytes) can't fit new bitmap "
    185                   "(%zu bytes)", mSize, size);
    186             return false;
    187         }
    188 
    189         mBitmap->reconfigure(info, bitmap->rowBytes());
    190         bitmap->setPixelRef(sk_ref_sp(mBitmap), 0, 0);
    191         return true;
    192     }
    193 
    194 private:
    195     android::Bitmap* const mBitmap;
    196     const unsigned int mSize;
    197 };
    198 
    199 // Necessary for decodes when the native decoder cannot scale to appropriately match the sampleSize
    200 // (for example, RAW). If the sampleSize divides evenly into the dimension, we require that the
    201 // scale matches exactly. If sampleSize does not divide evenly, we allow the decoder to choose how
    202 // best to round.
    203 static bool needsFineScale(const int fullSize, const int decodedSize, const int sampleSize) {
    204     if (fullSize % sampleSize == 0 && fullSize / sampleSize != decodedSize) {
    205         return true;
    206     } else if ((fullSize / sampleSize + 1) != decodedSize &&
    207                (fullSize / sampleSize) != decodedSize) {
    208         return true;
    209     }
    210     return false;
    211 }
    212 
    213 static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
    214                            const int sampleSize) {
    215     return needsFineScale(fullSize.width(), decodedSize.width(), sampleSize) ||
    216            needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
    217 }
    218 
    219 static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
    220     // This function takes ownership of the input stream.  Since the SkAndroidCodec
    221     // will take ownership of the stream, we don't necessarily need to take ownership
    222     // here.  This is a precaution - if we were to return before creating the codec,
    223     // we need to make sure that we delete the stream.
    224     std::unique_ptr<SkStreamRewindable> streamDeleter(stream);
    225 
    226     // Set default values for the options parameters.
    227     int sampleSize = 1;
    228     bool onlyDecodeSize = false;
    229     SkColorType prefColorType = kN32_SkColorType;
    230     bool isHardware = false;
    231     bool isMutable = false;
    232     float scale = 1.0f;
    233     bool requireUnpremultiplied = false;
    234     jobject javaBitmap = NULL;
    235     sk_sp<SkColorSpace> prefColorSpace = nullptr;
    236 
    237     // Update with options supplied by the client.
    238     if (options != NULL) {
    239         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
    240         // Correct a non-positive sampleSize.  sampleSize defaults to zero within the
    241         // options object, which is strange.
    242         if (sampleSize <= 0) {
    243             sampleSize = 1;
    244         }
    245 
    246         if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) {
    247             onlyDecodeSize = true;
    248         }
    249 
    250         // initialize these, in case we fail later on
    251         env->SetIntField(options, gOptions_widthFieldID, -1);
    252         env->SetIntField(options, gOptions_heightFieldID, -1);
    253         env->SetObjectField(options, gOptions_mimeFieldID, 0);
    254         env->SetObjectField(options, gOptions_outConfigFieldID, 0);
    255         env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0);
    256 
    257         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
    258         prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
    259         jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
    260         prefColorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
    261         isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
    262         isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
    263         requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
    264         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
    265 
    266         if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
    267             const int density = env->GetIntField(options, gOptions_densityFieldID);
    268             const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
    269             const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
    270             if (density != 0 && targetDensity != 0 && density != screenDensity) {
    271                 scale = (float) targetDensity / density;
    272             }
    273         }
    274     }
    275 
    276     if (isMutable && isHardware) {
    277         doThrowIAE(env, "Bitmaps with Config.HARWARE are always immutable");
    278         return nullObjectReturn("Cannot create mutable hardware bitmap");
    279     }
    280 
    281     // Create the codec.
    282     NinePatchPeeker peeker;
    283     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(
    284             streamDeleter.release(), &peeker));
    285     if (!codec.get()) {
    286         return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
    287     }
    288 
    289     // Do not allow ninepatch decodes to 565.  In the past, decodes to 565
    290     // would dither, and we do not want to pre-dither ninepatches, since we
    291     // know that they will be stretched.  We no longer dither 565 decodes,
    292     // but we continue to prevent ninepatches from decoding to 565, in order
    293     // to maintain the old behavior.
    294     if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) {
    295         prefColorType = kN32_SkColorType;
    296     }
    297 
    298     // Determine the output size.
    299     SkISize size = codec->getSampledDimensions(sampleSize);
    300 
    301     int scaledWidth = size.width();
    302     int scaledHeight = size.height();
    303     bool willScale = false;
    304 
    305     // Apply a fine scaling step if necessary.
    306     if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) {
    307         willScale = true;
    308         scaledWidth = codec->getInfo().width() / sampleSize;
    309         scaledHeight = codec->getInfo().height() / sampleSize;
    310     }
    311 
    312     // Set the decode colorType
    313     SkColorType decodeColorType = codec->computeOutputColorType(prefColorType);
    314     sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(
    315             decodeColorType, prefColorSpace);
    316 
    317     // Set the options and return if the client only wants the size.
    318     if (options != NULL) {
    319         jstring mimeType = encodedFormatToString(
    320                 env, (SkEncodedImageFormat)codec->getEncodedFormat());
    321         if (env->ExceptionCheck()) {
    322             return nullObjectReturn("OOM in encodedFormatToString()");
    323         }
    324         env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
    325         env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
    326         env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
    327 
    328         jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType);
    329         if (isHardware) {
    330             configID = GraphicsJNI::kHardware_LegacyBitmapConfig;
    331         }
    332         jobject config = env->CallStaticObjectMethod(gBitmapConfig_class,
    333                 gBitmapConfig_nativeToConfigMethodID, configID);
    334         env->SetObjectField(options, gOptions_outConfigFieldID, config);
    335 
    336         env->SetObjectField(options, gOptions_outColorSpaceFieldID,
    337                 GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
    338 
    339         if (onlyDecodeSize) {
    340             return nullptr;
    341         }
    342     }
    343 
    344     // Scale is necessary due to density differences.
    345     if (scale != 1.0f) {
    346         willScale = true;
    347         scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f);
    348         scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
    349     }
    350 
    351     android::Bitmap* reuseBitmap = nullptr;
    352     unsigned int existingBufferSize = 0;
    353     if (javaBitmap != NULL) {
    354         reuseBitmap = &bitmap::toBitmap(env, javaBitmap);
    355         if (reuseBitmap->isImmutable()) {
    356             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
    357             javaBitmap = NULL;
    358             reuseBitmap = nullptr;
    359         } else {
    360             existingBufferSize = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
    361         }
    362     }
    363 
    364     HeapAllocator defaultAllocator;
    365     RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
    366     ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
    367     SkBitmap::HeapAllocator heapAllocator;
    368     SkBitmap::Allocator* decodeAllocator;
    369     if (javaBitmap != nullptr && willScale) {
    370         // This will allocate pixels using a HeapAllocator, since there will be an extra
    371         // scaling step that copies these pixels into Java memory.  This allocator
    372         // also checks that the recycled javaBitmap is large enough.
    373         decodeAllocator = &scaleCheckingAllocator;
    374     } else if (javaBitmap != nullptr) {
    375         decodeAllocator = &recyclingAllocator;
    376     } else if (willScale || isHardware) {
    377         // This will allocate pixels using a HeapAllocator,
    378         // for scale case: there will be an extra scaling step.
    379         // for hardware case: there will be extra swizzling & upload to gralloc step.
    380         decodeAllocator = &heapAllocator;
    381     } else {
    382         decodeAllocator = &defaultAllocator;
    383     }
    384 
    385     SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
    386 
    387     const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(),
    388             decodeColorType, alphaType, decodeColorSpace);
    389 
    390     // For wide gamut images, we will leave the color space on the SkBitmap.  Otherwise,
    391     // use the default.
    392     SkImageInfo bitmapInfo = decodeInfo;
    393     if (decodeInfo.colorSpace() && decodeInfo.colorSpace()->isSRGB()) {
    394         bitmapInfo = bitmapInfo.makeColorSpace(GraphicsJNI::colorSpaceForType(decodeColorType));
    395     }
    396 
    397     if (decodeColorType == kGray_8_SkColorType) {
    398         // The legacy implementation of BitmapFactory used kAlpha8 for
    399         // grayscale images (before kGray8 existed).  While the codec
    400         // recognizes kGray8, we need to decode into a kAlpha8 bitmap
    401         // in order to avoid a behavior change.
    402         bitmapInfo =
    403                 bitmapInfo.makeColorType(kAlpha_8_SkColorType).makeAlphaType(kPremul_SkAlphaType);
    404     }
    405     SkBitmap decodingBitmap;
    406     if (!decodingBitmap.setInfo(bitmapInfo) ||
    407             !decodingBitmap.tryAllocPixels(decodeAllocator)) {
    408         // SkAndroidCodec should recommend a valid SkImageInfo, so setInfo()
    409         // should only only fail if the calculated value for rowBytes is too
    410         // large.
    411         // tryAllocPixels() can fail due to OOM on the Java heap, OOM on the
    412         // native heap, or the recycled javaBitmap being too small to reuse.
    413         return nullptr;
    414     }
    415 
    416     // Use SkAndroidCodec to perform the decode.
    417     SkAndroidCodec::AndroidOptions codecOptions;
    418     codecOptions.fZeroInitialized = decodeAllocator == &defaultAllocator ?
    419             SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
    420     codecOptions.fSampleSize = sampleSize;
    421     SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(),
    422             decodingBitmap.rowBytes(), &codecOptions);
    423     switch (result) {
    424         case SkCodec::kSuccess:
    425         case SkCodec::kIncompleteInput:
    426             break;
    427         default:
    428             return nullObjectReturn("codec->getAndroidPixels() failed.");
    429     }
    430 
    431     jbyteArray ninePatchChunk = NULL;
    432     if (peeker.mPatch != NULL) {
    433         if (willScale) {
    434             scaleNinePatchChunk(peeker.mPatch, scale, scaledWidth, scaledHeight);
    435         }
    436 
    437         size_t ninePatchArraySize = peeker.mPatch->serializedSize();
    438         ninePatchChunk = env->NewByteArray(ninePatchArraySize);
    439         if (ninePatchChunk == NULL) {
    440             return nullObjectReturn("ninePatchChunk == null");
    441         }
    442 
    443         jbyte* array = (jbyte*) env->GetPrimitiveArrayCritical(ninePatchChunk, NULL);
    444         if (array == NULL) {
    445             return nullObjectReturn("primitive array == null");
    446         }
    447 
    448         memcpy(array, peeker.mPatch, peeker.mPatchSize);
    449         env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
    450     }
    451 
    452     jobject ninePatchInsets = NULL;
    453     if (peeker.mHasInsets) {
    454         ninePatchInsets = env->NewObject(gInsetStruct_class, gInsetStruct_constructorMethodID,
    455                 peeker.mOpticalInsets[0], peeker.mOpticalInsets[1],
    456                 peeker.mOpticalInsets[2], peeker.mOpticalInsets[3],
    457                 peeker.mOutlineInsets[0], peeker.mOutlineInsets[1],
    458                 peeker.mOutlineInsets[2], peeker.mOutlineInsets[3],
    459                 peeker.mOutlineRadius, peeker.mOutlineAlpha, scale);
    460         if (ninePatchInsets == NULL) {
    461             return nullObjectReturn("nine patch insets == null");
    462         }
    463         if (javaBitmap != NULL) {
    464             env->SetObjectField(javaBitmap, gBitmap_ninePatchInsetsFieldID, ninePatchInsets);
    465         }
    466     }
    467 
    468     SkBitmap outputBitmap;
    469     if (willScale) {
    470         // This is weird so let me explain: we could use the scale parameter
    471         // directly, but for historical reasons this is how the corresponding
    472         // Dalvik code has always behaved. We simply recreate the behavior here.
    473         // The result is slightly different from simply using scale because of
    474         // the 0.5f rounding bias applied when computing the target image size
    475         const float sx = scaledWidth / float(decodingBitmap.width());
    476         const float sy = scaledHeight / float(decodingBitmap.height());
    477 
    478         // Set the allocator for the outputBitmap.
    479         SkBitmap::Allocator* outputAllocator;
    480         if (javaBitmap != nullptr) {
    481             outputAllocator = &recyclingAllocator;
    482         } else {
    483             outputAllocator = &defaultAllocator;
    484         }
    485 
    486         SkColorType scaledColorType = decodingBitmap.colorType();
    487         // FIXME: If the alphaType is kUnpremul and the image has alpha, the
    488         // colors may not be correct, since Skia does not yet support drawing
    489         // to/from unpremultiplied bitmaps.
    490         outputBitmap.setInfo(
    491                 bitmapInfo.makeWH(scaledWidth, scaledHeight).makeColorType(scaledColorType));
    492         if (!outputBitmap.tryAllocPixels(outputAllocator)) {
    493             // This should only fail on OOM.  The recyclingAllocator should have
    494             // enough memory since we check this before decoding using the
    495             // scaleCheckingAllocator.
    496             return nullObjectReturn("allocation failed for scaled bitmap");
    497         }
    498 
    499         SkPaint paint;
    500         // kSrc_Mode instructs us to overwrite the uninitialized pixels in
    501         // outputBitmap.  Otherwise we would blend by default, which is not
    502         // what we want.
    503         paint.setBlendMode(SkBlendMode::kSrc);
    504         paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering
    505 
    506         SkCanvas canvas(outputBitmap, SkCanvas::ColorBehavior::kLegacy);
    507         canvas.scale(sx, sy);
    508         canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
    509     } else {
    510         outputBitmap.swap(decodingBitmap);
    511     }
    512 
    513     if (padding) {
    514         if (peeker.mPatch != NULL) {
    515             GraphicsJNI::set_jrect(env, padding,
    516                     peeker.mPatch->paddingLeft, peeker.mPatch->paddingTop,
    517                     peeker.mPatch->paddingRight, peeker.mPatch->paddingBottom);
    518         } else {
    519             GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1);
    520         }
    521     }
    522 
    523     // If we get here, the outputBitmap should have an installed pixelref.
    524     if (outputBitmap.pixelRef() == NULL) {
    525         return nullObjectReturn("Got null SkPixelRef");
    526     }
    527 
    528     if (!isMutable && javaBitmap == NULL) {
    529         // promise we will never change our pixels (great for sharing and pictures)
    530         outputBitmap.setImmutable();
    531     }
    532 
    533     bool isPremultiplied = !requireUnpremultiplied;
    534     if (javaBitmap != nullptr) {
    535         bitmap::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
    536         outputBitmap.notifyPixelsChanged();
    537         // If a java bitmap was passed in for reuse, pass it back
    538         return javaBitmap;
    539     }
    540 
    541     int bitmapCreateFlags = 0x0;
    542     if (isMutable) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Mutable;
    543     if (isPremultiplied) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
    544 
    545     if (isHardware) {
    546         sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(outputBitmap);
    547         if (!hardwareBitmap.get()) {
    548             return nullObjectReturn("Failed to allocate a hardware bitmap");
    549         }
    550         return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags,
    551                 ninePatchChunk, ninePatchInsets, -1);
    552     }
    553 
    554     // now create the java bitmap
    555     return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
    556             bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
    557 }
    558 
    559 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
    560         jobject padding, jobject options) {
    561 
    562     jobject bitmap = NULL;
    563     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
    564 
    565     if (stream.get()) {
    566         std::unique_ptr<SkStreamRewindable> bufferedStream(
    567                 SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded()));
    568         SkASSERT(bufferedStream.get() != NULL);
    569         bitmap = doDecode(env, bufferedStream.release(), padding, options);
    570     }
    571     return bitmap;
    572 }
    573 
    574 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
    575         jobject padding, jobject bitmapFactoryOptions) {
    576 
    577     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
    578 
    579     int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
    580 
    581     struct stat fdStat;
    582     if (fstat(descriptor, &fdStat) == -1) {
    583         doThrowIOE(env, "broken file descriptor");
    584         return nullObjectReturn("fstat return -1");
    585     }
    586 
    587     // Restore the descriptor's offset on exiting this function. Even though
    588     // we dup the descriptor, both the original and dup refer to the same open
    589     // file description and changes to the file offset in one impact the other.
    590     AutoFDSeek autoRestore(descriptor);
    591 
    592     // Duplicate the descriptor here to prevent leaking memory. A leak occurs
    593     // if we only close the file descriptor and not the file object it is used to
    594     // create.  If we don't explicitly clean up the file (which in turn closes the
    595     // descriptor) the buffers allocated internally by fseek will be leaked.
    596     int dupDescriptor = dup(descriptor);
    597 
    598     FILE* file = fdopen(dupDescriptor, "r");
    599     if (file == NULL) {
    600         // cleanup the duplicated descriptor since it will not be closed when the
    601         // file is cleaned up (fclose).
    602         close(dupDescriptor);
    603         return nullObjectReturn("Could not open file");
    604     }
    605 
    606     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
    607 
    608     // If there is no offset for the file descriptor, we use SkFILEStream directly.
    609     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
    610         assert(isSeekable(dupDescriptor));
    611         return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions);
    612     }
    613 
    614     // Use a buffered stream. Although an SkFILEStream can be rewound, this
    615     // ensures that SkImageDecoder::Factory never rewinds beyond the
    616     // current position of the file descriptor.
    617     std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
    618             SkCodec::MinBufferedBytesNeeded()));
    619 
    620     return doDecode(env, stream.release(), padding, bitmapFactoryOptions);
    621 }
    622 
    623 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
    624         jobject padding, jobject options) {
    625 
    626     Asset* asset = reinterpret_cast<Asset*>(native_asset);
    627     // since we know we'll be done with the asset when we return, we can
    628     // just use a simple wrapper
    629     std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
    630     return doDecode(env, stream.release(), padding, options);
    631 }
    632 
    633 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
    634         jint offset, jint length, jobject options) {
    635 
    636     AutoJavaByteArray ar(env, byteArray);
    637     std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, false));
    638     return doDecode(env, stream.release(), NULL, options);
    639 }
    640 
    641 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
    642     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
    643     return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE;
    644 }
    645 
    646 jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
    647     SkMemoryStream stream(data, size);
    648     return doDecode(env, &stream, NULL, NULL);
    649 }
    650 
    651 ///////////////////////////////////////////////////////////////////////////////
    652 
    653 static const JNINativeMethod gMethods[] = {
    654     {   "nativeDecodeStream",
    655         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
    656         (void*)nativeDecodeStream
    657     },
    658 
    659     {   "nativeDecodeFileDescriptor",
    660         "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
    661         (void*)nativeDecodeFileDescriptor
    662     },
    663 
    664     {   "nativeDecodeAsset",
    665         "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
    666         (void*)nativeDecodeAsset
    667     },
    668 
    669     {   "nativeDecodeByteArray",
    670         "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
    671         (void*)nativeDecodeByteArray
    672     },
    673 
    674     {   "nativeIsSeekable",
    675         "(Ljava/io/FileDescriptor;)Z",
    676         (void*)nativeIsSeekable
    677     },
    678 };
    679 
    680 int register_android_graphics_BitmapFactory(JNIEnv* env) {
    681     jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
    682     gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
    683             "Landroid/graphics/Bitmap;");
    684     gOptions_justBoundsFieldID = GetFieldIDOrDie(env, options_class, "inJustDecodeBounds", "Z");
    685     gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I");
    686     gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig",
    687             "Landroid/graphics/Bitmap$Config;");
    688     gOptions_colorSpaceFieldID = GetFieldIDOrDie(env, options_class, "inPreferredColorSpace",
    689             "Landroid/graphics/ColorSpace;");
    690     gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z");
    691     gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z");
    692     gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z");
    693     gOptions_preferQualityOverSpeedFieldID = GetFieldIDOrDie(env, options_class,
    694             "inPreferQualityOverSpeed", "Z");
    695     gOptions_scaledFieldID = GetFieldIDOrDie(env, options_class, "inScaled", "Z");
    696     gOptions_densityFieldID = GetFieldIDOrDie(env, options_class, "inDensity", "I");
    697     gOptions_screenDensityFieldID = GetFieldIDOrDie(env, options_class, "inScreenDensity", "I");
    698     gOptions_targetDensityFieldID = GetFieldIDOrDie(env, options_class, "inTargetDensity", "I");
    699     gOptions_widthFieldID = GetFieldIDOrDie(env, options_class, "outWidth", "I");
    700     gOptions_heightFieldID = GetFieldIDOrDie(env, options_class, "outHeight", "I");
    701     gOptions_mimeFieldID = GetFieldIDOrDie(env, options_class, "outMimeType", "Ljava/lang/String;");
    702     gOptions_outConfigFieldID = GetFieldIDOrDie(env, options_class, "outConfig",
    703              "Landroid/graphics/Bitmap$Config;");
    704     gOptions_outColorSpaceFieldID = GetFieldIDOrDie(env, options_class, "outColorSpace",
    705              "Landroid/graphics/ColorSpace;");
    706     gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z");
    707 
    708     jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap");
    709     gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets",
    710             "Landroid/graphics/NinePatch$InsetStruct;");
    711 
    712     gInsetStruct_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
    713         "android/graphics/NinePatch$InsetStruct"));
    714     gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>",
    715                                                         "(IIIIIIIIFIF)V");
    716 
    717     gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
    718             "android/graphics/Bitmap$Config"));
    719     gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class,
    720             "nativeToConfig", "(I)Landroid/graphics/Bitmap$Config;");
    721 
    722     return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
    723                                          gMethods, NELEM(gMethods));
    724 }
    725