1 #include "CreateJavaOutputStreamAdaptor.h"
2 #include "GraphicsJNI.h"
3 #include <nativehelper/ScopedLocalRef.h>
4 #include "SkFrontBufferedStream.h"
5 #include "Movie.h"
6 #include "SkStream.h"
7 #include "SkUtils.h"
8 #include "Utils.h"
9 #include "core_jni_helpers.h"
10
11 #include <androidfw/Asset.h>
12 #include <androidfw/ResourceTypes.h>
13 #include <hwui/Canvas.h>
14 #include <hwui/Paint.h>
15 #include <jni.h>
16 #include <netinet/in.h>
17
18 static jclass gMovie_class;
19 static jmethodID gMovie_constructorMethodID;
20 static jfieldID gMovie_nativeInstanceID;
21
create_jmovie(JNIEnv * env,Movie * moov)22 jobject create_jmovie(JNIEnv* env, Movie* moov) {
23 if (NULL == moov) {
24 return NULL;
25 }
26 return env->NewObject(gMovie_class, gMovie_constructorMethodID,
27 static_cast<jlong>(reinterpret_cast<uintptr_t>(moov)));
28 }
29
J2Movie(JNIEnv * env,jobject movie)30 static Movie* J2Movie(JNIEnv* env, jobject movie) {
31 SkASSERT(env);
32 SkASSERT(movie);
33 SkASSERT(env->IsInstanceOf(movie, gMovie_class));
34 Movie* m = (Movie*)env->GetLongField(movie, gMovie_nativeInstanceID);
35 SkASSERT(m);
36 return m;
37 }
38
39 ///////////////////////////////////////////////////////////////////////////////
40
movie_width(JNIEnv * env,jobject movie)41 static jint movie_width(JNIEnv* env, jobject movie) {
42 NPE_CHECK_RETURN_ZERO(env, movie);
43 return static_cast<jint>(J2Movie(env, movie)->width());
44 }
45
movie_height(JNIEnv * env,jobject movie)46 static jint movie_height(JNIEnv* env, jobject movie) {
47 NPE_CHECK_RETURN_ZERO(env, movie);
48 return static_cast<jint>(J2Movie(env, movie)->height());
49 }
50
movie_isOpaque(JNIEnv * env,jobject movie)51 static jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
52 NPE_CHECK_RETURN_ZERO(env, movie);
53 return J2Movie(env, movie)->isOpaque() ? JNI_TRUE : JNI_FALSE;
54 }
55
movie_duration(JNIEnv * env,jobject movie)56 static jint movie_duration(JNIEnv* env, jobject movie) {
57 NPE_CHECK_RETURN_ZERO(env, movie);
58 return static_cast<jint>(J2Movie(env, movie)->duration());
59 }
60
movie_setTime(JNIEnv * env,jobject movie,jint ms)61 static jboolean movie_setTime(JNIEnv* env, jobject movie, jint ms) {
62 NPE_CHECK_RETURN_ZERO(env, movie);
63 return J2Movie(env, movie)->setTime(ms) ? JNI_TRUE : JNI_FALSE;
64 }
65
movie_draw(JNIEnv * env,jobject movie,jlong canvasHandle,jfloat fx,jfloat fy,jlong paintHandle)66 static void movie_draw(JNIEnv* env, jobject movie, jlong canvasHandle,
67 jfloat fx, jfloat fy, jlong paintHandle) {
68 NPE_CHECK_RETURN_VOID(env, movie);
69
70 android::Canvas* c = reinterpret_cast<android::Canvas*>(canvasHandle);
71 const android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
72
73 // Canvas should never be NULL. However paint is an optional parameter and
74 // therefore may be NULL.
75 SkASSERT(c != NULL);
76
77 Movie* m = J2Movie(env, movie);
78 const SkBitmap& b = m->bitmap();
79 sk_sp<android::Bitmap> wrapper = android::Bitmap::createFrom(b.info(), *b.pixelRef());
80 c->drawBitmap(*wrapper, fx, fy, p);
81 }
82
movie_decodeAsset(JNIEnv * env,jobject clazz,jlong native_asset)83 static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
84 android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
85 if (asset == NULL) return NULL;
86 android::AssetStreamAdaptor stream(asset);
87 Movie* moov = Movie::DecodeStream(&stream);
88 return create_jmovie(env, moov);
89 }
90
movie_decodeStream(JNIEnv * env,jobject clazz,jobject istream)91 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
92
93 NPE_CHECK_RETURN_ZERO(env, istream);
94
95 jbyteArray byteArray = env->NewByteArray(16*1024);
96 ScopedLocalRef<jbyteArray> scoper(env, byteArray);
97 SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
98 if (NULL == strm) {
99 return 0;
100 }
101
102 // Need to buffer enough input to be able to rewind as much as might be read by a decoder
103 // trying to determine the stream's format. The only decoder for movies is GIF, which
104 // will only read 6.
105 // FIXME: Get this number from SkImageDecoder
106 // bufferedStream takes ownership of strm
107 std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Make(
108 std::unique_ptr<SkStream>(strm), 6));
109 SkASSERT(bufferedStream.get() != NULL);
110
111 Movie* moov = Movie::DecodeStream(bufferedStream.get());
112 return create_jmovie(env, moov);
113 }
114
movie_decodeByteArray(JNIEnv * env,jobject clazz,jbyteArray byteArray,jint offset,jint length)115 static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
116 jbyteArray byteArray,
117 jint offset, jint length) {
118
119 NPE_CHECK_RETURN_ZERO(env, byteArray);
120
121 int totalLength = env->GetArrayLength(byteArray);
122 if ((offset | length) < 0 || offset + length > totalLength) {
123 doThrowAIOOBE(env);
124 return 0;
125 }
126
127 AutoJavaByteArray ar(env, byteArray);
128 Movie* moov = Movie::DecodeMemory(ar.ptr() + offset, length);
129 return create_jmovie(env, moov);
130 }
131
movie_destructor(JNIEnv * env,jobject,jlong movieHandle)132 static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
133 Movie* movie = (Movie*) movieHandle;
134 delete movie;
135 }
136
137 //////////////////////////////////////////////////////////////////////////////////////////////
138
139 static const JNINativeMethod gMethods[] = {
140 { "width", "()I", (void*)movie_width },
141 { "height", "()I", (void*)movie_height },
142 { "isOpaque", "()Z", (void*)movie_isOpaque },
143 { "duration", "()I", (void*)movie_duration },
144 { "setTime", "(I)Z", (void*)movie_setTime },
145 { "nDraw", "(JFFJ)V",
146 (void*)movie_draw },
147 { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
148 (void*)movie_decodeAsset },
149 { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
150 (void*)movie_decodeStream },
151 { "nativeDestructor","(J)V", (void*)movie_destructor },
152 { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
153 (void*)movie_decodeByteArray },
154 };
155
register_android_graphics_Movie(JNIEnv * env)156 int register_android_graphics_Movie(JNIEnv* env)
157 {
158 gMovie_class = android::FindClassOrDie(env, "android/graphics/Movie");
159 gMovie_class = android::MakeGlobalRefOrDie(env, gMovie_class);
160
161 gMovie_constructorMethodID = android::GetMethodIDOrDie(env, gMovie_class, "<init>", "(J)V");
162
163 gMovie_nativeInstanceID = android::GetFieldIDOrDie(env, gMovie_class, "mNativeMovie", "J");
164
165 return android::RegisterMethodsOrDie(env, "android/graphics/Movie", gMethods, NELEM(gMethods));
166 }
167