Loading core/jni/android/graphics/AnimatedImageDrawable.cpp +0 −6 Original line number Original line Diff line number Diff line Loading @@ -239,11 +239,6 @@ static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz* return drawable->byteSize(); return drawable->byteSize(); } } static void AnimatedImageDrawable_nMarkInvisible(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); drawable->markInvisible(); } static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jboolean mirrored) { jboolean mirrored) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); Loading @@ -264,7 +259,6 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount }, { "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount }, { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nMarkInvisible", "(J)V", (void*) AnimatedImageDrawable_nMarkInvisible }, { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored }, { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored }, }; }; Loading graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +2 −20 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Rect; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; import android.os.SystemClock; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.DisplayMetrics; import android.util.TypedValue; import android.util.TypedValue; Loading Loading @@ -348,7 +349,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { if (mRunnable == null) { if (mRunnable == null) { mRunnable = this::invalidateSelf; mRunnable = this::invalidateSelf; } } scheduleSelf(mRunnable, nextUpdate); scheduleSelf(mRunnable, nextUpdate + SystemClock.uptimeMillis()); } else if (nextUpdate == FINISHED) { } else if (nextUpdate == FINISHED) { // This means the animation was drawn in software mode and ended. // This means the animation was drawn in software mode and ended. postOnAnimationEnd(); postOnAnimationEnd(); Loading Loading @@ -430,23 +431,6 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { return mState.mAutoMirrored; return mState.mAutoMirrored; } } @Override public boolean setVisible(boolean visible, boolean restart) { if (!super.setVisible(visible, restart)) { return false; } if (mState.mNativePtr == 0) { throw new IllegalStateException("called setVisible on empty AnimatedImageDrawable"); } if (!visible) { nMarkInvisible(mState.mNativePtr); } return true; } // Animatable overrides // Animatable overrides /** /** * Return whether the animation is currently running. * Return whether the animation is currently running. Loading Loading @@ -616,7 +600,5 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { @FastNative @FastNative private static native long nNativeByteSize(long nativePtr); private static native long nNativeByteSize(long nativePtr); @FastNative @FastNative private static native void nMarkInvisible(long nativePtr); @FastNative private static native void nSetMirrored(long nativePtr, boolean mirror); private static native void nSetMirrored(long nativePtr, boolean mirror); } } libs/hwui/TreeInfo.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,12 @@ public: // *OR* will post itself for the next vsync automatically, use this // *OR* will post itself for the next vsync automatically, use this // only to avoid calling draw() // only to avoid calling draw() bool canDrawThisFrame = true; bool canDrawThisFrame = true; // Sentinel for animatedImageDelay meaning there is no need to post such // a message. static constexpr nsecs_t kNoAnimatedImageDelay = -1; // This is used to post a message to redraw when it is time to draw the // next frame of an AnimatedImageDrawable. nsecs_t animatedImageDelay = kNoAnimatedImageDelay; } out; } out; // This flag helps to disable projection for receiver nodes that do not have any backward // This flag helps to disable projection for receiver nodes that do not have any backward Loading libs/hwui/hwui/AnimatedImageDrawable.cpp +47 −36 Original line number Original line Diff line number Diff line Loading @@ -22,13 +22,12 @@ #include <SkPicture.h> #include <SkPicture.h> #include <SkRefCnt.h> #include <SkRefCnt.h> #include <SkTLazy.h> #include <SkTLazy.h> #include <SkTime.h> namespace android { namespace android { AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { mTimeToShowNextSnapshot = mSkAnimatedImage->currentFrameDuration(); mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration()); } } void AnimatedImageDrawable::syncProperties() { void AnimatedImageDrawable::syncProperties() { Loading Loading @@ -62,28 +61,42 @@ bool AnimatedImageDrawable::nextSnapshotReady() const { } } // Only called on the RenderThread while UI thread is locked. // Only called on the RenderThread while UI thread is locked. bool AnimatedImageDrawable::isDirty() { bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) { const double currentTime = SkTime::GetMSecs(); *outDelay = 0; const double lastWallTime = mLastWallTime; const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC); const nsecs_t lastWallTime = mLastWallTime; mLastWallTime = currentTime; mLastWallTime = currentTime; if (!mRunning) { if (!mRunning) { mDidDraw = false; return false; return false; } } std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; if (mDidDraw) { mCurrentTime += currentTime - lastWallTime; mCurrentTime += currentTime - lastWallTime; mDidDraw = false; } if (!mNextSnapshot.valid()) { if (!mNextSnapshot.valid()) { // Need to trigger onDraw in order to start decoding the next frame. // Need to trigger onDraw in order to start decoding the next frame. *outDelay = mTimeToShowNextSnapshot - mCurrentTime; return true; return true; } } return nextSnapshotReady() && mCurrentTime >= mTimeToShowNextSnapshot; if (mTimeToShowNextSnapshot > mCurrentTime) { *outDelay = mTimeToShowNextSnapshot - mCurrentTime; } else if (nextSnapshotReady()) { // We have not yet updated mTimeToShowNextSnapshot. Read frame duration // directly from mSkAnimatedImage. lock.unlock(); std::unique_lock imageLock{mImageLock}; *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration()); return true; } else { // The next snapshot has not yet been decoded, but we've already passed // time to draw it. There's not a good way to know when decoding will // finish, so request an update immediately. *outDelay = 0; } return false; } } // Only called on the AnimatedImageThread. // Only called on the AnimatedImageThread. Loading @@ -91,7 +104,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() { Snapshot snap; Snapshot snap; { { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; snap.mDuration = mSkAnimatedImage->decodeNextFrame(); snap.mDurationMS = mSkAnimatedImage->decodeNextFrame(); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); } } Loading @@ -105,7 +118,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; mSkAnimatedImage->reset(); mSkAnimatedImage->reset(); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); snap.mDuration = mSkAnimatedImage->currentFrameDuration(); snap.mDurationMS = mSkAnimatedImage->currentFrameDuration(); } } return snap; return snap; Loading @@ -127,8 +140,6 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { canvas->scale(-1, 1); canvas->scale(-1, 1); } } mDidDraw = true; const bool starting = mStarting; const bool starting = mStarting; mStarting = false; mStarting = false; Loading Loading @@ -157,12 +168,12 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; if (mCurrentTime >= mTimeToShowNextSnapshot) { if (mCurrentTime >= mTimeToShowNextSnapshot) { mSnapshot = mNextSnapshot.get(); mSnapshot = mNextSnapshot.get(); const double timeToShowCurrentSnap = mTimeToShowNextSnapshot; const nsecs_t timeToShowCurrentSnap = mTimeToShowNextSnapshot; if (mSnapshot.mDuration == SkAnimatedImage::kFinished) { if (mSnapshot.mDurationMS == SkAnimatedImage::kFinished) { finalFrame = true; finalFrame = true; mRunning = false; mRunning = false; } else { } else { mTimeToShowNextSnapshot += mSnapshot.mDuration; mTimeToShowNextSnapshot += ms2ns(mSnapshot.mDurationMS); if (mCurrentTime >= mTimeToShowNextSnapshot) { if (mCurrentTime >= mTimeToShowNextSnapshot) { // This would mean showing the current frame very briefly. It's // This would mean showing the current frame very briefly. It's // possible that not being displayed for a time resulted in // possible that not being displayed for a time resulted in Loading Loading @@ -192,7 +203,7 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { } } } } double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { SkAutoCanvasRestore acr(canvas, false); SkAutoCanvasRestore acr(canvas, false); if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) { if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) { SkPaint paint; SkPaint paint; Loading @@ -211,69 +222,69 @@ double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { // to redraw. // to redraw. std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; canvas->drawDrawable(mSkAnimatedImage.get()); canvas->drawDrawable(mSkAnimatedImage.get()); return 0.0; return 0; } } if (mStarting) { if (mStarting) { mStarting = false; mStarting = false; double duration = 0.0; int durationMS = 0; { { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; mSkAnimatedImage->reset(); mSkAnimatedImage->reset(); duration = mSkAnimatedImage->currentFrameDuration(); durationMS = mSkAnimatedImage->currentFrameDuration(); } } { { std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; mLastWallTime = 0.0; mLastWallTime = 0; mTimeToShowNextSnapshot = duration; // The current time will be added later, below. mTimeToShowNextSnapshot = ms2ns(durationMS); } } } } bool update = false; bool update = false; { { const double currentTime = SkTime::GetMSecs(); const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC); std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; // mLastWallTime starts off at 0. If it is still 0, just update it to // mLastWallTime starts off at 0. If it is still 0, just update it to // the current time and avoid updating // the current time and avoid updating if (mLastWallTime == 0.0) { if (mLastWallTime == 0) { mCurrentTime = currentTime; mCurrentTime = currentTime; // mTimeToShowNextSnapshot is already set to the duration of the // mTimeToShowNextSnapshot is already set to the duration of the // first frame. // first frame. mTimeToShowNextSnapshot += currentTime; mTimeToShowNextSnapshot += currentTime; } else if (mRunning && mDidDraw) { } else if (mRunning) { mCurrentTime += currentTime - mLastWallTime; mCurrentTime += currentTime - mLastWallTime; update = mCurrentTime >= mTimeToShowNextSnapshot; update = mCurrentTime >= mTimeToShowNextSnapshot; } } mLastWallTime = currentTime; mLastWallTime = currentTime; } } double duration = 0.0; int durationMS = 0; { { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; if (update) { if (update) { duration = mSkAnimatedImage->decodeNextFrame(); durationMS = mSkAnimatedImage->decodeNextFrame(); } } canvas->drawDrawable(mSkAnimatedImage.get()); canvas->drawDrawable(mSkAnimatedImage.get()); } } mDidDraw = true; std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; if (update) { if (update) { if (duration == SkAnimatedImage::kFinished) { if (durationMS == SkAnimatedImage::kFinished) { mRunning = false; mRunning = false; return duration; return SkAnimatedImage::kFinished; } } const double timeToShowCurrentSnapshot = mTimeToShowNextSnapshot; const nsecs_t timeToShowCurrentSnapshot = mTimeToShowNextSnapshot; mTimeToShowNextSnapshot += duration; mTimeToShowNextSnapshot += ms2ns(durationMS); if (mCurrentTime >= mTimeToShowNextSnapshot) { if (mCurrentTime >= mTimeToShowNextSnapshot) { // As in onDraw, prevent speedy catch-up behavior. // As in onDraw, prevent speedy catch-up behavior. mCurrentTime = timeToShowCurrentSnapshot; mCurrentTime = timeToShowCurrentSnapshot; } } } } return mTimeToShowNextSnapshot; return ns2ms(mTimeToShowNextSnapshot - mCurrentTime); } } } // namespace android } // namespace android libs/hwui/hwui/AnimatedImageDrawable.h +14 −13 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <cutils/compiler.h> #include <cutils/compiler.h> #include <utils/Macros.h> #include <utils/Macros.h> #include <utils/RefBase.h> #include <utils/RefBase.h> #include <utils/Timers.h> #include <SkAnimatedImage.h> #include <SkAnimatedImage.h> #include <SkCanvas.h> #include <SkCanvas.h> Loading Loading @@ -50,12 +51,15 @@ public: AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed); AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed); /** /** * This updates the internal time and returns true if the animation needs * This updates the internal time and returns true if the image needs * to be redrawn. * to be redrawn this frame. * * * This is called on RenderThread, while the UI thread is locked. * This is called on RenderThread, while the UI thread is locked. * * @param outDelay Nanoseconds in the future when the following frame * will need to be drawn. 0 if not running. */ */ bool isDirty(); bool isDirty(nsecs_t* outDelay); int getStagingAlpha() const { return mStagingProperties.mAlpha; } int getStagingAlpha() const { return mStagingProperties.mAlpha; } void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; } void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; } Loading @@ -68,7 +72,9 @@ public: virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); } virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); } // Draw to software canvas, and return time to next draw. // Draw to software canvas, and return time to next draw. double drawStaging(SkCanvas* canvas); // 0 means the animation is not running. // -1 means the animation advanced to the final frame. int drawStaging(SkCanvas* canvas); // Returns true if the animation was started; false otherwise (e.g. it was // Returns true if the animation was started; false otherwise (e.g. it was // already running) // already running) Loading @@ -84,11 +90,9 @@ public: mEndListener = std::move(listener); mEndListener = std::move(listener); } } void markInvisible() { mDidDraw = false; } struct Snapshot { struct Snapshot { sk_sp<SkPicture> mPic; sk_sp<SkPicture> mPic; int mDuration; int mDurationMS; Snapshot() = default; Snapshot() = default; Loading Loading @@ -122,16 +126,13 @@ private: bool nextSnapshotReady() const; bool nextSnapshotReady() const; // When to switch from mSnapshot to mNextSnapshot. // When to switch from mSnapshot to mNextSnapshot. double mTimeToShowNextSnapshot = 0.0; nsecs_t mTimeToShowNextSnapshot = 0; // The current time for the drawable itself. // The current time for the drawable itself. double mCurrentTime = 0.0; nsecs_t mCurrentTime = 0; // The wall clock of the last time we called isDirty. // The wall clock of the last time we called isDirty. double mLastWallTime = 0.0; nsecs_t mLastWallTime = 0; // Whether we drew since the last call to isDirty. bool mDidDraw = false; // Locked when assigning snapshots and times. Operations while this is held // Locked when assigning snapshots and times. Operations while this is held // should be short. // should be short. Loading Loading
core/jni/android/graphics/AnimatedImageDrawable.cpp +0 −6 Original line number Original line Diff line number Diff line Loading @@ -239,11 +239,6 @@ static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz* return drawable->byteSize(); return drawable->byteSize(); } } static void AnimatedImageDrawable_nMarkInvisible(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); drawable->markInvisible(); } static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jboolean mirrored) { jboolean mirrored) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); Loading @@ -264,7 +259,6 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount }, { "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount }, { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nMarkInvisible", "(J)V", (void*) AnimatedImageDrawable_nMarkInvisible }, { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored }, { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored }, }; }; Loading
graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +2 −20 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Rect; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; import android.os.SystemClock; import android.util.AttributeSet; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.DisplayMetrics; import android.util.TypedValue; import android.util.TypedValue; Loading Loading @@ -348,7 +349,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { if (mRunnable == null) { if (mRunnable == null) { mRunnable = this::invalidateSelf; mRunnable = this::invalidateSelf; } } scheduleSelf(mRunnable, nextUpdate); scheduleSelf(mRunnable, nextUpdate + SystemClock.uptimeMillis()); } else if (nextUpdate == FINISHED) { } else if (nextUpdate == FINISHED) { // This means the animation was drawn in software mode and ended. // This means the animation was drawn in software mode and ended. postOnAnimationEnd(); postOnAnimationEnd(); Loading Loading @@ -430,23 +431,6 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { return mState.mAutoMirrored; return mState.mAutoMirrored; } } @Override public boolean setVisible(boolean visible, boolean restart) { if (!super.setVisible(visible, restart)) { return false; } if (mState.mNativePtr == 0) { throw new IllegalStateException("called setVisible on empty AnimatedImageDrawable"); } if (!visible) { nMarkInvisible(mState.mNativePtr); } return true; } // Animatable overrides // Animatable overrides /** /** * Return whether the animation is currently running. * Return whether the animation is currently running. Loading Loading @@ -616,7 +600,5 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { @FastNative @FastNative private static native long nNativeByteSize(long nativePtr); private static native long nNativeByteSize(long nativePtr); @FastNative @FastNative private static native void nMarkInvisible(long nativePtr); @FastNative private static native void nSetMirrored(long nativePtr, boolean mirror); private static native void nSetMirrored(long nativePtr, boolean mirror); } }
libs/hwui/TreeInfo.h +6 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,12 @@ public: // *OR* will post itself for the next vsync automatically, use this // *OR* will post itself for the next vsync automatically, use this // only to avoid calling draw() // only to avoid calling draw() bool canDrawThisFrame = true; bool canDrawThisFrame = true; // Sentinel for animatedImageDelay meaning there is no need to post such // a message. static constexpr nsecs_t kNoAnimatedImageDelay = -1; // This is used to post a message to redraw when it is time to draw the // next frame of an AnimatedImageDrawable. nsecs_t animatedImageDelay = kNoAnimatedImageDelay; } out; } out; // This flag helps to disable projection for receiver nodes that do not have any backward // This flag helps to disable projection for receiver nodes that do not have any backward Loading
libs/hwui/hwui/AnimatedImageDrawable.cpp +47 −36 Original line number Original line Diff line number Diff line Loading @@ -22,13 +22,12 @@ #include <SkPicture.h> #include <SkPicture.h> #include <SkRefCnt.h> #include <SkRefCnt.h> #include <SkTLazy.h> #include <SkTLazy.h> #include <SkTime.h> namespace android { namespace android { AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { mTimeToShowNextSnapshot = mSkAnimatedImage->currentFrameDuration(); mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration()); } } void AnimatedImageDrawable::syncProperties() { void AnimatedImageDrawable::syncProperties() { Loading Loading @@ -62,28 +61,42 @@ bool AnimatedImageDrawable::nextSnapshotReady() const { } } // Only called on the RenderThread while UI thread is locked. // Only called on the RenderThread while UI thread is locked. bool AnimatedImageDrawable::isDirty() { bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) { const double currentTime = SkTime::GetMSecs(); *outDelay = 0; const double lastWallTime = mLastWallTime; const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC); const nsecs_t lastWallTime = mLastWallTime; mLastWallTime = currentTime; mLastWallTime = currentTime; if (!mRunning) { if (!mRunning) { mDidDraw = false; return false; return false; } } std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; if (mDidDraw) { mCurrentTime += currentTime - lastWallTime; mCurrentTime += currentTime - lastWallTime; mDidDraw = false; } if (!mNextSnapshot.valid()) { if (!mNextSnapshot.valid()) { // Need to trigger onDraw in order to start decoding the next frame. // Need to trigger onDraw in order to start decoding the next frame. *outDelay = mTimeToShowNextSnapshot - mCurrentTime; return true; return true; } } return nextSnapshotReady() && mCurrentTime >= mTimeToShowNextSnapshot; if (mTimeToShowNextSnapshot > mCurrentTime) { *outDelay = mTimeToShowNextSnapshot - mCurrentTime; } else if (nextSnapshotReady()) { // We have not yet updated mTimeToShowNextSnapshot. Read frame duration // directly from mSkAnimatedImage. lock.unlock(); std::unique_lock imageLock{mImageLock}; *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration()); return true; } else { // The next snapshot has not yet been decoded, but we've already passed // time to draw it. There's not a good way to know when decoding will // finish, so request an update immediately. *outDelay = 0; } return false; } } // Only called on the AnimatedImageThread. // Only called on the AnimatedImageThread. Loading @@ -91,7 +104,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() { Snapshot snap; Snapshot snap; { { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; snap.mDuration = mSkAnimatedImage->decodeNextFrame(); snap.mDurationMS = mSkAnimatedImage->decodeNextFrame(); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); } } Loading @@ -105,7 +118,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; mSkAnimatedImage->reset(); mSkAnimatedImage->reset(); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot()); snap.mDuration = mSkAnimatedImage->currentFrameDuration(); snap.mDurationMS = mSkAnimatedImage->currentFrameDuration(); } } return snap; return snap; Loading @@ -127,8 +140,6 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { canvas->scale(-1, 1); canvas->scale(-1, 1); } } mDidDraw = true; const bool starting = mStarting; const bool starting = mStarting; mStarting = false; mStarting = false; Loading Loading @@ -157,12 +168,12 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; if (mCurrentTime >= mTimeToShowNextSnapshot) { if (mCurrentTime >= mTimeToShowNextSnapshot) { mSnapshot = mNextSnapshot.get(); mSnapshot = mNextSnapshot.get(); const double timeToShowCurrentSnap = mTimeToShowNextSnapshot; const nsecs_t timeToShowCurrentSnap = mTimeToShowNextSnapshot; if (mSnapshot.mDuration == SkAnimatedImage::kFinished) { if (mSnapshot.mDurationMS == SkAnimatedImage::kFinished) { finalFrame = true; finalFrame = true; mRunning = false; mRunning = false; } else { } else { mTimeToShowNextSnapshot += mSnapshot.mDuration; mTimeToShowNextSnapshot += ms2ns(mSnapshot.mDurationMS); if (mCurrentTime >= mTimeToShowNextSnapshot) { if (mCurrentTime >= mTimeToShowNextSnapshot) { // This would mean showing the current frame very briefly. It's // This would mean showing the current frame very briefly. It's // possible that not being displayed for a time resulted in // possible that not being displayed for a time resulted in Loading Loading @@ -192,7 +203,7 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { } } } } double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { SkAutoCanvasRestore acr(canvas, false); SkAutoCanvasRestore acr(canvas, false); if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) { if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) { SkPaint paint; SkPaint paint; Loading @@ -211,69 +222,69 @@ double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { // to redraw. // to redraw. std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; canvas->drawDrawable(mSkAnimatedImage.get()); canvas->drawDrawable(mSkAnimatedImage.get()); return 0.0; return 0; } } if (mStarting) { if (mStarting) { mStarting = false; mStarting = false; double duration = 0.0; int durationMS = 0; { { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; mSkAnimatedImage->reset(); mSkAnimatedImage->reset(); duration = mSkAnimatedImage->currentFrameDuration(); durationMS = mSkAnimatedImage->currentFrameDuration(); } } { { std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; mLastWallTime = 0.0; mLastWallTime = 0; mTimeToShowNextSnapshot = duration; // The current time will be added later, below. mTimeToShowNextSnapshot = ms2ns(durationMS); } } } } bool update = false; bool update = false; { { const double currentTime = SkTime::GetMSecs(); const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC); std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; // mLastWallTime starts off at 0. If it is still 0, just update it to // mLastWallTime starts off at 0. If it is still 0, just update it to // the current time and avoid updating // the current time and avoid updating if (mLastWallTime == 0.0) { if (mLastWallTime == 0) { mCurrentTime = currentTime; mCurrentTime = currentTime; // mTimeToShowNextSnapshot is already set to the duration of the // mTimeToShowNextSnapshot is already set to the duration of the // first frame. // first frame. mTimeToShowNextSnapshot += currentTime; mTimeToShowNextSnapshot += currentTime; } else if (mRunning && mDidDraw) { } else if (mRunning) { mCurrentTime += currentTime - mLastWallTime; mCurrentTime += currentTime - mLastWallTime; update = mCurrentTime >= mTimeToShowNextSnapshot; update = mCurrentTime >= mTimeToShowNextSnapshot; } } mLastWallTime = currentTime; mLastWallTime = currentTime; } } double duration = 0.0; int durationMS = 0; { { std::unique_lock lock{mImageLock}; std::unique_lock lock{mImageLock}; if (update) { if (update) { duration = mSkAnimatedImage->decodeNextFrame(); durationMS = mSkAnimatedImage->decodeNextFrame(); } } canvas->drawDrawable(mSkAnimatedImage.get()); canvas->drawDrawable(mSkAnimatedImage.get()); } } mDidDraw = true; std::unique_lock lock{mSwapLock}; std::unique_lock lock{mSwapLock}; if (update) { if (update) { if (duration == SkAnimatedImage::kFinished) { if (durationMS == SkAnimatedImage::kFinished) { mRunning = false; mRunning = false; return duration; return SkAnimatedImage::kFinished; } } const double timeToShowCurrentSnapshot = mTimeToShowNextSnapshot; const nsecs_t timeToShowCurrentSnapshot = mTimeToShowNextSnapshot; mTimeToShowNextSnapshot += duration; mTimeToShowNextSnapshot += ms2ns(durationMS); if (mCurrentTime >= mTimeToShowNextSnapshot) { if (mCurrentTime >= mTimeToShowNextSnapshot) { // As in onDraw, prevent speedy catch-up behavior. // As in onDraw, prevent speedy catch-up behavior. mCurrentTime = timeToShowCurrentSnapshot; mCurrentTime = timeToShowCurrentSnapshot; } } } } return mTimeToShowNextSnapshot; return ns2ms(mTimeToShowNextSnapshot - mCurrentTime); } } } // namespace android } // namespace android
libs/hwui/hwui/AnimatedImageDrawable.h +14 −13 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <cutils/compiler.h> #include <cutils/compiler.h> #include <utils/Macros.h> #include <utils/Macros.h> #include <utils/RefBase.h> #include <utils/RefBase.h> #include <utils/Timers.h> #include <SkAnimatedImage.h> #include <SkAnimatedImage.h> #include <SkCanvas.h> #include <SkCanvas.h> Loading Loading @@ -50,12 +51,15 @@ public: AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed); AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed); /** /** * This updates the internal time and returns true if the animation needs * This updates the internal time and returns true if the image needs * to be redrawn. * to be redrawn this frame. * * * This is called on RenderThread, while the UI thread is locked. * This is called on RenderThread, while the UI thread is locked. * * @param outDelay Nanoseconds in the future when the following frame * will need to be drawn. 0 if not running. */ */ bool isDirty(); bool isDirty(nsecs_t* outDelay); int getStagingAlpha() const { return mStagingProperties.mAlpha; } int getStagingAlpha() const { return mStagingProperties.mAlpha; } void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; } void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; } Loading @@ -68,7 +72,9 @@ public: virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); } virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); } // Draw to software canvas, and return time to next draw. // Draw to software canvas, and return time to next draw. double drawStaging(SkCanvas* canvas); // 0 means the animation is not running. // -1 means the animation advanced to the final frame. int drawStaging(SkCanvas* canvas); // Returns true if the animation was started; false otherwise (e.g. it was // Returns true if the animation was started; false otherwise (e.g. it was // already running) // already running) Loading @@ -84,11 +90,9 @@ public: mEndListener = std::move(listener); mEndListener = std::move(listener); } } void markInvisible() { mDidDraw = false; } struct Snapshot { struct Snapshot { sk_sp<SkPicture> mPic; sk_sp<SkPicture> mPic; int mDuration; int mDurationMS; Snapshot() = default; Snapshot() = default; Loading Loading @@ -122,16 +126,13 @@ private: bool nextSnapshotReady() const; bool nextSnapshotReady() const; // When to switch from mSnapshot to mNextSnapshot. // When to switch from mSnapshot to mNextSnapshot. double mTimeToShowNextSnapshot = 0.0; nsecs_t mTimeToShowNextSnapshot = 0; // The current time for the drawable itself. // The current time for the drawable itself. double mCurrentTime = 0.0; nsecs_t mCurrentTime = 0; // The wall clock of the last time we called isDirty. // The wall clock of the last time we called isDirty. double mLastWallTime = 0.0; nsecs_t mLastWallTime = 0; // Whether we drew since the last call to isDirty. bool mDidDraw = false; // Locked when assigning snapshots and times. Operations while this is held // Locked when assigning snapshots and times. Operations while this is held // should be short. // should be short. Loading