| /* |
| * 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); |
| } |