Bug 702964 - Support subregion lock with native plugin surfaces r=blassey
authorJames Willcox <jwillcox@mozilla.com>
Wed, 16 Nov 2011 11:15:53 -0500
changeset 81863 fc9431ac4617ae4ae4cc4efe13f820d2e7a6ec2a
parent 81862 96949a8ed9225e534c6744416de7a1b1f69b3f52
child 81864 245b412faf415626348c277128920012af7799f2
push idunknown
push userunknown
push dateunknown
reviewersblassey
bugs702964
milestone11.0a1
Bug 702964 - Support subregion lock with native plugin surfaces r=blassey
dom/plugins/base/android/ANPSurface.cpp
--- a/dom/plugins/base/android/ANPSurface.cpp
+++ b/dom/plugins/base/android/ANPSurface.cpp
@@ -40,45 +40,58 @@
 #include <android/log.h>
 #include "ANPBase.h"
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
 #define ASSIGN(obj, name)   (obj)->name = anp_surface_##name
 
 #define CLEAR_EXCEPTION(env) if (env->ExceptionOccurred()) env->ExceptionClear();
 
+#define ANDROID_REGION_SIZE 512
+
 // Copied from Android headers
 enum {
     PIXEL_FORMAT_RGBA_8888   = 1,
     PIXEL_FORMAT_RGB_565     = 4,
 };
 
 struct SurfaceInfo {
     uint32_t    w;
     uint32_t    h;
     uint32_t    s;
     uint32_t    usage;
     uint32_t    format;
     unsigned char* bits;
     uint32_t    reserved[2];
 };
 
+typedef struct ARect {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} ARect;
+
+
 // used to cache JNI method and field IDs for Surface Objects
 static struct ANPSurfaceInterfaceJavaGlue {
     bool        initialized;
     jmethodID   getSurfaceHolder;
     jmethodID   getSurface;
     jfieldID    surfacePointer;
 } gSurfaceJavaGlue;
 
 static struct ANPSurfaceFunctions {
     bool initialized;
 
     int (* lock)(void*, SurfaceInfo*, void*);
     int (* unlockAndPost)(void*);
+
+    void* (* regionConstructor)(void*);
+    void (* setRegion)(void*, ARect const&);
 } gSurfaceFunctions;
 
 
 static inline void* getSurface(JNIEnv* env, jobject view) {
   if (!env || !view) {
     return NULL;
   }
 
@@ -159,17 +172,27 @@ static bool init() {
   if (!handle) {
     LOG("Failed to open libsurfaceflinger_client.so");
     return false;
   }
 
   gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
   gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
 
-  gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost);
+  handle = dlopen("/system/lib/libui.so", RTLD_LAZY);
+  if (!handle) {
+    LOG("Failed to open libui.so");
+    return false;
+  }
+
+  gSurfaceFunctions.regionConstructor = (void* (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev");
+  gSurfaceFunctions.setRegion = (void (*)(void*, ARect const&))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE");
+
+  gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost &&
+                                   gSurfaceFunctions.regionConstructor && gSurfaceFunctions.setRegion);
   LOG("Initialized? %d\n", gSurfaceFunctions.initialized);
   return gSurfaceFunctions.initialized;
 }
 
 static bool anp_surface_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRectI* dirtyRect) {
   if (!bitmap || !surfaceView) {
     return false;
   }
@@ -179,30 +202,51 @@ static bool anp_surface_lock(JNIEnv* env
   if (!bitmap || !surface) {
     return false;
   }
 
   if (!init()) {
     return false;
   }
 
+  void* region = NULL;
+  if (dirtyRect) {
+    region = malloc(ANDROID_REGION_SIZE);
+    gSurfaceFunctions.regionConstructor(region);
+
+    ARect rect;
+    rect.left = dirtyRect->left;
+    rect.top = dirtyRect->top;
+    rect.right = dirtyRect->right;
+    rect.bottom = dirtyRect->bottom;
+
+    gSurfaceFunctions.setRegion(region, rect);
+  }
+
   SurfaceInfo info;
-  int err = gSurfaceFunctions.lock(surface, &info, NULL);
+  int err = gSurfaceFunctions.lock(surface, &info, region);
   if (err < 0) {
+    LOG("Failed to lock surface");
     return false;
   }
 
+  // the surface may have expanded the dirty region so we must to pass that
+  // information back to the plugin.
   if (dirtyRect) {
-    // We can't lock the specific region, so we must expand the dirty rect
-    // to be the whole surface
-    dirtyRect->left = dirtyRect->top = 0;
-    dirtyRect->right = info.w;
-    dirtyRect->bottom = info.h;
+    ARect* dirtyBounds = (ARect*)region; // The bounds are the first member, so this should work!
+
+    dirtyRect->left = dirtyBounds->left;
+    dirtyRect->right = dirtyBounds->right;
+    dirtyRect->top = dirtyBounds->top;
+    dirtyRect->bottom = dirtyBounds->bottom;
   }
 
+  if (region)
+    free(region);
+
   int bpr = info.s * bytesPerPixel(info.format);
 
   bitmap->format = convertPixelFormat(info.format);
   bitmap->width = info.w;
   bitmap->height = info.h;
   bitmap->rowBytes = bpr;
 
   if (info.w > 0 && info.h > 0) {