Home | History | Annotate | Download | only in graphics
      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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
     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::Create(strm, 6));
    108     SkASSERT(bufferedStream.get() != NULL);
    109 
    110     Movie* moov = Movie::DecodeStream(bufferedStream.get());
    111     return create_jmovie(env, moov);
    112 }
    113 
    114 static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
    115                                      jbyteArray byteArray,
    116                                      jint offset, jint length) {
    117 
    118     NPE_CHECK_RETURN_ZERO(env, byteArray);
    119 
    120     int totalLength = env->GetArrayLength(byteArray);
    121     if ((offset | length) < 0 || offset + length > totalLength) {
    122         doThrowAIOOBE(env);
    123         return 0;
    124     }
    125 
    126     AutoJavaByteArray   ar(env, byteArray);
    127     Movie* moov = Movie::DecodeMemory(ar.ptr() + offset, length);
    128     return create_jmovie(env, moov);
    129 }
    130 
    131 static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
    132     Movie* movie = (Movie*) movieHandle;
    133     delete movie;
    134 }
    135 
    136 //////////////////////////////////////////////////////////////////////////////////////////////
    137 
    138 static const JNINativeMethod gMethods[] = {
    139     {   "width",    "()I",  (void*)movie_width  },
    140     {   "height",   "()I",  (void*)movie_height  },
    141     {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
    142     {   "duration", "()I",  (void*)movie_duration  },
    143     {   "setTime",  "(I)Z", (void*)movie_setTime  },
    144     {   "nDraw",    "(JFFJ)V",
    145                             (void*)movie_draw  },
    146     { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
    147                             (void*)movie_decodeAsset },
    148     { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
    149                             (void*)movie_decodeStream },
    150     { "nativeDestructor","(J)V", (void*)movie_destructor },
    151     { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
    152                             (void*)movie_decodeByteArray },
    153 };
    154 
    155 int register_android_graphics_Movie(JNIEnv* env)
    156 {
    157     gMovie_class = android::FindClassOrDie(env, "android/graphics/Movie");
    158     gMovie_class = android::MakeGlobalRefOrDie(env, gMovie_class);
    159 
    160     gMovie_constructorMethodID = android::GetMethodIDOrDie(env, gMovie_class, "<init>", "(J)V");
    161 
    162     gMovie_nativeInstanceID = android::GetFieldIDOrDie(env, gMovie_class, "mNativeMovie", "J");
    163 
    164     return android::RegisterMethodsOrDie(env, "android/graphics/Movie", gMethods, NELEM(gMethods));
    165 }
    166