dom/plugins/base/android/ANPSurface.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     6 #include <dlfcn.h>
     7 #include <android/log.h>
     8 #include "ANPBase.h"
    10 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
    11 #define ASSIGN(obj, name)   (obj)->name = anp_surface_##name
    13 #define CLEAR_EXCEPTION(env) if (env->ExceptionOccurred()) env->ExceptionClear();
    15 #define ANDROID_REGION_SIZE 512
    17 enum {
    18     PIXEL_FORMAT_RGBA_8888   = 1,
    19     PIXEL_FORMAT_RGB_565     = 4,
    20 };
    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 };
    32 typedef struct ARect {
    33     int32_t left;
    34     int32_t top;
    35     int32_t right;
    36     int32_t bottom;
    37 } ARect;
    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;
    48 static struct ANPSurfaceFunctions {
    49     bool initialized;
    51     int (* lock)(void*, SurfaceInfo*, void*);
    52     int (* unlockAndPost)(void*);
    54     void* (* regionConstructor)(void*);
    55     void (* setRegion)(void*, ARect const&);
    56 } gSurfaceFunctions;
    59 static inline void* getSurface(JNIEnv* env, jobject view) {
    60   if (!env || !view) {
    61     return nullptr;
    62   }
    64   if (!gSurfaceJavaGlue.initialized) {
    66     jclass surfaceViewClass = env->FindClass("android/view/SurfaceView");
    67     gSurfaceJavaGlue.getSurfaceHolder = env->GetMethodID(surfaceViewClass, "getHolder", "()Landroid/view/SurfaceHolder;");
    69     jclass surfaceHolderClass = env->FindClass("android/view/SurfaceHolder");
    70     gSurfaceJavaGlue.getSurface = env->GetMethodID(surfaceHolderClass, "getSurface", "()Landroid/view/Surface;");
    72     jclass surfaceClass = env->FindClass("android/view/Surface");
    73     gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
    74         "mSurfacePointer", "I");
    76     if (!gSurfaceJavaGlue.surfacePointer) {
    77       CLEAR_EXCEPTION(env);
    79       // It was something else in 2.2.
    80       gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
    81           "mSurface", "I");
    83       if (!gSurfaceJavaGlue.surfacePointer) {
    84         CLEAR_EXCEPTION(env);
    86         // And something else in 2.3+
    87         gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass,
    88             "mNativeSurface", "I");
    90         CLEAR_EXCEPTION(env);
    91       }
    92     }
    94     if (!gSurfaceJavaGlue.surfacePointer) {
    95       LOG("Failed to acquire surface pointer");
    96       return nullptr;
    97     }
    99     env->DeleteLocalRef(surfaceClass);
   100     env->DeleteLocalRef(surfaceViewClass);
   101     env->DeleteLocalRef(surfaceHolderClass);
   103     gSurfaceJavaGlue.initialized = (gSurfaceJavaGlue.surfacePointer != nullptr);
   104   }
   106   jobject holder = env->CallObjectMethod(view, gSurfaceJavaGlue.getSurfaceHolder);
   107   jobject surface = env->CallObjectMethod(holder, gSurfaceJavaGlue.getSurface);
   108   jint surfacePointer = env->GetIntField(surface, gSurfaceJavaGlue.surfacePointer);
   110   env->DeleteLocalRef(holder);
   111   env->DeleteLocalRef(surface);
   113   return (void*)surfacePointer;
   114 }
   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 }
   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 }
   132 static bool init() {
   133   if (gSurfaceFunctions.initialized)
   134     return true;
   136   void* handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY);
   138   if (!handle) {
   139     LOG("Failed to open libsurfaceflinger_client.so");
   140     return false;
   141   }
   143   gSurfaceFunctions.lock = (int (*)(void*, SurfaceInfo*, void*))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
   144   gSurfaceFunctions.unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
   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   }
   154   handle = dlopen("libui.so", RTLD_LAZY);
   155   if (!handle) {
   156     LOG("Failed to open libui.so");
   157     return false;
   158   }
   160   gSurfaceFunctions.regionConstructor = (void* (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev");
   161   gSurfaceFunctions.setRegion = (void (*)(void*, ARect const&))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE");
   163   gSurfaceFunctions.initialized = (gSurfaceFunctions.lock && gSurfaceFunctions.unlockAndPost &&
   164                                    gSurfaceFunctions.regionConstructor && gSurfaceFunctions.setRegion);
   165   LOG("Initialized? %d\n", gSurfaceFunctions.initialized);
   166   return gSurfaceFunctions.initialized;
   167 }
   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   }
   175   void* surface = getSurface(env, surfaceView);
   177   if (!bitmap || !surface) {
   178     return false;
   179   }
   181   if (!init()) {
   182     return false;
   183   }
   185   void* region = nullptr;
   186   if (dirtyRect) {
   187     region = malloc(ANDROID_REGION_SIZE);
   188     gSurfaceFunctions.regionConstructor(region);
   190     ARect rect;
   191     rect.left = dirtyRect->left;
   192     rect.top = dirtyRect->top;
   193     rect.right = dirtyRect->right;
   194     rect.bottom = dirtyRect->bottom;
   196     gSurfaceFunctions.setRegion(region, rect);
   197   }
   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   }
   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!
   211     dirtyRect->left = dirtyBounds->left;
   212     dirtyRect->right = dirtyBounds->right;
   213     dirtyRect->top = dirtyBounds->top;
   214     dirtyRect->bottom = dirtyBounds->bottom;
   215   }
   217   if (region)
   218     free(region);
   220   int bpr = info.s * bytesPerPixel(info.format);
   222   bitmap->format = convertPixelFormat(info.format);
   223   bitmap->width = info.w;
   224   bitmap->height = info.h;
   225   bitmap->rowBytes = bpr;
   227   if (info.w > 0 && info.h > 0) {
   228     bitmap->baseAddr = info.bits;
   229   } else {
   230     bitmap->baseAddr = nullptr;
   231     return false;
   232   }
   234   return true;
   235 }
   237 static void anp_surface_unlock(JNIEnv* env, jobject surfaceView) {
   238   if (!surfaceView) {
   239     return;
   240   }
   242   if (!init()) {
   243     return;
   244   }
   246   void* surface = getSurface(env, surfaceView);
   248   if (!surface) {
   249     return;
   250   }
   252   gSurfaceFunctions.unlockAndPost(surface);
   253 }
   255 ///////////////////////////////////////////////////////////////////////////////
   257 void InitSurfaceInterface(ANPSurfaceInterfaceV0* i) {
   258   ASSIGN(i, lock);
   259   ASSIGN(i, unlock);
   261   // setup the java glue struct
   262   gSurfaceJavaGlue.initialized = false;
   264   // setup the function struct
   265   gSurfaceFunctions.initialized = false;
   266 }

mercurial