dom/plugins/base/android/ANPSurface.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:a5c627200025
1 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include <dlfcn.h>
7 #include <android/log.h>
8 #include "ANPBase.h"
9
10 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
11 #define ASSIGN(obj, name) (obj)->name = anp_surface_##name
12
13 #define CLEAR_EXCEPTION(env) if (env->ExceptionOccurred()) env->ExceptionClear();
14
15 #define ANDROID_REGION_SIZE 512
16
17 enum {
18 PIXEL_FORMAT_RGBA_8888 = 1,
19 PIXEL_FORMAT_RGB_565 = 4,
20 };
21
22 struct SurfaceInfo {
23 uint32_t w;
24 uint32_t h;
25 uint32_t s;
26 uint32_t usage;
27 uint32_t format;
28 unsigned char* bits;
29 uint32_t reserved[2];
30 };
31
32 typedef struct ARect {
33 int32_t left;
34 int32_t top;
35 int32_t right;
36 int32_t bottom;
37 } ARect;
38
39
40 // used to cache JNI method and field IDs for Surface Objects
41 static struct ANPSurfaceInterfaceJavaGlue {
42 bool initialized;
43 jmethodID getSurfaceHolder;
44 jmethodID getSurface;
45 jfieldID surfacePointer;
46 } gSurfaceJavaGlue;
47
48 static struct ANPSurfaceFunctions {
49 bool initialized;
50
51 int (* lock)(void*, SurfaceInfo*, void*);
52 int (* unlockAndPost)(void*);
53
54 void* (* regionConstructor)(void*);
55 void (* setRegion)(void*, ARect const&);
56 } gSurfaceFunctions;
57
58
59 static inline void* getSurface(JNIEnv* env, jobject view) {
60 if (!env || !view) {
61 return nullptr;
62 }
63
64 if (!gSurfaceJavaGlue.initialized) {
65
66 jclass surfaceViewClass = env->FindClass("android/view/SurfaceView");
67 gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", "()Landroid/view/SurfaceHolder;");
68
69 jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder");
70 gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", "()Landroid/view/Surface;");
71
72 jclass surfaceClass = env->FindClass("android/view/Surface");
73 gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
74 "mSurfacePointer", "I");
75
76 if (!gSurfaceJavaGlue.surfacePointer) {
77 CLEAR_EXCEPTION(env);
78
79 // It was something else in 2.2.
80 gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
81 "mSurface", "I");
82
83 if (!gSurfaceJavaGlue.surfacePointer) {
84 CLEAR_EXCEPTION(env);
85
86 // And something else in 2.3+
87 gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
88 "mNativeSurface", "I");
89
90 CLEAR_EXCEPTION(env);
91 }
92 }
93
94 if (!gSurfaceJavaGlue.surfacePointer) {
95 LOG("Failed to acquire surface pointer");
96 return nullptr;
97 }
98
99 env->DeleteLocalRef(surfaceClass);
100 env->DeleteLocalRef(surfaceViewClass);
101 env->DeleteLocalRef(surfaceHolderClass);
102
103 gSurfaceJavaGlue.initialized = (gSurfaceJavaGlue.surfacePointer != nullptr);
104 }
105
106 jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder);
107 jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface);
108 jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer);
109
110 env->DeleteLocalRef(holder);
111 env->DeleteLocalRef(surface);
112
113 return (void*)surfacePointer;
114 }
115
116 static ANPBitmapFormat convertPixelFormat(int32_t format) {
117 switch (format) {
118 case PIXEL_FORMAT_RGBA_8888: return kRGBA_8888_ANPBitmapFormat;
119 case PIXEL_FORMAT_RGB_565: return kRGB_565_ANPBitmapFormat;
120 default: return kUnknown_ANPBitmapFormat;
121 }
122 }
123
124 static int bytesPerPixel(int32_t format) {
125 switch (format) {
126 case PIXEL_FORMAT_RGBA_8888: return 4;
127 case PIXEL_FORMAT_RGB_565: return 2;
128 default: return -1;
129 }
130 }
131
132 static bool init() {
133 if (gSurfaceFunctions.initialized)
134 return true;
135
136 void* handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY);
137
138 if (!handle) {
139 LOG("Failed to open libsurfaceflinger_client.so");
140 return false;
141 }
142
143 gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
144 gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
145
146
147 if (!gSurfaceFunctions.lock) {
148 // Stuff changed in 3.0/4.0
149 handle = dlopen("libgui.so", RTLD_LAZY);
150 gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionE");
151 gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
152 }
153
154 handle = dlopen("libui.so", RTLD_LAZY);
155 if (!handle) {
156 LOG("Failed to open libui.so");
157 return false;
158 }
159
160 gSurfaceFunctions.regionConstructor = (void* (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev");
161 gSurfaceFunctions.setRegion = (void (*)(void*, ARect const&))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE");
162
163 gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost &&
164 gSurfaceFunctions.regionConstructor && gSurfaceFunctions.setRegion);
165 LOG("Initialized? %d\n", gSurfaceFunctions.initialized);
166 return gSurfaceFunctions.initialized;
167 }
168
169 // FIXME: All of this should be changed to use the equivalent things in AndroidBridge, bug 758612
170 static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
171 if (!bitmap || !surfaceView) {
172 return false;
173 }
174
175 void* surface = getSurface(env, surfaceView);
176
177 if (!bitmap || !surface) {
178 return false;
179 }
180
181 if (!init()) {
182 return false;
183 }
184
185 void* region = nullptr;
186 if (dirtyRect) {
187 region = malloc(ANDROID_REGION_SIZE);
188 gSurfaceFunctions.regionConstructor(region);
189
190 ARect rect;
191 rect.left = dirtyRect->left;
192 rect.top = dirtyRect->top;
193 rect.right = dirtyRect->right;
194 rect.bottom = dirtyRect->bottom;
195
196 gSurfaceFunctions.setRegion(region, rect);
197 }
198
199 SurfaceInfo info;
200 int err = gSurfaceFunctions.lock(surface, &info, region);
201 if (err < 0) {
202 LOG("Failed to lock surface");
203 return false;
204 }
205
206 // the surface may have expanded the dirty region so we must to pass that
207 // information back to the plugin.
208 if (dirtyRect) {
209 ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work!
210
211 dirtyRect->left = dirtyBounds->left;
212 dirtyRect->right = dirtyBounds->right;
213 dirtyRect->top = dirtyBounds->top;
214 dirtyRect->bottom = dirtyBounds->bottom;
215 }
216
217 if (region)
218 free(region);
219
220 int bpr = info.s * bytesPerPixel(info.format);
221
222 bitmap->format = convertPixelFormat(info.format);
223 bitmap->width = info.w;
224 bitmap->height = info.h;
225 bitmap->rowBytes = bpr;
226
227 if (info.w > 0 && info.h > 0) {
228 bitmap->baseAddr = info.bits;
229 } else {
230 bitmap->baseAddr = nullptr;
231 return false;
232 }
233
234 return true;
235 }
236
237 static void anp_surface_unlock(JNIEnv* env, jobject surfaceView) {
238 if (!surfaceView) {
239 return;
240 }
241
242 if (!init()) {
243 return;
244 }
245
246 void* surface = getSurface(env, surfaceView);
247
248 if (!surface) {
249 return;
250 }
251
252 gSurfaceFunctions.unlockAndPost(surface);
253 }
254
255 ///////////////////////////////////////////////////////////////////////////////
256
257 void InitSurfaceInterface(ANPSurfaceInterfaceV0* i) {
258 ASSIGN(i, lock);
259 ASSIGN(i, unlock);
260
261 // setup the java glue struct
262 gSurfaceJavaGlue.initialized = false;
263
264 // setup the function struct
265 gSurfaceFunctions.initialized = false;
266 }

mercurial