Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb3b38e2 authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

Report native allocation size of AnimatedImageDrawable

Bug: 73641604
Test: infeasible

Fix nNativeByteSize's return value to be jlong, instead of long.
Add up the bytes used by the SkAnimatedImage and SkPictures and store
them on the AnimatedImageDrawable for registration.
Note that this is an approximation, and it assumes it will be drawn to a
hardware canvas and animated.
parent bf190fd9
Loading
Loading
Loading
Loading
+36 −5
Original line number Diff line number Diff line
@@ -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) {
+1 −2
Original line number Diff line number Diff line
@@ -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);
+2 −2
Original line number Diff line number Diff line
@@ -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();
}

+9 −1
Original line number Diff line number Diff line
@@ -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;