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/GLConsumer.h> 26 #include <gui/Surface.h> 27 28 #include <SkBitmap.h> 29 #include <SkCanvas.h> 30 31 namespace android { 32 33 // ---------------------------------------------------------------------------- 34 // JNI Glue 35 // ---------------------------------------------------------------------------- 36 37 static struct { 38 jmethodID set; 39 jfieldID left; 40 jfieldID top; 41 jfieldID right; 42 jfieldID bottom; 43 } gRectClassInfo; 44 45 static struct { 46 jfieldID mFinalizer; 47 jfieldID mNativeCanvas; 48 jfieldID mSurfaceFormat; 49 } gCanvasClassInfo; 50 51 static struct { 52 jfieldID mNativeCanvas; 53 } gCanvasFinalizerClassInfo; 54 55 static struct { 56 jfieldID nativeWindow; 57 } gTextureViewClassInfo; 58 59 #define GET_INT(object, field) \ 60 env->GetIntField(object, field) 61 62 #define SET_INT(object, field, value) \ 63 env->SetIntField(object, field, value) 64 65 #define INVOKEV(object, method, ...) \ 66 env->CallVoidMethod(object, method, __VA_ARGS__) 67 68 // ---------------------------------------------------------------------------- 69 // Native layer 70 // ---------------------------------------------------------------------------- 71 72 static inline SkBitmap::Config convertPixelFormat(int32_t format) { 73 switch (format) { 74 case WINDOW_FORMAT_RGBA_8888: 75 return SkBitmap::kARGB_8888_Config; 76 case WINDOW_FORMAT_RGBX_8888: 77 return SkBitmap::kARGB_8888_Config; 78 case WINDOW_FORMAT_RGB_565: 79 return SkBitmap::kRGB_565_Config; 80 default: 81 return SkBitmap::kNo_Config; 82 } 83 } 84 85 /** 86 * This is a private API, and this implementation is also provided in the NDK. 87 * However, the NDK links against android_runtime, which means that using the 88 * NDK implementation would create a circular dependency between the libraries. 89 */ 90 static int32_t native_window_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, 91 Rect* inOutDirtyBounds) { 92 return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds); 93 } 94 95 static int32_t native_window_unlockAndPost(ANativeWindow* window) { 96 return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST); 97 } 98 99 static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView, 100 jobject surface) { 101 102 sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surface)); 103 sp<ANativeWindow> window = new Surface(producer, true); 104 105 window->incStrong((void*)android_view_TextureView_createNativeWindow); 106 SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get())); 107 } 108 109 static void android_view_TextureView_destroyNativeWindow(JNIEnv* env, jobject textureView) { 110 111 ANativeWindow* nativeWindow = (ANativeWindow*) 112 GET_INT(textureView, gTextureViewClassInfo.nativeWindow); 113 114 if (nativeWindow) { 115 sp<ANativeWindow> window(nativeWindow); 116 window->decStrong((void*)android_view_TextureView_createNativeWindow); 117 SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0); 118 } 119 } 120 121 static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) { 122 jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer); 123 SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>( 124 env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas)); 125 env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas); 126 env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas); 127 SkSafeUnref(previousCanvas); 128 } 129 130 static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject, 131 jint nativeWindow, jobject canvas, jobject dirtyRect) { 132 133 if (!nativeWindow) { 134 return false; 135 } 136 137 ANativeWindow_Buffer buffer; 138 139 Rect rect; 140 if (dirtyRect) { 141 rect.left = GET_INT(dirtyRect, gRectClassInfo.left); 142 rect.top = GET_INT(dirtyRect, gRectClassInfo.top); 143 rect.right = GET_INT(dirtyRect, gRectClassInfo.right); 144 rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom); 145 } else { 146 rect.set(Rect(0x3FFF, 0x3FFF)); 147 } 148 149 sp<ANativeWindow> window((ANativeWindow*) nativeWindow); 150 int32_t status = native_window_lock(window.get(), &buffer, &rect); 151 if (status) return false; 152 153 ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format); 154 155 SkBitmap bitmap; 156 bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount); 157 158 if (buffer.format == WINDOW_FORMAT_RGBX_8888) { 159 bitmap.setIsOpaque(true); 160 } 161 162 if (buffer.width > 0 && buffer.height > 0) { 163 bitmap.setPixels(buffer.bits); 164 } else { 165 bitmap.setPixels(NULL); 166 } 167 168 SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format); 169 170 SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); 171 swapCanvasPtr(env, canvas, nativeCanvas); 172 173 SkRect clipRect; 174 clipRect.set(rect.left, rect.top, rect.right, rect.bottom); 175 nativeCanvas->clipRect(clipRect); 176 177 if (dirtyRect) { 178 INVOKEV(dirtyRect, gRectClassInfo.set, 179 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 180 } 181 182 return true; 183 } 184 185 static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, 186 jint nativeWindow, jobject canvas) { 187 188 SkCanvas* nativeCanvas = SkNEW(SkCanvas); 189 swapCanvasPtr(env, canvas, nativeCanvas); 190 191 if (nativeWindow) { 192 sp<ANativeWindow> window((ANativeWindow*) nativeWindow); 193 native_window_unlockAndPost(window.get()); 194 } 195 } 196 197 // ---------------------------------------------------------------------------- 198 // JNI Glue 199 // ---------------------------------------------------------------------------- 200 201 const char* const kClassPathName = "android/view/TextureView"; 202 203 static JNINativeMethod gMethods[] = { 204 { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V", 205 (void*) android_view_TextureView_createNativeWindow }, 206 { "nDestroyNativeWindow", "()V", 207 (void*) android_view_TextureView_destroyNativeWindow }, 208 209 { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", 210 (void*) android_view_TextureView_lockCanvas }, 211 { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V", 212 (void*) android_view_TextureView_unlockCanvasAndPost }, 213 }; 214 215 #define FIND_CLASS(var, className) \ 216 var = env->FindClass(className); \ 217 LOG_FATAL_IF(!var, "Unable to find class " className); 218 219 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 220 var = env->GetMethodID(clazz, methodName, methodDescriptor); \ 221 LOG_FATAL_IF(!var, "Unable to find method " methodName); 222 223 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ 224 var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ 225 LOG_FATAL_IF(!var, "Unable to find field" fieldName); 226 227 int register_android_view_TextureView(JNIEnv* env) { 228 jclass clazz; 229 FIND_CLASS(clazz, "android/graphics/Rect"); 230 GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V"); 231 GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I"); 232 GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I"); 233 GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I"); 234 GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I"); 235 236 FIND_CLASS(clazz, "android/graphics/Canvas"); 237 GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer", 238 "Landroid/graphics/Canvas$CanvasFinalizer;"); 239 GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 240 GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I"); 241 242 FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer"); 243 GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "I"); 244 245 FIND_CLASS(clazz, "android/view/TextureView"); 246 GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I"); 247 248 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); 249 } 250 251 }; 252