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

Commit 2be87bb7 authored by John Reck's avatar John Reck
Browse files

Follow Firefox & Chrome GIF behavior

If a GIF animation has a duration <= 10ms then bump it to
100ms. This isn't correct behavior, but it's one that browsers
have been doing for so long that gifs are now authored to rely
on this behavior

Fixes: 192511662
Test: app in bug
Change-Id: Ia07f12aa15595193ed9e56910929dc6da9754128
parent 7220f21d
Loading
Loading
Loading
Loading
+25 −8
Original line number Diff line number Diff line
@@ -29,9 +29,10 @@

namespace android {

AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed)
        : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) {
    mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration());
AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed,
                                             SkEncodedImageFormat format)
        : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed), mFormat(format) {
    mTimeToShowNextSnapshot = ms2ns(currentFrameDuration());
    setStagingBounds(mSkAnimatedImage->getBounds());
}

@@ -92,7 +93,7 @@ bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) {
        // directly from mSkAnimatedImage.
        lock.unlock();
        std::unique_lock imageLock{mImageLock};
        *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration());
        *outDelay = ms2ns(currentFrameDuration());
        return true;
    } else {
        // The next snapshot has not yet been decoded, but we've already passed
@@ -109,7 +110,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() {
    Snapshot snap;
    {
        std::unique_lock lock{mImageLock};
        snap.mDurationMS = mSkAnimatedImage->decodeNextFrame();
        snap.mDurationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame());
        snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
    }

@@ -123,7 +124,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() {
        std::unique_lock lock{mImageLock};
        mSkAnimatedImage->reset();
        snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
        snap.mDurationMS = mSkAnimatedImage->currentFrameDuration();
        snap.mDurationMS = currentFrameDuration();
    }

    return snap;
@@ -274,7 +275,7 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
        {
            std::unique_lock lock{mImageLock};
            mSkAnimatedImage->reset();
            durationMS = mSkAnimatedImage->currentFrameDuration();
            durationMS = currentFrameDuration();
        }
        {
            std::unique_lock lock{mSwapLock};
@@ -306,7 +307,7 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
    {
        std::unique_lock lock{mImageLock};
        if (update) {
            durationMS = mSkAnimatedImage->decodeNextFrame();
            durationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame());
        }

        canvas->drawDrawable(mSkAnimatedImage.get());
@@ -336,4 +337,20 @@ SkRect AnimatedImageDrawable::onGetBounds() {
    return SkRectMakeLargest();
}

int AnimatedImageDrawable::adjustFrameDuration(int durationMs) {
    if (durationMs == SkAnimatedImage::kFinished) {
        return SkAnimatedImage::kFinished;
    }

    if (mFormat == SkEncodedImageFormat::kGIF) {
        // Match Chrome & Firefox behavior that gifs with a duration <= 10ms is bumped to 100ms
        return durationMs <= 10 ? 100 : durationMs;
    }
    return durationMs;
}

int AnimatedImageDrawable::currentFrameDuration() {
    return adjustFrameDuration(mSkAnimatedImage->currentFrameDuration());
}

}  // namespace android
+11 −6
Original line number Diff line number Diff line
@@ -16,16 +16,16 @@

#pragma once

#include <cutils/compiler.h>
#include <utils/Macros.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>

#include <SkAnimatedImage.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
#include <SkDrawable.h>
#include <SkEncodedImageFormat.h>
#include <SkPicture.h>
#include <cutils/compiler.h>
#include <utils/Macros.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>

#include <future>
#include <mutex>
@@ -48,7 +48,8 @@ class AnimatedImageDrawable : public SkDrawable {
public:
    // bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the
    // Snapshots.
    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);
    AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed,
                          SkEncodedImageFormat format);

    /**
     * This updates the internal time and returns true if the image needs
@@ -115,6 +116,7 @@ protected:
private:
    sk_sp<SkAnimatedImage> mSkAnimatedImage;
    const size_t mBytesUsed;
    const SkEncodedImageFormat mFormat;

    bool mRunning = false;
    bool mStarting = false;
@@ -157,6 +159,9 @@ private:
    Properties mProperties;

    std::unique_ptr<OnAnimationEndListener> mEndListener;

    int adjustFrameDuration(int);
    int currentFrameDuration();
};

}  // namespace android
+3 −3
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
        bytesUsed += picture->approximateBytesUsed();
    }


    SkEncodedImageFormat format = imageDecoder->mCodec->getEncodedFormat();
    sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
                                                               info, subset,
                                                               std::move(picture));
@@ -108,8 +108,8 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,

    bytesUsed += sizeof(animatedImg.get());

    sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(std::move(animatedImg),
                                                                    bytesUsed));
    sk_sp<AnimatedImageDrawable> drawable(
            new AnimatedImageDrawable(std::move(animatedImg), bytesUsed, format));
    return reinterpret_cast<jlong>(drawable.release());
}