Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93856250 authored by Matt Sarett's avatar Matt Sarett Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'BitmapFactory'

* changes:
  Allow SkAndroidCodec to compute the decode color type and alpha type
  Modify BitmapFactory to use SkAndroidCodec
  Make NinePatchPeeker inherit from SkPngChunkReader
parents 2336f716 9e7cd635
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -96,7 +96,6 @@ LOCAL_SRC_FILES:= \
    android_util_jar_StrictJarFile.cpp \
    android_graphics_Canvas.cpp \
    android_graphics_Picture.cpp \
    android/graphics/AutoDecodeCancel.cpp \
    android/graphics/AvoidXfermode.cpp \
    android/graphics/Bitmap.cpp \
    android/graphics/BitmapFactory.cpp \
+0 −101
Original line number Diff line number Diff line
#include "AutoDecodeCancel.h"
#include "SkMutex.h"

SK_DECLARE_STATIC_MUTEX(gAutoDecoderCancelMutex);
static AutoDecoderCancel* gAutoDecoderCancel;
#ifdef SK_DEBUG
static int gAutoDecoderCancelCount;
#endif

AutoDecoderCancel::AutoDecoderCancel(jobject joptions,
                                       SkImageDecoder* decoder) {
    fJOptions = joptions;
    fDecoder = decoder;

    if (NULL != joptions) {
        SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);

        // Add us as the head of the list
        fPrev = NULL;
        fNext = gAutoDecoderCancel;
        if (gAutoDecoderCancel) {
            gAutoDecoderCancel->fPrev = this;
        }
        gAutoDecoderCancel = this;

        SkDEBUGCODE(gAutoDecoderCancelCount += 1;)
        Validate();
    }
}

AutoDecoderCancel::~AutoDecoderCancel() {
    if (NULL != fJOptions) {
        SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);

        // take us out of the dllist
        AutoDecoderCancel* prev = fPrev;
        AutoDecoderCancel* next = fNext;

        if (prev) {
            SkASSERT(prev->fNext == this);
            prev->fNext = next;
        } else {
            SkASSERT(gAutoDecoderCancel == this);
            gAutoDecoderCancel = next;
        }
        if (next) {
            SkASSERT(next->fPrev == this);
            next->fPrev = prev;
        }

        SkDEBUGCODE(gAutoDecoderCancelCount -= 1;)
        Validate();
    }
}

bool AutoDecoderCancel::RequestCancel(jobject joptions) {
    SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);

    Validate();

    AutoDecoderCancel* pair = gAutoDecoderCancel;
    while (pair != NULL) {
        if (pair->fJOptions == joptions) {
            pair->fDecoder->cancelDecode();
            return true;
        }
        pair = pair->fNext;
    }
    return false;
}

#ifdef SK_DEBUG
// can only call this inside a lock on gAutoDecoderCancelMutex
void AutoDecoderCancel::Validate() {
    const int gCount = gAutoDecoderCancelCount;

    if (gCount == 0) {
        SkASSERT(gAutoDecoderCancel == NULL);
    } else {
        SkASSERT(gCount > 0);

        AutoDecoderCancel* curr = gAutoDecoderCancel;
        SkASSERT(curr);
        SkASSERT(curr->fPrev == NULL);

        int count = 0;
        while (curr) {
            count += 1;
            SkASSERT(count <= gCount);
            if (curr->fPrev) {
                SkASSERT(curr->fPrev->fNext == curr);
            }
            if (curr->fNext) {
                SkASSERT(curr->fNext->fPrev == curr);
            }
            curr = curr->fNext;
        }
        SkASSERT(count == gCount);
    }
}
#endif
+0 −27
Original line number Diff line number Diff line
#ifndef _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
#define _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_

#include <jni.h>
#include "SkImageDecoder.h"

class AutoDecoderCancel {
public:
    AutoDecoderCancel(jobject options, SkImageDecoder* decoder);
    ~AutoDecoderCancel();

    static bool RequestCancel(jobject options);

private:
    AutoDecoderCancel*  fNext;
    AutoDecoderCancel*  fPrev;
    jobject             fJOptions;  // java options object
    SkImageDecoder*     fDecoder;

#ifdef SK_DEBUG
    static void Validate();
#else
    static void Validate() {}
#endif
};

#endif  // _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
+179 −118
Original line number Diff line number Diff line
#define LOG_TAG "BitmapFactory"

#include "AutoDecodeCancel.h"
#include "BitmapFactory.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "GraphicsJNI.h"
#include "NinePatchPeeker.h"
#include "SkAndroidCodec.h"
#include "SkBRDAllocator.h"
#include "SkFrontBufferedStream.h"
#include "SkImageDecoder.h"
#include "SkMath.h"
@@ -48,41 +49,44 @@ jmethodID gInsetStruct_constructorMethodID;

using namespace android;

jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
    static const struct {
        SkImageDecoder::Format fFormat;
        const char*            fMimeType;
    } gMimeTypes[] = {
        { SkImageDecoder::kBMP_Format,  "image/bmp" },
        { SkImageDecoder::kGIF_Format,  "image/gif" },
        { SkImageDecoder::kICO_Format,  "image/x-ico" },
        { SkImageDecoder::kJPEG_Format, "image/jpeg" },
        { SkImageDecoder::kPNG_Format,  "image/png" },
        { SkImageDecoder::kWEBP_Format, "image/webp" },
        { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
    };

    const char* cstr = nullptr;
    for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
        if (gMimeTypes[i].fFormat == format) {
            cstr = gMimeTypes[i].fMimeType;
jstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format) {
    const char* mimeType;
    switch (format) {
        case SkEncodedFormat::kBMP_SkEncodedFormat:
            mimeType = "image/bmp";
            break;
        case SkEncodedFormat::kGIF_SkEncodedFormat:
            mimeType = "image/gif";
            break;
        case SkEncodedFormat::kICO_SkEncodedFormat:
            mimeType = "image/x-ico";
            break;
        case SkEncodedFormat::kJPEG_SkEncodedFormat:
            mimeType = "image/jpeg";
            break;
        case SkEncodedFormat::kPNG_SkEncodedFormat:
            mimeType = "image/png";
            break;
        case SkEncodedFormat::kWEBP_SkEncodedFormat:
            mimeType = "image/webp";
            break;
        case SkEncodedFormat::kWBMP_SkEncodedFormat:
            mimeType = "image/vnd.wap.wbmp";
            break;
        default:
            mimeType = nullptr;
            break;
        }
    }

    jstring jstr = nullptr;
    if (cstr != nullptr) {
    if (mimeType) {
        // NOTE: Caller should env->ExceptionCheck() for OOM
        // (can't check for nullptr as it's a valid return value)
        jstr = env->NewStringUTF(cstr);
        jstr = env->NewStringUTF(mimeType);
    }
    return jstr;
}

static bool optionsJustBounds(JNIEnv* env, jobject options) {
    return options != NULL && env->GetBooleanField(options, gOptions_justBoundsFieldID);
}

static void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) {
    for (int i = 0; i < count; i++) {
        divs[i] = int32_t(divs[i] * scale + 0.5f);
@@ -198,24 +202,32 @@ private:
};

static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
    // This function takes ownership of the input stream.  Since the SkAndroidCodec
    // will take ownership of the stream, we don't necessarily need to take ownership
    // here.  This is a precaution - if we were to return before creating the codec,
    // we need to make sure that we delete the stream.
    std::unique_ptr<SkStreamRewindable> streamDeleter(stream);

    // Set default values for the options parameters.
    int sampleSize = 1;

    SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodePixels_Mode;
    bool onlyDecodeSize = false;
    SkColorType prefColorType = kN32_SkColorType;

    bool doDither = true;
    bool isMutable = false;
    float scale = 1.0f;
    bool preferQualityOverSpeed = false;
    bool requireUnpremultiplied = false;

    jobject javaBitmap = NULL;

    // Update with options supplied by the client.
    if (options != NULL) {
        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
        if (optionsJustBounds(env, options)) {
            decodeMode = SkImageDecoder::kDecodeBounds_Mode;
        // Correct a non-positive sampleSize.  sampleSize defaults to zero within the
        // options object, which is strange.
        if (sampleSize <= 0) {
            sampleSize = 1;
        }

        if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) {
            onlyDecodeSize = true;
        }

        // initialize these, in case we fail later on
@@ -226,9 +238,6 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
        prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
        isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
        preferQualityOverSpeed = env->GetBooleanField(options,
                gOptions_preferQualityOverSpeedFieldID);
        requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
        javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);

@@ -241,18 +250,31 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
            }
        }
    }

    const bool willScale = scale != 1.0f;

    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
    if (decoder == NULL) {
        return nullObjectReturn("SkImageDecoder::Factory returned null");
    // Create the codec.
    NinePatchPeeker peeker;
    std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(),
            &peeker));
    if (!codec.get()) {
        return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
    }

    decoder->setSampleSize(sampleSize);
    decoder->setDitherImage(doDither);
    decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
    decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
    // Determine the output size and return if the client only wants the size.
    SkISize size = codec->getSampledDimensions(sampleSize);
    if (options != NULL) {
        jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat());
        if (env->ExceptionCheck()) {
            return nullObjectReturn("OOM in getEncodedFormat()");
        }
        env->SetIntField(options, gOptions_widthFieldID, size.width());
        env->SetIntField(options, gOptions_heightFieldID, size.height());
        env->SetObjectField(options, gOptions_mimeFieldID, mimeType);

        if (onlyDecodeSize) {
            return nullptr;
        }
    }

    android::Bitmap* reuseBitmap = nullptr;
    unsigned int existingBufferSize = 0;
@@ -267,71 +289,104 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        }
    }

    NinePatchPeeker peeker(decoder);
    decoder->setPeeker(&peeker);

    JavaPixelAllocator javaAllocator(env);
    RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
    ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
    SkBitmap::Allocator* outputAllocator = (javaBitmap != NULL) ?
            (SkBitmap::Allocator*)&recyclingAllocator : (SkBitmap::Allocator*)&javaAllocator;
    if (decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
        if (!willScale) {
            // If the java allocator is being used to allocate the pixel memory, the decoder
            // need not write zeroes, since the memory is initialized to 0.
            decoder->setSkipWritingZeroes(outputAllocator == &javaAllocator);
            decoder->setAllocator(outputAllocator);
        } else if (javaBitmap != NULL) {
            // check for eventual scaled bounds at allocation time, so we don't decode the bitmap
            // only to find the scaled result too large to fit in the allocation
            decoder->setAllocator(&scaleCheckingAllocator);
        }
    }

    // Only setup the decoder to be deleted after its stack-based, refcounted
    // components (allocators, peekers, etc) are declared. This prevents RefCnt
    // asserts from firing due to the order objects are deleted from the stack.
    std::unique_ptr<SkImageDecoder> add(decoder);

    AutoDecoderCancel adc(options, decoder);

    // To fix the race condition in case "requestCancelDecode"
    // happens earlier than AutoDecoderCancel object is added
    // to the gAutoDecoderCancelMutex linked list.
    if (options != NULL && env->GetBooleanField(options, gOptions_mCancelID)) {
        return nullObjectReturn("gOptions_mCancelID");
    SkBitmap::HeapAllocator heapAllocator;
    SkBitmap::Allocator* decodeAllocator;
    if (javaBitmap != nullptr && willScale) {
        // This will allocate pixels using a HeapAllocator, since there will be an extra
        // scaling step that copies these pixels into Java memory.  This allocator
        // also checks that the recycled javaBitmap is large enough.
        decodeAllocator = &scaleCheckingAllocator;
    } else if (javaBitmap != nullptr) {
        decodeAllocator = &recyclingAllocator;
    } else if (willScale) {
        // This will allocate pixels using a HeapAllocator, since there will be an extra
        // scaling step that copies these pixels into Java memory.
        decodeAllocator = &heapAllocator;
    } else {
        decodeAllocator = &javaAllocator;
    }

    // Set the decode colorType.  This is necessary because we can't always support
    // the requested colorType.
    SkColorType decodeColorType = codec->computeOutputColorType(prefColorType);

    // Construct a color table for the decode if necessary
    SkAutoTUnref<SkColorTable> colorTable(nullptr);
    SkPMColor* colorPtr = nullptr;
    int* colorCount = nullptr;
    int maxColors = 256;
    SkPMColor colors[256];
    if (kIndex_8_SkColorType == decodeColorType) {
        colorTable.reset(new SkColorTable(colors, maxColors));

        // SkColorTable expects us to initialize all of the colors before creating an
        // SkColorTable.  However, we are using SkBitmap with an Allocator to allocate
        // memory for the decode, so we need to create the SkColorTable before decoding.
        // It is safe for SkAndroidCodec to modify the colors because this SkBitmap is
        // not being used elsewhere.
        colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
        colorCount = &maxColors;
    }

    // Set the alpha type for the decode.
    SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);

    const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType,
            alphaType);
    SkImageInfo bitmapInfo = decodeInfo;
    if (decodeColorType == kGray_8_SkColorType) {
        // The legacy implementation of BitmapFactory used kAlpha8 for
        // grayscale images (before kGray8 existed).  While the codec
        // recognizes kGray8, we need to decode into a kAlpha8 bitmap
        // in order to avoid a behavior change.
        bitmapInfo = SkImageInfo::MakeA8(size.width(), size.height());
    }

    SkBitmap decodingBitmap;
    if (decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)
                != SkImageDecoder::kSuccess) {
        return nullObjectReturn("decoder->decode returned false");
    if (!decodingBitmap.setInfo(bitmapInfo) ||
            !decodingBitmap.tryAllocPixels(decodeAllocator, colorTable)) {
        // SkAndroidCodec should recommend a valid SkImageInfo, so setInfo()
        // should only only fail if the calculated value for rowBytes is too
        // large.
        // tryAllocPixels() can fail due to OOM on the Java heap, OOM on the
        // native heap, or the recycled javaBitmap being too small to reuse.
        return nullptr;
    }

    // Use SkAndroidCodec to perform the decode.
    SkAndroidCodec::AndroidOptions codecOptions;
    codecOptions.fZeroInitialized = (decodeAllocator == &javaAllocator) ?
            SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
    codecOptions.fColorPtr = colorPtr;
    codecOptions.fColorCount = colorCount;
    codecOptions.fSampleSize = sampleSize;
    SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(),
            decodingBitmap.rowBytes(), &codecOptions);
    switch (result) {
        case SkCodec::kSuccess:
        case SkCodec::kIncompleteInput:
            break;
        default:
            return nullObjectReturn("codec->getAndoridPixels() failed.");
    }

    int scaledWidth = decodingBitmap.width();
    int scaledHeight = decodingBitmap.height();
    // Some images may initially report that they have alpha due to the format
    // of the encoded data, but then never use any colors which have alpha
    // less than 100%.  Here we check if the image really had alpha, and
    // mark it as opaque if it is actually opaque.
    if (kOpaque_SkAlphaType != alphaType && !codec->reallyHasAlpha()) {
        decodingBitmap.setAlphaType(kOpaque_SkAlphaType);
    }

    if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
    int scaledWidth = size.width();
    int scaledHeight = size.height();
    if (willScale) {
        scaledWidth = int(scaledWidth * scale + 0.5f);
        scaledHeight = int(scaledHeight * scale + 0.5f);
    }

    // update options (if any)
    if (options != NULL) {
        jstring mimeType = getMimeTypeString(env, decoder->getFormat());
        if (env->ExceptionCheck()) {
            return nullObjectReturn("OOM in getMimeTypeString()");
        }
        env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
        env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
        env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
    }

    // if we're in justBounds mode, return now (skip the java bitmap)
    if (decodeMode == SkImageDecoder::kDecodeBounds_Mode) {
        return NULL;
    }

    jbyteArray ninePatchChunk = NULL;
    if (peeker.mPatch != NULL) {
        if (willScale) {
@@ -377,29 +432,36 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        const float sx = scaledWidth / float(decodingBitmap.width());
        const float sy = scaledHeight / float(decodingBitmap.height());

        // TODO: avoid copying when scaled size equals decodingBitmap size
        SkColorType colorType = colorTypeForScaledOutput(decodingBitmap.colorType());
        // Set the allocator for the outputBitmap.
        SkBitmap::Allocator* outputAllocator;
        if (javaBitmap != nullptr) {
            outputAllocator = &recyclingAllocator;
        } else {
            outputAllocator = &javaAllocator;
        }

        SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType());
        // FIXME: If the alphaType is kUnpremul and the image has alpha, the
        // colors may not be correct, since Skia does not yet support drawing
        // to/from unpremultiplied bitmaps.
        outputBitmap.setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,
                colorType, decodingBitmap.alphaType()));
                scaledColorType, decodingBitmap.alphaType()));
        if (!outputBitmap.tryAllocPixels(outputAllocator, NULL)) {
            // This should only fail on OOM.  The recyclingAllocator should have
            // enough memory since we check this before decoding using the
            // scaleCheckingAllocator.
            return nullObjectReturn("allocation failed for scaled bitmap");
        }

        // If outputBitmap's pixels are newly allocated by Java, there is no need
        // to erase to 0, since the pixels were initialized to 0.
        if (outputAllocator != &javaAllocator) {
            outputBitmap.eraseColor(0);
        }

        SkPaint paint;
        // kSrc_Mode instructs us to overwrite the unininitialized pixels in
        // outputBitmap.  Otherwise we would blend by default, which is not
        // what we want.
        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
        paint.setFilterQuality(kLow_SkFilterQuality);

        SkCanvas canvas(outputBitmap);
        canvas.scale(sx, sy);
        canvas.drawARGB(0x00, 0x00, 0x00, 0x00);
        canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
    } else {
        outputBitmap.swap(decodingBitmap);
@@ -415,8 +477,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        }
    }

    // if we get here, we're in kDecodePixels_Mode and will therefore
    // already have a pixelref installed.
    // If we get here, the outputBitmap should have an installed pixelref.
    if (outputBitmap.pixelRef() == NULL) {
        return nullObjectReturn("Got null SkPixelRef");
    }
@@ -426,8 +487,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        outputBitmap.setImmutable();
    }

    if (javaBitmap != NULL) {
    bool isPremultiplied = !requireUnpremultiplied;
    if (javaBitmap != nullptr) {
        GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
        outputBitmap.notifyPixelsChanged();
        // If a java bitmap was passed in for reuse, pass it back
@@ -436,7 +497,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding

    int bitmapCreateFlags = 0x0;
    if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
    if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
    if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;

    // now create the java bitmap
    return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(),
@@ -445,8 +506,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding

// Need to buffer enough input to be able to rewind as much as might be read by a decoder
// trying to determine the stream's format. Currently the most is 64, read by
// SkImageDecoder_libwebp.
// FIXME: Get this number from SkImageDecoder
// SkWebpCodec.
// FIXME: Get this number from SkCodec
#define BYTES_TO_BUFFER 64

static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
@@ -459,7 +520,7 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA
        std::unique_ptr<SkStreamRewindable> bufferedStream(
                SkFrontBufferedStream::Create(stream.release(), BYTES_TO_BUFFER));
        SkASSERT(bufferedStream.get() != NULL);
        bitmap = doDecode(env, bufferedStream.get(), padding, options);
        bitmap = doDecode(env, bufferedStream.release(), padding, options);
    }
    return bitmap;
}
@@ -505,7 +566,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
    std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
            BYTES_TO_BUFFER));

    return doDecode(env, stream.get(), padding, bitmapFactoryOptions);
    return doDecode(env, stream.release(), padding, bitmapFactoryOptions);
}

static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
@@ -514,20 +575,20 @@ static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
    Asset* asset = reinterpret_cast<Asset*>(native_asset);
    // since we know we'll be done with the asset when we return, we can
    // just use a simple wrapper
    AssetStreamAdaptor stream(asset);
    return doDecode(env, &stream, padding, options);
    std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
    return doDecode(env, stream.release(), padding, options);
}

static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
        jint offset, jint length, jobject options) {

    AutoJavaByteArray ar(env, byteArray);
    SkMemoryStream stream(ar.ptr() + offset, length, false);
    return doDecode(env, &stream, NULL, options);
    std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, false));
    return doDecode(env, stream.release(), NULL, options);
}

static void nativeRequestCancel(JNIEnv*, jobject joptions) {
    (void)AutoDecoderCancel::RequestCancel(joptions);
    // Deprecated
}

static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
+2 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
#define _ANDROID_GRAPHICS_BITMAP_FACTORY_H_

#include "GraphicsJNI.h"
#include "SkEncodedFormat.h"

extern jclass gOptions_class;
extern jfieldID gOptions_justBoundsFieldID;
@@ -19,7 +20,7 @@ extern jfieldID gOptions_mimeFieldID;
extern jfieldID gOptions_mCancelID;
extern jfieldID gOptions_bitmapFieldID;

jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format);
jstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format);

jobject decodeBitmap(JNIEnv* env, void* data, size_t size);

Loading