Home | History | Annotate | Download | only in plugin
      1 /*
      2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
      3  * Copyright (C) 2009 Holger Hans Peter Freyther
      4  * Copyright (C) 2010 Collabora Ltd.
      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 "PluginObject.h"
     29 
     30 #include "PluginTest.h"
     31 #include "TestObject.h"
     32 #include <assert.h>
     33 #include <stdarg.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 
     38 // Helper function which takes in the plugin window object for logging to the console object.
     39 static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message)
     40 {
     41     NPVariant consoleVariant;
     42     if (!browser->getproperty(instance, windowObject, browser->getstringidentifier("console"), &consoleVariant)) {
     43         fprintf(stderr, "Failed to retrieve console object while logging: %s\n", message);
     44         return;
     45     }
     46 
     47     NPObject* consoleObject = NPVARIANT_TO_OBJECT(consoleVariant);
     48 
     49     NPVariant messageVariant;
     50     STRINGZ_TO_NPVARIANT(message, messageVariant);
     51 
     52     NPVariant result;
     53     if (!browser->invoke(instance, consoleObject, browser->getstringidentifier("log"), &messageVariant, 1, &result)) {
     54         fprintf(stderr, "Failed to invoke console.log while logging: %s\n", message);
     55         browser->releaseobject(consoleObject);
     56         return;
     57     }
     58 
     59     browser->releasevariantvalue(&result);
     60     browser->releaseobject(consoleObject);
     61 }
     62 
     63 void pluginLogWithArguments(NPP instance, const char* format, va_list args)
     64 {
     65     const size_t messageBufferSize = 2048;
     66     char message[messageBufferSize] = "PLUGIN: ";
     67     int messageLength = sizeof("PLUGIN: ") - 1;
     68     messageLength += vsnprintf(message + messageLength, messageBufferSize - 1 - messageLength, format, args);
     69     message[messageLength] = '\0';
     70 
     71     NPObject* windowObject = 0;
     72     NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject);
     73     if (error != NPERR_NO_ERROR) {
     74         fprintf(stderr, "Failed to retrieve window object while logging: %s\n", message);
     75         return;
     76     }
     77 
     78     pluginLogWithWindowObject(windowObject, instance, message);
     79     browser->releaseobject(windowObject);
     80 }
     81 
     82 // Helper function to log to the console object.
     83 void pluginLog(NPP instance, const char* format, ...)
     84 {
     85     va_list args;
     86     va_start(args, format);
     87     pluginLogWithArguments(instance, format, args);
     88     va_end(args);
     89 }
     90 
     91 static void pluginInvalidate(NPObject*);
     92 static bool pluginHasProperty(NPObject*, NPIdentifier name);
     93 static bool pluginHasMethod(NPObject*, NPIdentifier name);
     94 static bool pluginGetProperty(NPObject*, NPIdentifier name, NPVariant*);
     95 static bool pluginSetProperty(NPObject*, NPIdentifier name, const NPVariant*);
     96 static bool pluginInvoke(NPObject*, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result);
     97 static NPObject* pluginAllocate(NPP npp, NPClass*);
     98 static void pluginDeallocate(NPObject*);
     99 
    100 NPNetscapeFuncs* browser;
    101 NPPluginFuncs* pluginFunctions;
    102 
    103 static NPClass pluginClass_ = {
    104     NP_CLASS_STRUCT_VERSION,
    105     pluginAllocate,
    106     pluginDeallocate,
    107     pluginInvalidate,
    108     pluginHasMethod,
    109     pluginInvoke,
    110     0, // NPClass::invokeDefault,
    111     pluginHasProperty,
    112     pluginGetProperty,
    113     pluginSetProperty,
    114     0, // NPClass::removeProperty
    115     0, // NPClass::enumerate
    116     0, // NPClass::construct
    117 };
    118 
    119 NPClass* createPluginClass(void)
    120 {
    121     NPClass* pluginClass = new NPClass;
    122     *pluginClass = pluginClass_;
    123     return pluginClass;
    124 }
    125 
    126 static bool identifiersInitialized = false;
    127 
    128 enum {
    129     ID_PROPERTY_PROPERTY = 0,
    130     ID_PROPERTY_EVENT_LOGGING,
    131     ID_PROPERTY_HAS_STREAM,
    132     ID_PROPERTY_TEST_OBJECT,
    133     ID_PROPERTY_LOG_DESTROY,
    134     ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM,
    135     ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE,
    136     ID_PROPERTY_THROW_EXCEPTION_PROPERTY,
    137     ID_LAST_SET_WINDOW_ARGUMENTS,
    138     ID_PROPERTY_WINDOWED_PLUGIN,
    139     ID_PROPERTY_TEST_OBJECT_COUNT,
    140     ID_PROPERTY_DELETE_IN_GET_PROPERTY,
    141     ID_PROPERTY_DELETE_IN_HAS_PROPERTY_RETURN_TRUE,
    142     ID_PROPERTY_DELETE_IN_SET_PROPERTY,
    143     NUM_PROPERTY_IDENTIFIERS
    144 };
    145 
    146 static NPIdentifier pluginPropertyIdentifiers[NUM_PROPERTY_IDENTIFIERS];
    147 static const NPUTF8 *pluginPropertyIdentifierNames[NUM_PROPERTY_IDENTIFIERS] = {
    148     "property",
    149     "eventLoggingEnabled",
    150     "hasStream",
    151     "testObject",
    152     "logDestroy",
    153     "returnErrorFromNewStream",
    154     "returnNegativeOneFromWrite",
    155     "testThrowExceptionProperty",
    156     "lastSetWindowArguments",
    157     "windowedPlugin",
    158     "testObjectCount",
    159     "deletePluginInGetProperty",
    160     "deletePluginInHasPropertyReturnTrue",
    161     "deletePluginInSetProperty"
    162 };
    163 
    164 enum {
    165     ID_TEST_CALLBACK_METHOD = 0,
    166     ID_TEST_CALLBACK_METHOD_RETURN,
    167     ID_TEST_GETURL,
    168     ID_TEST_DOM_ACCESS,
    169     ID_TEST_GET_URL_NOTIFY,
    170     ID_TEST_INVOKE_DEFAULT,
    171     ID_DESTROY_STREAM,
    172     ID_TEST_ENUMERATE,
    173     ID_TEST_GETINTIDENTIFIER,
    174     ID_TEST_GET_PROPERTY,
    175     ID_TEST_HAS_PROPERTY,
    176     ID_TEST_HAS_METHOD,
    177     ID_TEST_EVALUATE,
    178     ID_TEST_GET_PROPERTY_RETURN_VALUE,
    179     ID_TEST_IDENTIFIER_TO_STRING,
    180     ID_TEST_IDENTIFIER_TO_INT,
    181     ID_TEST_PASS_TEST_OBJECT,
    182     ID_TEST_POSTURL_FILE,
    183     ID_TEST_CONSTRUCT,
    184     ID_TEST_THROW_EXCEPTION_METHOD,
    185     ID_TEST_FAIL_METHOD,
    186     ID_TEST_CLONE_OBJECT,
    187     ID_TEST_SCRIPT_OBJECT_INVOKE,
    188     ID_TEST_CREATE_TEST_OBJECT,
    189     ID_DESTROY_NULL_STREAM,
    190     ID_TEST_RELOAD_PLUGINS_NO_PAGES,
    191     ID_TEST_RELOAD_PLUGINS_AND_PAGES,
    192     ID_TEST_GET_BROWSER_PROPERTY,
    193     ID_TEST_SET_BROWSER_PROPERTY,
    194     ID_REMEMBER,
    195     ID_GET_REMEMBERED_OBJECT,
    196     ID_GET_AND_FORGET_REMEMBERED_OBJECT,
    197     ID_REF_COUNT,
    198     ID_SET_STATUS,
    199     ID_RESIZE_TO,
    200     ID_NORMALIZE,
    201     ID_INVALIDATE_RECT,
    202     ID_OBJECTS_ARE_SAME,
    203     ID_TEST_DELETE_WITHIN_INVOKE,
    204     NUM_METHOD_IDENTIFIERS
    205 };
    206 
    207 static NPIdentifier pluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
    208 static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
    209     "testCallback",
    210     "testCallbackReturn",
    211     "getURL",
    212     "testDOMAccess",
    213     "getURLNotify",
    214     "testInvokeDefault",
    215     "destroyStream",
    216     "testEnumerate",
    217     "testGetIntIdentifier",
    218     "testGetProperty",
    219     "testHasProperty",
    220     "testHasMethod",
    221     "testEvaluate",
    222     "testGetPropertyReturnValue",
    223     "testIdentifierToString",
    224     "testIdentifierToInt",
    225     "testPassTestObject",
    226     "testPostURLFile",
    227     "testConstruct",
    228     "testThrowException",
    229     "testFail",
    230     "testCloneObject",
    231     "testScriptObjectInvoke",
    232     "testCreateTestObject",
    233     "destroyNullStream",
    234     "reloadPluginsNoPages",
    235     "reloadPluginsAndPages",
    236     "testGetBrowserProperty",
    237     "testSetBrowserProperty",
    238     "remember",
    239     "getRememberedObject",
    240     "getAndForgetRememberedObject",
    241     "refCount",
    242     "setStatus",
    243     "resizeTo",
    244     "normalize",
    245     "invalidateRect",
    246     "objectsAreSame",
    247     "testDeleteWithinInvoke"
    248 };
    249 
    250 static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
    251 {
    252     size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length;
    253     NPUTF8* result = (NPUTF8*)malloc(length + 1);
    254     memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length);
    255     result[length] = '\0';
    256     return result;
    257 }
    258 
    259 static void initializeIdentifiers(void)
    260 {
    261     browser->getstringidentifiers(pluginPropertyIdentifierNames, NUM_PROPERTY_IDENTIFIERS, pluginPropertyIdentifiers);
    262     browser->getstringidentifiers(pluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, pluginMethodIdentifiers);
    263 }
    264 
    265 static bool callDeletePlugin(NPObject* obj, NPIdentifier name, NPIdentifier identifierToMatch)
    266 {
    267     if (name != identifierToMatch)
    268         return false;
    269 
    270     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
    271     NPObject* windowScriptObject;
    272     browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject);
    273 
    274     NPIdentifier callbackIdentifier = browser->getstringidentifier("deletePlugin");
    275     NPVariant browserResult;
    276     if (browser->invoke(plugin->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult))
    277         browser->releasevariantvalue(&browserResult);
    278     return true;
    279 }
    280 
    281 static bool pluginHasProperty(NPObject *obj, NPIdentifier name)
    282 {
    283     if (callDeletePlugin(obj, name, browser->getstringidentifier("deletePluginInHasPropertyReturnFalse")))
    284         return false;
    285 
    286     callDeletePlugin(obj, name, pluginPropertyIdentifiers[ID_PROPERTY_DELETE_IN_HAS_PROPERTY_RETURN_TRUE]);
    287 
    288     for (int i = 0; i < NUM_PROPERTY_IDENTIFIERS; i++)
    289         if (name == pluginPropertyIdentifiers[i])
    290             return true;
    291     return false;
    292 }
    293 
    294 static bool pluginHasMethod(NPObject *obj, NPIdentifier name)
    295 {
    296     if (callDeletePlugin(obj, name, browser->getstringidentifier("deletePluginInHasMethod")))
    297         return true;
    298 
    299     for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++)
    300         if (name == pluginMethodIdentifiers[i])
    301             return true;
    302     return false;
    303 }
    304 
    305 static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* result)
    306 {
    307     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
    308     if (name == pluginPropertyIdentifiers[ID_PROPERTY_PROPERTY]) {
    309         static const char* originalString = "property";
    310         char* buf = static_cast<char*>(browser->memalloc(strlen(originalString) + 1));
    311         strcpy(buf, originalString);
    312         STRINGZ_TO_NPVARIANT(buf, *result);
    313         return true;
    314     }
    315     if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
    316         BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result);
    317         return true;
    318     }
    319     if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
    320         BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result);
    321         return true;
    322     }
    323     if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) {
    324         BOOLEAN_TO_NPVARIANT(plugin->stream, *result);
    325         return true;
    326     }
    327     if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) {
    328         NPObject* testObject = plugin->testObject;
    329         browser->retainobject(testObject);
    330         OBJECT_TO_NPVARIANT(testObject, *result);
    331         return true;
    332     }
    333     if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
    334         BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result);
    335         return true;
    336     }
    337     if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) {
    338         BOOLEAN_TO_NPVARIANT(plugin->returnNegativeOneFromWrite, *result);
    339         return true;
    340     }
    341     if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
    342         browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
    343         return true;
    344     }
    345     if (name == pluginPropertyIdentifiers[ID_LAST_SET_WINDOW_ARGUMENTS]) {
    346         char* buf = static_cast<char*>(browser->memalloc(256));
    347         snprintf(buf, 256, "x: %d, y: %d, width: %u, height: %u, clipRect: (%u, %u, %u, %u)", (int)plugin->lastWindow.x, (int)plugin->lastWindow.y, (unsigned)plugin->lastWindow.width, (unsigned)plugin->lastWindow.height,
    348             plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.top, plugin->lastWindow.clipRect.right - plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.bottom - plugin->lastWindow.clipRect.top);
    349 
    350         STRINGZ_TO_NPVARIANT(buf, *result);
    351         return true;
    352     }
    353     if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT_COUNT]) {
    354         INT32_TO_NPVARIANT(getTestObjectCount(), *result);
    355         return true;
    356     }
    357 
    358     if (name == pluginPropertyIdentifiers[ID_PROPERTY_DELETE_IN_GET_PROPERTY]) {
    359         browser->retainobject(obj);
    360         callDeletePlugin(obj, name, pluginPropertyIdentifiers[ID_PROPERTY_DELETE_IN_GET_PROPERTY]);
    361         NPObject* testObject = plugin->testObject;
    362         browser->retainobject(testObject);
    363         OBJECT_TO_NPVARIANT(testObject, *result);
    364         browser->releaseobject(obj);
    365         return true;
    366     }
    367 
    368     return false;
    369 }
    370 
    371 static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant)
    372 {
    373     PluginObject* plugin = reinterpret_cast<PluginObject*>(obj);
    374     if (callDeletePlugin(obj, name, pluginPropertyIdentifiers[ID_PROPERTY_DELETE_IN_SET_PROPERTY]))
    375         return true;
    376 
    377     if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) {
    378         plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant);
    379         return true;
    380     }
    381     if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) {
    382         plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant);
    383         return true;
    384     }
    385     if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) {
    386         plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant);
    387         return true;
    388     }
    389     if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) {
    390         plugin->returnNegativeOneFromWrite = NPVARIANT_TO_BOOLEAN(*variant);
    391         return true;
    392     }
    393     if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) {
    394         browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS");
    395         return true;
    396     }
    397     if (name == pluginPropertyIdentifiers[ID_PROPERTY_WINDOWED_PLUGIN]) {
    398         browser->setvalue(plugin->npp, NPPVpluginWindowBool, (void *)NPVARIANT_TO_BOOLEAN(*variant));
    399         return true;
    400     }
    401 
    402     return false;
    403 }
    404 
    405 static bool testDOMAccess(PluginObject* obj, const NPVariant*, uint32_t, NPVariant* result)
    406 {
    407     // Get plug-in's DOM element
    408     NPObject* elementObject;
    409     if (browser->getvalue(obj->npp, NPNVPluginElementNPObject, &elementObject) == NPERR_NO_ERROR) {
    410         // Get style
    411         NPVariant styleVariant;
    412         NPIdentifier styleIdentifier = browser->getstringidentifier("style");
    413         if (browser->getproperty(obj->npp, elementObject, styleIdentifier, &styleVariant) && NPVARIANT_IS_OBJECT(styleVariant)) {
    414             // Set style.border
    415             NPIdentifier borderIdentifier = browser->getstringidentifier("border");
    416             NPVariant borderVariant;
    417             STRINGZ_TO_NPVARIANT("3px solid red", borderVariant);
    418             browser->setproperty(obj->npp, NPVARIANT_TO_OBJECT(styleVariant), borderIdentifier, &borderVariant);
    419             browser->releasevariantvalue(&styleVariant);
    420         }
    421 
    422         browser->releaseobject(elementObject);
    423     }
    424     VOID_TO_NPVARIANT(*result);
    425     return true;
    426 }
    427 
    428 static NPIdentifier stringVariantToIdentifier(NPVariant variant)
    429 {
    430     assert(NPVARIANT_IS_STRING(variant));
    431     NPUTF8* utf8String = createCStringFromNPVariant(&variant);
    432     NPIdentifier identifier = browser->getstringidentifier(utf8String);
    433     free(utf8String);
    434     return identifier;
    435 }
    436 
    437 static NPIdentifier int32VariantToIdentifier(NPVariant variant)
    438 {
    439     assert(NPVARIANT_IS_INT32(variant));
    440     int32_t integer = NPVARIANT_TO_INT32(variant);
    441     return browser->getintidentifier(integer);
    442 }
    443 
    444 static NPIdentifier doubleVariantToIdentifier(NPVariant variant)
    445 {
    446     assert(NPVARIANT_IS_DOUBLE(variant));
    447     double value = NPVARIANT_TO_DOUBLE(variant);
    448     // Sadly there is no "getdoubleidentifier"
    449     int32_t integer = static_cast<int32_t>(value);
    450     return browser->getintidentifier(integer);
    451 }
    452 
    453 static NPIdentifier variantToIdentifier(NPVariant variant)
    454 {
    455     if (NPVARIANT_IS_STRING(variant))
    456         return stringVariantToIdentifier(variant);
    457     if (NPVARIANT_IS_INT32(variant))
    458         return int32VariantToIdentifier(variant);
    459     if (NPVARIANT_IS_DOUBLE(variant))
    460         return doubleVariantToIdentifier(variant);
    461     return 0;
    462 }
    463 
    464 static bool testIdentifierToString(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    465 {
    466     if (argCount != 1)
    467         return true;
    468     NPIdentifier identifier = variantToIdentifier(args[0]);
    469     if (!identifier)
    470         return true;
    471     NPUTF8* utf8String = browser->utf8fromidentifier(identifier);
    472     if (!utf8String)
    473         return true;
    474     STRINGZ_TO_NPVARIANT(utf8String, *result);
    475     return true;
    476 }
    477 
    478 static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    479 {
    480     if (argCount != 1)
    481         return false;
    482     NPIdentifier identifier = variantToIdentifier(args[0]);
    483     if (!identifier)
    484         return false;
    485     int32_t integer = browser->intfromidentifier(identifier);
    486     INT32_TO_NPVARIANT(integer, *result);
    487     return true;
    488 }
    489 
    490 static bool testPassTestObject(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    491 {
    492     if (argCount != 2 || !NPVARIANT_IS_STRING(args[0]))
    493         return false;
    494 
    495     NPObject* windowScriptObject;
    496     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    497 
    498     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
    499     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    500     free(callbackString);
    501 
    502     NPVariant browserResult;
    503     browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &browserResult);
    504     browser->releasevariantvalue(&browserResult);
    505 
    506     VOID_TO_NPVARIANT(*result);
    507     return true;
    508 }
    509 
    510 static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    511 {
    512     if (!argCount || !NPVARIANT_IS_STRING(args[0]))
    513         return false;
    514 
    515     NPObject* windowScriptObject;
    516     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    517 
    518     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
    519     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    520     free(callbackString);
    521 
    522     NPVariant browserResult;
    523     if (browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, 0, 0, &browserResult))
    524         browser->releasevariantvalue(&browserResult);
    525 
    526     browser->releaseobject(windowScriptObject);
    527 
    528     VOID_TO_NPVARIANT(*result);
    529     return true;
    530 }
    531 
    532 static bool testCallbackReturn(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    533 {
    534     if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
    535         return false;
    536 
    537     NPObject* windowScriptObject;
    538     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    539 
    540     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
    541     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    542     free(callbackString);
    543 
    544     NPVariant callbackArgs[1];
    545     OBJECT_TO_NPVARIANT(windowScriptObject, callbackArgs[0]);
    546 
    547     NPVariant browserResult;
    548     browser->invoke(obj->npp, windowScriptObject, callbackIdentifier,
    549                     callbackArgs, 1, &browserResult);
    550 
    551     if (NPVARIANT_IS_OBJECT(browserResult))
    552         OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(browserResult), *result);
    553     else {
    554         browser->releasevariantvalue(&browserResult);
    555         VOID_TO_NPVARIANT(*result);
    556     }
    557 
    558     return true;
    559 }
    560 
    561 static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    562 {
    563     if (argCount == 2 && NPVARIANT_IS_STRING(args[0]) && NPVARIANT_IS_STRING(args[1])) {
    564         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
    565         NPUTF8* targetString = createCStringFromNPVariant(&args[1]);
    566         NPError npErr = browser->geturl(obj->npp, urlString, targetString);
    567         free(urlString);
    568         free(targetString);
    569 
    570         INT32_TO_NPVARIANT(npErr, *result);
    571         return true;
    572     }
    573     if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) {
    574         NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
    575         NPError npErr = browser->geturl(obj->npp, urlString, 0);
    576         free(urlString);
    577 
    578         INT32_TO_NPVARIANT(npErr, *result);
    579         return true;
    580     }
    581     return false;
    582 }
    583 
    584 static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    585 {
    586     if (argCount != 3 || !NPVARIANT_IS_STRING(args[0])
    587         || (!NPVARIANT_IS_STRING(args[1]) && !NPVARIANT_IS_NULL(args[1]))
    588         || !NPVARIANT_IS_STRING(args[2]))
    589         return false;
    590 
    591     NPUTF8* urlString = createCStringFromNPVariant(&args[0]);
    592     NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : 0);
    593     NPUTF8* callbackString = createCStringFromNPVariant(&args[2]);
    594 
    595     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    596     browser->geturlnotify(obj->npp, urlString, targetString, callbackIdentifier);
    597 
    598     free(urlString);
    599     free(targetString);
    600     free(callbackString);
    601 
    602     VOID_TO_NPVARIANT(*result);
    603     return true;
    604 }
    605 
    606 static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    607 {
    608     if (!NPVARIANT_IS_OBJECT(args[0]))
    609         return false;
    610 
    611     NPObject* callback = NPVARIANT_TO_OBJECT(args[0]);
    612 
    613     NPVariant invokeArgs[1];
    614     NPVariant browserResult;
    615 
    616     STRINGZ_TO_NPVARIANT("test", invokeArgs[0]);
    617     bool retval = browser->invokeDefault(obj->npp, callback, invokeArgs, 1, &browserResult);
    618 
    619     if (retval)
    620         browser->releasevariantvalue(&browserResult);
    621 
    622     BOOLEAN_TO_NPVARIANT(retval, *result);
    623     return true;
    624 }
    625 
    626 static bool destroyStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    627 {
    628     NPError npError = browser->destroystream(obj->npp, obj->stream, NPRES_USER_BREAK);
    629     INT32_TO_NPVARIANT(npError, *result);
    630     return true;
    631 }
    632 
    633 static bool destroyNullStream(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    634 {
    635     NPError npError = browser->destroystream(obj->npp, 0, NPRES_USER_BREAK);
    636     INT32_TO_NPVARIANT(npError, *result);
    637     return true;
    638 }
    639 
    640 static bool testEnumerate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    641 {
    642     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
    643         return false;
    644 
    645     uint32_t count;
    646     NPIdentifier* identifiers;
    647     if (browser->enumerate(obj->npp, NPVARIANT_TO_OBJECT(args[0]), &identifiers, &count)) {
    648         NPObject* outArray = NPVARIANT_TO_OBJECT(args[1]);
    649         NPIdentifier pushIdentifier = browser->getstringidentifier("push");
    650 
    651         for (uint32_t i = 0; i < count; i++) {
    652             NPUTF8* string = browser->utf8fromidentifier(identifiers[i]);
    653 
    654             if (!string)
    655                 continue;
    656 
    657             NPVariant args[1];
    658             STRINGZ_TO_NPVARIANT(string, args[0]);
    659             NPVariant browserResult;
    660             if (browser->invoke(obj->npp, outArray, pushIdentifier, args, 1, &browserResult))
    661                 browser->releasevariantvalue(&browserResult);
    662             browser->memfree(string);
    663         }
    664 
    665         browser->memfree(identifiers);
    666     }
    667 
    668     VOID_TO_NPVARIANT(*result);
    669     return true;
    670 }
    671 
    672 static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t argCount, NPVariant* result)
    673 {
    674     if (argCount != 1 || !NPVARIANT_IS_DOUBLE(args[0]))
    675         return false;
    676 
    677     NPIdentifier identifier = browser->getintidentifier((int)NPVARIANT_TO_DOUBLE(args[0]));
    678     INT32_TO_NPVARIANT((int32_t)(long long)identifier, *result);
    679     return true;
    680 }
    681 
    682 static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    683 {
    684     if (!argCount)
    685         return false;
    686 
    687     NPObject* object;
    688     browser->getvalue(obj->npp, NPNVWindowNPObject, &object);
    689 
    690     for (uint32_t i = 0; i < argCount; i++) {
    691         assert(NPVARIANT_IS_STRING(args[i]));
    692         NPUTF8* propertyString = createCStringFromNPVariant(&args[i]);
    693         NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    694         free(propertyString);
    695 
    696         NPVariant variant;
    697         bool retval = browser->getproperty(obj->npp, object, propertyIdentifier, &variant);
    698         browser->releaseobject(object);
    699 
    700         if (!retval)
    701             break;
    702 
    703         if (i + 1 < argCount) {
    704             assert(NPVARIANT_IS_OBJECT(variant));
    705             object = NPVARIANT_TO_OBJECT(variant);
    706         } else {
    707             *result = variant;
    708             return true;
    709         }
    710     }
    711 
    712     VOID_TO_NPVARIANT(*result);
    713     return false;
    714 }
    715 
    716 static bool testHasProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    717 {
    718     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    719         return false;
    720 
    721     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
    722     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    723     free(propertyString);
    724 
    725     bool retval = browser->hasproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier);
    726 
    727     BOOLEAN_TO_NPVARIANT(retval, *result);
    728     return true;
    729 }
    730 
    731 static bool testHasMethod(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    732 {
    733     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    734         return false;
    735 
    736     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
    737     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    738     free(propertyString);
    739 
    740     bool retval = browser->hasmethod(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier);
    741 
    742     BOOLEAN_TO_NPVARIANT(retval, *result);
    743     return true;
    744 }
    745 
    746 static bool testEvaluate(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    747 {
    748     if (argCount != 1 || !NPVARIANT_IS_STRING(args[0]))
    749         return false;
    750     NPObject* windowScriptObject;
    751     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    752 
    753     NPString s = NPVARIANT_TO_STRING(args[0]);
    754 
    755     bool retval = browser->evaluate(obj->npp, windowScriptObject, &s, result);
    756     browser->releaseobject(windowScriptObject);
    757     return retval;
    758 }
    759 
    760 static bool testGetPropertyReturnValue(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    761 {
    762     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    763         return false;
    764 
    765     NPUTF8* propertyString = createCStringFromNPVariant(&args[1]);
    766     NPIdentifier propertyIdentifier = browser->getstringidentifier(propertyString);
    767     free(propertyString);
    768 
    769     NPVariant variant;
    770     bool retval = browser->getproperty(obj->npp, NPVARIANT_TO_OBJECT(args[0]), propertyIdentifier, &variant);
    771     if (retval)
    772         browser->releasevariantvalue(&variant);
    773 
    774     BOOLEAN_TO_NPVARIANT(retval, *result);
    775     return true;
    776 }
    777 
    778 static char* toCString(const NPString& string)
    779 {
    780     char* result = static_cast<char*>(malloc(string.UTF8Length + 1));
    781     memcpy(result, string.UTF8Characters, string.UTF8Length);
    782     result[string.UTF8Length] = '\0';
    783 
    784     return result;
    785 }
    786 
    787 static bool testPostURLFile(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    788 {
    789     if (argCount != 4 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]) || !NPVARIANT_IS_STRING(args[2]) || !NPVARIANT_IS_STRING(args[3]))
    790         return false;
    791 
    792     NPString urlString = NPVARIANT_TO_STRING(args[0]);
    793     char* url = toCString(urlString);
    794 
    795     NPString targetString = NPVARIANT_TO_STRING(args[1]);
    796     char* target = toCString(targetString);
    797 
    798     NPString pathString = NPVARIANT_TO_STRING(args[2]);
    799     char* path = toCString(pathString);
    800 
    801     NPString contentsString = NPVARIANT_TO_STRING(args[3]);
    802 
    803     FILE* tempFile = fopen(path, "w");
    804     if (!tempFile)
    805         return false;
    806 
    807     size_t written = fwrite(contentsString.UTF8Characters, contentsString.UTF8Length, 1, tempFile);
    808     fclose(tempFile);
    809     if (!written)
    810         return false;
    811 
    812     NPError error = browser->posturl(obj->npp, url, target, pathString.UTF8Length, path, true);
    813 
    814     free(path);
    815     free(target);
    816     free(url);
    817 
    818     BOOLEAN_TO_NPVARIANT(error == NPERR_NO_ERROR, *result);
    819     return true;
    820 }
    821 
    822 static bool testConstruct(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    823 {
    824     if (!argCount || !NPVARIANT_IS_OBJECT(args[0]))
    825         return false;
    826 
    827     return browser->construct(obj->npp, NPVARIANT_TO_OBJECT(args[0]), args + 1, argCount - 1, result);
    828 }
    829 
    830 // Invoke a script callback to get a script NPObject. Then call a method on the
    831 // script NPObject passing it a freshly created NPObject.
    832 static bool testScriptObjectInvoke(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    833 {
    834     if (argCount != 2 || !NPVARIANT_IS_STRING(args[0]) || !NPVARIANT_IS_STRING(args[1]))
    835         return false;
    836     NPObject* windowScriptObject;
    837     browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject);
    838 
    839     // Arg1 is the name of the callback
    840     NPUTF8* callbackString = createCStringFromNPVariant(&args[0]);
    841     NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString);
    842     free(callbackString);
    843 
    844     // Invoke a callback that returns a script object
    845     NPVariant object_result;
    846     browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &object_result);
    847 
    848     // Script object returned
    849     NPObject* script_object = object_result.value.objectValue;
    850 
    851     // Arg2 is the name of the method to be called on the script object
    852     NPUTF8* object_mehod_string = createCStringFromNPVariant(&args[1]);
    853     NPIdentifier object_method = browser->getstringidentifier(object_mehod_string);
    854     free(object_mehod_string);
    855 
    856     // Create a fresh NPObject to be passed as an argument
    857     NPObject* object_arg = browser->createobject(obj->npp, obj->header._class);
    858 
    859     NPVariant invoke_args[1];
    860     OBJECT_TO_NPVARIANT(object_arg, invoke_args[0]);
    861 
    862     // Invoke the script method
    863     NPVariant object_method_result;
    864     browser->invoke(obj->npp, script_object, object_method, invoke_args, 1, &object_method_result);
    865 
    866     browser->releasevariantvalue(&object_result);
    867     VOID_TO_NPVARIANT(*result);
    868     if (NPVARIANT_IS_OBJECT(object_method_result)) {
    869         // Now return the callbacks return value back to our caller.
    870         // BUG 897451: This should be the same as the
    871         // windowScriptObject, but its not (in Chrome) - or at least, it
    872         // has a different refcount. This means Chrome will delete the
    873         // object before returning it and the calling JS gets a garbage
    874         // value.  Firefox handles it fine.
    875         OBJECT_TO_NPVARIANT(NPVARIANT_TO_OBJECT(object_method_result), *result);
    876     } else {
    877         browser->releasevariantvalue(&object_method_result);
    878         VOID_TO_NPVARIANT(*result);
    879     }
    880 
    881     browser->releaseobject(object_arg);
    882 
    883     return true;
    884 }
    885 
    886 // Helper function to notify the layout test controller that the test completed.
    887 void notifyTestCompletion(NPP npp, NPObject* object)
    888 {
    889     NPVariant result;
    890     NPString script;
    891     script.UTF8Characters = "javascript:window.testRunner.notifyDone();";
    892     script.UTF8Length = strlen("javascript:window.testRunner.notifyDone();");
    893     browser->evaluate(npp, object, &script, &result);
    894     browser->releasevariantvalue(&result);
    895 }
    896 
    897 bool testDocumentOpen(NPP npp)
    898 {
    899     NPIdentifier documentId = browser->getstringidentifier("document");
    900     NPIdentifier openId = browser->getstringidentifier("open");
    901 
    902     NPObject* windowObject = 0;
    903     browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
    904     if (!windowObject)
    905         return false;
    906 
    907     NPVariant docVariant;
    908     browser->getproperty(npp, windowObject, documentId, &docVariant);
    909     if (docVariant.type != NPVariantType_Object) {
    910         browser->releaseobject(windowObject);
    911         return false;
    912     }
    913 
    914     NPObject* documentObject = NPVARIANT_TO_OBJECT(docVariant);
    915 
    916     NPVariant openArgs[2];
    917     STRINGZ_TO_NPVARIANT("text/html", openArgs[0]);
    918     STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
    919 
    920     NPVariant result;
    921     if (!browser->invoke(npp, documentObject, openId, openArgs, 2, &result)) {
    922         browser->releaseobject(windowObject);
    923         browser->releaseobject(documentObject);
    924         return false;
    925     }
    926 
    927     browser->releaseobject(documentObject);
    928 
    929     if (result.type != NPVariantType_Object) {
    930         browser->releaseobject(windowObject);
    931         browser->releasevariantvalue(&result);
    932         return false;
    933     }
    934 
    935     pluginLogWithWindowObject(windowObject, npp, "PLUGIN: DOCUMENT OPEN SUCCESS");
    936     notifyTestCompletion(npp, result.value.objectValue);
    937     browser->releaseobject(result.value.objectValue);
    938     browser->releaseobject(windowObject);
    939     return true;
    940 }
    941 
    942 bool testWindowOpen(NPP npp)
    943 {
    944     NPIdentifier openId = browser->getstringidentifier("open");
    945 
    946     NPObject* windowObject = 0;
    947     browser->getvalue(npp, NPNVWindowNPObject, &windowObject);
    948     if (!windowObject)
    949         return false;
    950 
    951     NPVariant openArgs[2];
    952     STRINGZ_TO_NPVARIANT("about:blank", openArgs[0]);
    953     STRINGZ_TO_NPVARIANT("_blank", openArgs[1]);
    954 
    955     NPVariant result;
    956     if (!browser->invoke(npp, windowObject, openId, openArgs, 2, &result)) {
    957         browser->releaseobject(windowObject);
    958         return false;
    959     }
    960 
    961     if (result.type != NPVariantType_Object) {
    962         browser->releaseobject(windowObject);
    963         browser->releasevariantvalue(&result);
    964         return false;
    965     }
    966 
    967     pluginLogWithWindowObject(windowObject, npp, "PLUGIN: WINDOW OPEN SUCCESS");
    968     notifyTestCompletion(npp, result.value.objectValue);
    969     browser->releaseobject(result.value.objectValue);
    970     browser->releaseobject(windowObject);
    971     return true;
    972 }
    973 
    974 static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    975 {
    976     char* message = 0;
    977     if (argCount && NPVARIANT_IS_STRING(args[0])) {
    978         NPString statusString = NPVARIANT_TO_STRING(args[0]);
    979         message = toCString(statusString);
    980     }
    981 
    982     browser->status(obj->npp, message);
    983 
    984     free(message);
    985     return true;
    986 }
    987 
    988 static bool testResizeTo(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
    989 {
    990     VOID_TO_NPVARIANT(*result);
    991 
    992     NPObject* windowObject;
    993     if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject))
    994         return false;
    995 
    996     NPVariant callResult;
    997     if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("resizePlugin"), args, argCount, &callResult))
    998         browser->releasevariantvalue(&callResult);
    999 
   1000     // Force layout.
   1001     if (browser->getproperty(obj->npp, windowObject, browser->getstringidentifier("pageYOffset"), &callResult))
   1002         browser->releasevariantvalue(&callResult);
   1003 
   1004     return true;
   1005 }
   1006 
   1007 static bool normalizeOverride(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
   1008 {
   1009     VOID_TO_NPVARIANT(*result);
   1010 
   1011     NPObject* windowObject;
   1012     if (NPERR_NO_ERROR != browser->getvalue(obj->npp, NPNVWindowNPObject, &windowObject))
   1013         return false;
   1014 
   1015     NPVariant callResult;
   1016     if (browser->invoke(obj->npp, windowObject, browser->getstringidentifier("pluginCallback"), args, argCount, &callResult))
   1017         browser->releasevariantvalue(&callResult);
   1018 
   1019     return true;
   1020 }
   1021 
   1022 static bool invalidateRect(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
   1023 {
   1024     if (argCount != 4)
   1025         return false;
   1026 
   1027     NPRect rect;
   1028     rect.left = static_cast<int>(NPVARIANT_TO_DOUBLE(args[0]));
   1029     rect.top = static_cast<int>(NPVARIANT_TO_DOUBLE(args[1]));
   1030     rect.right = static_cast<int>(NPVARIANT_TO_DOUBLE(args[2]));
   1031     rect.bottom = static_cast<int>(NPVARIANT_TO_DOUBLE(args[3]));
   1032 
   1033     browser->invalidaterect(obj->npp, &rect);
   1034     return true;
   1035 }
   1036 
   1037 static bool objectsAreSame(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
   1038 {
   1039     if (argCount != 2 || !NPVARIANT_IS_OBJECT(args[0]) || !NPVARIANT_IS_OBJECT(args[1]))
   1040         return false;
   1041 
   1042     BOOLEAN_TO_NPVARIANT(NPVARIANT_TO_OBJECT(args[0]) == NPVARIANT_TO_OBJECT(args[1]), *result);
   1043     return true;
   1044 }
   1045 
   1046 static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
   1047 {
   1048     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
   1049     if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD])
   1050         return testCallback(plugin, args, argCount, result);
   1051     if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD_RETURN])
   1052         return testCallbackReturn(plugin, args, argCount, result);
   1053     if (name == pluginMethodIdentifiers[ID_TEST_GETURL])
   1054         return getURL(plugin, args, argCount, result);
   1055     if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS])
   1056         return testDOMAccess(plugin, args, argCount, result);
   1057     if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY])
   1058         return getURLNotify(plugin, args, argCount, result);
   1059     if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT])
   1060         return testInvokeDefault(plugin, args, argCount, result);
   1061     if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE])
   1062         return testEnumerate(plugin, args, argCount, result);
   1063     if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM])
   1064         return destroyStream(plugin, args, argCount, result);
   1065     if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER])
   1066         return testGetIntIdentifier(plugin, args, argCount, result);
   1067     if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE])
   1068         return testEvaluate(plugin, args, argCount, result);
   1069     if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY])
   1070         return testGetProperty(plugin, args, argCount, result);
   1071     if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE])
   1072         return testGetPropertyReturnValue(plugin, args, argCount, result);
   1073     if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY])
   1074         return testHasProperty(plugin, args, argCount, result);
   1075     if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD])
   1076         return testHasMethod(plugin, args, argCount, result);
   1077     if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING])
   1078         return testIdentifierToString(plugin, args, argCount, result);
   1079     if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT])
   1080         return testIdentifierToInt(plugin, args, argCount, result);
   1081     if (name == pluginMethodIdentifiers[ID_TEST_PASS_TEST_OBJECT])
   1082         return testPassTestObject(plugin, args, argCount, result);
   1083     if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE])
   1084         return testPostURLFile(plugin, args, argCount, result);
   1085     if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT])
   1086         return testConstruct(plugin, args, argCount, result);
   1087     if (name == pluginMethodIdentifiers[ID_TEST_SCRIPT_OBJECT_INVOKE])
   1088         return testScriptObjectInvoke(plugin, args, argCount, result);
   1089     if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) {
   1090         browser->setexception(header, "plugin object testThrowException SUCCESS");
   1091         return true;
   1092     }
   1093     if (name == pluginMethodIdentifiers[ID_TEST_FAIL_METHOD]) {
   1094         NPObject* windowScriptObject;
   1095         browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject);
   1096         browser->invoke(plugin->npp, windowScriptObject, name, args, argCount, result);
   1097         return false;
   1098     }
   1099     if (name == pluginMethodIdentifiers[ID_TEST_CLONE_OBJECT]) {
   1100         NPObject* new_object = browser->createobject(plugin->npp, plugin->header._class);
   1101         assert(new_object->referenceCount == 1);
   1102         OBJECT_TO_NPVARIANT(new_object, *result);
   1103         return true;
   1104     }
   1105     if (name == pluginMethodIdentifiers[ID_TEST_CREATE_TEST_OBJECT]) {
   1106         NPObject* testObject = browser->createobject(plugin->npp, getTestClass());
   1107         assert(testObject->referenceCount == 1);
   1108         OBJECT_TO_NPVARIANT(testObject, *result);
   1109         return true;
   1110     }
   1111     if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM])
   1112         return destroyNullStream(plugin, args, argCount, result);
   1113     if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) {
   1114         browser->reloadplugins(false);
   1115         return true;
   1116     }
   1117     if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) {
   1118         browser->reloadplugins(true);
   1119         return true;
   1120     }
   1121     if (name == pluginMethodIdentifiers[ID_TEST_GET_BROWSER_PROPERTY]) {
   1122         browser->getproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), result);
   1123         return true;
   1124     }
   1125     if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) {
   1126         browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]);
   1127         return true;
   1128     }
   1129     if (name == pluginMethodIdentifiers[ID_REMEMBER]) {
   1130         if (plugin->rememberedObject)
   1131             browser->releaseobject(plugin->rememberedObject);
   1132         plugin->rememberedObject = NPVARIANT_TO_OBJECT(args[0]);
   1133         browser->retainobject(plugin->rememberedObject);
   1134         VOID_TO_NPVARIANT(*result);
   1135         return true;
   1136     }
   1137     if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) {
   1138         assert(plugin->rememberedObject);
   1139         browser->retainobject(plugin->rememberedObject);
   1140         OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result);
   1141         return true;
   1142     }
   1143     if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) {
   1144         assert(plugin->rememberedObject);
   1145         OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result);
   1146         plugin->rememberedObject = 0;
   1147         return true;
   1148     }
   1149     if (name == pluginMethodIdentifiers[ID_REF_COUNT]) {
   1150         uint32_t refCount = NPVARIANT_TO_OBJECT(args[0])->referenceCount;
   1151         INT32_TO_NPVARIANT(refCount, *result);
   1152         return true;
   1153     }
   1154     if (name == pluginMethodIdentifiers[ID_SET_STATUS])
   1155         return testSetStatus(plugin, args, argCount, result);
   1156     if (name == pluginMethodIdentifiers[ID_RESIZE_TO])
   1157         return testResizeTo(plugin, args, argCount, result);
   1158     if (name == pluginMethodIdentifiers[ID_NORMALIZE])
   1159         return normalizeOverride(plugin, args, argCount, result);
   1160     if (name == pluginMethodIdentifiers[ID_INVALIDATE_RECT])
   1161         return invalidateRect(plugin, args, argCount, result);
   1162     if (name == pluginMethodIdentifiers[ID_OBJECTS_ARE_SAME])
   1163         return objectsAreSame(plugin, args, argCount, result);
   1164     if (name == pluginMethodIdentifiers[ID_TEST_DELETE_WITHIN_INVOKE]) {
   1165         NPObject* newObject = browser->createobject(plugin->npp, plugin->header._class);
   1166         OBJECT_TO_NPVARIANT(newObject, *result);
   1167         callDeletePlugin(header, name, pluginMethodIdentifiers[ID_TEST_DELETE_WITHIN_INVOKE]);
   1168         return true;
   1169     }
   1170     return false;
   1171 }
   1172 
   1173 static void pluginInvalidate(NPObject* header)
   1174 {
   1175     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
   1176     plugin->testObject = 0;
   1177     plugin->rememberedObject = 0;
   1178 }
   1179 
   1180 static NPObject *pluginAllocate(NPP npp, NPClass *theClass)
   1181 {
   1182     PluginObject* newInstance = (PluginObject*)malloc(sizeof(PluginObject));
   1183 
   1184     if (!identifiersInitialized) {
   1185         identifiersInitialized = true;
   1186         initializeIdentifiers();
   1187     }
   1188 
   1189     newInstance->pluginTest = 0;
   1190     newInstance->npp = npp;
   1191     newInstance->testObject = browser->createobject(npp, getTestClass());
   1192     newInstance->rememberedObject = 0;
   1193     newInstance->eventLogging = false;
   1194     newInstance->onStreamLoad = 0;
   1195     newInstance->onStreamDestroy = 0;
   1196     newInstance->onDestroy = 0;
   1197     newInstance->onURLNotify = 0;
   1198     newInstance->onSetWindow = 0;
   1199     newInstance->onPaintEvent = 0;
   1200     newInstance->logDestroy = false;
   1201     newInstance->logSetWindow = false;
   1202     newInstance->returnErrorFromNewStream = false;
   1203     newInstance->returnNegativeOneFromWrite = false;
   1204     newInstance->stream = 0;
   1205 
   1206     newInstance->firstUrl = 0;
   1207     newInstance->firstHeaders = 0;
   1208     newInstance->lastUrl = 0;
   1209     newInstance->lastHeaders = 0;
   1210 
   1211     newInstance->testGetURLOnDestroy = false;
   1212     newInstance->testWindowOpen = false;
   1213     newInstance->testKeyboardFocusForPlugins = false;
   1214 
   1215     newInstance->mouseDownForEvaluateScript = false;
   1216     newInstance->evaluateScriptOnMouseDownOrKeyDown = 0;
   1217 
   1218     return (NPObject*)newInstance;
   1219 }
   1220 
   1221 static void pluginDeallocate(NPObject* header)
   1222 {
   1223     PluginObject* plugin = reinterpret_cast<PluginObject*>(header);
   1224     delete plugin->pluginTest;
   1225     if (plugin->testObject)
   1226         browser->releaseobject(plugin->testObject);
   1227     if (plugin->rememberedObject)
   1228         browser->releaseobject(plugin->rememberedObject);
   1229 
   1230     free(plugin->firstUrl);
   1231     free(plugin->firstHeaders);
   1232     free(plugin->lastUrl);
   1233     free(plugin->lastHeaders);
   1234     free(plugin);
   1235 }
   1236 
   1237 void handleCallback(PluginObject* object, const char *url, NPReason reason, void *notifyData)
   1238 {
   1239     assert(object);
   1240 
   1241     NPVariant args[2];
   1242 
   1243     NPObject* windowScriptObject;
   1244     browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject);
   1245 
   1246     NPIdentifier callbackIdentifier = notifyData;
   1247 
   1248     INT32_TO_NPVARIANT(reason, args[0]);
   1249 
   1250     char* strHdr = 0;
   1251     if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) {
   1252         // Format expected by JavaScript validator: four fields separated by \n\n:
   1253         // First URL; first header block; last URL; last header block.
   1254         // Note that header blocks already end with \n due to how NPStream::headers works.
   1255         int len = strlen(object->firstUrl) + 2
   1256             + strlen(object->firstHeaders) + 1
   1257             + strlen(object->lastUrl) + 2
   1258             + strlen(object->lastHeaders) + 1;
   1259         strHdr = (char*)malloc(len + 1);
   1260         snprintf(strHdr, len + 1, "%s\n\n%s\n%s\n\n%s\n",
   1261                  object->firstUrl, object->firstHeaders, object->lastUrl, object->lastHeaders);
   1262         STRINGN_TO_NPVARIANT(strHdr, len, args[1]);
   1263     } else
   1264         NULL_TO_NPVARIANT(args[1]);
   1265 
   1266     NPVariant browserResult;
   1267     if (browser->invoke(object->npp, windowScriptObject, callbackIdentifier, args, 2, &browserResult))
   1268         browser->releasevariantvalue(&browserResult);
   1269 
   1270     free(strHdr);
   1271 }
   1272 
   1273 void notifyStream(PluginObject* object, const char *url, const char *headers)
   1274 {
   1275     if (!object->firstUrl) {
   1276         if (url)
   1277             object->firstUrl = strdup(url);
   1278         if (headers)
   1279             object->firstHeaders = strdup(headers);
   1280     } else {
   1281         free(object->lastUrl);
   1282         free(object->lastHeaders);
   1283         object->lastUrl = (url ? strdup(url) : 0);
   1284         object->lastHeaders = (headers ? strdup(headers) : 0);
   1285     }
   1286 }
   1287 
   1288 void testNPRuntime(NPP npp)
   1289 {
   1290     NPObject* windowScriptObject;
   1291     browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject);
   1292 
   1293     // Invoke
   1294     NPIdentifier testNPInvoke = browser->getstringidentifier("testNPInvoke");
   1295     NPVariant args[7];
   1296 
   1297     VOID_TO_NPVARIANT(args[0]);
   1298     NULL_TO_NPVARIANT(args[1]);
   1299     BOOLEAN_TO_NPVARIANT(true, args[2]);
   1300     INT32_TO_NPVARIANT(242, args[3]);
   1301     DOUBLE_TO_NPVARIANT(242.242, args[4]);
   1302     STRINGZ_TO_NPVARIANT("Hello, World", args[5]);
   1303     OBJECT_TO_NPVARIANT(windowScriptObject, args[6]);
   1304 
   1305     NPVariant result;
   1306     if (browser->invoke(npp, windowScriptObject, testNPInvoke, args, 7, &result))
   1307         browser->releasevariantvalue(&result);
   1308 
   1309     browser->releaseobject(windowScriptObject);
   1310 }
   1311