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