1
2 /*
3 * Copyright 2018 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "include/codec/SkCodec.h"
10 #include "include/codec/SkGifDecoder.h"
11 #include "include/codec/SkJpegDecoder.h"
12 #include "include/codec/SkPngDecoder.h"
13 #include "include/core/SkBitmap.h"
14 #include "include/core/SkCanvas.h"
15 #include "include/core/SkColor.h"
16 #include "include/core/SkColorSpace.h"
17 #include "include/core/SkFontMgr.h"
18 #include "include/core/SkStream.h"
19 #include "include/core/SkSurface.h"
20 #include "include/ports/SkFontMgr_empty.h"
21
22 #include "include/gpu/ganesh/GrBackendSurface.h"
23 #include "include/gpu/ganesh/GrContextOptions.h"
24 #include "include/gpu/ganesh/GrDirectContext.h"
25 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
26 #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
27 #include "include/gpu/ganesh/gl/GrGLDirectContext.h"
28 #include "include/gpu/ganesh/gl/GrGLInterface.h"
29 #include "include/gpu/ganesh/gl/GrGLTypes.h"
30 #include "include/gpu/ganesh/gl/egl/GrGLMakeEGLInterface.h"
31
32 #include "modules/skottie/include/Skottie.h"
33 #include "modules/skresources/include/SkResources.h"
34 #include "modules/sksg/include/SkSGInvalidationController.h"
35 #include "modules/skshaper/utils/FactoryHelpers.h"
36
37 #include <jni.h>
38 #include <math.h>
39 #include <string>
40 #include <utility>
41
42 #include <GLES2/gl2.h>
43 #include <GLES2/gl2ext.h>
44
45 #include <GLES3/gl3.h>
46
47 #define STENCIL_BUFFER_SIZE 8
48
49 /*#define ATRACE_NAME(name) ScopedTrace ___tracer(name)
50
51 // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
52 #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
53 namespace {
54 class ScopedTrace {
55 public:
56 inline ScopedTrace(const char *name) {
57 ATrace_beginSection(name);
58 }
59
60 inline ~ScopedTrace() {
61 ATrace_endSection();
62 }
63 };
64
65 }*/
66
67 //disable atrace
68 #define ATRACE_NAME(name)
69 #define ATRACE_CALL()
70
71 struct SkottieRunner {
72 sk_sp<GrDirectContext> mDContext;
73 };
74
75 static JavaVM* sJVM = nullptr;
76
release_global_jni_ref(const void *,void * context)77 static void release_global_jni_ref(const void* /*data*/, void* context) {
78 JNIEnv* env;
79 if (sJVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
80 SK_ABORT("Attempting to release a JNI ref on a thread without a JVM attached.");
81 }
82 jobject obj = reinterpret_cast<jobject>(context);
83 env->DeleteGlobalRef(obj);
84 }
85
86 extern "C" JNIEXPORT jlong
87 JNICALL
Java_org_skia_skottie_SkottieRunner_nCreateProxy(JNIEnv * env,jclass clazz)88 Java_org_skia_skottie_SkottieRunner_nCreateProxy(JNIEnv *env, jclass clazz) {
89 sk_sp<const GrGLInterface> glInterface = GrGLInterfaces::MakeEGL();
90 if (!glInterface) {
91 return 0;
92 }
93
94 GrContextOptions options;
95 options.fDisableDistanceFieldPaths = true;
96 sk_sp<GrDirectContext> dContext = GrDirectContexts::MakeGL(std::move(glInterface), options);
97 if (!dContext) {
98 return 0;
99 }
100
101 SkottieRunner* skottie = new SkottieRunner();
102 skottie->mDContext = std::move(dContext);
103
104 return (jlong) skottie;
105 }
106
107 extern "C" JNIEXPORT void
108 JNICALL
Java_org_skia_skottie_SkottieRunner_nDeleteProxy(JNIEnv * env,jclass clazz,jlong nativeProxy)109 Java_org_skia_skottie_SkottieRunner_nDeleteProxy(JNIEnv *env, jclass clazz, jlong nativeProxy) {
110 if (!nativeProxy) {
111 return;
112 }
113 SkottieRunner* skottie = reinterpret_cast<SkottieRunner*>(nativeProxy);
114 if (skottie->mDContext) {
115 skottie->mDContext->releaseResourcesAndAbandonContext();
116 skottie->mDContext.reset();
117 }
118 delete skottie;
119 }
120
121
122 extern "C" JNIEXPORT void
123 JNICALL
Java_org_skia_skottie_SkottieRunner_nSetMaxCacheSize(JNIEnv * env,jclass clazz,jint maxCacheSize,jlong nativeProxy)124 Java_org_skia_skottie_SkottieRunner_nSetMaxCacheSize(JNIEnv *env, jclass clazz, jint maxCacheSize,
125 jlong nativeProxy) {
126 if (!nativeProxy) {
127 return;
128 }
129 SkottieRunner* skottie = reinterpret_cast<SkottieRunner*>(nativeProxy);
130 if (skottie->mDContext) {
131 skottie->mDContext->setResourceCacheLimit(maxCacheSize);
132 }
133 }
134
135 struct SkottieAnimation {
136 SkottieRunner *mRunner;
137 std::unique_ptr<SkStream> mStream;
138 sk_sp<skottie::Animation> mAnimation;
139 long mTimeBase;
140 float mDuration; //in milliseconds
141 };
142
143 extern "C" JNIEXPORT jlong
144 JNICALL
Java_org_skia_skottie_SkottieAnimation_nCreateProxy(JNIEnv * env,jobject clazz,jlong runner,jobject bufferObj)145 Java_org_skia_skottie_SkottieAnimation_nCreateProxy(JNIEnv *env,
146 jobject clazz,
147 jlong runner,
148 jobject bufferObj) {
149
150 if (!runner) {
151 return 0;
152 }
153 SkottieRunner *skottieRunner = reinterpret_cast<SkottieRunner*>(runner);
154
155 const void* buffer = env->GetDirectBufferAddress(bufferObj);
156 jlong bufferSize = env->GetDirectBufferCapacity(bufferObj);
157 if (buffer == nullptr || bufferSize <= 0) {
158 return 0;
159 }
160
161 env->GetJavaVM(&sJVM);
162 jobject bufferRef = env->NewGlobalRef(bufferObj);
163 if (bufferRef == nullptr) {
164 return 0;
165 }
166
167 sk_sp<SkData> data(SkData::MakeWithProc(buffer, bufferSize, release_global_jni_ref,
168 reinterpret_cast<void*>(bufferRef)));
169 std::unique_ptr<SkStream> stream = SkMemoryStream::Make(data);
170 if (!stream) {
171 // Cannot create a stream
172 return 0;
173 }
174
175 SkottieAnimation* skottieAnimation = new SkottieAnimation();
176 skottieAnimation->mRunner = skottieRunner;
177 skottieAnimation->mStream = std::move(stream);
178
179 sk_sp<SkFontMgr> freetypeMgr = SkFontMgr_New_Custom_Empty();
180
181 SkCodecs::Register(SkPngDecoder::Decoder());
182 SkCodecs::Register(SkGifDecoder::Decoder());
183 SkCodecs::Register(SkJpegDecoder::Decoder());
184
185 skottieAnimation->mAnimation = skottie::Animation::Builder()
186 // Note, this nullptr ResourceProvider will only be able to decode base64 encoded images
187 // (using the above registered codecs) or base64 encoded FreeType typefaces.
188 .setResourceProvider(skresources::DataURIResourceProviderProxy::Make(nullptr,
189 skresources::ImageDecodeStrategy::kPreDecode, freetypeMgr))
190 .setTextShapingFactory(sk_make_sp<SkShapers::HarfbuzzFactory>())
191 .make(skottieAnimation->mStream.get());
192 skottieAnimation->mTimeBase = 0.0f; // force a time reset
193 skottieAnimation->mDuration = 1000 * skottieAnimation->mAnimation->duration();
194
195 if (!skottieAnimation->mAnimation) {
196 //failed to load Bodymovin animation
197 delete skottieAnimation;
198 return 0;
199 }
200
201 return (jlong) skottieAnimation;
202 }
203
204 extern "C" JNIEXPORT void
205 JNICALL
Java_org_skia_skottie_SkottieAnimation_nDeleteProxy(JNIEnv * env,jclass clazz,jlong nativeProxy)206 Java_org_skia_skottie_SkottieAnimation_nDeleteProxy(JNIEnv *env, jclass clazz,
207 jlong nativeProxy) {
208 if (!nativeProxy) {
209 return;
210 }
211 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
212 delete skottieAnimation;
213 }
214
215 extern "C" JNIEXPORT bool
216 JNICALL
Java_org_skia_skottie_SkottieAnimation_nDrawFrame(JNIEnv * env,jclass clazz,jlong nativeProxy,jint width,jint height,jboolean wideColorGamut,jfloat progress,jint backgroundColor,jboolean forceDraw)217 Java_org_skia_skottie_SkottieAnimation_nDrawFrame(JNIEnv *env, jclass clazz,
218 jlong nativeProxy, jint width,
219 jint height,
220 jboolean wideColorGamut,
221 jfloat progress,
222 jint backgroundColor,
223 jboolean forceDraw) {
224 ATRACE_NAME("SkottieDrawFrame");
225 if (!nativeProxy) {
226 return false;
227 }
228 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
229
230 auto dContext = skottieAnimation->mRunner->mDContext.get();
231
232 if (!dContext) {
233 return false;
234 }
235
236 sksg::InvalidationController ic;
237
238 if (skottieAnimation->mAnimation) {
239 skottieAnimation->mAnimation->seek(progress, &ic);
240 if (!forceDraw && ic.bounds().isEmpty()) {
241 return false;
242 }
243 }
244
245 SkColorType colorType;
246 // setup surface for fbo0
247 GrGLFramebufferInfo fboInfo;
248 fboInfo.fFBOID = 0;
249 if (wideColorGamut) {
250 fboInfo.fFormat = GL_RGBA16F;
251 colorType = kRGBA_F16_SkColorType;
252 } else {
253 fboInfo.fFormat = GL_RGBA8;
254 colorType = kN32_SkColorType;
255 }
256 fboInfo.fProtected = skgpu::Protected::kNo;
257 auto backendRT = GrBackendRenderTargets::MakeGL(width, height, 0, STENCIL_BUFFER_SIZE, fboInfo);
258
259 SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
260
261 sk_sp<SkSurface> renderTarget(SkSurfaces::WrapBackendRenderTarget(
262 dContext, backendRT, kBottomLeft_GrSurfaceOrigin, colorType, nullptr, &props));
263
264 auto canvas = renderTarget->getCanvas();
265 canvas->clear(backgroundColor);
266
267 SkAutoCanvasRestore acr(canvas, true);
268 SkRect bounds = SkRect::MakeWH(width, height);
269 skottieAnimation->mAnimation->render(canvas, &bounds);
270 dContext->flushAndSubmit();
271 return true;
272 }
273
274 extern "C" JNIEXPORT jlong
275 JNICALL
Java_org_skia_skottie_SkottieAnimation_nGetDuration(JNIEnv * env,jclass clazz,jlong nativeProxy)276 Java_org_skia_skottie_SkottieAnimation_nGetDuration(JNIEnv *env,
277 jclass clazz,
278 jlong nativeProxy) {
279 if (!nativeProxy) {
280 return 0;
281 }
282 SkottieAnimation* skottieAnimation = reinterpret_cast<SkottieAnimation*>(nativeProxy);
283 return (jlong) skottieAnimation->mDuration;
284 }
285