summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2018-01-24 15:45:08 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-01-24 15:45:08 +0000
commit08a45549af12d725b8df34f504bcc876b1a3cd28 (patch)
tree541fb5266a6ded41b84a40efa3dbd9373a95bd55
parentdf64ef9be42b55e94b8da1f4b41acbd75bdd475f (diff)
parent2d14213849d6df70d0fa80319ab4ffc08743a683 (diff)
Merge "Initial implmentation of AnimatedImageDrawables on the RenderThread."
-rw-r--r--core/jni/android/graphics/AnimatedImageDrawable.cpp39
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedImageDrawable.java18
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/RecordingCanvas.cpp4
-rw-r--r--libs/hwui/RecordingCanvas.h3
-rw-r--r--libs/hwui/SkiaCanvas.cpp14
-rw-r--r--libs/hwui/SkiaCanvas.h3
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.cpp152
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.h91
-rw-r--r--libs/hwui/hwui/Canvas.h4
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.cpp16
-rw-r--r--libs/hwui/pipeline/skia/SkiaDisplayList.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp10
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h12
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp6
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h1
16 files changed, 330 insertions, 46 deletions
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
index ec15cce1f1d5..8b3ce663fae6 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -18,6 +18,7 @@
#include "ImageDecoder.h"
#include "core_jni_helpers.h"
+#include <hwui/AnimatedImageDrawable.h>
#include <hwui/Canvas.h>
#include <SkAndroidCodec.h>
#include <SkAnimatedImage.h>
@@ -27,10 +28,6 @@
using namespace android;
-struct AnimatedImageDrawable {
- sk_sp<SkAnimatedImage> mDrawable;
- SkPaint mPaint;
-};
// Note: jpostProcess holds a handle to the ImageDecoder.
static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
@@ -65,20 +62,22 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
picture = recorder.finishRecordingAsPicture();
}
- std::unique_ptr<AnimatedImageDrawable> drawable(new AnimatedImageDrawable);
- drawable->mDrawable = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
- scaledSize, subset, std::move(picture));
- if (!drawable->mDrawable) {
+
+ sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
+ scaledSize, subset,
+ std::move(picture));
+ if (!animatedImg) {
doThrowIOE(env, "Failed to create drawable");
return 0;
}
- drawable->mDrawable->start();
+ sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(animatedImg));
+ drawable->start();
return reinterpret_cast<jlong>(drawable.release());
}
static void AnimatedImageDrawable_destruct(AnimatedImageDrawable* drawable) {
- delete drawable;
+ SkSafeUnref(drawable);
}
static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
@@ -86,45 +85,43 @@ static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject
}
static jlong AnimatedImageDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
- jlong canvasPtr, jlong msecs) {
+ jlong canvasPtr) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- double timeToNextUpdate = drawable->mDrawable->update(msecs);
auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
- canvas->drawAnimatedImage(drawable->mDrawable.get(), 0, 0, &drawable->mPaint);
- return (jlong) timeToNextUpdate;
+ return (jlong) canvas->drawAnimatedImage(drawable);
}
static void AnimatedImageDrawable_nSetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
jint alpha) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- drawable->mPaint.setAlpha(alpha);
+ drawable->setStagingAlpha(alpha);
}
static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- return drawable->mPaint.getAlpha();
+ return drawable->getStagingAlpha();
}
static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
jlong nativeFilter) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter);
- drawable->mPaint.setColorFilter(sk_ref_sp(filter));
+ drawable->setStagingColorFilter(sk_ref_sp(filter));
}
static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- return drawable->mDrawable->isRunning();
+ return drawable->isRunning();
}
static void AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- drawable->mDrawable->start();
+ drawable->start();
}
static void AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- drawable->mDrawable->stop();
+ drawable->stop();
}
static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
@@ -136,7 +133,7 @@ static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/
static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
{ "nCreate", "(JLandroid/graphics/ImageDecoder;IILandroid/graphics/Rect;)J", (void*) AnimatedImageDrawable_nCreate },
{ "nGetNativeFinalizer", "()J", (void*) AnimatedImageDrawable_nGetNativeFinalizer },
- { "nDraw", "(JJJ)J", (void*) AnimatedImageDrawable_nDraw },
+ { "nDraw", "(JJ)J", (void*) AnimatedImageDrawable_nDraw },
{ "nSetAlpha", "(JI)V", (void*) AnimatedImageDrawable_nSetAlpha },
{ "nGetAlpha", "(J)I", (void*) AnimatedImageDrawable_nGetAlpha },
{ "nSetColorFilter", "(JJ)V", (void*) AnimatedImageDrawable_nSetColorFilter },
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index da170c0fae24..6d3ddd5c2c28 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -118,9 +118,12 @@ public class AnimatedImageDrawable extends Drawable implements Animatable {
@Override
public void draw(@NonNull Canvas canvas) {
- long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper(),
- SystemClock.uptimeMillis());
- scheduleSelf(mRunnable, nextUpdate);
+ long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper());
+ // a value <= 0 indicates that the drawable is stopped or that renderThread
+ // will manage the animation
+ if (nextUpdate > 0) {
+ scheduleSelf(mRunnable, nextUpdate);
+ }
}
@Override
@@ -130,6 +133,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable {
+ " 255! provided " + alpha);
}
nSetAlpha(mNativePtr, alpha);
+ invalidateSelf();
}
@Override
@@ -141,6 +145,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable {
public void setColorFilter(@Nullable ColorFilter colorFilter) {
long nativeFilter = colorFilter == null ? 0 : colorFilter.getNativeInstance();
nSetColorFilter(mNativePtr, nativeFilter);
+ invalidateSelf();
}
@Override
@@ -161,7 +166,10 @@ public class AnimatedImageDrawable extends Drawable implements Animatable {
@Override
public void start() {
- nStart(mNativePtr);
+ if (isRunning() == false) {
+ nStart(mNativePtr);
+ invalidateSelf();
+ }
}
@Override
@@ -173,7 +181,7 @@ public class AnimatedImageDrawable extends Drawable implements Animatable {
@Nullable ImageDecoder decoder, int width, int height, Rect cropRect)
throws IOException;
private static native long nGetNativeFinalizer();
- private static native long nDraw(long nativePtr, long canvasNativePtr, long msecs);
+ private static native long nDraw(long nativePtr, long canvasNativePtr);
private static native void nSetAlpha(long nativePtr, int alpha);
private static native int nGetAlpha(long nativePtr);
private static native void nSetColorFilter(long nativePtr, long nativeFilter);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 7cacaf6a16ad..17f9b7cd62fc 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -137,6 +137,7 @@ cc_defaults {
whole_static_libs: ["libskia"],
srcs: [
+ "hwui/AnimatedImageDrawable.cpp",
"hwui/Bitmap.cpp",
"font/CacheTexture.cpp",
"font/Font.cpp",
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index fb7b24623568..e1df1e7725b5 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -495,9 +495,9 @@ void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patc
refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
}
-void RecordingCanvas::drawAnimatedImage(SkAnimatedImage*, float left, float top,
- const SkPaint*) {
+double RecordingCanvas::drawAnimatedImage(AnimatedImageDrawable*) {
// Unimplemented
+ return 0;
}
// Text
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index dd06ada9da3d..e663402a80f3 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -183,8 +183,7 @@ public:
virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) override;
- virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
- const SkPaint* paint) override;
+ virtual double drawAnimatedImage(AnimatedImageDrawable*) override;
// Text
virtual bool drawTextAbsolutePos() const override { return false; }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index dc274cf50a52..b2edd3392873 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -725,18 +725,8 @@ void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, floa
mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawAnimatedImage(SkAnimatedImage* image, float left, float top,
- const SkPaint* paint) {
- sk_sp<SkPicture> pic(image->newPictureSnapshot());
- SkMatrix matrixStorage;
- SkMatrix* matrix;
- if (left == 0.0f && top == 0.0f) {
- matrix = nullptr;
- } else {
- matrixStorage = SkMatrix::MakeTrans(left, top);
- matrix = &matrixStorage;
- }
- mCanvas->drawPicture(pic.get(), matrix, paint);
+double SkiaCanvas::drawAnimatedImage(AnimatedImageDrawable* imgDrawable) {
+ return imgDrawable->drawStaging(mCanvas);
}
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 7137210406fb..3efc22a03cdf 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -124,8 +124,7 @@ public:
virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) override;
- virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
- const SkPaint* paint) override;
+ virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) override;
virtual bool drawTextAbsolutePos() const override { return true; }
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
new file mode 100644
index 000000000000..36dd06f2fce9
--- /dev/null
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AnimatedImageDrawable.h"
+
+#include "thread/Task.h"
+#include "thread/TaskManager.h"
+#include "thread/TaskProcessor.h"
+#include "utils/TraceUtils.h"
+
+#include <SkPicture.h>
+#include <SkRefCnt.h>
+#include <SkTime.h>
+#include <SkTLazy.h>
+
+namespace android {
+
+AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage)
+ : mSkAnimatedImage(std::move(animatedImage)) { }
+
+void AnimatedImageDrawable::syncProperties() {
+ mAlpha = mStagingAlpha;
+ mColorFilter = mStagingColorFilter;
+}
+
+void AnimatedImageDrawable::start() {
+ SkAutoExclusive lock(mLock);
+
+ mSnapshot.reset(mSkAnimatedImage->newPictureSnapshot());
+
+ mSkAnimatedImage->start();
+}
+
+void AnimatedImageDrawable::stop() {
+ SkAutoExclusive lock(mLock);
+ mSkAnimatedImage->stop();
+ mSnapshot.reset(nullptr);
+}
+
+bool AnimatedImageDrawable::isRunning() {
+ return mSkAnimatedImage->isRunning();
+}
+
+// This is really a Task<void> but that doesn't really work when Future<>
+// expects to be able to get/set a value
+class AnimatedImageDrawable::AnimatedImageTask : public uirenderer::Task<bool> {
+public:
+ AnimatedImageTask(AnimatedImageDrawable* animatedImageDrawable)
+ : mAnimatedImageDrawable(sk_ref_sp(animatedImageDrawable)) {}
+
+ sk_sp<AnimatedImageDrawable> mAnimatedImageDrawable;
+ bool mIsCompleted = false;
+};
+
+class AnimatedImageDrawable::AnimatedImageTaskProcessor : public uirenderer::TaskProcessor<bool> {
+public:
+ explicit AnimatedImageTaskProcessor(uirenderer::TaskManager* taskManager)
+ : uirenderer::TaskProcessor<bool>(taskManager) {}
+ ~AnimatedImageTaskProcessor() {}
+
+ virtual void onProcess(const sp<uirenderer::Task<bool>>& task) override {
+ ATRACE_NAME("Updating AnimatedImageDrawables");
+ AnimatedImageTask* t = static_cast<AnimatedImageTask*>(task.get());
+ t->mAnimatedImageDrawable->update();
+ t->mIsCompleted = true;
+ task->setResult(true);
+ };
+};
+
+void AnimatedImageDrawable::scheduleUpdate(uirenderer::TaskManager* taskManager) {
+ if (!mSkAnimatedImage->isRunning()
+ || (mDecodeTask.get() != nullptr && !mDecodeTask->mIsCompleted)) {
+ return;
+ }
+
+ if (!mDecodeTaskProcessor.get()) {
+ mDecodeTaskProcessor = new AnimatedImageTaskProcessor(taskManager);
+ }
+
+ // TODO get one frame ahead and only schedule updates when you need to replenish
+ mDecodeTask = new AnimatedImageTask(this);
+ mDecodeTaskProcessor->add(mDecodeTask);
+}
+
+void AnimatedImageDrawable::update() {
+ SkAutoExclusive lock(mLock);
+
+ if (!mSkAnimatedImage->isRunning()) {
+ return;
+ }
+
+ const double currentTime = SkTime::GetMSecs();
+ if (currentTime >= mNextFrameTime) {
+ mNextFrameTime = mSkAnimatedImage->update(currentTime);
+ mSnapshot.reset(mSkAnimatedImage->newPictureSnapshot());
+ mIsDirty = true;
+ }
+}
+
+void AnimatedImageDrawable::onDraw(SkCanvas* canvas) {
+ SkTLazy<SkPaint> lazyPaint;
+ if (mAlpha != SK_AlphaOPAQUE || mColorFilter.get()) {
+ lazyPaint.init();
+ lazyPaint.get()->setAlpha(mAlpha);
+ lazyPaint.get()->setColorFilter(mColorFilter);
+ lazyPaint.get()->setFilterQuality(kLow_SkFilterQuality);
+ }
+
+ SkAutoExclusive lock(mLock);
+ if (mSkAnimatedImage->isRunning()) {
+ canvas->drawPicture(mSnapshot, nullptr, lazyPaint.getMaybeNull());
+ } else {
+ // TODO: we could potentially keep the cached surface around if there is a paint and we know
+ // the drawable is attached to the view system
+ SkAutoCanvasRestore acr(canvas, false);
+ if (lazyPaint.isValid()) {
+ canvas->saveLayer(mSkAnimatedImage->getBounds(), lazyPaint.get());
+ }
+ mSkAnimatedImage->draw(canvas);
+ }
+
+ mIsDirty = false;
+}
+
+double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
+ // update the drawable with the current time
+ double nextUpdate = mSkAnimatedImage->update(SkTime::GetMSecs());
+ SkAutoCanvasRestore acr(canvas, false);
+ if (mStagingAlpha != SK_AlphaOPAQUE || mStagingColorFilter.get()) {
+ SkPaint paint;
+ paint.setAlpha(mStagingAlpha);
+ paint.setColorFilter(mStagingColorFilter);
+ canvas->saveLayer(mSkAnimatedImage->getBounds(), &paint);
+ }
+ canvas->drawDrawable(mSkAnimatedImage.get());
+ return nextUpdate;
+}
+
+}; // namespace android
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
new file mode 100644
index 000000000000..18764afde138
--- /dev/null
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cutils/compiler.h>
+#include <utils/RefBase.h>
+
+#include <SkAnimatedImage.h>
+#include <SkCanvas.h>
+#include <SkColorFilter.h>
+#include <SkDrawable.h>
+#include <SkMutex.h>
+
+class SkPicture;
+
+namespace android {
+
+namespace uirenderer {
+class TaskManager;
+}
+
+/**
+ * Native component of android.graphics.drawable.AnimatedImageDrawables.java. This class can be
+ * drawn into Canvas.h and maintains the state needed to drive the animation from the RenderThread.
+ */
+class ANDROID_API AnimatedImageDrawable : public SkDrawable {
+public:
+ AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage);
+
+ /**
+ * This returns true if the animation has updated and signals that the next draw will contain
+ * new content.
+ */
+ bool isDirty() const { return mIsDirty; }
+
+ int getStagingAlpha() const { return mStagingAlpha; }
+ void setStagingAlpha(int alpha) { mStagingAlpha = alpha; }
+ void setStagingColorFilter(sk_sp<SkColorFilter> filter) { mStagingColorFilter = filter; }
+ void syncProperties();
+
+ virtual SkRect onGetBounds() override {
+ return mSkAnimatedImage->getBounds();
+ }
+
+ double drawStaging(SkCanvas* canvas);
+
+ void start();
+ void stop();
+ bool isRunning();
+
+ void scheduleUpdate(uirenderer::TaskManager* taskManager);
+
+protected:
+ virtual void onDraw(SkCanvas* canvas) override;
+
+private:
+ void update();
+
+ sk_sp<SkAnimatedImage> mSkAnimatedImage;
+ sk_sp<SkPicture> mSnapshot;
+ SkMutex mLock;
+
+ int mStagingAlpha = SK_AlphaOPAQUE;
+ sk_sp<SkColorFilter> mStagingColorFilter;
+
+ int mAlpha = SK_AlphaOPAQUE;
+ sk_sp<SkColorFilter> mColorFilter;
+ double mNextFrameTime = 0.0;
+ bool mIsDirty = false;
+
+ class AnimatedImageTask;
+ class AnimatedImageTaskProcessor;
+ sp<AnimatedImageTask> mDecodeTask;
+ sp<AnimatedImageTaskProcessor> mDecodeTaskProcessor;
+};
+
+}; // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 5efd35764635..cae4542b18e8 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -73,6 +73,7 @@ typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
typedef std::function<void(uint16_t* text, float* positions)> ReadGlyphFunc;
+class AnimatedImageDrawable;
class Bitmap;
class Paint;
struct Typeface;
@@ -238,8 +239,7 @@ public:
float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) = 0;
- virtual void drawAnimatedImage(SkAnimatedImage*, float left, float top,
- const SkPaint* paint) = 0;
+ virtual double drawAnimatedImage(AnimatedImageDrawable* imgDrawable) = 0;
/**
* Specifies if the positions passed to ::drawText are absolute or relative
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index cb10901c4ccf..cf0b6a4d1dcc 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -31,6 +31,9 @@ void SkiaDisplayList::syncContents() {
for (auto& functor : mChildFunctors) {
functor.syncFunctor();
}
+ for (auto& animatedImage : mAnimatedImages) {
+ animatedImage->syncProperties();
+ }
for (auto& vectorDrawable : mVectorDrawables) {
vectorDrawable->syncProperties();
}
@@ -89,6 +92,18 @@ bool SkiaDisplayList::prepareListAndChildren(
}
bool isDirty = false;
+ for (auto& animatedImage : mAnimatedImages) {
+ // If any animated image in the display list needs updated, then damage the node.
+ if (animatedImage->isDirty()) {
+ isDirty = true;
+ }
+ if (animatedImage->isRunning()) {
+ static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
+ ->scheduleDeferredUpdate(animatedImage);
+ info.out.hasAnimations = true;
+ }
+ }
+
for (auto& vectorDrawable : mVectorDrawables) {
// If any vector drawable in the display list needs update, damage the node.
if (vectorDrawable->isDirty()) {
@@ -109,6 +124,7 @@ void SkiaDisplayList::reset() {
mMutableImages.clear();
mVectorDrawables.clear();
+ mAnimatedImages.clear();
mChildFunctors.clear();
mChildNodes.clear();
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 6883d33291ec..818ec114a5b3 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -17,6 +17,7 @@
#pragma once
#include "DisplayList.h"
+#include "hwui/AnimatedImageDrawable.h"
#include "GLFunctorDrawable.h"
#include "RenderNodeDrawable.h"
@@ -144,6 +145,7 @@ public:
std::deque<GLFunctorDrawable> mChildFunctors;
std::vector<SkImage*> mMutableImages;
std::vector<VectorDrawableRoot*> mVectorDrawables;
+ std::vector<AnimatedImageDrawable*> mAnimatedImages;
SkLiteDL mDisplayList;
// mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 9db39d954e4c..534782a5dc02 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -40,6 +40,7 @@ uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+ mAnimatedImageDrawables.reserve(30);
mVectorDrawables.reserve(30);
}
@@ -326,6 +327,15 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
ATRACE_NAME("flush commands");
surface->getCanvas()->flush();
+
+ // TODO move to another method
+ if (!mAnimatedImageDrawables.empty()) {
+ ATRACE_NAME("Update AnimatedImageDrawables");
+ for (auto animatedImage : mAnimatedImageDrawables) {
+ animatedImage->scheduleUpdate(getTaskManager());
+ }
+ mAnimatedImageDrawables.clear();
+ }
}
namespace {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 27092270bb80..cc75e9c5b38d 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -18,6 +18,7 @@
#include <SkSurface.h>
#include "FrameBuilder.h"
+#include "hwui/AnimatedImageDrawable.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/IRenderPipeline.h"
@@ -54,6 +55,12 @@ public:
std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
+ void scheduleDeferredUpdate(AnimatedImageDrawable* imageDrawable) {
+ mAnimatedImageDrawables.push_back(imageDrawable);
+ }
+
+ std::vector<AnimatedImageDrawable*>* getAnimatingImages() { return &mAnimatedImageDrawables; }
+
static void destroyLayer(RenderNode* node);
static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
@@ -137,6 +144,11 @@ private:
*/
std::vector<VectorDrawableRoot*> mVectorDrawables;
+ /**
+ * populated by prepareTree with images with active animations
+ */
+ std::vector<AnimatedImageDrawable*> mAnimatedImageDrawables;
+
// Block of properties used only for debugging to record a SkPicture and save it in a file.
/**
* mCapturedFile is used to enforce we don't capture more than once for a given name (cause
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 035cea3f61b0..eabe2e87fc49 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -246,6 +246,12 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch
}
}
+double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedImage) {
+ drawDrawable(animatedImage);
+ mDisplayList->mAnimatedImages.push_back(animatedImage);
+ return 0;
+}
+
}; // namespace skiapipeline
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index d35bbabb652f..0e5dbdbab078 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -53,6 +53,7 @@ public:
virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) override;
+ virtual double drawAnimatedImage(AnimatedImageDrawable* animatedImage) override;
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
uirenderer::CanvasPropertyPrimitive* top,