• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "ScopedLocalRef.h"
2 #include "SkFrontBufferedStream.h"
3 #include "SkMovie.h"
4 #include "SkStream.h"
5 #include "GraphicsJNI.h"
6 #include "SkTemplates.h"
7 #include "SkUtils.h"
8 #include "Utils.h"
9 #include "CreateJavaOutputStreamAdaptor.h"
10 #include "Paint.h"
11 
12 #include <androidfw/Asset.h>
13 #include <androidfw/ResourceTypes.h>
14 #include <netinet/in.h>
15 
16 #if 0
17     #define TRACE_BITMAP(code)  code
18 #else
19     #define TRACE_BITMAP(code)
20 #endif
21 
22 static jclass       gMovie_class;
23 static jmethodID    gMovie_constructorMethodID;
24 static jfieldID     gMovie_nativeInstanceID;
25 
create_jmovie(JNIEnv * env,SkMovie * moov)26 jobject create_jmovie(JNIEnv* env, SkMovie* moov) {
27     if (NULL == moov) {
28         return NULL;
29     }
30     return env->NewObject(gMovie_class, gMovie_constructorMethodID,
31             static_cast<jlong>(reinterpret_cast<uintptr_t>(moov)));
32 }
33 
J2Movie(JNIEnv * env,jobject movie)34 static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
35     SkASSERT(env);
36     SkASSERT(movie);
37     SkASSERT(env->IsInstanceOf(movie, gMovie_class));
38     SkMovie* m = (SkMovie*)env->GetLongField(movie, gMovie_nativeInstanceID);
39     SkASSERT(m);
40     return m;
41 }
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 
movie_width(JNIEnv * env,jobject movie)45 static jint movie_width(JNIEnv* env, jobject movie) {
46     NPE_CHECK_RETURN_ZERO(env, movie);
47     return static_cast<jint>(J2Movie(env, movie)->width());
48 }
49 
movie_height(JNIEnv * env,jobject movie)50 static jint movie_height(JNIEnv* env, jobject movie) {
51     NPE_CHECK_RETURN_ZERO(env, movie);
52     return static_cast<jint>(J2Movie(env, movie)->height());
53 }
54 
movie_isOpaque(JNIEnv * env,jobject movie)55 static jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
56     NPE_CHECK_RETURN_ZERO(env, movie);
57     return J2Movie(env, movie)->isOpaque() ? JNI_TRUE : JNI_FALSE;
58 }
59 
movie_duration(JNIEnv * env,jobject movie)60 static jint movie_duration(JNIEnv* env, jobject movie) {
61     NPE_CHECK_RETURN_ZERO(env, movie);
62     return static_cast<jint>(J2Movie(env, movie)->duration());
63 }
64 
movie_setTime(JNIEnv * env,jobject movie,jint ms)65 static jboolean movie_setTime(JNIEnv* env, jobject movie, jint ms) {
66     NPE_CHECK_RETURN_ZERO(env, movie);
67     return J2Movie(env, movie)->setTime(ms) ? JNI_TRUE : JNI_FALSE;
68 }
69 
movie_draw(JNIEnv * env,jobject movie,jobject canvas,jfloat fx,jfloat fy,jobject jpaint)70 static void movie_draw(JNIEnv* env, jobject movie, jobject canvas,
71                        jfloat fx, jfloat fy, jobject jpaint) {
72     NPE_CHECK_RETURN_VOID(env, movie);
73     NPE_CHECK_RETURN_VOID(env, canvas);
74     // its OK for paint to be null
75 
76     SkMovie* m = J2Movie(env, movie);
77     SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
78     const SkBitmap& b = m->bitmap();
79     const SkPaint* p = jpaint ? GraphicsJNI::getNativePaint(env, jpaint) : NULL;
80 
81     c->drawBitmap(b, fx, fy, p);
82 }
83 
movie_decodeAsset(JNIEnv * env,jobject clazz,jlong native_asset)84 static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
85     android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
86     if (asset == NULL) return NULL;
87     SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset,
88             android::AssetStreamAdaptor::kNo_OwnAsset,
89             android::AssetStreamAdaptor::kNo_HasMemoryBase));
90     SkMovie* moov = SkMovie::DecodeStream(stream.get());
91     return create_jmovie(env, moov);
92 }
93 
movie_decodeStream(JNIEnv * env,jobject clazz,jobject istream)94 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
95 
96     NPE_CHECK_RETURN_ZERO(env, istream);
97 
98     jbyteArray byteArray = env->NewByteArray(16*1024);
99     ScopedLocalRef<jbyteArray> scoper(env, byteArray);
100     SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
101     if (NULL == strm) {
102         return 0;
103     }
104 
105     // Need to buffer enough input to be able to rewind as much as might be read by a decoder
106     // trying to determine the stream's format. The only decoder for movies is GIF, which
107     // will only read 6.
108     // FIXME: Get this number from SkImageDecoder
109     SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
110     SkASSERT(bufferedStream.get() != NULL);
111 
112     SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
113     strm->unref();
114     return create_jmovie(env, moov);
115 }
116 
movie_decodeByteArray(JNIEnv * env,jobject clazz,jbyteArray byteArray,jint offset,jint length)117 static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
118                                      jbyteArray byteArray,
119                                      jint offset, jint length) {
120 
121     NPE_CHECK_RETURN_ZERO(env, byteArray);
122 
123     int totalLength = env->GetArrayLength(byteArray);
124     if ((offset | length) < 0 || offset + length > totalLength) {
125         doThrowAIOOBE(env);
126         return 0;
127     }
128 
129     AutoJavaByteArray   ar(env, byteArray);
130     SkMovie* moov = SkMovie::DecodeMemory(ar.ptr() + offset, length);
131     return create_jmovie(env, moov);
132 }
133 
movie_destructor(JNIEnv * env,jobject,jlong movieHandle)134 static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
135     SkMovie* movie = (SkMovie*) movieHandle;
136     delete movie;
137 }
138 
139 //////////////////////////////////////////////////////////////////////////////////////////////
140 
141 #include <android_runtime/AndroidRuntime.h>
142 
143 static JNINativeMethod gMethods[] = {
144     {   "width",    "()I",  (void*)movie_width  },
145     {   "height",   "()I",  (void*)movie_height  },
146     {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
147     {   "duration", "()I",  (void*)movie_duration  },
148     {   "setTime",  "(I)Z", (void*)movie_setTime  },
149     {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
150                             (void*)movie_draw  },
151     { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
152                             (void*)movie_decodeAsset },
153     { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
154                             (void*)movie_decodeStream },
155     { "nativeDestructor","(J)V", (void*)movie_destructor },
156     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
157                             (void*)movie_decodeByteArray },
158 };
159 
160 #define kClassPathName  "android/graphics/Movie"
161 
162 #define RETURN_ERR_IF_NULL(value)   do { if (!(value)) { assert(0); return -1; } } while (false)
163 
register_android_graphics_Movie(JNIEnv * env)164 int register_android_graphics_Movie(JNIEnv* env)
165 {
166     gMovie_class = env->FindClass(kClassPathName);
167     RETURN_ERR_IF_NULL(gMovie_class);
168     gMovie_class = (jclass)env->NewGlobalRef(gMovie_class);
169 
170     gMovie_constructorMethodID = env->GetMethodID(gMovie_class, "<init>", "(J)V");
171     RETURN_ERR_IF_NULL(gMovie_constructorMethodID);
172 
173     gMovie_nativeInstanceID = env->GetFieldID(gMovie_class, "mNativeMovie", "J");
174     RETURN_ERR_IF_NULL(gMovie_nativeInstanceID);
175 
176     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
177                                                        gMethods, SK_ARRAY_COUNT(gMethods));
178 }
179