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