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