/* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Zan Dobersek <zandobersek@gmail.com> * Copyright (C) 2009 Holger Hans Peter Freyther * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "PluginObject.h" #include "PluginTest.h" #include "npapi.h" #include "npruntime.h" #include "npfunctions.h" #include <stdarg.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <string> using namespace std; extern "C" { NPError NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable); NPError NP_Shutdown(void); NPError NP_GetValue(void *future, NPPVariable variable, void *value); char* NP_GetMIMEDescription(void); } static void executeScript(const PluginObject* obj, const char* script); static NPError webkit_test_plugin_new_instance(NPMIMEType mimetype, NPP instance, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData* savedData) { if (browser->version >= 14) { PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass()); instance->pdata = obj; string testIdentifier; for (int i = 0; i < argc; i++) { if (strcasecmp(argn[i], "test") == 0) testIdentifier = argv[i]; else if (strcasecmp(argn[i], "onstreamload") == 0 && !obj->onStreamLoad) obj->onStreamLoad = strdup(argv[i]); else if (strcasecmp(argn[i], "onStreamDestroy") == 0 && !obj->onStreamDestroy) obj->onStreamDestroy = strdup(argv[i]); else if (strcasecmp(argn[i], "onURLNotify") == 0 && !obj->onURLNotify) obj->onURLNotify = strdup(argv[i]); else if (strcasecmp(argn[i], "src") == 0 && strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0) obj->returnErrorFromNewStream = TRUE; else if (!strcasecmp(argn[i], "src") && !strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded")) executeScript(obj, "alert('Plugin Loaded!')"); else if (strcasecmp(argn[i], "logfirstsetwindow") == 0) obj->logSetWindow = TRUE; else if (strcasecmp(argn[i], "testnpruntime") == 0) testNPRuntime(instance); else if (strcasecmp(argn[i], "logSrc") == 0) { for (int i = 0; i < argc; i++) if (strcasecmp(argn[i], "src") == 0) pluginLog(instance, "src: %s", argv[i]); } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0) executeScript(obj, "document.body.innerHTML = ''"); else if (!strcasecmp(argn[i], "ondestroy")) obj->onDestroy = strdup(argv[i]); else if (strcasecmp(argn[i], "testwindowopen") == 0) obj->testWindowOpen = TRUE; else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow) obj->onSetWindow = strdup(argv[i]); } browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode); obj->pluginTest = PluginTest::create(instance, testIdentifier); return obj->pluginTest->NPP_New(mimetype, mode, argc, argn, argv, savedData); } return NPERR_NO_ERROR; } static NPError webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** save) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); if (obj) { if (obj->onDestroy) { executeScript(obj, obj->onDestroy); free(obj->onDestroy); } if (obj->onStreamLoad) free(obj->onStreamLoad); if (obj->onStreamDestroy) free(obj->onStreamDestroy); if (obj->onURLNotify) free(obj->onURLNotify); if (obj->logDestroy) pluginLog(instance, "NPP_Destroy"); if (obj->onSetWindow) free(obj->onSetWindow); obj->pluginTest->NPP_Destroy(save); browser->releaseobject(&obj->header); } return NPERR_NO_ERROR; } static NPError webkit_test_plugin_set_window(NPP instance, NPWindow *window) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); if (obj) { obj->lastWindow = *window; if (obj->logSetWindow) { pluginLog(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height); obj->logSetWindow = false; } if (obj->onSetWindow) executeScript(obj, obj->onSetWindow); if (obj->testWindowOpen) { testWindowOpen(instance); obj->testWindowOpen = FALSE; } } return obj->pluginTest->NPP_SetWindow(instance, window); } static void executeScript(const PluginObject* obj, const char* script) { NPObject *windowScriptObject; browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); NPString npScript; npScript.UTF8Characters = script; npScript.UTF8Length = strlen(script); NPVariant browserResult; browser->evaluate(obj->npp, windowScriptObject, &npScript, &browserResult); browser->releasevariantvalue(&browserResult); } static NPError webkit_test_plugin_new_stream(NPP instance, NPMIMEType /*type*/, NPStream *stream, NPBool /*seekable*/, uint16_t* stype) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); obj->stream = stream; *stype = NP_NORMAL; if (obj->returnErrorFromNewStream) return NPERR_GENERIC_ERROR; if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS) notifyStream(obj, stream->url, stream->headers); if (obj->onStreamLoad) executeScript(obj, obj->onStreamLoad); return NPERR_NO_ERROR; } static NPError webkit_test_plugin_destroy_stream(NPP instance, NPStream* stream, NPError reason) { PluginObject* obj = (PluginObject*)instance->pdata; if (obj->onStreamDestroy) { NPObject* windowObject = 0; NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject); if (error == NPERR_NO_ERROR) { NPVariant onStreamDestroyVariant; if (browser->getproperty(instance, windowObject, browser->getstringidentifier(obj->onStreamDestroy), &onStreamDestroyVariant)) { if (NPVARIANT_IS_OBJECT(onStreamDestroyVariant)) { NPObject* onStreamDestroyFunction = NPVARIANT_TO_OBJECT(onStreamDestroyVariant); NPVariant reasonVariant; INT32_TO_NPVARIANT(reason, reasonVariant); NPVariant result; browser->invokeDefault(instance, onStreamDestroyFunction, &reasonVariant, 1, &result); browser->releasevariantvalue(&result); } browser->releasevariantvalue(&onStreamDestroyVariant); } browser->releaseobject(windowObject); } } return obj->pluginTest->NPP_DestroyStream(stream, reason); } static void webkit_test_plugin_stream_as_file(NPP /*instance*/, NPStream* /*stream*/, const char* /*fname*/) { } static int32_t webkit_test_plugin_write_ready(NPP /*instance*/, NPStream* /*stream*/) { return 4096; } static int32_t webkit_test_plugin_write(NPP instance, NPStream* /*stream*/, int32_t /*offset*/, int32_t len, void* /*buffer*/) { PluginObject* obj = (PluginObject*)instance->pdata; if (obj->returnNegativeOneFromWrite) return -1; return len; } static void webkit_test_plugin_print(NPP /*instance*/, NPPrint* /*platformPrint*/) { } static char keyEventToChar(XKeyEvent* event) { char c = ' '; XLookupString(event, &c, sizeof(c), 0, 0); return c; } static int16_t webkit_test_plugin_handle_event(NPP instance, void* event) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); if (!obj->eventLogging) return 0; XEvent* evt = static_cast<XEvent*>(event); switch (evt->type) { case ButtonRelease: pluginLog(instance, "mouseUp at (%d, %d)", evt->xbutton.x, evt->xbutton.y); break; case ButtonPress: pluginLog(instance, "mouseDown at (%d, %d)", evt->xbutton.x, evt->xbutton.y); break; case KeyRelease: pluginLog(instance, "keyUp '%c'", keyEventToChar(&evt->xkey)); break; case KeyPress: pluginLog(instance, "keyDown '%c'", keyEventToChar(&evt->xkey)); break; case MotionNotify: case EnterNotify: case LeaveNotify: break; case FocusIn: pluginLog(instance, "getFocusEvent"); break; case FocusOut: pluginLog(instance, "loseFocusEvent"); break; default: pluginLog(instance, "event %d", evt->type); } return 0; } static void webkit_test_plugin_url_notify(NPP instance, const char* url, NPReason reason, void* notifyData) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); if (obj->onURLNotify) executeScript(obj, obj->onURLNotify); handleCallback(obj, url, reason, notifyData); } static NPError webkit_test_plugin_get_value(NPP instance, NPPVariable variable, void *value) { PluginObject* obj = 0; if (instance) obj = static_cast<PluginObject*>(instance->pdata); // First, check if the PluginTest object supports getting this value. if (obj && obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR) return NPERR_NO_ERROR; NPError err = NPERR_NO_ERROR; switch (variable) { case NPPVpluginNameString: *((char **)value) = const_cast<char*>("WebKit Test PlugIn"); break; case NPPVpluginDescriptionString: *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit"); break; case NPPVpluginNeedsXEmbed: *((NPBool *)value) = TRUE; break; case NPPVpluginScriptableIID: case NPPVpluginScriptableInstance: case NPPVpluginScriptableNPObject: err = NPERR_GENERIC_ERROR; break; default: err = NPERR_GENERIC_ERROR; break; } if (variable == NPPVpluginScriptableNPObject) { void **v = (void **)value; browser->retainobject((NPObject *)obj); *v = obj; err = NPERR_NO_ERROR; } return err; } static NPError webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); switch (variable) { case NPNVprivateModeBool: obj->cachedPrivateBrowsingMode = *(NPBool*)value; return NPERR_NO_ERROR; default: return NPERR_GENERIC_ERROR; } } char * NP_GetMIMEDescription(void) { // We sentence-case the mime-type here to ensure that ports are not // case-sensitive when loading plugins. See https://webkit.org/b/36815 return const_cast<char*>("application/x-Webkit-Test-Netscape:testnetscape:test netscape content"); } NPError NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable) { if (aMozillaVTable == NULL || aPluginVTable == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; if ((aMozillaVTable->version >> 8) > NP_VERSION_MAJOR) return NPERR_INCOMPATIBLE_VERSION_ERROR; if (aPluginVTable->size < sizeof (NPPluginFuncs)) return NPERR_INVALID_FUNCTABLE_ERROR; browser = aMozillaVTable; pluginFunctions = aPluginVTable; aPluginVTable->size = sizeof (NPPluginFuncs); aPluginVTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; aPluginVTable->newp = webkit_test_plugin_new_instance; aPluginVTable->destroy = webkit_test_plugin_destroy_instance; aPluginVTable->setwindow = webkit_test_plugin_set_window; aPluginVTable->newstream = webkit_test_plugin_new_stream; aPluginVTable->destroystream = webkit_test_plugin_destroy_stream; aPluginVTable->asfile = webkit_test_plugin_stream_as_file; aPluginVTable->writeready = webkit_test_plugin_write_ready; aPluginVTable->write = webkit_test_plugin_write; aPluginVTable->print = webkit_test_plugin_print; aPluginVTable->event = webkit_test_plugin_handle_event; aPluginVTable->urlnotify = webkit_test_plugin_url_notify; aPluginVTable->javaClass = NULL; aPluginVTable->getvalue = webkit_test_plugin_get_value; aPluginVTable->setvalue = webkit_test_plugin_set_value; return NPERR_NO_ERROR; } NPError NP_Shutdown(void) { return NPERR_NO_ERROR; } NPError NP_GetValue(void* /*future*/, NPPVariable variable, void *value) { return webkit_test_plugin_get_value(NULL, variable, value); }