Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / testing / plugin / 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 <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 }