Home | History | Annotate | Download | only in graphics
      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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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