1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "jni.h" 18#include <nativehelper/JNIHelp.h> 19#include <android_runtime/AndroidRuntime.h> 20#include <android_runtime/android_graphics_SurfaceTexture.h> 21 22#include <ui/Region.h> 23#include <ui/Rect.h> 24 25#include <gui/SurfaceTexture.h> 26#include <gui/SurfaceTextureClient.h> 27 28#include <SkBitmap.h> 29#include <SkCanvas.h> 30 31namespace android { 32 33// ---------------------------------------------------------------------------- 34// JNI Glue 35// ---------------------------------------------------------------------------- 36 37static struct { 38 jmethodID set; 39 jfieldID left; 40 jfieldID top; 41 jfieldID right; 42 jfieldID bottom; 43} gRectClassInfo; 44 45static struct { 46 jfieldID nativeCanvas; 47 jfieldID surfaceFormat; 48} gCanvasClassInfo; 49 50static struct { 51 jfieldID nativeWindow; 52} gTextureViewClassInfo; 53 54#define GET_INT(object, field) \ 55 env->GetIntField(object, field) 56 57#define SET_INT(object, field, value) \ 58 env->SetIntField(object, field, value) 59 60#define INVOKEV(object, method, ...) \ 61 env->CallVoidMethod(object, method, __VA_ARGS__) 62 63// ---------------------------------------------------------------------------- 64// Native layer 65// ---------------------------------------------------------------------------- 66 67static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject, 68 jobject surface, jint width, jint height) { 69 70 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface)); 71 surfaceTexture->setDefaultBufferSize(width, height); 72} 73 74static inline SkBitmap::Config convertPixelFormat(int32_t format) { 75 switch (format) { 76 case WINDOW_FORMAT_RGBA_8888: 77 return SkBitmap::kARGB_8888_Config; 78 case WINDOW_FORMAT_RGBX_8888: 79 return SkBitmap::kARGB_8888_Config; 80 case WINDOW_FORMAT_RGB_565: 81 return SkBitmap::kRGB_565_Config; 82 default: 83 return SkBitmap::kNo_Config; 84 } 85} 86 87/** 88 * This is a private API, and this implementation is also provided in the NDK. 89 * However, the NDK links against android_runtime, which means that using the 90 * NDK implementation would create a circular dependency between the libraries. 91 */ 92static int32_t native_window_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, 93 Rect* inOutDirtyBounds) { 94 return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds); 95} 96 97static int32_t native_window_unlockAndPost(ANativeWindow* window) { 98 return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST); 99} 100 101static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView, 102 jobject surface) { 103 104 sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface)); 105 sp<ANativeWindow> window = new SurfaceTextureClient(surfaceTexture); 106 107 window->incStrong(0); 108 SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get())); 109} 110 111static void android_view_TextureView_destroyNativeWindow(JNIEnv* env, jobject textureView) { 112 113 ANativeWindow* nativeWindow = (ANativeWindow*) 114 GET_INT(textureView, gTextureViewClassInfo.nativeWindow); 115 116 if (nativeWindow) { 117 sp<ANativeWindow> window(nativeWindow); 118 window->decStrong(0); 119 SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0); 120 } 121} 122 123static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject, 124 jint nativeWindow, jobject canvas, jobject dirtyRect) { 125 126 if (!nativeWindow) { 127 return; 128 } 129 130 ANativeWindow_Buffer buffer; 131 132 Rect rect; 133 if (dirtyRect) { 134 rect.left = GET_INT(dirtyRect, gRectClassInfo.left); 135 rect.top = GET_INT(dirtyRect, gRectClassInfo.top); 136 rect.right = GET_INT(dirtyRect, gRectClassInfo.right); 137 rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); 138 } else { 139 rect.set(Rect(0x3FFF, 0x3FFF)); 140 } 141 142 sp<ANativeWindow> window((ANativeWindow*) nativeWindow); 143 native_window_lock(window.get(), &buffer, &rect); 144 145 ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format); 146 147 SkBitmap bitmap; 148 bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount); 149 150 if (buffer.format == WINDOW_FORMAT_RGBX_8888) { 151 bitmap.setIsOpaque(true); 152 } 153 154 if (buffer.width > 0 && buffer.height > 0) { 155 bitmap.setPixels(buffer.bits); 156 } else { 157 bitmap.setPixels(NULL); 158 } 159 160 SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format); 161 SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas); 162 nativeCanvas->setBitmapDevice(bitmap); 163 164 SkRect clipRect; 165 clipRect.set(rect.left, rect.top, rect.right, rect.bottom); 166 nativeCanvas->clipRect(clipRect); 167 168 if (dirtyRect) { 169 INVOKEV(dirtyRect, gRectClassInfo.set, 170 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 171 } 172} 173 174static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, 175 jint nativeWindow, jobject canvas) { 176 177 SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas); 178 nativeCanvas->setBitmapDevice(SkBitmap()); 179 180 if (nativeWindow) { 181 sp<ANativeWindow> window((ANativeWindow*) nativeWindow); 182 native_window_unlockAndPost(window.get()); 183 } 184} 185 186// ---------------------------------------------------------------------------- 187// JNI Glue 188// ---------------------------------------------------------------------------- 189 190const char* const kClassPathName = "android/view/TextureView"; 191 192static JNINativeMethod gMethods[] = { 193 { "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V", 194 (void*) android_view_TextureView_setDefaultBufferSize }, 195 196 { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V", 197 (void*) android_view_TextureView_createNativeWindow }, 198 { "nDestroyNativeWindow", "()V", 199 (void*) android_view_TextureView_destroyNativeWindow }, 200 201 { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V", 202 (void*) android_view_TextureView_lockCanvas }, 203 { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V", 204 (void*) android_view_TextureView_unlockCanvasAndPost }, 205}; 206 207#define FIND_CLASS(var, className) \ 208 var = env->FindClass(className); \ 209 LOG_FATAL_IF(!var, "Unable to find class " className); 210 211#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 212 var = env->GetMethodID(clazz, methodName, methodDescriptor); \ 213 LOG_FATAL_IF(!var, "Unable to find method " methodName); 214 215#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 216 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 217 LOG_FATAL_IF(!var, "Unable to find field" fieldName); 218 219int register_android_view_TextureView(JNIEnv* env) { 220 jclass clazz; 221 FIND_CLASS(clazz, "android/graphics/Rect"); 222 GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V"); 223 GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I"); 224 GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I"); 225 GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I"); 226 GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I"); 227 228 FIND_CLASS(clazz, "android/graphics/Canvas"); 229 GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I"); 230 GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I"); 231 232 FIND_CLASS(clazz, "android/view/TextureView"); 233 GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I"); 234 235 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 236} 237 238}; 239