summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Matt Sarett <msarett@google.com> 2015-12-16 16:05:42 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2015-12-16 16:05:42 +0000
commit938562500707b461506191d1336f634037addd20 (patch)
treed55f07dd644e10284d72ef1b599a1fdb27cc0d8c
parent2336f716c8f062a49b302bb1c8520ad73eb7cf37 (diff)
parent9e7cd6351b8245d3b0eff902beb89dc4c6d3ed19 (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.mk1
-rw-r--r--core/jni/android/graphics/AutoDecodeCancel.cpp101
-rw-r--r--core/jni/android/graphics/AutoDecodeCancel.h27
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp297
-rw-r--r--core/jni/android/graphics/BitmapFactory.h3
-rw-r--r--core/jni/android/graphics/BitmapRegionDecoder.cpp38
-rw-r--r--core/jni/android/graphics/NinePatchPeeker.cpp8
-rw-r--r--core/jni/android/graphics/NinePatchPeeker.h16
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;