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