Loading graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +9 −0 Original line number Diff line number Diff line Loading @@ -570,6 +570,13 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { } } @Override protected void onBoundsChange(Rect bounds) { if (mState.mNativePtr != 0) { nSetBounds(mState.mNativePtr, bounds); } } private static native long nCreate(long nativeImageDecoder, @Nullable ImageDecoder decoder, int width, int height, long colorSpaceHandle, Loading Loading @@ -601,4 +608,6 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { private static native long nNativeByteSize(long nativePtr); @FastNative private static native void nSetMirrored(long nativePtr, boolean mirror); @FastNative private static native void nSetBounds(long nativePtr, Rect rect); } libs/hwui/hwui/AnimatedImageDrawable.cpp +57 −14 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #endif #include "utils/TraceUtils.h" #include "pipeline/skia/SkiaUtils.h" #include <SkPicture.h> #include <SkRefCnt.h> Loading @@ -31,6 +32,7 @@ namespace android { AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration()); setStagingBounds(mSkAnimatedImage->getBounds()); } void AnimatedImageDrawable::syncProperties() { Loading Loading @@ -127,21 +129,38 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() { return snap; } // Update the matrix to map from the intrinsic bounds of the SkAnimatedImage to // the bounds specified by Drawable#setBounds. static void handleBounds(SkMatrix* matrix, const SkRect& intrinsicBounds, const SkRect& bounds) { matrix->preTranslate(bounds.left(), bounds.top()); matrix->preScale(bounds.width() / intrinsicBounds.width(), bounds.height() / intrinsicBounds.height()); } // Only called on the RenderThread. void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { // Store the matrix used to handle bounds and mirroring separate from the // canvas. We may need to invert the matrix to determine the proper bounds // to pass to saveLayer, and this matrix (as opposed to, potentially, the // canvas' matrix) only uses scale and translate, so it must be invertible. SkMatrix matrix; SkAutoCanvasRestore acr(canvas, true); handleBounds(&matrix, mSkAnimatedImage->getBounds(), mProperties.mBounds); if (mProperties.mMirrored) { matrix.preTranslate(mSkAnimatedImage->getBounds().width(), 0); matrix.preScale(-1, 1); } std::optional<SkPaint> lazyPaint; SkAutoCanvasRestore acr(canvas, false); if (mProperties.mAlpha != SK_AlphaOPAQUE || mProperties.mColorFilter.get()) { lazyPaint.emplace(); lazyPaint->setAlpha(mProperties.mAlpha); lazyPaint->setColorFilter(mProperties.mColorFilter); lazyPaint->setFilterQuality(kLow_SkFilterQuality); } if (mProperties.mMirrored) { canvas->save(); canvas->translate(mSkAnimatedImage->getBounds().width(), 0); canvas->scale(-1, 1); } canvas->concat(matrix); const bool starting = mStarting; mStarting = false; Loading @@ -151,7 +170,11 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { // The image is not animating, and never was. Draw directly from // mSkAnimatedImage. if (lazyPaint) { canvas->saveLayer(mSkAnimatedImage->getBounds(), &*lazyPaint); SkMatrix inverse; (void) matrix.invert(&inverse); SkRect r = mProperties.mBounds; inverse.mapRect(&r); canvas->saveLayer(r, &*lazyPaint); } std::unique_lock lock{mImageLock}; Loading Loading @@ -211,17 +234,31 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { } int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { SkAutoCanvasRestore acr(canvas, false); // Store the matrix used to handle bounds and mirroring separate from the // canvas. We may need to invert the matrix to determine the proper bounds // to pass to saveLayer, and this matrix (as opposed to, potentially, the // canvas' matrix) only uses scale and translate, so it must be invertible. SkMatrix matrix; SkAutoCanvasRestore acr(canvas, true); handleBounds(&matrix, mSkAnimatedImage->getBounds(), mStagingProperties.mBounds); if (mStagingProperties.mMirrored) { matrix.preTranslate(mSkAnimatedImage->getBounds().width(), 0); matrix.preScale(-1, 1); } canvas->concat(matrix); if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) { SkPaint paint; paint.setAlpha(mStagingProperties.mAlpha); paint.setColorFilter(mStagingProperties.mColorFilter); canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint); } if (mStagingProperties.mMirrored) { canvas->save(); canvas->translate(mSkAnimatedImage->getBounds().width(), 0); canvas->scale(-1, 1); SkMatrix inverse; (void) matrix.invert(&inverse); SkRect r = mStagingProperties.mBounds; inverse.mapRect(&r); canvas->saveLayer(r, &paint); } if (!mRunning) { Loading Loading @@ -294,4 +331,10 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { return ns2ms(mTimeToShowNextSnapshot - mCurrentTime); } SkRect AnimatedImageDrawable::onGetBounds() { // This must return a bounds that is valid for all possible states, // including if e.g. the client calls setBounds. return SkRectMakeLargest(); } } // namespace android libs/hwui/hwui/AnimatedImageDrawable.h +4 −2 Original line number Diff line number Diff line Loading @@ -67,9 +67,10 @@ public: mStagingProperties.mColorFilter = filter; } void setStagingMirrored(bool mirrored) { mStagingProperties.mMirrored = mirrored; } void setStagingBounds(const SkRect& bounds) { mStagingProperties.mBounds = bounds; } void syncProperties(); virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); } SkRect onGetBounds() override; // Draw to software canvas, and return time to next draw. // 0 means the animation is not running. Loading Loading @@ -109,7 +110,7 @@ public: size_t byteSize() const { return sizeof(*this) + mBytesUsed; } protected: virtual void onDraw(SkCanvas* canvas) override; void onDraw(SkCanvas* canvas) override; private: sk_sp<SkAnimatedImage> mSkAnimatedImage; Loading Loading @@ -145,6 +146,7 @@ private: int mAlpha = SK_AlphaOPAQUE; sk_sp<SkColorFilter> mColorFilter; bool mMirrored = false; SkRect mBounds; Properties() = default; Properties(Properties&) = default; Loading libs/hwui/jni/AnimatedImageDrawable.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -244,6 +244,14 @@ static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, j drawable->setStagingMirrored(mirrored); } static void AnimatedImageDrawable_nSetBounds(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jobject jrect) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); SkRect rect; GraphicsJNI::jrect_to_rect(env, jrect, &rect); drawable->setStagingBounds(rect); } static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nCreate", "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",(void*) AnimatedImageDrawable_nCreate }, { "nGetNativeFinalizer", "()J", (void*) AnimatedImageDrawable_nGetNativeFinalizer }, Loading @@ -259,6 +267,7 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored }, { "nSetBounds", "(JLandroid/graphics/Rect;)V", (void*) AnimatedImageDrawable_nSetBounds }, }; int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) { Loading Loading
graphics/java/android/graphics/drawable/AnimatedImageDrawable.java +9 −0 Original line number Diff line number Diff line Loading @@ -570,6 +570,13 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { } } @Override protected void onBoundsChange(Rect bounds) { if (mState.mNativePtr != 0) { nSetBounds(mState.mNativePtr, bounds); } } private static native long nCreate(long nativeImageDecoder, @Nullable ImageDecoder decoder, int width, int height, long colorSpaceHandle, Loading Loading @@ -601,4 +608,6 @@ public class AnimatedImageDrawable extends Drawable implements Animatable2 { private static native long nNativeByteSize(long nativePtr); @FastNative private static native void nSetMirrored(long nativePtr, boolean mirror); @FastNative private static native void nSetBounds(long nativePtr, Rect rect); }
libs/hwui/hwui/AnimatedImageDrawable.cpp +57 −14 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #endif #include "utils/TraceUtils.h" #include "pipeline/skia/SkiaUtils.h" #include <SkPicture.h> #include <SkRefCnt.h> Loading @@ -31,6 +32,7 @@ namespace android { AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed) : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) { mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration()); setStagingBounds(mSkAnimatedImage->getBounds()); } void AnimatedImageDrawable::syncProperties() { Loading Loading @@ -127,21 +129,38 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() { return snap; } // Update the matrix to map from the intrinsic bounds of the SkAnimatedImage to // the bounds specified by Drawable#setBounds. static void handleBounds(SkMatrix* matrix, const SkRect& intrinsicBounds, const SkRect& bounds) { matrix->preTranslate(bounds.left(), bounds.top()); matrix->preScale(bounds.width() / intrinsicBounds.width(), bounds.height() / intrinsicBounds.height()); } // Only called on the RenderThread. void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { // Store the matrix used to handle bounds and mirroring separate from the // canvas. We may need to invert the matrix to determine the proper bounds // to pass to saveLayer, and this matrix (as opposed to, potentially, the // canvas' matrix) only uses scale and translate, so it must be invertible. SkMatrix matrix; SkAutoCanvasRestore acr(canvas, true); handleBounds(&matrix, mSkAnimatedImage->getBounds(), mProperties.mBounds); if (mProperties.mMirrored) { matrix.preTranslate(mSkAnimatedImage->getBounds().width(), 0); matrix.preScale(-1, 1); } std::optional<SkPaint> lazyPaint; SkAutoCanvasRestore acr(canvas, false); if (mProperties.mAlpha != SK_AlphaOPAQUE || mProperties.mColorFilter.get()) { lazyPaint.emplace(); lazyPaint->setAlpha(mProperties.mAlpha); lazyPaint->setColorFilter(mProperties.mColorFilter); lazyPaint->setFilterQuality(kLow_SkFilterQuality); } if (mProperties.mMirrored) { canvas->save(); canvas->translate(mSkAnimatedImage->getBounds().width(), 0); canvas->scale(-1, 1); } canvas->concat(matrix); const bool starting = mStarting; mStarting = false; Loading @@ -151,7 +170,11 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { // The image is not animating, and never was. Draw directly from // mSkAnimatedImage. if (lazyPaint) { canvas->saveLayer(mSkAnimatedImage->getBounds(), &*lazyPaint); SkMatrix inverse; (void) matrix.invert(&inverse); SkRect r = mProperties.mBounds; inverse.mapRect(&r); canvas->saveLayer(r, &*lazyPaint); } std::unique_lock lock{mImageLock}; Loading Loading @@ -211,17 +234,31 @@ void AnimatedImageDrawable::onDraw(SkCanvas* canvas) { } int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { SkAutoCanvasRestore acr(canvas, false); // Store the matrix used to handle bounds and mirroring separate from the // canvas. We may need to invert the matrix to determine the proper bounds // to pass to saveLayer, and this matrix (as opposed to, potentially, the // canvas' matrix) only uses scale and translate, so it must be invertible. SkMatrix matrix; SkAutoCanvasRestore acr(canvas, true); handleBounds(&matrix, mSkAnimatedImage->getBounds(), mStagingProperties.mBounds); if (mStagingProperties.mMirrored) { matrix.preTranslate(mSkAnimatedImage->getBounds().width(), 0); matrix.preScale(-1, 1); } canvas->concat(matrix); if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) { SkPaint paint; paint.setAlpha(mStagingProperties.mAlpha); paint.setColorFilter(mStagingProperties.mColorFilter); canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint); } if (mStagingProperties.mMirrored) { canvas->save(); canvas->translate(mSkAnimatedImage->getBounds().width(), 0); canvas->scale(-1, 1); SkMatrix inverse; (void) matrix.invert(&inverse); SkRect r = mStagingProperties.mBounds; inverse.mapRect(&r); canvas->saveLayer(r, &paint); } if (!mRunning) { Loading Loading @@ -294,4 +331,10 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) { return ns2ms(mTimeToShowNextSnapshot - mCurrentTime); } SkRect AnimatedImageDrawable::onGetBounds() { // This must return a bounds that is valid for all possible states, // including if e.g. the client calls setBounds. return SkRectMakeLargest(); } } // namespace android
libs/hwui/hwui/AnimatedImageDrawable.h +4 −2 Original line number Diff line number Diff line Loading @@ -67,9 +67,10 @@ public: mStagingProperties.mColorFilter = filter; } void setStagingMirrored(bool mirrored) { mStagingProperties.mMirrored = mirrored; } void setStagingBounds(const SkRect& bounds) { mStagingProperties.mBounds = bounds; } void syncProperties(); virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); } SkRect onGetBounds() override; // Draw to software canvas, and return time to next draw. // 0 means the animation is not running. Loading Loading @@ -109,7 +110,7 @@ public: size_t byteSize() const { return sizeof(*this) + mBytesUsed; } protected: virtual void onDraw(SkCanvas* canvas) override; void onDraw(SkCanvas* canvas) override; private: sk_sp<SkAnimatedImage> mSkAnimatedImage; Loading Loading @@ -145,6 +146,7 @@ private: int mAlpha = SK_AlphaOPAQUE; sk_sp<SkColorFilter> mColorFilter; bool mMirrored = false; SkRect mBounds; Properties() = default; Properties(Properties&) = default; Loading
libs/hwui/jni/AnimatedImageDrawable.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -244,6 +244,14 @@ static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, j drawable->setStagingMirrored(mirrored); } static void AnimatedImageDrawable_nSetBounds(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jobject jrect) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); SkRect rect; GraphicsJNI::jrect_to_rect(env, jrect, &rect); drawable->setStagingBounds(rect); } static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nCreate", "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",(void*) AnimatedImageDrawable_nCreate }, { "nGetNativeFinalizer", "()J", (void*) AnimatedImageDrawable_nGetNativeFinalizer }, Loading @@ -259,6 +267,7 @@ static const JNINativeMethod gAnimatedImageDrawableMethods[] = { { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener }, { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize }, { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored }, { "nSetBounds", "(JLandroid/graphics/Rect;)V", (void*) AnimatedImageDrawable_nSetBounds }, }; int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) { Loading