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