Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2008, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <stdio.h>
     29 #include "main.h"
     30 #include "PluginObject.h"
     31 #include "AnimationPlugin.h"
     32 #include "AudioPlugin.h"
     33 #include "BackgroundPlugin.h"
     34 #include "FormPlugin.h"
     35 #include "NavigationPlugin.h"
     36 #include "PaintPlugin.h"
     37 #include "VideoPlugin.h"
     38 
     39 NPNetscapeFuncs* browser;
     40 JavaVM* gVM;
     41 
     42 #define EXPORT __attribute__((visibility("default")))
     43 
     44 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
     45         char* argn[], char* argv[], NPSavedData* saved);
     46 NPError NPP_Destroy(NPP instance, NPSavedData** save);
     47 NPError NPP_SetWindow(NPP instance, NPWindow* window);
     48 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream,
     49         NPBool seekable, uint16* stype);
     50 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
     51 int32   NPP_WriteReady(NPP instance, NPStream* stream);
     52 int32   NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len,
     53         void* buffer);
     54 void    NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname);
     55 void    NPP_Print(NPP instance, NPPrint* platformPrint);
     56 int16   NPP_HandleEvent(NPP instance, void* event);
     57 void    NPP_URLNotify(NPP instance, const char* URL, NPReason reason,
     58         void* notifyData);
     59 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
     60 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value);
     61 
     62 extern "C" {
     63 EXPORT NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env);
     64 EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value);
     65 EXPORT const char* NP_GetMIMEDescription(void);
     66 EXPORT void NP_Shutdown(void);
     67 };
     68 
     69 ANPAudioTrackInterfaceV0    gSoundI;
     70 ANPBitmapInterfaceV0        gBitmapI;
     71 ANPCanvasInterfaceV0        gCanvasI;
     72 ANPEventInterfaceV0         gEventI;
     73 ANPLogInterfaceV0           gLogI;
     74 ANPPaintInterfaceV0         gPaintI;
     75 ANPPathInterfaceV0          gPathI;
     76 ANPSurfaceInterfaceV0       gSurfaceI;
     77 ANPSystemInterfaceV0        gSystemI;
     78 ANPTypefaceInterfaceV0      gTypefaceI;
     79 ANPWindowInterfaceV0        gWindowI;
     80 
     81 #define ARRAY_COUNT(array)      (sizeof(array) / sizeof(array[0]))
     82 #define DEBUG_PLUGIN_EVENTS     0
     83 
     84 NPError NP_Initialize(NPNetscapeFuncs* browserFuncs, NPPluginFuncs* pluginFuncs, void *java_env)
     85 {
     86     // Make sure we have a function table equal or larger than we are built against.
     87     if (browserFuncs->size < sizeof(NPNetscapeFuncs)) {
     88         return NPERR_GENERIC_ERROR;
     89     }
     90 
     91     // Copy the function table (structure)
     92     browser = (NPNetscapeFuncs*) malloc(sizeof(NPNetscapeFuncs));
     93     memcpy(browser, browserFuncs, sizeof(NPNetscapeFuncs));
     94 
     95     // Build the plugin function table
     96     pluginFuncs->version = 11;
     97     pluginFuncs->size = sizeof(pluginFuncs);
     98     pluginFuncs->newp = NPP_New;
     99     pluginFuncs->destroy = NPP_Destroy;
    100     pluginFuncs->setwindow = NPP_SetWindow;
    101     pluginFuncs->newstream = NPP_NewStream;
    102     pluginFuncs->destroystream = NPP_DestroyStream;
    103     pluginFuncs->asfile = NPP_StreamAsFile;
    104     pluginFuncs->writeready = NPP_WriteReady;
    105     pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write;
    106     pluginFuncs->print = NPP_Print;
    107     pluginFuncs->event = NPP_HandleEvent;
    108     pluginFuncs->urlnotify = NPP_URLNotify;
    109     pluginFuncs->getvalue = NPP_GetValue;
    110     pluginFuncs->setvalue = NPP_SetValue;
    111 
    112     static const struct {
    113         NPNVariable     v;
    114         uint32_t        size;
    115         ANPInterface*   i;
    116     } gPairs[] = {
    117         { kAudioTrackInterfaceV0_ANPGetValue,   sizeof(gSoundI),    &gSoundI },
    118         { kBitmapInterfaceV0_ANPGetValue,       sizeof(gBitmapI),   &gBitmapI },
    119         { kCanvasInterfaceV0_ANPGetValue,       sizeof(gCanvasI),   &gCanvasI },
    120         { kEventInterfaceV0_ANPGetValue,        sizeof(gEventI),    &gEventI },
    121         { kLogInterfaceV0_ANPGetValue,          sizeof(gLogI),      &gLogI },
    122         { kPaintInterfaceV0_ANPGetValue,        sizeof(gPaintI),    &gPaintI },
    123         { kPathInterfaceV0_ANPGetValue,         sizeof(gPathI),     &gPathI },
    124         { kSurfaceInterfaceV0_ANPGetValue,      sizeof(gSurfaceI),  &gSurfaceI },
    125         { kSystemInterfaceV0_ANPGetValue,       sizeof(gSystemI),   &gSystemI },
    126         { kTypefaceInterfaceV0_ANPGetValue,     sizeof(gTypefaceI), &gTypefaceI },
    127         { kWindowInterfaceV0_ANPGetValue,       sizeof(gWindowI),   &gWindowI },
    128     };
    129     for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
    130         gPairs[i].i->inSize = gPairs[i].size;
    131         NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
    132         if (err) {
    133             return err;
    134         }
    135     }
    136 
    137     // store the JavaVM for the plugin
    138     JNIEnv* env = (JNIEnv*)java_env;
    139     env->GetJavaVM(&gVM);
    140 
    141     return NPERR_NO_ERROR;
    142 }
    143 
    144 void NP_Shutdown(void)
    145 {
    146 
    147 }
    148 
    149 const char *NP_GetMIMEDescription(void)
    150 {
    151     return "application/x-testbrowserplugin:tst:Test plugin mimetype is application/x-testbrowserplugin";
    152 }
    153 
    154 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
    155                 char* argn[], char* argv[], NPSavedData* saved)
    156 {
    157 
    158     /* BEGIN: STANDARD PLUGIN FRAMEWORK */
    159     PluginObject *obj = NULL;
    160 
    161     // Scripting functions appeared in NPAPI version 14
    162     if (browser->version >= 14) {
    163         instance->pdata = browser->createobject (instance, getPluginClass());
    164         obj = static_cast<PluginObject*>(instance->pdata);
    165     }
    166     /* END: STANDARD PLUGIN FRAMEWORK */
    167 
    168     // select the drawing model based on user input
    169     ANPDrawingModel model = kBitmap_ANPDrawingModel;
    170 
    171     for (int i = 0; i < argc; i++) {
    172         if (!strcmp(argn[i], "DrawingModel")) {
    173             if (!strcmp(argv[i], "Bitmap")) {
    174                 model = kBitmap_ANPDrawingModel;
    175             }
    176             else if (!strcmp(argv[i], "Surface")) {
    177                model = kSurface_ANPDrawingModel;
    178             }
    179             gLogI.log(kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model);
    180             break;
    181         }
    182     }
    183 
    184     // notify the plugin API of the drawing model we wish to use. This must be
    185     // done prior to creating certain subPlugin objects (e.g. surfaceViews)
    186     NPError err = browser->setvalue(instance, kRequestDrawingModel_ANPSetValue,
    187                             reinterpret_cast<void*>(model));
    188     if (err) {
    189         gLogI.log(kError_ANPLogType, "request model %d err %d", model, err);
    190         return err;
    191     }
    192 
    193     const char* path = gSystemI.getApplicationDataDirectory();
    194     if (path) {
    195         gLogI.log(kDebug_ANPLogType, "Application data dir is %s", path);
    196     } else {
    197         gLogI.log(kError_ANPLogType, "Can't find Application data dir");
    198     }
    199 
    200     // select the pluginType
    201     for (int i = 0; i < argc; i++) {
    202         if (!strcmp(argn[i], "PluginType")) {
    203             if (!strcmp(argv[i], "Animation")) {
    204                 obj->pluginType = kAnimation_PluginType;
    205                 obj->activePlugin = new BallAnimation(instance);
    206             }
    207             else if (!strcmp(argv[i], "Audio")) {
    208                 obj->pluginType = kAudio_PluginType;
    209                 obj->activePlugin = new AudioPlugin(instance);
    210             }
    211             else if (!strcmp(argv[i], "Background")) {
    212                 obj->pluginType = kBackground_PluginType;
    213                 obj->activePlugin = new BackgroundPlugin(instance);
    214             }
    215             else if (!strcmp(argv[i], "Form")) {
    216                 obj->pluginType = kForm_PluginType;
    217                 obj->activePlugin = new FormPlugin(instance);
    218             }
    219             else if (!strcmp(argv[i], "Navigation")) {
    220                 obj->pluginType = kNavigation_PluginType;
    221                 obj->activePlugin = new NavigationPlugin(instance);
    222             }
    223             else if (!strcmp(argv[i], "Paint")) {
    224                 obj->pluginType = kPaint_PluginType;
    225                 obj->activePlugin = new PaintPlugin(instance);
    226             }
    227             else if (!strcmp(argv[i], "Video")) {
    228                 obj->pluginType = kVideo_PluginType;
    229                 obj->activePlugin = new VideoPlugin(instance);
    230             }
    231             gLogI.log(kDebug_ANPLogType, "------ %p PluginType is %d", instance, obj->pluginType);
    232             break;
    233         }
    234     }
    235 
    236     // if no pluginType is specified then default to Animation
    237     if (!obj->pluginType) {
    238         gLogI.log(kError_ANPLogType, "------ %p No PluginType attribute was found", instance);
    239         obj->pluginType = kAnimation_PluginType;
    240         obj->activePlugin = new BallAnimation(instance);
    241     }
    242 
    243     // check to ensure the pluginType supports the model
    244     if (!obj->activePlugin->supportsDrawingModel(model)) {
    245         gLogI.log(kError_ANPLogType, "------ %p Unsupported DrawingModel (%d)", instance, model);
    246         return NPERR_GENERIC_ERROR;
    247     }
    248 
    249     // if the plugin uses the surface drawing model then set the java context
    250     if (model == kSurface_ANPDrawingModel) {
    251         SurfaceSubPlugin* surfacePlugin = static_cast<SurfaceSubPlugin*>(obj->activePlugin);
    252 
    253         jobject context;
    254         NPError err = browser->getvalue(instance, kJavaContext_ANPGetValue,
    255                                         static_cast<void*>(&context));
    256         if (err) {
    257             gLogI.log(kError_ANPLogType, "request context err: %d", err);
    258             return err;
    259         }
    260 
    261         surfacePlugin->setContext(context);
    262     }
    263 
    264 
    265     return NPERR_NO_ERROR;
    266 }
    267 
    268 NPError NPP_Destroy(NPP instance, NPSavedData** save)
    269 {
    270     PluginObject *obj = (PluginObject*) instance->pdata;
    271     if (obj) {
    272         delete obj->activePlugin;
    273         browser->releaseobject(&obj->header);
    274     }
    275 
    276     return NPERR_NO_ERROR;
    277 }
    278 
    279 NPError NPP_SetWindow(NPP instance, NPWindow* window)
    280 {
    281     PluginObject *obj = (PluginObject*) instance->pdata;
    282 
    283     // Do nothing if browser didn't support NPN_CreateObject which would have created the PluginObject.
    284     if (obj != NULL) {
    285         obj->window = window;
    286     }
    287 
    288     browser->invalidaterect(instance, NULL);
    289 
    290     return NPERR_NO_ERROR;
    291 }
    292 
    293 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype)
    294 {
    295     *stype = NP_ASFILEONLY;
    296     return NPERR_NO_ERROR;
    297 }
    298 
    299 NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
    300 {
    301     return NPERR_NO_ERROR;
    302 }
    303 
    304 int32 NPP_WriteReady(NPP instance, NPStream* stream)
    305 {
    306     return 0;
    307 }
    308 
    309 int32 NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer)
    310 {
    311     return 0;
    312 }
    313 
    314 void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
    315 {
    316 }
    317 
    318 void NPP_Print(NPP instance, NPPrint* platformPrint)
    319 {
    320 }
    321 
    322 int16 NPP_HandleEvent(NPP instance, void* event)
    323 {
    324     PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
    325     const ANPEvent* evt = reinterpret_cast<const ANPEvent*>(event);
    326 
    327 #if DEBUG_PLUGIN_EVENTS
    328     switch (evt->eventType) {
    329         case kDraw_ANPEventType:
    330 
    331             if (evt->data.draw.model == kBitmap_ANPDrawingModel) {
    332 
    333                 static ANPBitmapFormat currentFormat = -1;
    334                 if (evt->data.draw.data.bitmap.format != currentFormat) {
    335                     currentFormat = evt->data.draw.data.bitmap.format;
    336                     gLogI.log(kDebug_ANPLogType, "---- %p Draw (bitmap)"
    337                               " clip=%d,%d,%d,%d format=%d", instance,
    338                               evt->data.draw.clip.left,
    339                               evt->data.draw.clip.top,
    340                               evt->data.draw.clip.right,
    341                               evt->data.draw.clip.bottom,
    342                               evt->data.draw.data.bitmap.format);
    343                 }
    344             }
    345             break;
    346 
    347         case kKey_ANPEventType:
    348             gLogI.log(kDebug_ANPLogType, "---- %p Key action=%d"
    349                       " code=%d vcode=%d unichar=%d repeat=%d mods=%x", instance,
    350                       evt->data.key.action,
    351                       evt->data.key.nativeCode,
    352                       evt->data.key.virtualCode,
    353                       evt->data.key.unichar,
    354                       evt->data.key.repeatCount,
    355                       evt->data.key.modifiers);
    356             break;
    357 
    358         case kLifecycle_ANPEventType:
    359             gLogI.log(kDebug_ANPLogType, "---- %p Lifecycle action=%d",
    360                                 instance, evt->data.lifecycle.action);
    361             break;
    362 
    363        case kTouch_ANPEventType:
    364             gLogI.log(kDebug_ANPLogType, "---- %p Touch action=%d [%d %d]",
    365                       instance, evt->data.touch.action, evt->data.touch.x,
    366                       evt->data.touch.y);
    367             break;
    368 
    369        case kMouse_ANPEventType:
    370             gLogI.log(kDebug_ANPLogType, "---- %p Mouse action=%d [%d %d]",
    371                       instance, evt->data.mouse.action, evt->data.mouse.x,
    372                       evt->data.mouse.y);
    373             break;
    374 
    375        case kVisibleRect_ANPEventType:
    376             gLogI.log(kDebug_ANPLogType, "---- %p VisibleRect [%d %d %d %d]",
    377                       instance, evt->data.visibleRect.rect.left, evt->data.visibleRect.rect.top,
    378                       evt->data.visibleRect.rect.right, evt->data.visibleRect.rect.bottom);
    379             break;
    380 
    381         default:
    382             gLogI.log(kError_ANPLogType, "---- %p Unknown Event [%d]",
    383                       instance, evt->eventType);
    384             break;
    385     }
    386 #endif
    387 
    388     if(!obj->activePlugin) {
    389         gLogI.log(kError_ANPLogType, "the active plugin is null.");
    390         return 0; // unknown or unhandled event
    391     }
    392     else {
    393         return obj->activePlugin->handleEvent(evt);
    394     }
    395 }
    396 
    397 void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
    398 {
    399 
    400 }
    401 
    402 EXPORT NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) {
    403 
    404     if (variable == NPPVpluginNameString) {
    405         const char **str = (const char **)value;
    406         *str = "Test Plugin";
    407         return NPERR_NO_ERROR;
    408     }
    409 
    410     if (variable == NPPVpluginDescriptionString) {
    411         const char **str = (const char **)value;
    412         *str = "Description of Test Plugin";
    413         return NPERR_NO_ERROR;
    414     }
    415 
    416     return NPERR_GENERIC_ERROR;
    417 }
    418 
    419 NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value)
    420 {
    421     if (variable == NPPVpluginScriptableNPObject) {
    422         void **v = (void **)value;
    423         PluginObject *obj = (PluginObject*) instance->pdata;
    424 
    425         if (obj)
    426             browser->retainobject(&obj->header);
    427 
    428         *v = &(obj->header);
    429         return NPERR_NO_ERROR;
    430     }
    431 
    432     if (variable == kJavaSurface_ANPGetValue) {
    433         //get the surface sub-plugin
    434         PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    435         if (obj && obj->activePlugin) {
    436 
    437             if(obj->activePlugin->supportsDrawingModel(kSurface_ANPDrawingModel)) {
    438                 SurfaceSubPlugin* plugin = static_cast<SurfaceSubPlugin*>(obj->activePlugin);
    439                 jobject* surface = static_cast<jobject*>(value);
    440                 *surface = plugin->getSurface();
    441                 return NPERR_NO_ERROR;
    442             } else {
    443                 gLogI.log(kError_ANPLogType,
    444                           "-- %p Tried to retrieve surface for non-surface plugin",
    445                           instance);
    446             }
    447         }
    448     }
    449 
    450     return NPERR_GENERIC_ERROR;
    451 }
    452 
    453 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
    454 {
    455     return NPERR_GENERIC_ERROR;
    456 }
    457 
    458