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