Merge "Implement AnimatedImageDrawable#setBounds" into sc-dev
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index ebf7cea..dd64327 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -570,6 +570,13 @@
}
}
+ @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,
@@ -601,4 +608,6 @@
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);
}
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 638de85..0d3d3e3 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -20,6 +20,7 @@
#endif
#include "utils/TraceUtils.h"
+#include "pipeline/skia/SkiaUtils.h"
#include <SkPicture.h>
#include <SkRefCnt.h>
@@ -31,6 +32,7 @@
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() {
@@ -127,21 +129,38 @@
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;
@@ -151,7 +170,11 @@
// 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};
@@ -211,17 +234,31 @@
}
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) {
@@ -294,4 +331,10 @@
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
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index f81a5a4..8ca3c7e 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -67,9 +67,10 @@
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.
@@ -109,7 +110,7 @@
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;
@@ -145,6 +146,7 @@
int mAlpha = SK_AlphaOPAQUE;
sk_sp<SkColorFilter> mColorFilter;
bool mMirrored = false;
+ SkRect mBounds;
Properties() = default;
Properties(Properties&) = default;
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index 1ff1565..c9433ec8 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -244,6 +244,14 @@
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 },
@@ -259,6 +267,7 @@
{ "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) {