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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user