diff --git a/api/current.xml b/api/current.xml index acc7e3d030cb7..36d169942f707 100644 --- a/api/current.xml +++ b/api/current.xml @@ -75752,6 +75752,16 @@ visibility="public" > + + - + @@ -264830,9 +264840,9 @@ deprecated="not deprecated" visibility="public" > - + - + @@ -273853,7 +273863,7 @@ - + - + - + - + - + - + @@ -276705,9 +276715,9 @@ > - + - + @@ -276743,9 +276753,9 @@ > - + - + - + - + - + - + GetIntField(options, gOptions_sampleSizeFieldID); @@ -203,6 +207,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, doDither = env->GetBooleanField(options, gOptions_ditherFieldID); preferQualityOverSpeed = env->GetBooleanField(options, gOptions_preferQualityOverSpeedFieldID); + javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); } SkImageDecoder* decoder = SkImageDecoder::Factory(stream); @@ -216,7 +221,14 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, NinePatchPeeker peeker(decoder); JavaPixelAllocator javaAllocator(env, reportSizeToVM); - SkBitmap* bitmap = new SkBitmap; + SkBitmap* bitmap; + if (javaBitmap == NULL) { + bitmap = new SkBitmap; + } else { + bitmap = (SkBitmap *) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID); + // config of supplied bitmap overrules config set in options + prefConfig = bitmap->getConfig(); + } Res_png_9patch dummy9Patch; SkAutoTDelete add(decoder); @@ -233,14 +245,14 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, // happens earlier than AutoDecoderCancel object is added // to the gAutoDecoderCancelMutex linked list. if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { - return nullObjectReturn("gOptions_mCancelID");; + return nullObjectReturn("gOptions_mCancelID"); } SkImageDecoder::Mode decodeMode = mode; if (isPurgeable) { decodeMode = SkImageDecoder::kDecodeBounds_Mode; } - if (!decoder->decode(stream, bitmap, prefConfig, decodeMode)) { + if (!decoder->decode(stream, bitmap, prefConfig, decodeMode, javaBitmap != NULL)) { return nullObjectReturn("decoder->decode returned false"); } @@ -301,6 +313,11 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, } // promise we will never change our pixels (great for sharing and pictures) pr->setImmutable(); + + if (javaBitmap != NULL) { + // If a java bitmap was passed in for reuse, pass it back + return javaBitmap; + } // now create the java bitmap return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk); } @@ -554,6 +571,8 @@ static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, int register_android_graphics_BitmapFactory(JNIEnv* env); int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options"); + gOptions_bitmapFieldID = getFieldIDCheck(env, gOptions_class, "inBitmap", + "Landroid/graphics/Bitmap;"); gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z"); gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I"); gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig", @@ -569,6 +588,8 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) { gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;"); gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z"); + gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); + gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I"); gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor"); gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I"); diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 66f8f700a7854..f6a9c639699f8 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -42,6 +42,26 @@ public class BitmapFactory { inScaled = true; } + /** + * If set, decode methods that take the Options object will attempt to + * reuse this bitmap when loading content. This is a hint to the decoder + * only, and the decoder may choose to create a new Bitmap instead. The + * current implementation necessitates that the reused bitmap be of the + * same size as the source content and in jpeg format (whether as a + * resource or as a stream). The {@link android.graphics.Bitmap.Config + * configuration} of the reused bitmap will override the setting of + * {@link #inPreferredConfig}, if set. + * + *

You should still always use the returned Bitmap of the decode + * method and not assume that reusing the bitmap worked, due to the + * constraints outlined above and failure situations that can occur. + * Checking whether the return value matches the value of the inBitmap + * set in the Options structure is a way to see if the bitmap was reused, + * but in all cases you should use the returned Bitmap to make sure + * that you are using the bitmap that was used as the decode destination.

+ */ + public Bitmap inBitmap; + /** * If set to true, the decoder will return null (no bitmap), but * the out... fields will still be set, allowing the caller to query