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::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 
    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 
    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 
    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