1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/plugins/base/android/ANPSurface.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,266 @@ 1.4 +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <dlfcn.h> 1.10 +#include <android/log.h> 1.11 +#include "ANPBase.h" 1.12 + 1.13 +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) 1.14 +#define ASSIGN(obj, name) (obj)->name = anp_surface_##name 1.15 + 1.16 +#define CLEAR_EXCEPTION(env) if (env->ExceptionOccurred()) env->ExceptionClear(); 1.17 + 1.18 +#define ANDROID_REGION_SIZE 512 1.19 + 1.20 +enum { 1.21 + PIXEL_FORMAT_RGBA_8888 = 1, 1.22 + PIXEL_FORMAT_RGB_565 = 4, 1.23 +}; 1.24 + 1.25 +struct SurfaceInfo { 1.26 + uint32_t w; 1.27 + uint32_t h; 1.28 + uint32_t s; 1.29 + uint32_t usage; 1.30 + uint32_t format; 1.31 + unsigned char* bits; 1.32 + uint32_t reserved[2]; 1.33 +}; 1.34 + 1.35 +typedef struct ARect { 1.36 + int32_t left; 1.37 + int32_t top; 1.38 + int32_t right; 1.39 + int32_t bottom; 1.40 +} ARect; 1.41 + 1.42 + 1.43 +// used to cache JNI method and field IDs for Surface Objects 1.44 +static struct ANPSurfaceInterfaceJavaGlue { 1.45 + bool initialized; 1.46 + jmethodID getSurfaceHolder; 1.47 + jmethodID getSurface; 1.48 + jfieldID surfacePointer; 1.49 +} gSurfaceJavaGlue; 1.50 + 1.51 +static struct ANPSurfaceFunctions { 1.52 + bool initialized; 1.53 + 1.54 + int (* lock)(void*, SurfaceInfo*, void*); 1.55 + int (* unlockAndPost)(void*); 1.56 + 1.57 + void* (* regionConstructor)(void*); 1.58 + void (* setRegion)(void*, ARect const&); 1.59 +} gSurfaceFunctions; 1.60 + 1.61 + 1.62 +static inline void* getSurface(JNIEnv* env, jobject view) { 1.63 + if (!env || !view) { 1.64 + return nullptr; 1.65 + } 1.66 + 1.67 + if (!gSurfaceJavaGlue.initialized) { 1.68 + 1.69 + jclass surfaceViewClass = env->FindClass("android/view/SurfaceView"); 1.70 + gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", "()Landroid/view/SurfaceHolder;"); 1.71 + 1.72 + jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder"); 1.73 + gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", "()Landroid/view/Surface;"); 1.74 + 1.75 + jclass surfaceClass = env->FindClass("android/view/Surface"); 1.76 + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, 1.77 + "mSurfacePointer", "I"); 1.78 + 1.79 + if (!gSurfaceJavaGlue.surfacePointer) { 1.80 + CLEAR_EXCEPTION(env); 1.81 + 1.82 + // It was something else in 2.2. 1.83 + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, 1.84 + "mSurface", "I"); 1.85 + 1.86 + if (!gSurfaceJavaGlue.surfacePointer) { 1.87 + CLEAR_EXCEPTION(env); 1.88 + 1.89 + // And something else in 2.3+ 1.90 + gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, 1.91 + "mNativeSurface", "I"); 1.92 + 1.93 + CLEAR_EXCEPTION(env); 1.94 + } 1.95 + } 1.96 + 1.97 + if (!gSurfaceJavaGlue.surfacePointer) { 1.98 + LOG("Failed to acquire surface pointer"); 1.99 + return nullptr; 1.100 + } 1.101 + 1.102 + env->DeleteLocalRef(surfaceClass); 1.103 + env->DeleteLocalRef(surfaceViewClass); 1.104 + env->DeleteLocalRef(surfaceHolderClass); 1.105 + 1.106 + gSurfaceJavaGlue.initialized = (gSurfaceJavaGlue.surfacePointer != nullptr); 1.107 + } 1.108 + 1.109 + jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder); 1.110 + jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface); 1.111 + jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer); 1.112 + 1.113 + env->DeleteLocalRef(holder); 1.114 + env->DeleteLocalRef(surface); 1.115 + 1.116 + return (void*)surfacePointer; 1.117 +} 1.118 + 1.119 +static ANPBitmapFormat convertPixelFormat(int32_t format) { 1.120 + switch (format) { 1.121 + case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat; 1.122 + case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat; 1.123 + default: return kUnknown_ANPBitmapFormat; 1.124 + } 1.125 +} 1.126 + 1.127 +static int bytesPerPixel(int32_t format) { 1.128 + switch (format) { 1.129 + case PIXEL_FORMAT_RGBA_8888: return 4; 1.130 + case PIXEL_FORMAT_RGB_565: return 2; 1.131 + default: return -1; 1.132 + } 1.133 +} 1.134 + 1.135 +static bool init() { 1.136 + if (gSurfaceFunctions.initialized) 1.137 + return true; 1.138 + 1.139 + void* handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY); 1.140 + 1.141 + if (!handle) { 1.142 + LOG("Failed to open libsurfaceflinger_client.so"); 1.143 + return false; 1.144 + } 1.145 + 1.146 + gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb"); 1.147 + gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv"); 1.148 + 1.149 + 1.150 + if (!gSurfaceFunctions.lock) { 1.151 + // Stuff changed in 3.0/4.0 1.152 + handle = dlopen("libgui.so", RTLD_LAZY); 1.153 + gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE"); 1.154 + gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv"); 1.155 + } 1.156 + 1.157 + handle = dlopen("libui.so", RTLD_LAZY); 1.158 + if (!handle) { 1.159 + LOG("Failed to open libui.so"); 1.160 + return false; 1.161 + } 1.162 + 1.163 + gSurfaceFunctions.regionConstructor = (void* (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev"); 1.164 + gSurfaceFunctions.setRegion = (void (*)(void*, ARect const&))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE"); 1.165 + 1.166 + gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost && 1.167 + gSurfaceFunctions.regionConstructor && gSurfaceFunctions.setRegion); 1.168 + LOG("Initialized? %d\n", gSurfaceFunctions.initialized); 1.169 + return gSurfaceFunctions.initialized; 1.170 +} 1.171 + 1.172 +// FIXME: All of this should be changed to use the equivalent things in AndroidBridge, bug 758612 1.173 +static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) { 1.174 + if (!bitmap || !surfaceView) { 1.175 + return false; 1.176 + } 1.177 + 1.178 + void* surface = getSurface(env, surfaceView); 1.179 + 1.180 + if (!bitmap || !surface) { 1.181 + return false; 1.182 + } 1.183 + 1.184 + if (!init()) { 1.185 + return false; 1.186 + } 1.187 + 1.188 + void* region = nullptr; 1.189 + if (dirtyRect) { 1.190 + region = malloc(ANDROID_REGION_SIZE); 1.191 + gSurfaceFunctions.regionConstructor(region); 1.192 + 1.193 + ARect rect; 1.194 + rect.left = dirtyRect->left; 1.195 + rect.top = dirtyRect->top; 1.196 + rect.right = dirtyRect->right; 1.197 + rect.bottom = dirtyRect->bottom; 1.198 + 1.199 + gSurfaceFunctions.setRegion(region, rect); 1.200 + } 1.201 + 1.202 + SurfaceInfo info; 1.203 + int err = gSurfaceFunctions.lock(surface, &info, region); 1.204 + if (err < 0) { 1.205 + LOG("Failed to lock surface"); 1.206 + return false; 1.207 + } 1.208 + 1.209 + // the surface may have expanded the dirty region so we must to pass that 1.210 + // information back to the plugin. 1.211 + if (dirtyRect) { 1.212 + ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work! 1.213 + 1.214 + dirtyRect->left = dirtyBounds->left; 1.215 + dirtyRect->right = dirtyBounds->right; 1.216 + dirtyRect->top = dirtyBounds->top; 1.217 + dirtyRect->bottom = dirtyBounds->bottom; 1.218 + } 1.219 + 1.220 + if (region) 1.221 + free(region); 1.222 + 1.223 + int bpr = info.s * bytesPerPixel(info.format); 1.224 + 1.225 + bitmap->format = convertPixelFormat(info.format); 1.226 + bitmap->width = info.w; 1.227 + bitmap->height = info.h; 1.228 + bitmap->rowBytes = bpr; 1.229 + 1.230 + if (info.w > 0 && info.h > 0) { 1.231 + bitmap->baseAddr = info.bits; 1.232 + } else { 1.233 + bitmap->baseAddr = nullptr; 1.234 + return false; 1.235 + } 1.236 + 1.237 + return true; 1.238 +} 1.239 + 1.240 +static void anp_surface_unlock(JNIEnv* env, jobject surfaceView) { 1.241 + if (!surfaceView) { 1.242 + return; 1.243 + } 1.244 + 1.245 + if (!init()) { 1.246 + return; 1.247 + } 1.248 + 1.249 + void* surface = getSurface(env, surfaceView); 1.250 + 1.251 + if (!surface) { 1.252 + return; 1.253 + } 1.254 + 1.255 + gSurfaceFunctions.unlockAndPost(surface); 1.256 +} 1.257 + 1.258 +/////////////////////////////////////////////////////////////////////////////// 1.259 + 1.260 +void InitSurfaceInterface(ANPSurfaceInterfaceV0* i) { 1.261 + ASSIGN(i, lock); 1.262 + ASSIGN(i, unlock); 1.263 + 1.264 + // setup the java glue struct 1.265 + gSurfaceJavaGlue.initialized = false; 1.266 + 1.267 + // setup the function struct 1.268 + gSurfaceFunctions.initialized = false; 1.269 +}