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 
     11 #include <androidfw/Asset.h>
     12 #include <androidfw/ResourceTypes.h>
     13 #include <netinet/in.h>
     14 
     15 #if 0
     16     #define TRACE_BITMAP(code)  code
     17 #else
     18     #define TRACE_BITMAP(code)
     19 #endif
     20 
     21 static jclass       gMovie_class;
     22 static jmethodID    gMovie_constructorMethodID;
     23 static jfieldID     gMovie_nativeInstanceID;
     24 
     25 jobject create_jmovie(JNIEnv* env, SkMovie* moov) {
     26     if (NULL == moov) {
     27         return NULL;
     28     }
     29     return env->NewObject(gMovie_class, gMovie_constructorMethodID,
     30             static_cast<jint>(reinterpret_cast<uintptr_t>(moov)));
     31 }
     32 
     33 static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
     34     SkASSERT(env);
     35     SkASSERT(movie);
     36     SkASSERT(env->IsInstanceOf(movie, gMovie_class));
     37     SkMovie* m = (SkMovie*)env->GetIntField(movie, gMovie_nativeInstanceID);
     38     SkASSERT(m);
     39     return m;
     40 }
     41 
     42 ///////////////////////////////////////////////////////////////////////////////
     43 
     44 static int movie_width(JNIEnv* env, jobject movie) {
     45     NPE_CHECK_RETURN_ZERO(env, movie);
     46     return J2Movie(env, movie)->width();
     47 }
     48 
     49 static int movie_height(JNIEnv* env, jobject movie) {
     50     NPE_CHECK_RETURN_ZERO(env, movie);
     51     return J2Movie(env, movie)->height();
     52 }
     53 
     54 static jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
     55     NPE_CHECK_RETURN_ZERO(env, movie);
     56     return J2Movie(env, movie)->isOpaque();
     57 }
     58 
     59 static int movie_duration(JNIEnv* env, jobject movie) {
     60     NPE_CHECK_RETURN_ZERO(env, movie);
     61     return J2Movie(env, movie)->duration();
     62 }
     63 
     64 static jboolean movie_setTime(JNIEnv* env, jobject movie, int ms) {
     65     NPE_CHECK_RETURN_ZERO(env, movie);
     66     return J2Movie(env, movie)->setTime(ms);
     67 }
     68 
     69 static void movie_draw(JNIEnv* env, jobject movie, jobject canvas,
     70                        jfloat fx, jfloat fy, jobject jpaint) {
     71     NPE_CHECK_RETURN_VOID(env, movie);
     72     NPE_CHECK_RETURN_VOID(env, canvas);
     73     // its OK for paint to be null
     74 
     75     SkMovie* m = J2Movie(env, movie);
     76     SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
     77     SkScalar sx = SkFloatToScalar(fx);
     78     SkScalar sy = SkFloatToScalar(fy);
     79     const SkBitmap& b = m->bitmap();
     80     const SkPaint* p = jpaint ? GraphicsJNI::getNativePaint(env, jpaint) : NULL;
     81 
     82     c->drawBitmap(b, sx, sy, p);
     83 }
     84 
     85 static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jint native_asset) {
     86     android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
     87     if (asset == NULL) return NULL;
     88     SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset,
     89             android::AssetStreamAdaptor::kNo_OwnAsset,
     90             android::AssetStreamAdaptor::kNo_HasMemoryBase));
     91     SkMovie* moov = SkMovie::DecodeStream(stream.get());
     92     return create_jmovie(env, moov);
     93 }
     94 
     95 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
     96 
     97     NPE_CHECK_RETURN_ZERO(env, istream);
     98 
     99     jbyteArray byteArray = env->NewByteArray(16*1024);
    100     ScopedLocalRef<jbyteArray> scoper(env, byteArray);
    101     SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
    102     if (NULL == strm) {
    103         return 0;
    104     }
    105 
    106     // Need to buffer enough input to be able to rewind as much as might be read by a decoder
    107     // trying to determine the stream's format. The only decoder for movies is GIF, which
    108     // will only read 6.
    109     // FIXME: Get this number from SkImageDecoder
    110     SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
    111     SkASSERT(bufferedStream.get() != NULL);
    112 
    113     SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
    114     strm->unref();
    115     return create_jmovie(env, moov);
    116 }
    117 
    118 static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
    119                                      jbyteArray byteArray,
    120                                      int offset, int length) {
    121 
    122     NPE_CHECK_RETURN_ZERO(env, byteArray);
    123 
    124     int totalLength = env->GetArrayLength(byteArray);
    125     if ((offset | length) < 0 || offset + length > totalLength) {
    126         doThrowAIOOBE(env);
    127         return 0;
    128     }
    129 
    130     AutoJavaByteArray   ar(env, byteArray);
    131     SkMovie* moov = SkMovie::DecodeMemory(ar.ptr() + offset, length);
    132     return create_jmovie(env, moov);
    133 }
    134 
    135 static void movie_destructor(JNIEnv* env, jobject, SkMovie* movie) {
    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", "(I)Landroid/graphics/Movie;",
    152                             (void*)movie_decodeAsset },
    153     { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
    154                             (void*)movie_decodeStream },
    155     { "nativeDestructor","(I)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>", "(I)V");
    171     RETURN_ERR_IF_NULL(gMovie_constructorMethodID);
    172 
    173     gMovie_nativeInstanceID = env->GetFieldID(gMovie_class, "mNativeMovie", "I");
    174     RETURN_ERR_IF_NULL(gMovie_nativeInstanceID);
    175 
    176     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
    177                                                        gMethods, SK_ARRAY_COUNT(gMethods));
    178 }
    179