summaryrefslogtreecommitdiffstats
path: root/graphics/java/android/graphics/BitmapFactory.java
diff options
context:
space:
mode:
authorLeon Scroggins III <scroggo@google.com>2013-09-10 20:26:05 -0400
committerLeon Scroggins III <scroggo@google.com>2013-09-18 12:01:20 -0400
commit7315f1baee19476363235127bc1438e2a291fa15 (patch)
tree376c68ec739e970b66165d059cf8e1e8e6d86980 /graphics/java/android/graphics/BitmapFactory.java
parentc255a7113a6a6b058f1b3b5b128fba1d24bbd3d9 (diff)
downloadframeworks_base-7315f1baee19476363235127bc1438e2a291fa15.zip
frameworks_base-7315f1baee19476363235127bc1438e2a291fa15.tar.gz
frameworks_base-7315f1baee19476363235127bc1438e2a291fa15.tar.bz2
Use a native buffer for decoding images.
Fixes BUG:10725383 Depends on https://googleplex-android-review.git.corp.google.com/#/c/357300/ in external/skia. In the previous fix for BUG:8432093 and BUG:6493544 (https://googleplex-android-review.googlesource.com/#/c/346191/), instead of calling mark on the provided input stream, we copied the entire stream in native code (except in one case; more details below), allowing rewind no matter how much of the stream had been read. This was because two decoders may rewind after reading an arbitrary amount of the stream: SkImageDecoder_wbmp and SkImageDecoder_libjpeg. It turns out that the jpeg decoder does not need this rewind after arbitrary length (it is a failure recovery case, and libjpeg has a default recovery we can use - the above referenced CL in Skia uses the default). Although the wbmp decoder could read any amount given a stream with the "right" data, and then return false, such a stream would not be a valid stream of another format, so it is okay for this rewind to fail. Further, the previous fix was inefficient in the common case where the caller decodes just the bounds, resets, then decodes the entire image (since we have copied the entire stream twice). The copy also resulted in the crashes seen in BUG:10725383. In this CL, buffer only the amount of input needed by SkImageDecoder::Factory to determine the type of image decoder needed. Do not mark the input stream provided by the caller, so their mark (if any) can remain in tact. The new Skia class SkFrontBufferedStream allows buffering just the beginning of the stream. core/jni/android/graphics/BitmapFactory.cpp: Instead of calling GetRewindableStream (which has been removed), call CreateJavaInputStreamAdaptor. Then wrap it in an SkFrontBufferedStream, with a large enough buffer to determine which type of image is used. core/jni/android/graphics/CreateJavaOutputStreamAdaptor.h: core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp: Remove mark, markSupported, and rewind. CreateJavaInputStreamAdaptor now turns an SkStream which is not rewindable. If the caller needs rewind that needs to be handled differently (for example, by using SkFrontBufferedStream, as is done in BitmapFactory and Movie. Remove RewindableJavaStream and GetRewindableStream. Remove code specific to ByteArrayInputStream, which makes slow JNI calls. Instead, depend on the caller to buffer the input in the general case. There is no reason to special case this stream (especially since we already have decodeByteArray). Remove CheckForAssetStream, which is now always special cased in Java. core/jni/android/graphics/Movie.cpp: Call CreateJavaInputStreamAdaptor and use an SkFrontBufferedStream. Add a native function for decoding an Asset, and remove old call to CheckForAssetStream. graphics/java/android/graphics/BitmapFactory.java: Write a helper function for decoding a stream to consolidate common code. Buffer enough of the input so that SkImageDecoder::Factory can rewind after having read enough to determine the type. Unlike the old code, do NOT mark the caller's stream. This is handled in native code. The caller's mark (if any) is left alone. graphics/java/android/graphics/Movie.java: Check for an Asset stream before passing to native, and call a native function for handling the asset directly. BUG:6493544 BUG:8432093 BUG:10725383 Change-Id: Ide74d3606ff4bb2a8c6cdbf11bae3f96696f331a
Diffstat (limited to 'graphics/java/android/graphics/BitmapFactory.java')
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java24
1 files changed, 14 insertions, 10 deletions
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 23606a1..c8ace44 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -569,10 +569,7 @@ public class BitmapFactory {
final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
bm = nativeDecodeAsset(asset, outPadding, opts);
} else {
- byte [] tempStorage = null;
- if (opts != null) tempStorage = opts.inTempStorage;
- if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
- bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
+ bm = decodeStreamInternal(is, outPadding, opts);
}
if (bm == null && opts != null && opts.inBitmap != null) {
@@ -588,6 +585,18 @@ public class BitmapFactory {
}
/**
+ * Private helper function for decoding an InputStream natively. Buffers the input enough to
+ * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
+ */
+ private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+ // ASSERT(is != null);
+ byte [] tempStorage = null;
+ if (opts != null) tempStorage = opts.inTempStorage;
+ if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
+ return nativeDecodeStream(is, tempStorage, outPadding, opts);
+ }
+
+ /**
* Decode an input stream into a bitmap. If the input stream is null, or
* cannot be used to decode a bitmap, the function returns null.
* The stream's position will be where ever it was after the encoded data
@@ -624,13 +633,8 @@ public class BitmapFactory {
bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
} else {
FileInputStream fis = new FileInputStream(fd);
- // FIXME: If nativeDecodeStream grabbed the pointer to tempStorage
- // from Options, this code would not need to be duplicated.
- byte [] tempStorage = null;
- if (opts != null) tempStorage = opts.inTempStorage;
- if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
try {
- bm = nativeDecodeStream(fis, tempStorage, outPadding, opts);
+ bm = decodeStreamInternal(fis, outPadding, opts);
} finally {
try {
fis.close();