diff options
-rw-r--r-- | core/jni/android/graphics/AnimatedImageDrawable.cpp | 41 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/AnimatedImageDrawable.java | 3 | ||||
-rw-r--r-- | libs/hwui/hwui/AnimatedImageDrawable.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/hwui/AnimatedImageDrawable.h | 10 |
4 files changed, 48 insertions, 10 deletions
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp index d6496cdf499a..7166c757e602 100644 --- a/core/jni/android/graphics/AnimatedImageDrawable.cpp +++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp @@ -42,7 +42,6 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, } auto* imageDecoder = reinterpret_cast<ImageDecoder*>(nativeImageDecoder); - auto info = imageDecoder->mCodec->getInfo(); const SkISize scaledSize = SkISize::Make(width, height); SkIRect subset; if (jsubset) { @@ -51,6 +50,35 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, subset = SkIRect::MakeWH(width, height); } + auto info = imageDecoder->mCodec->getInfo(); + bool hasRestoreFrame = false; + if (imageDecoder->mCodec->getEncodedFormat() == SkEncodedImageFormat::kWEBP) { + if (width < info.width() && height < info.height()) { + // WebP will scale its SkBitmap to the scaled size. + // FIXME: b/73529447 GIF should do the same. + info = info.makeWH(width, height); + } + } else { + const int frameCount = imageDecoder->mCodec->codec()->getFrameCount(); + for (int i = 0; i < frameCount; ++i) { + SkCodec::FrameInfo frameInfo; + if (!imageDecoder->mCodec->codec()->getFrameInfo(i, &frameInfo)) { + doThrowIOE(env, "Failed to read frame info!"); + return 0; + } + if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) { + hasRestoreFrame = true; + break; + } + } + } + + size_t bytesUsed = info.computeMinByteSize(); + // SkAnimatedImage has one SkBitmap for decoding, plus an extra one if there is a + // kRestorePrevious frame. AnimatedImageDrawable has two SkPictures storing the current + // frame and the next frame. (The former assumes that the image is animated, and the + // latter assumes that it is drawn to a hardware canvas.) + bytesUsed *= hasRestoreFrame ? 4 : 3; sk_sp<SkPicture> picture; if (jpostProcess) { SkRect bounds = SkRect::MakeWH(subset.width(), subset.height()); @@ -63,6 +91,7 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, return 0; } picture = recorder.finishRecordingAsPicture(); + bytesUsed += picture->approximateBytesUsed(); } @@ -74,7 +103,10 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/, return 0; } - sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(animatedImg)); + bytesUsed += sizeof(animatedImg.get()); + + sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(std::move(animatedImg), + bytesUsed)); return reinterpret_cast<jlong>(drawable.release()); } @@ -202,10 +234,9 @@ static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobjec } } -static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { +static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - // FIXME: Report the size of the internal SkBitmap etc. - return sizeof(drawable); + return drawable->byteSize(); } static void AnimatedImageDrawable_nMarkInvisible(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java index c0f49208e27e..a47ecf517c70 100644 --- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java @@ -292,8 +292,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { mState = new State(nCreate(nativeImageDecoder, decoder, width, height, cropRect), inputStream, afd); - // FIXME: Use the right size for the native allocation. - long nativeSize = 200; + final long nativeSize = nNativeByteSize(mState.mNativePtr); NativeAllocationRegistry registry = new NativeAllocationRegistry( AnimatedImageDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize); registry.registerNativeAllocation(mState, mState.mNativePtr); diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp index 28d0bc42ad2f..c529f8773bbd 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.cpp +++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp @@ -26,8 +26,8 @@ namespace android { -AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage) - : mSkAnimatedImage(std::move(animatedImage)) { +AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) + : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { mTimeToShowNextSnapshot = mSkAnimatedImage->currentFrameDuration(); } diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h index f4e2ba751b70..a92b62db14f0 100644 --- a/libs/hwui/hwui/AnimatedImageDrawable.h +++ b/libs/hwui/hwui/AnimatedImageDrawable.h @@ -45,7 +45,9 @@ public: */ class ANDROID_API AnimatedImageDrawable : public SkDrawable { public: - AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage); + // bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the + // Snapshots. + AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed); /** * This updates the internal time and returns true if the animation needs @@ -100,11 +102,17 @@ public: Snapshot decodeNextFrame(); Snapshot reset(); + size_t byteSize() const { + return sizeof(this) + mBytesUsed; + } + protected: virtual void onDraw(SkCanvas* canvas) override; private: sk_sp<SkAnimatedImage> mSkAnimatedImage; + const size_t mBytesUsed; + bool mRunning = false; bool mStarting = false; |