diff options
| author | 2015-12-16 16:05:42 +0000 | |
|---|---|---|
| committer | 2015-12-16 16:05:42 +0000 | |
| commit | 938562500707b461506191d1336f634037addd20 (patch) | |
| tree | d55f07dd644e10284d72ef1b599a1fdb27cc0d8c | |
| parent | 2336f716c8f062a49b302bb1c8520ad73eb7cf37 (diff) | |
| parent | 9e7cd6351b8245d3b0eff902beb89dc4c6d3ed19 (diff) | |
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
| -rw-r--r-- | core/jni/Android.mk | 1 | ||||
| -rw-r--r-- | core/jni/android/graphics/AutoDecodeCancel.cpp | 101 | ||||
| -rw-r--r-- | core/jni/android/graphics/AutoDecodeCancel.h | 27 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapFactory.cpp | 297 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapFactory.h | 3 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapRegionDecoder.cpp | 38 | ||||
| -rw-r--r-- | core/jni/android/graphics/NinePatchPeeker.cpp | 8 | ||||
| -rw-r--r-- | core/jni/android/graphics/NinePatchPeeker.h | 16 |
8 files changed, 190 insertions, 301 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index bdbd096326d5..a9a198bc40d1 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -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 \ diff --git a/core/jni/android/graphics/AutoDecodeCancel.cpp b/core/jni/android/graphics/AutoDecodeCancel.cpp deleted file mode 100644 index 0641b9673ae7..000000000000 --- a/core/jni/android/graphics/AutoDecodeCancel.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#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 diff --git a/core/jni/android/graphics/AutoDecodeCancel.h b/core/jni/android/graphics/AutoDecodeCancel.h deleted file mode 100644 index dd6a0d450171..000000000000 --- a/core/jni/android/graphics/AutoDecodeCancel.h +++ /dev/null @@ -1,27 +0,0 @@ -#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_ diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index ecaf9519d8bc..88b3769a1691 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -1,10 +1,11 @@ #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,69 +289,102 @@ 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); - } + 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; } - // 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"); + // 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; } - int scaledWidth = decodingBitmap.width(); - int scaledHeight = decodingBitmap.height(); - - if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) { - scaledWidth = int(scaledWidth * scale + 0.5f); - scaledHeight = int(scaledHeight * scale + 0.5f); + // 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."); } - // 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); + // 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 we're in justBounds mode, return now (skip the java bitmap) - if (decodeMode == SkImageDecoder::kDecodeBounds_Mode) { - return NULL; + int scaledWidth = size.width(); + int scaledHeight = size.height(); + if (willScale) { + scaledWidth = int(scaledWidth * scale + 0.5f); + scaledHeight = int(scaledHeight * scale + 0.5f); } jbyteArray ninePatchChunk = NULL; @@ -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; + 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) { diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h index 22a955f7b7b5..07825dfe42ef 100644 --- a/core/jni/android/graphics/BitmapFactory.h +++ b/core/jni/android/graphics/BitmapFactory.h @@ -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); diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index f10f4bda3226..492d766e6f5c 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -25,7 +25,6 @@ #include "SkBitmapRegionDecoder.h" #include "SkCodec.h" #include "SkData.h" -#include "SkEncodedFormat.h" #include "SkUtils.h" #include "SkPixelRef.h" #include "SkStream.h" @@ -42,43 +41,6 @@ using namespace android; -// This is very similar to, and based on, getMimeTypeString() in BitmapFactory. -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 (mimeType != nullptr) { - jstr = env->NewStringUTF(mimeType); - } - return jstr; -} - // Takes ownership of the SkStreamRewindable. For consistency, deletes stream even // when returning null. static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) { diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp index 6c32a218087a..8a84a3574ceb 100644 --- a/core/jni/android/graphics/NinePatchPeeker.cpp +++ b/core/jni/android/graphics/NinePatchPeeker.cpp @@ -17,10 +17,11 @@ #include "NinePatchPeeker.h" #include "SkBitmap.h" +#include "SkImageDecoder.h" using namespace android; -bool NinePatchPeeker::peek(const char tag[], const void* data, size_t length) { +bool NinePatchPeeker::readChunk(const char tag[], const void* data, size_t length) { if (!strcmp("npTc", tag) && length >= sizeof(Res_png_9patch)) { Res_png_9patch* patch = (Res_png_9patch*) data; size_t patchSize = patch->serializedSize(); @@ -35,11 +36,6 @@ bool NinePatchPeeker::peek(const char tag[], const void* data, size_t length) { free(mPatch); mPatch = patchNew; mPatchSize = patchSize; - - // now update our host to force index or 32bit config - // 'cause we don't want 565 predithered, since as a 9patch, we know - // we will be stretched, and therefore we want to dither afterwards. - mHost->setPreserveSrcDepth(true); } else if (!strcmp("npLb", tag) && length == sizeof(int32_t) * 4) { mHasInsets = true; memcpy(&mOpticalInsets, data, sizeof(int32_t) * 4); diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h index 2d49b38f8e78..126eab25fc30 100644 --- a/core/jni/android/graphics/NinePatchPeeker.h +++ b/core/jni/android/graphics/NinePatchPeeker.h @@ -17,19 +17,17 @@ #ifndef _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_ #define _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_ -#include "SkImageDecoder.h" +#include "SkPngChunkReader.h" #include <androidfw/ResourceTypes.h> +class SkImageDecoder; + using namespace android; -class NinePatchPeeker : public SkImageDecoder::Peeker { -private: - // the host lives longer than we do, so a raw ptr is safe - SkImageDecoder* mHost; +class NinePatchPeeker : public SkPngChunkReader { public: - NinePatchPeeker(SkImageDecoder* host) - : mHost(host) - , mPatch(NULL) + NinePatchPeeker() + : mPatch(NULL) , mPatchSize(0) , mHasInsets(false) , mOutlineRadius(0) @@ -42,7 +40,7 @@ public: free(mPatch); } - virtual bool peek(const char tag[], const void* data, size_t length); + bool readChunk(const char tag[], const void* data, size_t length) override; Res_png_9patch* mPatch; size_t mPatchSize; |