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