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
100 lines
2.9 KiB
Java
100 lines
2.9 KiB
Java
/*
|
|
* Copyright (C) 2006 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.graphics;
|
|
|
|
import android.content.res.AssetManager;
|
|
import java.io.InputStream;
|
|
import java.io.FileInputStream;
|
|
|
|
public class Movie {
|
|
private final int mNativeMovie;
|
|
|
|
private Movie(int nativeMovie) {
|
|
if (nativeMovie == 0) {
|
|
throw new RuntimeException("native movie creation failed");
|
|
}
|
|
mNativeMovie = nativeMovie;
|
|
}
|
|
|
|
public native int width();
|
|
public native int height();
|
|
public native boolean isOpaque();
|
|
public native int duration();
|
|
|
|
public native boolean setTime(int relativeMilliseconds);
|
|
|
|
public native void draw(Canvas canvas, float x, float y, Paint paint);
|
|
|
|
public void draw(Canvas canvas, float x, float y) {
|
|
draw(canvas, x, y, null);
|
|
}
|
|
|
|
public static Movie decodeStream(InputStream is) {
|
|
if (is == null) {
|
|
return null;
|
|
}
|
|
if (is instanceof AssetManager.AssetInputStream) {
|
|
final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
|
|
return nativeDecodeAsset(asset);
|
|
}
|
|
|
|
return nativeDecodeStream(is);
|
|
}
|
|
|
|
private static native Movie nativeDecodeAsset(int asset);
|
|
private static native Movie nativeDecodeStream(InputStream is);
|
|
public static native Movie decodeByteArray(byte[] data, int offset,
|
|
int length);
|
|
|
|
private static native void nativeDestructor(int nativeMovie);
|
|
|
|
public static Movie decodeFile(String pathName) {
|
|
InputStream is;
|
|
try {
|
|
is = new FileInputStream(pathName);
|
|
}
|
|
catch (java.io.FileNotFoundException e) {
|
|
return null;
|
|
}
|
|
return decodeTempStream(is);
|
|
}
|
|
|
|
@Override
|
|
protected void finalize() throws Throwable {
|
|
try {
|
|
nativeDestructor(mNativeMovie);
|
|
} finally {
|
|
super.finalize();
|
|
}
|
|
}
|
|
|
|
private static Movie decodeTempStream(InputStream is) {
|
|
Movie moov = null;
|
|
try {
|
|
moov = decodeStream(is);
|
|
is.close();
|
|
}
|
|
catch (java.io.IOException e) {
|
|
/* do nothing.
|
|
If the exception happened on open, moov will be null.
|
|
If it happened on close, moov is still valid.
|
|
*/
|
|
}
|
|
return moov;
|
|
}
|
|
}
|