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