diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-14 23:15:00 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-14 23:15:00 +0000 |
commit | 97bf4edfdf217222c312da38d983ac1099c36163 (patch) | |
tree | 2bceb9507a0970f5588049713fca8723aa8bce37 | |
parent | 61424c0631ac4cc5838cf6a80406fc98ca60220d (diff) | |
download | chromium_src-97bf4edfdf217222c312da38d983ac1099c36163.zip chromium_src-97bf4edfdf217222c312da38d983ac1099c36163.tar.gz chromium_src-97bf4edfdf217222c312da38d983ac1099c36163.tar.bz2 |
Add a skeleton "Pepper" NPAPI plugin. This is basically a copy of the
npapi_layout_test_plugin with a modification of the MIME type. We will enhance
this code from here to support new pepper features.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/269087
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29060 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/tools/pepper_test_plugin/PluginObject.cpp | 926 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/PluginObject.h | 51 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/README | 8 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/TestObject.cpp | 210 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/TestObject.h | 36 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/main.cpp | 513 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp | 33 | ||||
-rw-r--r-- | webkit/tools/pepper_test_plugin/pepper_test_plugin.rc | 30 |
8 files changed, 1807 insertions, 0 deletions
diff --git a/webkit/tools/pepper_test_plugin/PluginObject.cpp b/webkit/tools/pepper_test_plugin/PluginObject.cpp new file mode 100644 index 0000000..0e21a09 --- /dev/null +++ b/webkit/tools/pepper_test_plugin/PluginObject.cpp @@ -0,0 +1,926 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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 "PluginObject.h" + +#include "TestObject.h" +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#ifdef WIN32 +#define snprintf sprintf_s +#endif + +static void pluginInvalidate(NPObject*); +static bool pluginHasProperty(NPObject*, NPIdentifier name); +static bool pluginHasMethod(NPObject*, NPIdentifier name); +static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*); +static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*); +static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool pluginInvokeDefault(NPObject*, const NPVariant* args, uint32_t argCount, NPVariant* result); +static NPObject* pluginAllocate(NPP npp, NPClass*); +static void pluginDeallocate(NPObject*); + +NPNetscapeFuncs* browser; + +static NPClass pluginClass = { + NP_CLASS_STRUCT_VERSION, + pluginAllocate, + pluginDeallocate, + pluginInvalidate, + pluginHasMethod, + pluginInvoke, + pluginInvokeDefault, + pluginHasProperty, + pluginGetProperty, + pluginSetProperty, +}; + +NPClass *getPluginClass(void) +{ + return &pluginClass; +} + +static bool identifiersInitialized = false; + +#define ID_PROPERTY_PROPERTY 0 +#define ID_PROPERTY_EVENT_LOGGING 1 +#define ID_PROPERTY_HAS_STREAM 2 +#define ID_PROPERTY_TEST_OBJECT 3 +#define ID_PROPERTY_LOG_DESTROY 4 +#define ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM 5 +#define ID_PROPERTY_TEST_OBJECT_COUNT 6 +#define NUM_PROPERTY_IDENTIFIERS 7 + +static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS]; +static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = { + "property", + "eventLoggingEnabled", + "hasStream", + "testObject", + "logDestroy", + "returnErrorFromNewStream", + "testObjectCount", +}; + +enum { + ID_TEST_CALLBACK_METHOD = 0, + ID_TEST_GETURL, + ID_REMOVE_DEFAULT_METHOD, + ID_TEST_DOM_ACCESS, + ID_TEST_GET_URL_NOTIFY, + ID_TEST_INVOKE_DEFAULT, + ID_DESTROY_STREAM, + ID_TEST_ENUMERATE, + ID_TEST_GETINTIDENTIFIER, + ID_TEST_GET_PROPERTY, + ID_TEST_EVALUATE, + ID_TEST_GET_PROPERTY_RETURN_VALUE, + ID_TEST_CALLBACK_METHOD_RET, + ID_TEST_CREATE_TEST_OBJECT, + ID_TEST_PASS_TEST_OBJECT, + ID_TEST_CLONE_OBJECT, + ID_TEST_SCRIPT_OBJECT_INVOKE, + ID_TEST_IDENTIFIER_TO_STRING, + ID_TEST_IDENTIFIER_TO_INT, + ID_TEST_POSTURL_FILE, + ID_TEST_CALLBACK_AND_GET_VALUE, + ID_TEST_CONSTRUCT, + ID_DESTROY_NULL_STREAM, + ID_TEST_HAS_PROPERTY, + ID_TEST_HAS_METHOD, + ID_TEST_THROW_EXCEPTION_METHOD, + NUM_METHOD_IDENTIFIERS +}; + +static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; +static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { + "testCallback", + "getURL", + "removeDefaultMethod", + "testDOMAccess", + "getURLNotify", + "testInvokeDefault", + "destroyStream", + "testEnumerate", + "testGetIntIdentifier", + "testGetProperty", + "testEvaluate", + "testGetPropertyReturnValue", + "testCallbackRet", // Chrome bug 897451 + "testCreateTestObject", // Chrome bug 1093606 + "testPassTestObject", // Chrome bug 1093606 + "testCloneObject", + "testScriptObjectInvoke", // Chrome bug 1175346 + "testIdentifierToString", + "testIdentifierToInt", + "testPostURLFile", + // Chrome bug http://code.google.com/p/chromium/issues/detail?id=4270 + "testCallbackAndGetValue", + "testConstruct", + "destroyNullStream", + "testHasProperty", + "testHasMethod", + "testThrowException" +}; + +static NPUTF8* createCStringFromNPVariant(const NPVariant* variant) +{ + size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length; + NPUTF8* result = (NPUTF8*)malloc(length + 1); + memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length); + result[length] = '\0'; + return result; +} + +static void initializeIdentifiers(void) +{ + browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers); + browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers); +} + +static bool pluginHasProperty(NPObject *obj, NPIdentifier name) +{ + for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++) + if (name == pluginPropertyIdentifiers[i]) + return true; + return false; +} + +static bool pluginHasMethod(NPObject *obj, NPIdentifier name) +{ + for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++) + if (name == pluginMethodIdentifiers[i]) + return true; + return false; +} + +static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(obj); + if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) { + STRINGZ_TO_NPVARIANT("property", *result); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { + BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { + BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) { + BOOLEAN_TO_NPVARIANT(plugin->stream != 0, *result); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) { + NPObject* testObject = plugin->testObject; + browser->retainobject(testObject); + OBJECT_TO_NPVARIANT(testObject, *result); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { + BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT_COUNT]) { + INT32_TO_NPVARIANT(getTestObjectCount(), *result); + return true; + } + return false; +} + +static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(obj); + if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { + plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { + plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { + plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant); + return true; + } + + return false; +} + +static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result) +{ + // Get plug-in's DOM element + NPObject* elementObject; + if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) { + // Get style + NPVariant styleVariant; + NPIdentifier styleIdentifier = browser->getstringidentifier("style"); + if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) { + // Set style.border + NPIdentifier borderIdentifier = browser->getstringidentifier("border"); + NPVariant borderVariant; + STRINGZ_TO_NPVARIANT("3px solid red", borderVariant); + browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant); + browser->releasevariantvalue(&styleVariant); + } + + browser->releaseobject(elementObject); + } + VOID_TO_NPVARIANT(*result); + return true; +} + +static NPIdentifier stringVariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_STRING(variant)); + NPUTF8* utf8String = createCStringFromNPVariant(&variant); + NPIdentifier identifier = browser->getstringidentifier(utf8String); + free(utf8String); + return identifier; +} + +static NPIdentifier int32VariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_INT32(variant)); + int32 integer = NPVARIANT_TO_INT32(variant); + return browser->getintidentifier(integer); +} + +static NPIdentifier doubleVariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_DOUBLE(variant)); + double value = NPVARIANT_TO_DOUBLE(variant); + // Sadly there is no "getdoubleidentifier" + int32 integer = static_cast<int32>(value); + return browser->getintidentifier(integer); +} + +static NPIdentifier variantToIdentifier(NPVariant variant) +{ + if (NPVARIANT_IS_STRING(variant)) + return stringVariantToIdentifier(variant); + else if (NPVARIANT_IS_INT32(variant)) + return int32VariantToIdentifier(variant); + else if (NPVARIANT_IS_DOUBLE(variant)) + return doubleVariantToIdentifier(variant); + return 0; +} + +static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1) + return false; + NPIdentifier identifier = variantToIdentifier(args[0]); + if (!identifier) + return false; + NPUTF8* utf8String = browser->utf8fromidentifier(identifier); + if (!utf8String) + return false; + STRINGZ_TO_NPVARIANT(utf8String, *result); + return true; +} + +static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1) + return false; + NPIdentifier identifier = variantToIdentifier(args[0]); + if (!identifier) + return false; + int32 integer = browser->intfromidentifier(identifier); + INT32_TO_NPVARIANT(integer, *result); + return true; +} + +static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount == 0 || !NPVARIANT_IS_STRING(args[0])) + return false; + + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant browserResult; + browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult); + browser->releasevariantvalue(&browserResult); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool testCallbackAndGetValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + NPP npp = obj->npp; + if (!testCallback(obj, args, argCount, result)) + return false; + + NPObject *global; + browser->getvalue(npp, NPNVWindowNPObject, &global); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) { + NPUTF8* urlString = createCStringFromNPVariant(&args[0]); + NPUTF8* targetString = createCStringFromNPVariant(&args[1]); + NPError npErr = browser->geturl(obj->npp, urlString, targetString); + free(urlString); + free(targetString); + + INT32_TO_NPVARIANT(npErr, *result); + return true; + } else if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) { + NPUTF8* urlString = createCStringFromNPVariant(&args[0]); + NPError npErr = browser->geturl(obj->npp, urlString, 0); + free(urlString); + + INT32_TO_NPVARIANT(npErr, *result); + return true; + } + return false; +} + +static bool removeDefaultMethod(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + pluginClass.invokeDefault = 0; + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 3 || !NPVARIANT_IS_STRING(args[0]) + || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1])) + || !NPVARIANT_IS_STRING(args[2])) + return false; + + NPUTF8* urlString = createCStringFromNPVariant(&args[0]); + NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : NULL); + NPUTF8* callbackString = createCStringFromNPVariant(&args[2]); + + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier); + + free(urlString); + free(targetString); + free(callbackString); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!NPVARIANT_IS_OBJECT(args[0])) + return false; + + NPObject *callback = NPVARIANT_TO_OBJECT(args[0]); + + NPVariant invokeArgs[1]; + NPVariant browserResult; + + STRINGZ_TO_NPVARIANT("test", invokeArgs[0]); + bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult); + + if (retval) + browser->releasevariantvalue(&browserResult); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK); + INT32_TO_NPVARIANT(npError, *result); + return true; +} + +static bool destroyNullStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + NPError npError = browser->destroystream(obj->npp, 0, NPRES_USER_BREAK); + INT32_TO_NPVARIANT(npError, *result); + return true; +} + +static bool testHasProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + + NPUTF8* propertyString = createCStringFromNPVariant(&args[1]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + bool retval = browser->hasproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static bool testHasMethod(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + + NPUTF8* propertyString = createCStringFromNPVariant(&args[1]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + bool retval = browser->hasmethod(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount == 2 && NPVARIANT_IS_OBJECT(args[0]) && NPVARIANT_IS_OBJECT(args[1])) { + uint32_t count; + NPIdentifier* identifiers; + + if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) { + NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]); + NPIdentifier pushIdentifier = browser->getstringidentifier("push"); + + for (uint32_t i = 0; i < count; i++) { + NPUTF8* string = browser->utf8fromidentifier(identifiers[i]); + + if (!string) + continue; + + NPVariant args[1]; + STRINGZ_TO_NPVARIANT(string, args[0]); + NPVariant browserResult; + browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult); + browser->releasevariantvalue(&browserResult); + browser->memfree(string); + } + + browser->memfree(identifiers); + } + + VOID_TO_NPVARIANT(*result); + return true; + } + return false; +} + +static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1) + return false; + + NPIdentifier identifier; + + if (NPVARIANT_IS_DOUBLE(args[0])) { + identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0])); + INT32_TO_NPVARIANT((int32)identifier, *result); + return true; + } else if (NPVARIANT_IS_INT32(args[0])) { + identifier = browser->getintidentifier((int)NPVARIANT_TO_INT32(args[0])); + INT32_TO_NPVARIANT((int32)identifier, *result); + return true; + } + return false; +} + +static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount == 0) + return false; + + NPObject *object; + browser->getvalue(obj->npp, NPNVWindowNPObject, &object); + + for (uint32_t i = 0; i < argCount; i++) { + assert(NPVARIANT_IS_STRING(args[i])); + NPUTF8* propertyString = createCStringFromNPVariant(&args[i]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + NPVariant variant; + bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant); + browser->releaseobject(object); + + if (!retval) + break; + + if (i + 1 < argCount) { + assert(NPVARIANT_IS_OBJECT(variant)); + object = NPVARIANT_TO_OBJECT(variant); + } else { + *result = variant; + return true; + } + } + + VOID_TO_NPVARIANT(*result); + return false; +} + +static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 1 || !NPVARIANT_IS_STRING(args[0])) + return false; + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPString s = NPVARIANT_TO_STRING(args[0]); + + bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result); + browser->releaseobject(windowScriptObject); + return retval; +} + +static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1])) + return false; + + NPUTF8* propertyString = createCStringFromNPVariant(&args[1]); + NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString); + free(propertyString); + + NPVariant variant; + bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant); + if (retval) + browser->releasevariantvalue(&variant); + + BOOLEAN_TO_NPVARIANT(retval, *result); + return true; +} + +static char* toCString(const NPString& string) +{ + char* result = static_cast<char*>(malloc(string.UTF8Length + 1)); + memcpy(result, string.UTF8Characters, string.UTF8Length); + result[string.UTF8Length] = '\0'; + + return result; +} + +static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 4 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2]) || !NPVARIANT_IS_STRING(args[3])) + return false; + + NPString urlString = NPVARIANT_TO_STRING(args[0]); + char* url = toCString(urlString); + + NPString targetString = NPVARIANT_TO_STRING(args[1]); + char* target = toCString(targetString); + + NPString pathString = NPVARIANT_TO_STRING(args[2]); + char* path = toCString(pathString); + + NPString contentsString = NPVARIANT_TO_STRING(args[3]); + + FILE* tempFile = fopen(path, "w"); + if (!tempFile) + return false; + + int written = fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile); + fclose(tempFile); + if (written != 1) + return false; + + NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, TRUE); + + free(path); + free(target); + free(url); + + BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result); + return true; +} + +static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!argCount || !NPVARIANT_IS_OBJECT(args[0])) + return false; + + return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result); +} + +static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(header); + if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD]) + return testCallback(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_GETURL]) + return getURL(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_REMOVE_DEFAULT_METHOD]) + return removeDefaultMethod(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS]) + return testDOMAccess(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY]) + return getURLNotify(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT]) + return testInvokeDefault(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE]) + return testEnumerate(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM]) + return destroyStream(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER]) + return testGetIntIdentifier(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE]) + return testEvaluate(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY]) + return testGetProperty(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE]) + return testGetPropertyReturnValue(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING]) + return testIdentifierToString(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT]) + return testIdentifierToInt(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE]) + return testPostURLFile(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD_RET]) { + // call whatever method name we're given, and pass it the 'window' obj. + // we expect the function to return its argument. + if (argCount > 0 && NPVARIANT_IS_STRING(args[0])) { + NPObject *windowScriptObject; + browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant callbackArgs[1]; + OBJECT_TO_NPVARIANT(windowScriptObject, callbackArgs[0]); + + NPVariant browserResult; + browser->invoke(plugin->npp, windowScriptObject, callbackIdentifier, + callbackArgs, 1, &browserResult); + + if (NPVARIANT_IS_OBJECT(browserResult)) { + // Now return the callbacks return value back to our caller. + // BUG 897451: This should be the same as the + // windowScriptObject, but its not (in Chrome) - or at least, it + // has a different refcount. This means Chrome will delete the + // object before returning it and the calling JS gets a garbage + // value. Firefox handles it fine. + OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(browserResult), *result); + } else { + browser->releasevariantvalue(&browserResult); + VOID_TO_NPVARIANT(*result); + } + + return true; + } + } else if (name == pluginMethodIdentifiers[ID_TEST_CREATE_TEST_OBJECT]) { + NPObject *testObject = browser->createobject(plugin->npp, getTestClass()); + assert(testObject->referenceCount == 1); + OBJECT_TO_NPVARIANT(testObject, *result); + return true; + } else if (name == pluginMethodIdentifiers[ID_TEST_PASS_TEST_OBJECT]) { + // call whatever method name we're given, and pass it our second + // argument. + if (argCount > 1 && NPVARIANT_IS_STRING(args[0])) { + NPObject *windowScriptObject; + browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant browserResult; + browser->invoke(plugin->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &browserResult); + browser->releasevariantvalue(&browserResult); + + VOID_TO_NPVARIANT(*result); + return true; + } + } else if (name == pluginMethodIdentifiers[ID_TEST_CLONE_OBJECT]) { + // Create another instance of the same class + NPObject *new_object = browser->createobject(plugin->npp, &pluginClass); + assert(new_object->referenceCount == 1); + OBJECT_TO_NPVARIANT(new_object, *result); + return true; + } else if (name == pluginMethodIdentifiers[ID_TEST_SCRIPT_OBJECT_INVOKE]) { + if (argCount > 1 && NPVARIANT_IS_STRING(args[0])) { + // Invoke a script callback to get a script NPObject. Then call + // a method on the script NPObject passing it a freshly created + // NPObject. + // Arguments: + // arg1: Callback that returns a script object. + // arg2: Name of the method to call on the script object returned + // from the callback + NPObject *windowScriptObject; + browser->getvalue(plugin->npp, NPNVWindowNPObject, + &windowScriptObject); + + // Arg1 is the name of the callback + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = + browser->getstringidentifier(callbackString); + free(callbackString); + + // Invoke a callback that returns a script object + NPVariant object_result; + browser->invoke(plugin->npp, windowScriptObject, callbackIdentifier, + &args[1], 1, &object_result); + + // Script object returned + NPObject *script_object = object_result.value.objectValue; + + // Arg2 is the name of the method to be called on the script object + NPUTF8* object_mehod_string = createCStringFromNPVariant(&args[1]); + NPIdentifier object_method = + browser->getstringidentifier(object_mehod_string); + free(object_mehod_string); + + // Create a fresh NPObject to be passed as an argument + NPObject *object_arg = browser->createobject(plugin->npp, &pluginClass); + NPVariant invoke_args[1]; + OBJECT_TO_NPVARIANT(object_arg, invoke_args[0]); + + // Invoke the script method + NPVariant object_method_result; + browser->invoke(plugin->npp, script_object, object_method, + invoke_args, 1, &object_method_result); + + browser->releasevariantvalue(&object_result); + VOID_TO_NPVARIANT(*result); + if (NPVARIANT_IS_OBJECT(object_method_result)) { + // Now return the callbacks return value back to our caller. + // BUG 897451: This should be the same as the + // windowScriptObject, but its not (in Chrome) - or at least, it + // has a different refcount. This means Chrome will delete the + // object before returning it and the calling JS gets a garbage + // value. Firefox handles it fine. + OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(object_method_result), + *result); + } else { + browser->releasevariantvalue(&object_method_result); + VOID_TO_NPVARIANT(*result); + } + return true; + } + } else if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_AND_GET_VALUE]) + return testCallbackAndGetValue(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT]) + return testConstruct(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM]) + return destroyNullStream(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY]) + return testHasProperty(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD]) + return testHasMethod(plugin, args, argCount, result); + else if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) { + browser->setexception(header, "plugin object testThrowException SUCCESS"); + return true; + } + + return false; +} + +static bool pluginInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + INT32_TO_NPVARIANT(1, *result); + return true; +} + +static void pluginInvalidate(NPObject* obj) +{ +} + +static NPObject *pluginAllocate(NPP npp, NPClass *theClass) +{ + PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject)); + + if (!identifiersInitialized) { + identifiersInitialized = true; + initializeIdentifiers(); + } + + newInstance->npp = npp; + newInstance->testObject = browser->createobject(npp, getTestClass()); + newInstance->eventLogging = FALSE; + newInstance->onStreamLoad = 0; + newInstance->onStreamDestroy = 0; + newInstance->onURLNotify = 0; + newInstance->logDestroy = FALSE; + newInstance->logSetWindow = FALSE; + newInstance->returnErrorFromNewStream = FALSE; + newInstance->stream = 0; + + newInstance->firstUrl = NULL; + newInstance->firstHeaders = NULL; + newInstance->lastUrl = NULL; + newInstance->lastHeaders = NULL; + + return (NPObject*)newInstance; +} + +static void pluginDeallocate(NPObject* header) +{ + PluginObject* plugin = reinterpret_cast<PluginObject*>(header); + browser->releaseobject(plugin->testObject); + + free(plugin->firstUrl); + free(plugin->firstHeaders); + free(plugin->lastUrl); + free(plugin->lastHeaders); + free(plugin); +} + +void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData) +{ + assert(object); + + NPVariant args[2]; + + NPObject *windowScriptObject; + browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject); + + NPIdentifier callbackIdentifier = notifyData; + + INT32_TO_NPVARIANT(reason, args[0]); + + char *strHdr = NULL; + if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) { + // Format expected by JavaScript validator: four fields separated by \n\n: + // First URL; first header block; last URL; last header block. + // Note that header blocks already end with \n due to how NPStream::headers works. + int len = strlen(object->firstUrl) + 2 + + strlen(object->firstHeaders) + 1 + + strlen(object->lastUrl) + 2 + + strlen(object->lastHeaders) + 1; + strHdr = (char*)malloc(len + 1); + snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n", + object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders); + STRINGN_TO_NPVARIANT(strHdr, len, args[1]); + } else + NULL_TO_NPVARIANT(args[1]); + + NPVariant browserResult; + browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult); + browser->releasevariantvalue(&browserResult); + + free(strHdr); +} + +void notifyStream(PluginObject* object, const char *url, const char *headers) +{ + if (object->firstUrl == NULL) { + if (url) + object->firstUrl = strdup(url); + if (headers) + object->firstHeaders = strdup(headers); + } else { + free(object->lastUrl); + free(object->lastHeaders); + object->lastUrl = (url ? strdup(url) : NULL); + object->lastHeaders = (headers ? strdup(headers) : NULL); + } +} + +void testNPRuntime(NPP npp) +{ + NPObject* windowScriptObject; + browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject); + + // Invoke + NPIdentifier testNPInvoke = browser->getstringidentifier("testNPInvoke"); + NPVariant args[7]; + + VOID_TO_NPVARIANT(args[0]); + NULL_TO_NPVARIANT(args[1]); + BOOLEAN_TO_NPVARIANT(true, args[2]); + INT32_TO_NPVARIANT(242, args[3]); + DOUBLE_TO_NPVARIANT(242.242, args[4]); + STRINGZ_TO_NPVARIANT("Hello, World", args[5]); + OBJECT_TO_NPVARIANT(windowScriptObject, args[6]); + + NPVariant result; + if (browser->invoke(npp, windowScriptObject, testNPInvoke, args, 7, &result)) + browser->releasevariantvalue(&result); + + browser->releaseobject(windowScriptObject); +} diff --git a/webkit/tools/pepper_test_plugin/PluginObject.h b/webkit/tools/pepper_test_plugin/PluginObject.h new file mode 100644 index 0000000..7162954 --- /dev/null +++ b/webkit/tools/pepper_test_plugin/PluginObject.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * 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 "webkit/glue/plugins/nphostapi.h" + +extern NPNetscapeFuncs *browser; + +typedef struct { + NPObject header; + NPP npp; + NPBool eventLogging; + NPBool logSetWindow; + NPBool logDestroy; + NPBool returnErrorFromNewStream; + NPObject* testObject; + NPStream* stream; + char* onStreamLoad; + char* onStreamDestroy; + char* onURLNotify; + char* firstUrl; + char* firstHeaders; + char* lastUrl; + char* lastHeaders; +} PluginObject; + +extern NPClass *getPluginClass(void); +extern void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData); +extern void notifyStream(PluginObject* object, const char *url, const char *headers); +extern void testNPRuntime(NPP npp); diff --git a/webkit/tools/pepper_test_plugin/README b/webkit/tools/pepper_test_plugin/README new file mode 100644 index 0000000..f6c57cd7 --- /dev/null +++ b/webkit/tools/pepper_test_plugin/README @@ -0,0 +1,8 @@ +This is a test plugin for manual testing of the Pepper plugin API. See
+ https://wiki.mozilla.org/Plugins:PlatformIndependentNPAPI
+
+To generate a project from the gyp file, use:
+ python ..\..\..\build\gyp_chromium pepper_test_plugin.gyp
+
+To load this plugin in Chrome, use the command line flag:
+ --load-plugin=<<<YOUR CHECKOUT ROOT>>\src\webkit\tools\pepper_test_plugin\Debug\pepper_test_plugin.dll
diff --git a/webkit/tools/pepper_test_plugin/TestObject.cpp b/webkit/tools/pepper_test_plugin/TestObject.cpp new file mode 100644 index 0000000..a839c1e --- /dev/null +++ b/webkit/tools/pepper_test_plugin/TestObject.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * 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 "TestObject.h" +#include "PluginObject.h" + +#include <stdlib.h> + +static bool testEnumerate(NPObject*, NPIdentifier **value, uint32_t *count); +static bool testHasMethod(NPObject*, NPIdentifier name); +static bool testInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool testInvokeDefault(NPObject*, const NPVariant *args, uint32_t argCount, NPVariant *result); +static bool testHasProperty(NPObject*, NPIdentifier name); +static bool testGetProperty(NPObject*, NPIdentifier name, NPVariant *variant); +static NPObject *testAllocate(NPP npp, NPClass *theClass); +static void testDeallocate(NPObject*); +static bool testConstruct(NPObject*, const NPVariant* args, uint32_t argCount, NPVariant* result); + + +static NPClass testClass = { + NP_CLASS_STRUCT_VERSION, + testAllocate, + testDeallocate, + 0, + testHasMethod, + testInvoke, + testInvokeDefault, + testHasProperty, + testGetProperty, + 0, + 0, + testEnumerate, + testConstruct +}; + +NPClass *getTestClass(void) +{ + return &testClass; +} + +int testObjectCount = 0; + +int getTestObjectCount(void) { + return testObjectCount; +} + +static bool identifiersInitialized = false; + +#define NUM_ENUMERABLE_TEST_IDENTIFIERS 4 +#define NUM_TEST_IDENTIFIERS 5 + +#define ID_PROPERTY_FOO 0 +#define ID_PROPERTY_BAR 1 +#define ID_PROPERTY_TEST_OBJECT 2 +#define ID_PROPERTY_REF_COUNT 3 +#define ID_PROPERTY_OBJECT_POINTER 4 + +static NPIdentifier testIdentifiers[NUM_TEST_IDENTIFIERS]; +static const NPUTF8 *testIdentifierNames[NUM_TEST_IDENTIFIERS] = { + "foo", + "bar", + "testObject", + "refCount", + "objectPointer", +}; + +#define ID_THROW_EXCEPTION_METHOD 0 +#define NUM_METHOD_IDENTIFIERS 1 + +static NPIdentifier testMethodIdentifiers[NUM_METHOD_IDENTIFIERS]; +static const NPUTF8 *testMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { + "throwException", +}; + +static void initializeIdentifiers(void) +{ + browser->getstringidentifiers(testIdentifierNames, NUM_TEST_IDENTIFIERS, testIdentifiers); + browser->getstringidentifiers(testMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, testMethodIdentifiers); +} + +static NPObject *testAllocate(NPP npp, NPClass *theClass) +{ + TestObject *newInstance = + static_cast<TestObject*>(malloc(sizeof(TestObject))); + newInstance->testObject = NULL; + ++testObjectCount; + + if (!identifiersInitialized) { + identifiersInitialized = true; + initializeIdentifiers(); + } + + return reinterpret_cast<NPObject*>(newInstance); +} + +static void testDeallocate(NPObject *obj) +{ + TestObject *testObject = reinterpret_cast<TestObject*>(obj); + if (testObject->testObject) + browser->releaseobject(testObject->testObject); + --testObjectCount; + free(obj); +} + +static bool testHasMethod(NPObject*, NPIdentifier name) +{ + for (unsigned i = 0; i < NUM_METHOD_IDENTIFIERS; i++) { + if (testMethodIdentifiers[i] == name) + return true; + } + return false; +} + +static bool testInvoke(NPObject* header, NPIdentifier name, const NPVariant* /*args*/, uint32_t /*argCount*/, NPVariant* /*result*/) +{ + if (name == testMethodIdentifiers[ID_THROW_EXCEPTION_METHOD]) { + browser->setexception(header, "test object throwException SUCCESS"); + return true; + } + return false; +} + +static bool testInvokeDefault(NPObject *obj, const NPVariant *args, + uint32_t argCount, NPVariant *result) +{ + INT32_TO_NPVARIANT(2, *result); + return true; +} + +static bool testHasProperty(NPObject*, NPIdentifier name) +{ + for (unsigned i = 0; i < NUM_TEST_IDENTIFIERS; i++) { + if (testIdentifiers[i] == name) + return true; + } + + return false; +} + +static bool testGetProperty(NPObject *obj, NPIdentifier name, + NPVariant *variant) +{ + if (name == testIdentifiers[ID_PROPERTY_FOO]) { + char* mem = static_cast<char*>(browser->memalloc(4)); + strcpy(mem, "foo"); + STRINGZ_TO_NPVARIANT(mem, *variant); + return true; + } else if (name == testIdentifiers[ID_PROPERTY_BAR]) { + BOOLEAN_TO_NPVARIANT(true, *variant); + return true; + } else if (name == testIdentifiers[ID_PROPERTY_TEST_OBJECT]) { + TestObject* testObject = reinterpret_cast<TestObject*>(obj); + if (testObject->testObject == NULL) + testObject->testObject = browser->createobject(NULL, &testClass); + browser->retainobject(testObject->testObject); + OBJECT_TO_NPVARIANT(testObject->testObject, *variant); + return true; + } else if (name == testIdentifiers[ID_PROPERTY_REF_COUNT]) { + INT32_TO_NPVARIANT(obj->referenceCount, *variant); + return true; + } else if (name == testIdentifiers[ID_PROPERTY_OBJECT_POINTER]) { + int32_t objectPointer = static_cast<int32_t>(reinterpret_cast<long long>(obj)); + INT32_TO_NPVARIANT(objectPointer, *variant); + return true; + } + return false; +} + +static bool testEnumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count) +{ + *count = NUM_ENUMERABLE_TEST_IDENTIFIERS; + + *value = (NPIdentifier*)browser->memalloc(NUM_ENUMERABLE_TEST_IDENTIFIERS * sizeof(NPIdentifier)); + memcpy(*value, testIdentifiers, sizeof(NPIdentifier) * NUM_ENUMERABLE_TEST_IDENTIFIERS); + + return true; +} + +static bool testConstruct(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + browser->retainobject(npobj); + + // Just return the same object. + OBJECT_TO_NPVARIANT(npobj, *result); + return true; +} + + diff --git a/webkit/tools/pepper_test_plugin/TestObject.h b/webkit/tools/pepper_test_plugin/TestObject.h new file mode 100644 index 0000000..fba904b --- /dev/null +++ b/webkit/tools/pepper_test_plugin/TestObject.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * 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 "third_party/npapi/bindings/npapi.h" +#include "third_party/npapi/bindings/npruntime.h" + + +typedef struct { + NPObject header; + NPObject* testObject; +} TestObject; + +NPClass *getTestClass(void); +int getTestObjectCount(void); diff --git a/webkit/tools/pepper_test_plugin/main.cpp b/webkit/tools/pepper_test_plugin/main.cpp new file mode 100644 index 0000000..e0862fe --- /dev/null +++ b/webkit/tools/pepper_test_plugin/main.cpp @@ -0,0 +1,513 @@ +/* + IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in + consideration of your agreement to the following terms, and your use, installation, + modification or redistribution of this Apple software constitutes acceptance of these + terms. If you do not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject to these + terms, Apple grants you a personal, non-exclusive license, under Appleās copyrights in + this original Apple software (the "Apple Software"), to use, reproduce, modify and + redistribute the Apple Software, with or without modifications, in source and/or binary + forms; provided that if you redistribute the Apple Software in its entirety and without + modifications, you must retain this notice and the following text and disclaimers in all + such redistributions of the Apple Software. Neither the name, trademarks, service marks + or logos of Apple Computer, Inc. may be used to endorse or promote products derived from + the Apple Software without specific prior written permission from Apple. Except as expressly + stated in this notice, no other rights or licenses, express or implied, are granted by Apple + herein, including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS + USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, + REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND + WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR + OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include "PluginObject.h" + +#ifdef WIN32 +#define strcasecmp _stricmp +#define NPAPI WINAPI +#else +#define NPAPI +#endif + +#if defined(OS_LINUX) +#include <X11/Xlib.h> +#endif + +static void log(NPP instance, const char* format, ...) +{ + va_list args; + va_start(args, format); + char message[2048] = "PLUGIN: "; + vsprintf(message + strlen(message), format, args); + va_end(args); + + NPObject* windowObject = 0; + NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject); + if (error != NPERR_NO_ERROR) { + fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message); + return; + } + + NPVariant consoleVariant; + if (!browser->getproperty(instance, windowObject, browser->getstringidentifier("console"), &consoleVariant)) { + fprintf(stderr, "Failed to retrieve console object while logging: %s\n", message); + browser->releaseobject(windowObject); + return; + } + + NPObject* consoleObject = NPVARIANT_TO_OBJECT(consoleVariant); + + NPVariant messageVariant; + STRINGZ_TO_NPVARIANT(message, messageVariant); + + NPVariant result; + if (!browser->invoke(instance, consoleObject, browser->getstringidentifier("log"), &messageVariant, 1, &result)) { + fprintf(stderr, "Failed to invoke console.log while logging: %s\n", message); + browser->releaseobject(consoleObject); + browser->releaseobject(windowObject); + return; + } + + browser->releasevariantvalue(&result); + browser->releaseobject(consoleObject); + browser->releaseobject(windowObject); +} + +// Plugin entry points +extern "C" { + NPError NPAPI NP_Initialize(NPNetscapeFuncs *browserFuncs +#if defined(OS_LINUX) + , NPPluginFuncs *pluginFuncs +#endif + ); + NPError NPAPI NP_GetEntryPoints(NPPluginFuncs *pluginFuncs); + void NPAPI NP_Shutdown(void); + +#if defined(OS_LINUX) + NPError NP_GetValue(NPP instance, NPPVariable variable, void *value); + const char* NP_GetMIMEDescription(void); +#endif +} + +// Plugin entry points +NPError NPAPI NP_Initialize(NPNetscapeFuncs *browserFuncs +#if defined(OS_LINUX) + , NPPluginFuncs *pluginFuncs +#endif +) +{ + browser = browserFuncs; +#if defined(OS_LINUX) + return NP_GetEntryPoints(pluginFuncs); +#else + return NPERR_NO_ERROR; +#endif +} + +NPError NPAPI NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) +{ + pluginFuncs->version = 11; + pluginFuncs->size = sizeof(pluginFuncs); + pluginFuncs->newp = NPP_New; + pluginFuncs->destroy = NPP_Destroy; + pluginFuncs->setwindow = NPP_SetWindow; + pluginFuncs->newstream = NPP_NewStream; + pluginFuncs->destroystream = NPP_DestroyStream; + pluginFuncs->asfile = NPP_StreamAsFile; + pluginFuncs->writeready = NPP_WriteReady; + pluginFuncs->write = (NPP_WriteProcPtr)NPP_Write; + pluginFuncs->print = NPP_Print; + pluginFuncs->event = NPP_HandleEvent; + pluginFuncs->urlnotify = NPP_URLNotify; + pluginFuncs->getvalue = NPP_GetValue; + pluginFuncs->setvalue = NPP_SetValue; + + return NPERR_NO_ERROR; +} + +void NPAPI NP_Shutdown(void) +{ +} + +static void executeScript(const PluginObject* obj, const char* script); + +NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char *argn[], char *argv[], NPSavedData *saved) +{ + if (browser->version >= 14) { + PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass()); + + for (int i = 0; i < argc; i++) { + 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], "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) { + log(instance, "src: %s", argv[i]); + fflush(stdout); + } + } + } else if (strcasecmp(argn[i], "cleardocumentduringnew") == 0) + executeScript(obj, "document.body.innerHTML = ''"); + } + + instance->pdata = obj; + } + + // On Windows and Unix, plugins only get events if they are windowless. + return browser->setvalue(instance, NPPVpluginWindowBool, NULL); +} + +NPError NPP_Destroy(NPP instance, NPSavedData **save) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + if (obj) { + if (obj->onStreamLoad) + free(obj->onStreamLoad); + + if (obj->onURLNotify) + free(obj->onURLNotify); + + if (obj->onStreamDestroy) + free(obj->onStreamDestroy); + + if (obj->logDestroy) + log(instance, "NPP_Destroy"); + + browser->releaseobject(&obj->header); + } + + fflush(stdout); + + return NPERR_NO_ERROR; +} + +NPError NPP_SetWindow(NPP instance, NPWindow *window) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + + if (obj) { + if (obj->logSetWindow) { + log(instance, "NPP_SetWindow: %d %d", (int)window->width, (int)window->height); + fflush(stdout); + obj->logSetWindow = false; + } + } + + return NPERR_NO_ERROR; +} + +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); +} + +NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + + if (obj->returnErrorFromNewStream) + return NPERR_GENERIC_ERROR; + + obj->stream = stream; + *stype = NP_ASFILEONLY; + + if (browser->version >= NPVERS_HAS_RESPONSE_HEADERS) + notifyStream(obj, stream->url, stream->headers); + + if (obj->onStreamLoad) + executeScript(obj, obj->onStreamLoad); + + return NPERR_NO_ERROR; +} + +NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + + if (obj->onStreamDestroy) + executeScript(obj, obj->onStreamDestroy); + + return NPERR_NO_ERROR; +} + +int32 NPP_WriteReady(NPP instance, NPStream *stream) +{ + return 0; +} + +int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer) +{ + return 0; +} + +void NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) +{ +} + +void NPP_Print(NPP instance, NPPrint *platformPrint) +{ +} + +int16 NPP_HandleEvent(NPP instance, void *event) +{ + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + if (!obj->eventLogging) + return 0; + +#ifdef WIN32 + // Below is the event handling code. Per the NPAPI spec, the events don't + // map directly between operating systems: + // http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/structures5.html#1000000 + NPEvent* evt = static_cast<NPEvent*>(event); + short x = static_cast<short>(evt->lParam & 0xffff); + short y = static_cast<short>(evt->lParam >> 16); + switch (evt->event) { + case WM_PAINT: + log(instance, "updateEvt"); + break; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + log(instance, "mouseDown at (%d, %d)", x, y); + break; + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + log(instance, "mouseUp at (%d, %d)", x, y); + break; + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + break; + case WM_MOUSEMOVE: + log(instance, "adjustCursorEvent"); + break; + case WM_KEYUP: + // TODO(tc): We need to convert evt->wParam from virtual-key code + // to key code. + log(instance, "NOTIMPLEMENTED: keyUp '%c'", ' '); + break; + case WM_KEYDOWN: + // TODO(tc): We need to convert evt->wParam from virtual-key code + // to key code. + log(instance, "NOTIMPLEMENTED: keyDown '%c'", ' '); + break; + case WM_SETCURSOR: + break; + case WM_SETFOCUS: + log(instance, "getFocusEvent"); + break; + case WM_KILLFOCUS: + log(instance, "loseFocusEvent"); + break; + default: + log(instance, "event %d", evt->event); + } + + fflush(stdout); + +#elif defined(OS_LINUX) + XEvent* evt = static_cast<XEvent*>(event); + XButtonPressedEvent* bpress_evt = reinterpret_cast<XButtonPressedEvent*>(evt); + XButtonReleasedEvent* brelease_evt = reinterpret_cast<XButtonReleasedEvent*>(evt); + switch (evt->type) { + case ButtonPress: + log(instance, "mouseDown at (%d, %d)", bpress_evt->x, bpress_evt->y); + break; + case ButtonRelease: + log(instance, "mouseUp at (%d, %d)", brelease_evt->x, brelease_evt->y); + break; + case KeyPress: + // TODO: extract key code + log(instance, "NOTIMPLEMENTED: keyDown '%c'", ' '); + break; + case KeyRelease: + // TODO: extract key code + log(instance, "NOTIMPLEMENTED: keyUp '%c'", ' '); + break; + case GraphicsExpose: + log(instance, "updateEvt"); + break; + // NPAPI events + case FocusIn: + log(instance, "getFocusEvent"); + break; + case FocusOut: + log(instance, "loseFocusEvent"); + break; + case EnterNotify: + case LeaveNotify: + case MotionNotify: + log(instance, "adjustCursorEvent"); + break; + default: + log(instance, "event %d", evt->type); + } + + fflush(stdout); +#else + +#ifdef MAC_EVENT_CODE_DISABLED_DUE_TO_ERRORS +// This code apparently never built on Mac, but Mac was previously +// using the Linux branch. It doesn't quite build. +// warning: 'GlobalToLocal' is deprecated (declared at +// .../Frameworks/QD.framework/Headers/QuickdrawAPI.h:2181) + EventRecord* evt = static_cast<EventRecord*>(event); + Point pt = { evt->where.v, evt->where.h }; + switch (evt->what) { + case nullEvent: + // these are delivered non-deterministically, don't log. + break; + case mouseDown: + GlobalToLocal(&pt); + log(instance, "mouseDown at (%d, %d)", pt.h, pt.v); + break; + case mouseUp: + GlobalToLocal(&pt); + log(instance, "mouseUp at (%d, %d)", pt.h, pt.v); + break; + case keyDown: + log(instance, "keyDown '%c'", (char)(evt->message & 0xFF)); + break; + case keyUp: + log(instance, "keyUp '%c'", (char)(evt->message & 0xFF)); + break; + case autoKey: + log(instance, "autoKey '%c'", (char)(evt->message & 0xFF)); + break; + case updateEvt: + log(instance, "updateEvt"); + break; + case diskEvt: + log(instance, "diskEvt"); + break; + case activateEvt: + log(instance, "activateEvt"); + break; + case osEvt: + switch ((evt->message & 0xFF000000) >> 24) { + case suspendResumeMessage: + log(instance, "osEvt - %s", (evt->message & 0x1) ? "resume" : "suspend"); + break; + case mouseMovedMessage: + log(instance, "osEvt - mouseMoved"); + break; + default: + log(instance, "osEvt - %08lX", evt->message); + } + break; + case kHighLevelEvent: + log(instance, "kHighLevelEvent"); + break; + // NPAPI events + case getFocusEvent: + log(instance, "getFocusEvent"); + break; + case loseFocusEvent: + log(instance, "loseFocusEvent"); + break; + case adjustCursorEvent: + log(instance, "adjustCursorEvent"); + break; + default: + log(instance, "event %d", evt->what); + } +#endif // MAC_EVENT_CODE_DISABLED_DUE_TO_ERRORS + +#endif + + return 0; +} + +void NPP_URLNotify(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); +} + +NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value) +{ + NPError err = NPERR_NO_ERROR; + + switch (variable) { +#if defined(OS_LINUX) + case NPPVpluginNameString: + *((const char **)value) = "Pepper Test PlugIn"; + break; + case NPPVpluginDescriptionString: + *((const char **)value) = "Simple Pepper plug-in for manual testing."; + break; + case NPPVpluginNeedsXEmbed: + *((NPBool *)value) = TRUE; + break; +#endif + case NPPVpluginScriptableNPObject: { + void **v = (void **)value; + PluginObject* obj = static_cast<PluginObject*>(instance->pdata); + // Return value is expected to be retained + browser->retainobject((NPObject *)obj); + *v = obj; + break; + } + default: + fprintf(stderr, "Unhandled variable to NPP_GetValue\n"); + err = NPERR_GENERIC_ERROR; + break; + } + + return err; +} + +NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value) +{ + return NPERR_GENERIC_ERROR; +} + +#if defined(OS_LINUX) +NPError NP_GetValue(NPP instance, NPPVariable variable, void *value) +{ + return NPP_GetValue(instance, variable, value); +} + +const char* NP_GetMIMEDescription(void) { + // The layout test LayoutTests/fast/js/navigator-mimeTypes-length.html + // asserts that the number of mimetypes handled by plugins should be + // greater than the number of plugins. This isn't true if we're + // the only plugin and we only handle one mimetype, so specify + // multiple mimetypes here. + return "pepper-application/x-pepper-test-plugin pepper test;"; +} +#endif diff --git a/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp b/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp new file mode 100644 index 0000000..c05db65 --- /dev/null +++ b/webkit/tools/pepper_test_plugin/pepper_test_plugin.gyp @@ -0,0 +1,33 @@ +
+{
+ 'targets': [
+ {
+ 'target_name': 'pepper_test_plugin',
+ 'type': 'shared_library',
+ 'dependencies': [
+ '../../../third_party/npapi/npapi.gyp:npapi',
+ ],
+ 'include_dirs': [
+ '../../..', # Root of Chrome Checkout
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'product_name': 'pepper_test_plugin',
+ 'msvs_guid': 'EE00E36E-9E8C-4DFB-925E-FBE32CEDB91A',
+ 'msvs_settings': {
+ },
+ 'sources': [
+ 'pepper_test_plugin.rc',
+ ],
+ }]
+ ],
+ 'sources': [
+ 'main.cpp',
+ 'PluginObject.cpp',
+ 'PluginObject.h',
+ 'TestObject.cpp',
+ 'TestObject.h',
+ ],
+ }
+ ],
+}
diff --git a/webkit/tools/pepper_test_plugin/pepper_test_plugin.rc b/webkit/tools/pepper_test_plugin/pepper_test_plugin.rc new file mode 100644 index 0000000..0faaafa --- /dev/null +++ b/webkit/tools/pepper_test_plugin/pepper_test_plugin.rc @@ -0,0 +1,30 @@ +1 VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+ FILEFLAGS 0x0L
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Google"
+ VALUE "FileDescription", "Pepper Test Plugin"
+ VALUE "FileVersion", "1, 0, 0, 1"
+ VALUE "InternalName", "pepper_test_plugin"
+ VALUE "LegalCopyright", "Copyright (C) 2009"
+ VALUE "OriginalFilename", "pepper_test_plugin.dll"
+ VALUE "ProductName", "Pepper Test Plugin"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ VALUE "MIMEType", "pepper-application/x-pepper-test-plugin"
+ VALUE "FileExtents", "ptp"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
|