Home | History | Annotate | Download | only in TestNetscapePlugin
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Zan Dobersek <zandobersek (at) gmail.com>
      4  * Copyright (C) 2009 Holger Hans Peter Freyther
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "config.h"
     29 #include "PluginObject.h"
     30 #include "PluginTest.h"
     31 
     32 #include "npapi.h"
     33 #include "npruntime.h"
     34 #include "npfunctions.h"
     35 
     36 #include <stdarg.h>
     37 #include <stdio.h>
     38 #include <string.h>
     39 #include <stdlib.h>
     40 #include <X11/Xlib.h>
     41 #include <X11/Xutil.h>
     42 #include <string>
     43 
     44 using namespace std;
     45 
     46 extern "C" {
     47     NPError NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable);
     48     NPError NP_Shutdown(void);
     49     NPError NP_GetValue(void *future, NPPVariable variable, void *value);
     50     char* NP_GetMIMEDescription(void);
     51 }
     52 
     53 static void executeScript(const PluginObject* obj, const char* script);
     54 
     55 static NPError
     56 webkit_test_plugin_new_instance(NPMIMEType mimetype,
     57                                 NPP instance,
     58                                 uint16_t mode,
     59                                 int16_t argc,
     60                                 char *argn[],
     61                                 char *argv[],
     62                                 NPSavedData* savedData)
     63 {
     64     if (browser->version >= 14) {
     65         PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
     66         instance->pdata = obj;
     67 
     68         string testIdentifier;
     69 
     70         for (int i = 0; i < argc; i++) {
     71             if (strcasecmp(argn[i], "test") == 0)
     72                 testIdentifier = argv[i];
     73             else if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad)
     74                 obj->onStreamLoad = strdup(argv[i]);
     75             else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy)
     76                 obj->onStreamDestroy = strdup(argv[i]);
     77             else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify)
     78                 obj->onURLNotify = strdup(argv[i]);
     79             else if (strcasecmp(argn[i], "src") == 0 &&
     80                      strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
     81                 obj->returnErrorFromNewStream = TRUE;
     82             else if (!strcasecmp(argn[i], "src")
     83                      && !strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded"))
     84                 executeScript(obj, "alert('Plugin Loaded!')");
     85             else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
     86                 obj->logSetWindow = TRUE;
     87             else if (strcasecmp(argn[i], "testnpruntime") == 0)
     88                 testNPRuntime(instance);
     89             else if (strcasecmp(argn[i], "logSrc") == 0) {
     90                 for (int i = 0; i < argc; i++)
     91                     if (strcasecmp(argn[i], "src") == 0)
     92                         pluginLog(instance, "src: %s", argv[i]);
     93             } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0)
     94                 executeScript(obj, "document.body.innerHTML = ''");
     95             else if (!strcasecmp(argn[i], "ondestroy"))
     96                 obj->onDestroy = strdup(argv[i]);
     97             else if (strcasecmp(argn[i], "testwindowopen") == 0)
     98                 obj->testWindowOpen = TRUE;
     99             else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
    100                 obj->onSetWindow = strdup(argv[i]);
    101         }
    102 
    103         browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
    104 
    105         obj->pluginTest = PluginTest::create(instance, testIdentifier);
    106 
    107         return obj->pluginTest->NPP_New(mimetype, mode, argc, argn, argv, savedData);
    108     }
    109 
    110     return NPERR_NO_ERROR;
    111 }
    112 
    113 static NPError
    114 webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** save)
    115 {
    116     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    117     if (obj) {
    118         if (obj->onDestroy) {
    119             executeScript(obj, obj->onDestroy);
    120             free(obj->onDestroy);
    121         }
    122 
    123         if (obj->onStreamLoad)
    124             free(obj->onStreamLoad);
    125 
    126         if (obj->onStreamDestroy)
    127             free(obj->onStreamDestroy);
    128 
    129         if (obj->onURLNotify)
    130             free(obj->onURLNotify);
    131 
    132         if (obj->logDestroy)
    133             pluginLog(instance, "NPP_Destroy");
    134 
    135         if (obj->onSetWindow)
    136             free(obj->onSetWindow);
    137 
    138         obj->pluginTest->NPP_Destroy(save);
    139 
    140         browser->releaseobject(&obj->header);
    141     }
    142 
    143     return NPERR_NO_ERROR;
    144 }
    145 
    146 static NPError
    147 webkit_test_plugin_set_window(NPP instance, NPWindow *window)
    148 {
    149     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    150 
    151     if (obj) {
    152         obj->lastWindow = *window;
    153 
    154         if (obj->logSetWindow) {
    155             pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height);
    156             obj->logSetWindow = false;
    157         }
    158         if (obj->onSetWindow)
    159             executeScript(obj, obj->onSetWindow);
    160 
    161         if (obj->testWindowOpen) {
    162             testWindowOpen(instance);
    163             obj->testWindowOpen = FALSE;
    164         }
    165 
    166     }
    167 
    168     return obj->pluginTest->NPP_SetWindow(instance, window);
    169 }
    170 
    171 static void executeScript(const PluginObject* obj, const char* script)
    172 {
    173     NPObject *windowScriptObject;
    174     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    175 
    176     NPString npScript;
    177     npScript.UTF8Characters = script;
    178     npScript.UTF8Length = strlen(script);
    179 
    180     NPVariant browserResult;
    181     browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult);
    182     browser->releasevariantvalue(&browserResult);
    183 }
    184 
    185 static NPError
    186 webkit_test_plugin_new_stream(NPP instance,
    187                               NPMIMEType /*type*/,
    188                               NPStream *stream,
    189                               NPBool /*seekable*/,
    190                               uint16_t* stype)
    191 {
    192     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    193     obj->stream = stream;
    194     *stype = NP_NORMAL;
    195 
    196     if (obj->returnErrorFromNewStream)
    197         return NPERR_GENERIC_ERROR;
    198 
    199     if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS)
    200         notifyStream(obj, stream->url, stream->headers);
    201 
    202     if (obj->onStreamLoad)
    203         executeScript(obj, obj->onStreamLoad);
    204 
    205     return NPERR_NO_ERROR;
    206 }
    207 
    208 static NPError
    209 webkit_test_plugin_destroy_stream(NPP instance, NPStream* stream, NPError reason)
    210 {
    211     PluginObject* obj = (PluginObject*)instance->pdata;
    212 
    213     if (obj->onStreamDestroy) {
    214         NPObject* windowObject = 0;
    215         NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
    216 
    217         if (error == NPERR_NO_ERROR) {
    218             NPVariant onStreamDestroyVariant;
    219             if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) {
    220                 if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) {
    221                     NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant);
    222 
    223                     NPVariant reasonVariant;
    224                     INT32_TO_NPVARIANT(reason, reasonVariant);
    225 
    226                     NPVariant result;
    227                     browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result);
    228                     browser->releasevariantvalue(&result);
    229                 }
    230                 browser->releasevariantvalue(&onStreamDestroyVariant);
    231             }
    232             browser->releaseobject(windowObject);
    233         }
    234     }
    235 
    236     return obj->pluginTest->NPP_DestroyStream(stream, reason);
    237 }
    238 
    239 static void
    240 webkit_test_plugin_stream_as_file(NPP /*instance*/, NPStream* /*stream*/, const char* /*fname*/)
    241 {
    242 }
    243 
    244 static int32_t
    245 webkit_test_plugin_write_ready(NPP /*instance*/, NPStream* /*stream*/)
    246 {
    247     return 4096;
    248 }
    249 
    250 static int32_t
    251 webkit_test_plugin_write(NPP instance,
    252                          NPStream* /*stream*/,
    253                          int32_t /*offset*/,
    254                          int32_t len,
    255                          void* /*buffer*/)
    256 {
    257     PluginObject* obj = (PluginObject*)instance->pdata;
    258 
    259     if (obj->returnNegativeOneFromWrite)
    260         return -1;
    261 
    262     return len;
    263 }
    264 
    265 static void
    266 webkit_test_plugin_print(NPP /*instance*/, NPPrint* /*platformPrint*/)
    267 {
    268 }
    269 
    270 static char keyEventToChar(XKeyEvent* event)
    271 {
    272     char c = ' ';
    273     XLookupString(event, &c, sizeof(c), 0, 0);
    274     return c;
    275 }
    276 
    277 static int16_t
    278 webkit_test_plugin_handle_event(NPP instance, void* event)
    279 {
    280     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    281     if (!obj->eventLogging)
    282         return 0;
    283 
    284     XEvent* evt = static_cast<XEvent*>(event);
    285 
    286     switch (evt->type) {
    287         case ButtonRelease:
    288             pluginLog(instance, "mouseUp at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
    289             break;
    290         case ButtonPress:
    291             pluginLog(instance, "mouseDown at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
    292             break;
    293         case KeyRelease:
    294             pluginLog(instance, "keyUp '%c'", keyEventToChar(&evt->xkey));
    295             break;
    296         case KeyPress:
    297             pluginLog(instance, "keyDown '%c'", keyEventToChar(&evt->xkey));
    298             break;
    299         case MotionNotify:
    300         case EnterNotify:
    301         case LeaveNotify:
    302             break;
    303         case FocusIn:
    304             pluginLog(instance, "getFocusEvent");
    305             break;
    306         case FocusOut:
    307             pluginLog(instance, "loseFocusEvent");
    308             break;
    309         default:
    310             pluginLog(instance, "event %d", evt->type);
    311     }
    312 
    313     return 0;
    314 }
    315 
    316 static void
    317 webkit_test_plugin_url_notify(NPP instance, const char* url, NPReason reason, void* notifyData)
    318 {
    319     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    320 
    321     if (obj->onURLNotify)
    322         executeScript(obj, obj->onURLNotify);
    323 
    324     handleCallback(obj, url, reason, notifyData);
    325 }
    326 
    327 static NPError
    328 webkit_test_plugin_get_value(NPP instance, NPPVariable variable, void *value)
    329 {
    330     PluginObject* obj = 0;
    331     if (instance)
    332         obj = static_cast<PluginObject*>(instance->pdata);
    333 
    334     // First, check if the PluginTest object supports getting this value.
    335     if (obj && obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
    336         return NPERR_NO_ERROR;
    337 
    338     NPError err = NPERR_NO_ERROR;
    339 
    340     switch (variable) {
    341         case NPPVpluginNameString:
    342             *((char **)value) = const_cast<char*>("WebKit Test PlugIn");
    343             break;
    344         case NPPVpluginDescriptionString:
    345             *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit");
    346             break;
    347         case NPPVpluginNeedsXEmbed:
    348             *((NPBool *)value) = TRUE;
    349             break;
    350         case NPPVpluginScriptableIID:
    351         case NPPVpluginScriptableInstance:
    352         case NPPVpluginScriptableNPObject:
    353             err = NPERR_GENERIC_ERROR;
    354             break;
    355         default:
    356             err = NPERR_GENERIC_ERROR;
    357             break;
    358     }
    359 
    360     if (variable == NPPVpluginScriptableNPObject) {
    361         void **v = (void **)value;
    362         browser->retainobject((NPObject *)obj);
    363         *v = obj;
    364         err = NPERR_NO_ERROR;
    365     }
    366 
    367     return err;
    368 }
    369 
    370 static NPError
    371 webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value)
    372 {
    373     PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
    374 
    375     switch (variable) {
    376         case NPNVprivateModeBool:
    377             obj->cachedPrivateBrowsingMode = *(NPBool*)value;
    378             return NPERR_NO_ERROR;
    379         default:
    380             return NPERR_GENERIC_ERROR;
    381     }
    382 }
    383 
    384 char *
    385 NP_GetMIMEDescription(void)
    386 {
    387     // We sentence-case the mime-type here to ensure that ports are not
    388     // case-sensitive when loading plugins. See https://webkit.org/b/36815
    389     return const_cast<char*>("application/x-Webkit-Test-Netscape:testnetscape:test netscape content");
    390 }
    391 
    392 NPError
    393 NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable)
    394 {
    395     if (aMozillaVTable == NULL || aPluginVTable == NULL)
    396         return NPERR_INVALID_FUNCTABLE_ERROR;
    397 
    398     if ((aMozillaVTable->version >> 8) > NP_VERSION_MAJOR)
    399         return NPERR_INCOMPATIBLE_VERSION_ERROR;
    400 
    401     if (aPluginVTable->size < sizeof (NPPluginFuncs))
    402         return NPERR_INVALID_FUNCTABLE_ERROR;
    403 
    404     browser = aMozillaVTable;
    405     pluginFunctions = aPluginVTable;
    406 
    407         aPluginVTable->size           = sizeof (NPPluginFuncs);
    408         aPluginVTable->version        = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
    409         aPluginVTable->newp           = webkit_test_plugin_new_instance;
    410         aPluginVTable->destroy        = webkit_test_plugin_destroy_instance;
    411         aPluginVTable->setwindow      = webkit_test_plugin_set_window;
    412         aPluginVTable->newstream      = webkit_test_plugin_new_stream;
    413         aPluginVTable->destroystream  = webkit_test_plugin_destroy_stream;
    414         aPluginVTable->asfile         = webkit_test_plugin_stream_as_file;
    415         aPluginVTable->writeready     = webkit_test_plugin_write_ready;
    416         aPluginVTable->write          = webkit_test_plugin_write;
    417         aPluginVTable->print          = webkit_test_plugin_print;
    418         aPluginVTable->event          = webkit_test_plugin_handle_event;
    419         aPluginVTable->urlnotify      = webkit_test_plugin_url_notify;
    420         aPluginVTable->javaClass      = NULL;
    421         aPluginVTable->getvalue       = webkit_test_plugin_get_value;
    422         aPluginVTable->setvalue       = webkit_test_plugin_set_value;
    423 
    424     return NPERR_NO_ERROR;
    425 }
    426 
    427 NPError
    428 NP_Shutdown(void)
    429 {
    430     return NPERR_NO_ERROR;
    431 }
    432 
    433 NPError
    434 NP_GetValue(void* /*future*/, NPPVariable variable, void *value)
    435 {
    436     return webkit_test_plugin_get_value(NULL, variable, value);
    437 }
    438