blob: 12900261bddd6ba7303b79f574b2e527184d1d11 [file] [log] [blame]
Leon Scroggins III671cce22018-01-14 16:52:17 -05001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "GraphicsJNI.h"
18#include "ImageDecoder.h"
Leon Scroggins III127d31a2018-01-19 12:29:47 -050019#include "Utils.h"
Leon Scroggins III5b7f4262018-01-26 11:03:54 -050020#include "core_jni_helpers.h"
Leon Scroggins III671cce22018-01-14 16:52:17 -050021
Leon Scroggins III671cce22018-01-14 16:52:17 -050022#include <SkAndroidCodec.h>
23#include <SkAnimatedImage.h>
24#include <SkColorFilter.h>
25#include <SkPicture.h>
26#include <SkPictureRecorder.h>
Leon Scroggins III5b7f4262018-01-26 11:03:54 -050027#include <hwui/AnimatedImageDrawable.h>
28#include <hwui/Canvas.h>
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -050029#include <utils/Looper.h>
Leon Scroggins III671cce22018-01-14 16:52:17 -050030
31using namespace android;
32
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -050033static jmethodID gAnimatedImageDrawable_onAnimationEndMethodID;
Leon Scroggins III671cce22018-01-14 16:52:17 -050034
35// Note: jpostProcess holds a handle to the ImageDecoder.
36static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
37 jlong nativeImageDecoder, jobject jpostProcess,
Leon Scroggins IIIeac14232019-02-04 10:30:22 -050038 jint width, jint height, jlong colorSpaceHandle,
39 jboolean extended, jobject jsubset) {
Leon Scroggins III671cce22018-01-14 16:52:17 -050040 if (nativeImageDecoder == 0) {
41 doThrowIOE(env, "Cannot create AnimatedImageDrawable from null!");
42 return 0;
43 }
44
45 auto* imageDecoder = reinterpret_cast<ImageDecoder*>(nativeImageDecoder);
Leon Scroggins III671cce22018-01-14 16:52:17 -050046 SkIRect subset;
47 if (jsubset) {
48 GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
49 } else {
50 subset = SkIRect::MakeWH(width, height);
51 }
52
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -040053 bool hasRestoreFrame = false;
Leon Scroggins IIIeac14232019-02-04 10:30:22 -050054 if (imageDecoder->mCodec->getEncodedFormat() != SkEncodedImageFormat::kWEBP) {
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -040055 const int frameCount = imageDecoder->mCodec->codec()->getFrameCount();
56 for (int i = 0; i < frameCount; ++i) {
57 SkCodec::FrameInfo frameInfo;
58 if (!imageDecoder->mCodec->codec()->getFrameInfo(i, &frameInfo)) {
59 doThrowIOE(env, "Failed to read frame info!");
60 return 0;
61 }
62 if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
63 hasRestoreFrame = true;
64 break;
65 }
66 }
67 }
68
Leon Scroggins IIIeac14232019-02-04 10:30:22 -050069 auto info = imageDecoder->mCodec->getInfo().makeWH(width, height)
70 .makeColorSpace(GraphicsJNI::getNativeColorSpace(colorSpaceHandle));
71 if (extended) {
72 info = info.makeColorType(kRGBA_F16_SkColorType);
73 }
74
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -040075 size_t bytesUsed = info.computeMinByteSize();
76 // SkAnimatedImage has one SkBitmap for decoding, plus an extra one if there is a
77 // kRestorePrevious frame. AnimatedImageDrawable has two SkPictures storing the current
78 // frame and the next frame. (The former assumes that the image is animated, and the
79 // latter assumes that it is drawn to a hardware canvas.)
80 bytesUsed *= hasRestoreFrame ? 4 : 3;
Leon Scroggins III671cce22018-01-14 16:52:17 -050081 sk_sp<SkPicture> picture;
82 if (jpostProcess) {
83 SkRect bounds = SkRect::MakeWH(subset.width(), subset.height());
84
85 SkPictureRecorder recorder;
86 SkCanvas* skcanvas = recorder.beginRecording(bounds);
87 std::unique_ptr<Canvas> canvas(Canvas::create_canvas(skcanvas));
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050088 postProcessAndRelease(env, jpostProcess, std::move(canvas));
Leon Scroggins III671cce22018-01-14 16:52:17 -050089 if (env->ExceptionCheck()) {
90 return 0;
91 }
92 picture = recorder.finishRecordingAsPicture();
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -040093 bytesUsed += picture->approximateBytesUsed();
Leon Scroggins III671cce22018-01-14 16:52:17 -050094 }
95
Derek Sollenberger2d142132018-01-22 10:25:26 -050096
97 sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
Leon Scroggins IIIeac14232019-02-04 10:30:22 -050098 info, subset,
Derek Sollenberger2d142132018-01-22 10:25:26 -050099 std::move(picture));
100 if (!animatedImg) {
Leon Scroggins III671cce22018-01-14 16:52:17 -0500101 doThrowIOE(env, "Failed to create drawable");
102 return 0;
103 }
Leon Scroggins III671cce22018-01-14 16:52:17 -0500104
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -0400105 bytesUsed += sizeof(animatedImg.get());
106
107 sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(std::move(animatedImg),
108 bytesUsed));
Leon Scroggins III671cce22018-01-14 16:52:17 -0500109 return reinterpret_cast<jlong>(drawable.release());
110}
111
112static void AnimatedImageDrawable_destruct(AnimatedImageDrawable* drawable) {
Derek Sollenberger2d142132018-01-22 10:25:26 -0500113 SkSafeUnref(drawable);
Leon Scroggins III671cce22018-01-14 16:52:17 -0500114}
115
116static jlong AnimatedImageDrawable_nGetNativeFinalizer(JNIEnv* /*env*/, jobject /*clazz*/) {
117 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&AnimatedImageDrawable_destruct));
118}
119
Leon Scroggins III5b7f4262018-01-26 11:03:54 -0500120// Java's FINISHED relies on this being -1
121static_assert(SkAnimatedImage::kFinished == -1);
122
Leon Scroggins III671cce22018-01-14 16:52:17 -0500123static jlong AnimatedImageDrawable_nDraw(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
Derek Sollenberger2d142132018-01-22 10:25:26 -0500124 jlong canvasPtr) {
Leon Scroggins III671cce22018-01-14 16:52:17 -0500125 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Leon Scroggins III671cce22018-01-14 16:52:17 -0500126 auto* canvas = reinterpret_cast<Canvas*>(canvasPtr);
Derek Sollenberger2d142132018-01-22 10:25:26 -0500127 return (jlong) canvas->drawAnimatedImage(drawable);
Leon Scroggins III671cce22018-01-14 16:52:17 -0500128}
129
130static void AnimatedImageDrawable_nSetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
131 jint alpha) {
132 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Derek Sollenberger2d142132018-01-22 10:25:26 -0500133 drawable->setStagingAlpha(alpha);
Leon Scroggins III671cce22018-01-14 16:52:17 -0500134}
135
136static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
137 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Derek Sollenberger2d142132018-01-22 10:25:26 -0500138 return drawable->getStagingAlpha();
Leon Scroggins III671cce22018-01-14 16:52:17 -0500139}
140
141static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
142 jlong nativeFilter) {
143 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
144 auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter);
Derek Sollenberger2d142132018-01-22 10:25:26 -0500145 drawable->setStagingColorFilter(sk_ref_sp(filter));
Leon Scroggins III671cce22018-01-14 16:52:17 -0500146}
147
148static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
149 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Derek Sollenberger2d142132018-01-22 10:25:26 -0500150 return drawable->isRunning();
Leon Scroggins III671cce22018-01-14 16:52:17 -0500151}
152
Leon Scroggins III057c91a2018-01-24 13:02:16 -0500153static jboolean AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III671cce22018-01-14 16:52:17 -0500154 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Leon Scroggins III057c91a2018-01-24 13:02:16 -0500155 return drawable->start();
Leon Scroggins III671cce22018-01-14 16:52:17 -0500156}
157
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500158static jboolean AnimatedImageDrawable_nStop(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III671cce22018-01-14 16:52:17 -0500159 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500160 return drawable->stop();
Leon Scroggins III671cce22018-01-14 16:52:17 -0500161}
162
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500163// Java's LOOP_INFINITE relies on this being the same.
164static_assert(SkCodec::kRepetitionCountInfinite == -1);
165
Leon Scroggins III6de55b82018-02-23 16:11:37 -0500166static jint AnimatedImageDrawable_nGetRepeatCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III1474b782018-02-23 09:38:12 -0500167 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
168 return drawable->getRepetitionCount();
169}
170
Leon Scroggins III6de55b82018-02-23 16:11:37 -0500171static void AnimatedImageDrawable_nSetRepeatCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
172 jint loopCount) {
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500173 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
174 drawable->setRepetitionCount(loopCount);
175}
176
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500177class InvokeListener : public MessageHandler {
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500178public:
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500179 InvokeListener(JNIEnv* env, jobject javaObject) {
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500180 LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJvm) != JNI_OK);
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500181 // Hold a weak reference to break a cycle that would prevent GC.
182 mWeakRef = env->NewWeakGlobalRef(javaObject);
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500183 }
184
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500185 ~InvokeListener() override {
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500186 auto* env = get_env_or_die(mJvm);
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500187 env->DeleteWeakGlobalRef(mWeakRef);
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500188 }
189
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500190 virtual void handleMessage(const Message&) override {
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500191 auto* env = get_env_or_die(mJvm);
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500192 jobject localRef = env->NewLocalRef(mWeakRef);
193 if (localRef) {
194 env->CallVoidMethod(localRef, gAnimatedImageDrawable_onAnimationEndMethodID);
195 }
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500196 }
197
198private:
199 JavaVM* mJvm;
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500200 jweak mWeakRef;
201};
202
203class JniAnimationEndListener : public OnAnimationEndListener {
204public:
205 JniAnimationEndListener(sp<Looper>&& looper, JNIEnv* env, jobject javaObject) {
206 mListener = new InvokeListener(env, javaObject);
207 mLooper = std::move(looper);
208 }
209
210 void onAnimationEnd() override { mLooper->sendMessage(mListener, 0); }
211
212private:
213 sp<InvokeListener> mListener;
214 sp<Looper> mLooper;
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500215};
216
217static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobject /*clazz*/,
218 jlong nativePtr, jobject jdrawable) {
219 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500220 if (!jdrawable) {
221 drawable->setOnAnimationEndListener(nullptr);
222 } else {
223 sp<Looper> looper = Looper::getForThread();
224 if (!looper.get()) {
225 doThrowISE(env,
226 "Must set AnimatedImageDrawable's AnimationCallback on a thread with a "
227 "looper!");
228 return;
229 }
230
231 drawable->setOnAnimationEndListener(
232 std::make_unique<JniAnimationEndListener>(std::move(looper), env, jdrawable));
233 }
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500234}
235
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -0400236static jlong AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III671cce22018-01-14 16:52:17 -0500237 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
Leon Scroggins IIIeb3b38e2018-03-20 11:11:13 -0400238 return drawable->byteSize();
Leon Scroggins III671cce22018-01-14 16:52:17 -0500239}
240
Leon Scroggins III5e8447f2018-03-05 14:22:51 -0500241static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
242 jboolean mirrored) {
243 auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
244 drawable->setStagingMirrored(mirrored);
245}
246
Leon Scroggins III671cce22018-01-14 16:52:17 -0500247static const JNINativeMethod gAnimatedImageDrawableMethods[] = {
Leon Scroggins IIIeac14232019-02-04 10:30:22 -0500248 { "nCreate", "(JLandroid/graphics/ImageDecoder;IIJZLandroid/graphics/Rect;)J",(void*) AnimatedImageDrawable_nCreate },
Leon Scroggins III671cce22018-01-14 16:52:17 -0500249 { "nGetNativeFinalizer", "()J", (void*) AnimatedImageDrawable_nGetNativeFinalizer },
Derek Sollenberger2d142132018-01-22 10:25:26 -0500250 { "nDraw", "(JJ)J", (void*) AnimatedImageDrawable_nDraw },
Leon Scroggins III671cce22018-01-14 16:52:17 -0500251 { "nSetAlpha", "(JI)V", (void*) AnimatedImageDrawable_nSetAlpha },
252 { "nGetAlpha", "(J)I", (void*) AnimatedImageDrawable_nGetAlpha },
253 { "nSetColorFilter", "(JJ)V", (void*) AnimatedImageDrawable_nSetColorFilter },
254 { "nIsRunning", "(J)Z", (void*) AnimatedImageDrawable_nIsRunning },
Leon Scroggins III057c91a2018-01-24 13:02:16 -0500255 { "nStart", "(J)Z", (void*) AnimatedImageDrawable_nStart },
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500256 { "nStop", "(J)Z", (void*) AnimatedImageDrawable_nStop },
Leon Scroggins III6de55b82018-02-23 16:11:37 -0500257 { "nGetRepeatCount", "(J)I", (void*) AnimatedImageDrawable_nGetRepeatCount },
258 { "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount },
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500259 { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
Leon Scroggins III671cce22018-01-14 16:52:17 -0500260 { "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize },
Leon Scroggins III5e8447f2018-03-05 14:22:51 -0500261 { "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored },
Leon Scroggins III671cce22018-01-14 16:52:17 -0500262};
263
264int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500265 jclass animatedImageDrawable_class = FindClassOrDie(env, "android/graphics/drawable/AnimatedImageDrawable");
Leon Scroggins IIIbeaf5d92018-01-26 11:03:54 -0500266 gAnimatedImageDrawable_onAnimationEndMethodID = GetMethodIDOrDie(env, animatedImageDrawable_class, "onAnimationEnd", "()V");
Leon Scroggins III127d31a2018-01-19 12:29:47 -0500267
Leon Scroggins III671cce22018-01-14 16:52:17 -0500268 return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
269 gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
270}
271