160126efd7d905ca24822765c6dafac17fef278abBen Wagner#include "CreateJavaOutputStreamAdaptor.h"
260126efd7d905ca24822765c6dafac17fef278abBen Wagner#include "GraphicsJNI.h"
3ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "ScopedLocalRef.h"
47315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III#include "SkFrontBufferedStream.h"
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkMovie.h"
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkStream.h"
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkUtils.h"
8ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "Utils.h"
960126efd7d905ca24822765c6dafac17fef278abBen Wagner#include "core_jni_helpers.h"
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/Asset.h>
12b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/ResourceTypes.h>
13dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <hwui/Canvas.h>
14dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <hwui/Paint.h>
1560126efd7d905ca24822765c6dafac17fef278abBen Wagner#include <jni.h>
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netinet/in.h>
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jclass       gMovie_class;
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jmethodID    gMovie_constructorMethodID;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID     gMovie_nativeInstanceID;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectjobject create_jmovie(JNIEnv* env, SkMovie* moov) {
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (NULL == moov) {
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return NULL;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26cf6f7a0f006c0fcf59bb634cbe79f2a8500fd92aElliott Hughes    return env->NewObject(gMovie_class, gMovie_constructorMethodID,
27dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat            static_cast<jlong>(reinterpret_cast<uintptr_t>(moov)));
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic SkMovie* J2Movie(JNIEnv* env, jobject movie) {
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkASSERT(env);
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkASSERT(movie);
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkASSERT(env->IsInstanceOf(movie, gMovie_class));
34dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    SkMovie* m = (SkMovie*)env->GetLongField(movie, gMovie_nativeInstanceID);
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkASSERT(m);
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return m;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhatstatic jint movie_width(JNIEnv* env, jobject movie) {
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, movie);
43dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    return static_cast<jint>(J2Movie(env, movie)->width());
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
46dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhatstatic jint movie_height(JNIEnv* env, jobject movie) {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, movie);
48dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    return static_cast<jint>(J2Movie(env, movie)->height());
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, movie);
53dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    return J2Movie(env, movie)->isOpaque() ? JNI_TRUE : JNI_FALSE;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
56dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhatstatic jint movie_duration(JNIEnv* env, jobject movie) {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, movie);
58dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    return static_cast<jint>(J2Movie(env, movie)->duration());
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
61dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhatstatic jboolean movie_setTime(JNIEnv* env, jobject movie, jint ms) {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, movie);
63dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    return J2Movie(env, movie)->setTime(ms) ? JNI_TRUE : JNI_FALSE;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
66304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenbergerstatic void movie_draw(JNIEnv* env, jobject movie, jlong canvasHandle,
67ab22c1c792bc5f422a029a4ab6a23861e44136d8Derek Sollenberger                       jfloat fx, jfloat fy, jlong paintHandle) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_VOID(env, movie);
69304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger
70304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger    android::Canvas* c = reinterpret_cast<android::Canvas*>(canvasHandle);
71304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger    const android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
72304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger
73304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger    // Canvas should never be NULL. However paint is an optional parameter and
74304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger    // therefore may be NULL.
75304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger    SkASSERT(c != NULL);
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkMovie* m = J2Movie(env, movie);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const SkBitmap& b = m->bitmap();
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
802e0103eb340822f9d580c1aa8492bae8394b8243Leon Scroggins III    c->drawBitmap(b, fx, fy, p);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
83dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhatstatic jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
847315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
857315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    if (asset == NULL) return NULL;
8660126efd7d905ca24822765c6dafac17fef278abBen Wagner    android::AssetStreamAdaptor stream(asset);
8760126efd7d905ca24822765c6dafac17fef278abBen Wagner    SkMovie* moov = SkMovie::DecodeStream(&stream);
887315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    return create_jmovie(env, moov);
897315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III}
907315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
928451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, istream);
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
957315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    jbyteArray byteArray = env->NewByteArray(16*1024);
967315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
977315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (NULL == strm) {
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1027315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
1037315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    // trying to determine the stream's format. The only decoder for movies is GIF, which
1047315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    // will only read 6.
1057315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    // FIXME: Get this number from SkImageDecoder
1063449789b9ca58fee7e5cd02ff89d544f4a6bc9b5Leon Scroggins III    // bufferedStream takes ownership of strm
10760126efd7d905ca24822765c6dafac17fef278abBen Wagner    std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
1087315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    SkASSERT(bufferedStream.get() != NULL);
1097315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III
11060126efd7d905ca24822765c6dafac17fef278abBen Wagner    SkMovie* moov = SkMovie::DecodeStream(bufferedStream.get());
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return create_jmovie(env, moov);
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                     jbyteArray byteArray,
116dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat                                     jint offset, jint length) {
1178451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    NPE_CHECK_RETURN_ZERO(env, byteArray);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int totalLength = env->GetArrayLength(byteArray);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if ((offset | length) < 0 || offset + length > totalLength) {
1228451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes        doThrowAIOOBE(env);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AutoJavaByteArray   ar(env, byteArray);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkMovie* moov = SkMovie::DecodeMemory(ar.ptr() + offset, length);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return create_jmovie(env, moov);
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
131dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhatstatic void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
132dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    SkMovie* movie = (SkMovie*) movieHandle;
13308d7778f081aae745e6ad9e5350221b21dbf352eKimiyoshi Kusaka    delete movie;
13408d7778f081aae745e6ad9e5350221b21dbf352eKimiyoshi Kusaka}
13508d7778f081aae745e6ad9e5350221b21dbf352eKimiyoshi Kusaka
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//////////////////////////////////////////////////////////////////////////////////////////////
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13876f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gMethods[] = {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {   "width",    "()I",  (void*)movie_width  },
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {   "height",   "()I",  (void*)movie_height  },
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {   "duration", "()I",  (void*)movie_duration  },
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    {   "setTime",  "(I)Z", (void*)movie_setTime  },
144304cc5387478618164cd9167f12564f91eb6cc66Derek Sollenberger    {   "nDraw",    "(JFFJ)V",
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (void*)movie_draw  },
146dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
1477315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III                            (void*)movie_decodeAsset },
1487315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (void*)movie_decodeStream },
150dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8cAshok Bhat    { "nativeDestructor","(J)V", (void*)movie_destructor },
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            (void*)movie_decodeByteArray },
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_graphics_Movie(JNIEnv* env)
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
157ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gMovie_class = android::FindClassOrDie(env, "android/graphics/Movie");
158ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gMovie_class = android::MakeGlobalRefOrDie(env, gMovie_class);
1598451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
160ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gMovie_constructorMethodID = android::GetMethodIDOrDie(env, gMovie_class, "<init>", "(J)V");
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
162ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gMovie_nativeInstanceID = android::GetFieldIDOrDie(env, gMovie_class, "mNativeMovie", "J");
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
164ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return android::RegisterMethodsOrDie(env, "android/graphics/Movie", gMethods, NELEM(gMethods));
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
166